@Override
  protected void reshape(int width, int height) {
    MatrixStack persMatrix = new MatrixStack();
    persMatrix.perspective(45.0f, (width / (float) height), zNear, zFar);

    ProjectionBlock projData = new ProjectionBlock();
    projData.cameraToClipMatrix = persMatrix.top();

    glBindBuffer(GL_UNIFORM_BUFFER, projectionUniformBuffer);
    glBufferSubData(GL_UNIFORM_BUFFER, 0, projData.fillAndFlipBuffer(mat4Buffer));
    glBindBuffer(GL_UNIFORM_BUFFER, 0);

    glViewport(0, 0, width, height);
  }
  private void initializePrograms() {
    smoothInterp = loadProgram("SmoothVertexColors.vert", "SmoothVertexColors.frag");
    linearInterp = loadProgram("NoCorrectVertexColors.vert", "NoCorrectVertexColors.frag");

    MatrixStack persMatrix = new MatrixStack();
    persMatrix.perspective(60.0f, 1.0f, zNear, zFar);

    glUseProgram(smoothInterp.theProgram);
    glUniformMatrix4(
        smoothInterp.cameraToClipMatrixUnif, false, persMatrix.top().fillAndFlipBuffer(mat4Buffer));
    glUseProgram(linearInterp.theProgram);
    glUniformMatrix4(
        linearInterp.cameraToClipMatrixUnif, false, persMatrix.top().fillAndFlipBuffer(mat4Buffer));
    glUseProgram(0);
  }
  @Override
  protected void display() {
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glClearDepth(1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    MatrixStack modelMatrix = new MatrixStack();
    modelMatrix.setMatrix(viewPole.calcMatrix());

    Vec4 lightDirCameraSpace = Mat4.mul(modelMatrix.top(), lightDirection);

    glUseProgram(whiteDiffuseColor.theProgram);
    glUniform3(whiteDiffuseColor.dirToLightUnif, lightDirCameraSpace.fillAndFlipBuffer(vec4Buffer));
    glUseProgram(vertexDiffuseColor.theProgram);
    glUniform3(
        vertexDiffuseColor.dirToLightUnif, lightDirCameraSpace.fillAndFlipBuffer(vec4Buffer));
    glUseProgram(0);

    {
      modelMatrix.push();

      // Render the ground plane.
      {
        modelMatrix.push();

        glUseProgram(whiteDiffuseColor.theProgram);
        glUniformMatrix4(
            whiteDiffuseColor.modelToCameraMatrixUnif,
            false,
            modelMatrix.top().fillAndFlipBuffer(mat4Buffer));
        Mat3 normMatrix = new Mat3(modelMatrix.top());
        glUniformMatrix3(
            whiteDiffuseColor.normalModelToCameraMatrixUnif,
            false,
            normMatrix.fillAndFlipBuffer(mat3Buffer));
        glUniform4f(whiteDiffuseColor.lightIntensityUnif, 1.0f, 1.0f, 1.0f, 1.0f);
        planeMesh.render();
        glUseProgram(0);

        modelMatrix.pop();
      }

      // Render the Cylinder
      {
        modelMatrix.push();

        modelMatrix.applyMatrix(objtPole.calcMatrix());

        if (drawColoredCyl) {
          glUseProgram(vertexDiffuseColor.theProgram);
          glUniformMatrix4(
              vertexDiffuseColor.modelToCameraMatrixUnif,
              false,
              modelMatrix.top().fillAndFlipBuffer(mat4Buffer));
          Mat3 normMatrix = new Mat3(modelMatrix.top());
          glUniformMatrix3(
              vertexDiffuseColor.normalModelToCameraMatrixUnif,
              false,
              normMatrix.fillAndFlipBuffer(mat3Buffer));
          glUniform4f(vertexDiffuseColor.lightIntensityUnif, 1.0f, 1.0f, 1.0f, 1.0f);
          cylinderMesh.render("lit-color");
        } else {
          glUseProgram(whiteDiffuseColor.theProgram);
          glUniformMatrix4(
              whiteDiffuseColor.modelToCameraMatrixUnif,
              false,
              modelMatrix.top().fillAndFlipBuffer(mat4Buffer));
          Mat3 normMatrix = new Mat3(modelMatrix.top());
          glUniformMatrix3(
              whiteDiffuseColor.normalModelToCameraMatrixUnif,
              false,
              normMatrix.fillAndFlipBuffer(mat3Buffer));
          glUniform4f(whiteDiffuseColor.lightIntensityUnif, 1.0f, 1.0f, 1.0f, 1.0f);
          cylinderMesh.render("lit");
        }

        glUseProgram(0);

        modelMatrix.pop();
      }

      modelMatrix.pop();
    }
  }