text: #include "glitter.hpp"
  
  namespace gl_examples
  {
      int MaterialProgram()
      {
          // glfw: initialize and configure
          // ------------------------------
          glfwInit();
          glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
          glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
          glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
  
  #ifdef __APPLE__
          glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
  #endif
  
          // glfw window creation
          // --------------------
          GLFWwindow *window = glfwCreateWindow(mWidth, mHeight, "LearnOpenGL", NULL, NULL);
          if (window == NULL)
          {
              std::cout << "Failed to create GLFW window" << std::endl;
              glfwTerminate();
              return -1;
          }
          glfwMakeContextCurrent(window);
          glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
          glfwSetCursorPosCallback(window, mouse_callback);
          glfwSetScrollCallback(window, scroll_callback);
  
          // tell GLFW to capture our mouse
          glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
  
          // glad: load all OpenGL function pointers
          // ---------------------------------------
          if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
          {
              std::cout << "Failed to initialize GLAD" << std::endl;
              return -1;
          }
  
          glEnable(GL_DEPTH_TEST);
  
          Shader lightingShader("2.2.2.basic_lighting.vert", "2.3.1.materials.frag");
          Shader lightCubeShader("2.1.1.colors.vert", "2.1.1.light_cube.frag");
  
          // configure global opengl state
          // set up vertex data (and buffer(s)) and configure vertex attributes
          // ------------------------------------------------------------------
          float vertices[] = {
              -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
              0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
              0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
              0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
              -0.5f, 0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
              -0.5f, -0.5f, -0.5f, 0.0f, 0.0f, -1.0f,
  
              -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
              0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
              0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
              0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
              -0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
              -0.5f, -0.5f, 0.5f, 0.0f, 0.0f, 1.0f,
  
              -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
              -0.5f, 0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
              -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
              -0.5f, -0.5f, -0.5f, -1.0f, 0.0f, 0.0f,
              -0.5f, -0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
              -0.5f, 0.5f, 0.5f, -1.0f, 0.0f, 0.0f,
  
              0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
              0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
              0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
              0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
              0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
              0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f,
  
              -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
              0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
              0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
              0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
              -0.5f, -0.5f, 0.5f, 0.0f, -1.0f, 0.0f,
              -0.5f, -0.5f, -0.5f, 0.0f, -1.0f, 0.0f,
  
              -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
              0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
              0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
              0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
              -0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f,
              -0.5f, 0.5f, -0.5f, 0.0f, 1.0f, 0.0f};
  
          glm::vec3 lightPos(1.2f, 1.0f, 2.0f);
  
          // first, configure the cube's VAO (and VBO)
          unsigned int VBO, cubeVAO;
          glGenVertexArrays(1, &cubeVAO);
          glGenBuffers(1, &VBO);
  
          glBindBuffer(GL_ARRAY_BUFFER, VBO);
          glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
  
          glBindVertexArray(cubeVAO);
  
          // position attribute
          glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
          glEnableVertexAttribArray(0);
  
          // normal attribute
          glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)(3 * sizeof(float)));
          glEnableVertexAttribArray(1);
  
          unsigned int lightCubeVAO;
          glGenVertexArrays(1, &lightCubeVAO);
          glBindVertexArray(lightCubeVAO);
  
          glBindBuffer(GL_ARRAY_BUFFER, VBO);
  
          glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void *)0);
          glEnableVertexAttribArray(0);
  
          while (!glfwWindowShouldClose(window))
          {
              float currentFrame = glfwGetTime();
              deltaTime = currentFrame - lastFrame;
              lastFrame = currentFrame;
  
              // input
              processInput(window);
  
              //render
              glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
              glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  
              // be sure to activate shader when setting uniforms/drawing objects
              lightingShader.use();
              lightingShader.setVec3("light.position", lightPos);
              lightingShader.setVec3("viewPos", camera.Position);
  
              // light properties
              glm::vec3 lightColor;
              lightColor.x = sin(glfwGetTime() * 2.0f);
              lightColor.y = sin(glfwGetTime() * 0.7f);
              lightColor.z = sin(glfwGetTime() * 1.3f);
              glm::vec3 diffuseColor = lightColor * glm::vec3(0.5f);
              glm::vec3 ambientColor = diffuseColor * glm::vec3(0.2f);
              lightingShader.setVec3("light.ambient", ambientColor);
              lightingShader.setVec3("light.diffuse", diffuseColor);
              lightingShader.setVec3("light.specular", 1.0f, 1.0f, 1.0f);
  
              // material properties
              lightingShader.setVec3("material.ambient", 1.0f, 0.5f, 0.31f);
              lightingShader.setVec3("material.diffuse", 1.0f, 0.5f, 0.31f);
              lightingShader.setVec3("material.specular", 0.5f, 0.5f, 0.5f);
              lightingShader.setFloat("material.shiness", 32.0f);
  
              // view/projection transformations
              glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)mWidth / (float)mHeight, 0.1f, 100.0f);
              glm::mat4 view = camera.GetViewMatrix();
              lightingShader.setMat4("projection", projection);
              lightingShader.setMat4("view", view);
  
              // world transformation
              glm::mat4 model = glm::mat4(1.0f);
              lightingShader.setMat4("model", model);
  
              // render the cube
              glBindVertexArray(cubeVAO);
              glDrawArrays(GL_TRIANGLES, 0, 36);
  
              // also draw the lamp object
              lightCubeShader.use();
              lightCubeShader.setMat4("projection", projection);
              lightCubeShader.setMat4("view", view);
              model = glm::mat4(1.0f);
              model = glm::translate(model, lightPos);
              model = glm::scale(model, glm::vec3(0.2f));
              lightCubeShader.setMat4("model", model);
  
              glBindVertexArray(lightCubeVAO);
              glDrawArrays(GL_TRIANGLES, 0, 36);
  
              glfwSwapBuffers(window);
              glfwPollEvents();
          }
  
          glDeleteVertexArrays(1, &cubeVAO);
          glDeleteVertexArrays(1, &lightCubeVAO);
          glDeleteBuffers(1, &VBO);
  
          glfwTerminate();
          return 0;
      }
  } // namespace gl_examples