@Override
  protected boolean render(GL gl) {

    GL4 gl4 = (GL4) gl;

    FloatUtil.makePerspective(
        projection,
        0,
        true,
        (float) Math.PI * 0.25f,
        (float) windowSize.x / windowSize.y,
        0.1f,
        100.0f);
    view = view();
    FloatUtil.makeIdentity(model);
    FloatUtil.multMatrix(projection, view);
    FloatUtil.multMatrix(projection, model);

    for (int i = 0; i < projection.length; i++) {
      mvp[i] = projection[i];
    }

    gl4.glProgramUniformMatrix4dv(
        programName[Program.VERT.ordinal()], uniformMvp, 1, false, mvp, 0);
    gl4.glProgramUniform4dv(
        programName[Program.FRAG.ordinal()],
        uniformDiffuse,
        1,
        new double[] {1.0f, 0.5f, 0.0f, 1.0f},
        0);

    gl4.glViewportIndexedfv(0, new float[] {0, 0, windowSize.x, windowSize.y}, 0);
    gl4.glClearBufferfv(GL_COLOR, 0, new float[] {0.0f, 0.0f, 0.0f, 0.0f}, 0);

    gl4.glBindProgramPipeline(pipelineName[0]);

    gl4.glBindVertexArray(vertexArrayName[0]);
    gl4.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bufferName[Buffer.ELEMENT.ordinal()]);
    gl4.glDrawElementsInstancedBaseVertex(GL_TRIANGLES, elementCount, GL_UNSIGNED_SHORT, 0, 1, 0);

    return true;
  }
  @Override
  protected boolean render(GL gl) {

    GL4 gl4 = (GL4) gl;

    {
      gl4.glBindBuffer(GL_UNIFORM_BUFFER, bufferName.get(Buffer.TRANSFORM));
      ByteBuffer pointer =
          gl4.glMapBufferRange(
              GL_UNIFORM_BUFFER, 0, Mat4.SIZE, GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT);

      Mat4 projection =
          glm.perspectiveFov_((float) Math.PI * 0.25f, windowSize.x, windowSize.y, 0.1f, 100.0f);
      Mat4 model = new Mat4(1.0f);

      pointer.asFloatBuffer().put(projection.mul(viewMat4()).mul(model).toFa_());

      // Make sure the uniform buffer is uploaded
      gl4.glUnmapBuffer(GL_UNIFORM_BUFFER);
    }

    gl4.glViewportIndexedf(0, 0, 0, windowSize.x, windowSize.y);
    gl4.glClearBufferfv(GL_COLOR, 0, new float[] {1.0f, 0.5f, 0.0f, 1.0f}, 0);

    gl4.glBindProgramPipeline(pipelineName.get(0));
    gl4.glActiveTexture(GL_TEXTURE0);
    gl4.glBindTexture(GL_TEXTURE_2D_ARRAY, textureName.get(0));
    gl4.glBindVertexArray(vertexArrayName.get(0));
    gl4.glBindBufferBase(
        GL_UNIFORM_BUFFER, Semantic.Uniform.TRANSFORM0, bufferName.get(Buffer.TRANSFORM));

    gl4.glDrawElementsInstancedBaseVertexBaseInstance(
        GL_TRIANGLES, elementCount, GL_UNSIGNED_SHORT, 0, 1, 0, 0);

    return true;
  }