Create a Light class and modify the Model class to draw objects with material properties.
Details
The Light class should:
- Inherit from the - GameObjectclass so that moving and turning the light should affect the light’s position and spot direction.
- Define the default constructor - Light()that initializes a light with the with the color white, i.e. rgb = (1, 1, 1).
- Define the constructor - Light(float r, float g, float b)that initializes a light with the properties:- Ambient light turned off. 
- Diffuse and specular light set to the specified color. 
- Constant, linear, and quadratic attenuation set to 1, 0, 0, respectively. 
- Spot cutoff and exponent set to 180 and 1 respectively. 
- Position set to the origin. 
- Spot direction set down the negative z axis. 
- Light is activate, or ‘on’. 
 
- Define the setters: - void SetColor(float r, float g, float b)that sets the light’s color to the specified rgb values. The light’s color should be used for its diffuse and specular color. The light’s ambient color should be black, rgb = (0, 0, 0). The method should assert that the input values define a valid color.
- void SetSpot(float cutoff, float exponent)that sets the light’s spotlight to the specified cutoff and and exponent values. The function should assert that cutoff is a valid angle.
- void SetAttenuation(float constant, float linear, float quadratic)that sets the light’s attenuation to the specified factors. The method should assert that the input values are a valid attenuations.
- void SetActivation(bool activate)that sets whether the light is ‘on’, that is, whether it is used in lighting calcualtions for subsequent drawing.
 
Note that there is a limit of 8 lights that can be created. Creating a light after 8 have already been created should print an error and create a light that is always off. Also note that it should be possible to destroy a light and have it no longer count towards the 8 light limit.
The Model class should be updated so that:
- The - void Load(const std::string &filepath)method should:- Read Wavefront obj files that define vertex normals. It should read - vnlines- flines that specify vertices and normals.- Assume that a obj file will only specify one type of face. Either vertex only lines (i.e. f 1 2 3) or vertex and normal lines (i.e. f 1//1 2//1 3//1). 
- Read Wavefront obj files that use materials. It should handle - mtlliband- usemtllines.- The - Loadmethod should parse Phong reflectance components from mtl files. It can ignore all mtl lines that are not- Ka,- Kd,- Ks, and- Ns.- If a face does not have a material specified or if the material name can not be found, or if there is an error reading an mtl file, the default material should be used: - Ka: 0.2 0.2 0.2 
 Kd: 0.8 0.8 0.8
 Ks: 0.0 0.0 0.0
 Ns: 0.0
 Any components of a material that are not specified should be set to their values in the default material.- The the filename of an mtl file is relative to the obj file it is used in, not to the execution directory. 
 
- The - void Draw() constmethod should draw a model using materials and lights. If the model’s obj file specifies vertex only faces, then it should draw faces without lighting by using the materieal’s ambient component for the color. If the model’s obj file specifies vertex and normal faces, then it should draw faces using lighting.
Extra Credit: Drawing a model that specifies normals using glDrawElements may require duplicating vertices and/or normals to keep the vertex and normal arrays perfectly aligned. The easy way to do this is to duplicate all vertex normal pairs so that the vertex and normal lists have (num_faces * 3 * 3) elements in them. However, this will often waste memory. For extra credit, efficiently build the vertex, normal, and index arrays such that no vertex normal pairs are duplicated.
Your code can use any library in the C++ Standard Library and the OpenGL Mathematics Library.
Your code should work on the lab computers. Test to verify.
Your code should be clean, readable, and efficient. Follow the Google C++ Style Guide for help with style. Use the cpplint tool to help check your code.
All classes should be declared inside of a namespace called engine.
Your project should have the following directory structure:
project
├──data
|  ├──model1.obj
|  ├──model2.obj
|  ├──model3.obj
|  └──...
├──makefile
├──lib
|  └──glm
|     ├──gtc
|     ├──gtx
|     └──vec3.hpp
├──src
|  └──engine
|     ├──camera.cc
|     ├──camera.h
|     ├──game_object.cc
|     ├──game_object.h
|     ├──light.cc
|     ├──light.h
|     ├──model.cc
|     ├──model.h
|     ├──rigid_body.cc
|     └──rigid_body.h
└──test
   ├──test1.cc
   ├──test2.cc
   ├──test3.cc
   └──...Your project should compile and run with this makefile.
Example
  #include <cstdlib>
  #include <cstdio>
  #include "GLFW/glfw3.h"
  #include "engine/model.h"
  #include "engine/rigid_body.h"
  #include "engine/camera.h"
  #include "engine/light.h"
  int main() {
    // Initialize GLFW
    if (!glfwInit()) {
      fprintf(stderr, "Failed to initialize GLFW\n");
      exit(EXIT_FAILURE);
    }
    // Create window
    GLFWwindow* window = glfwCreateWindow(640, 480, "Test", NULL, NULL);
    if (!window) {
      glfwTerminate();
      exit(EXIT_FAILURE);
    }
    glfwMakeContextCurrent(window);
    // Initialize OpenGL
    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    glEnable(GL_DEPTH_TEST);
    // create rigid body and camera
    engine::Model model("data/model.obj");
    engine::RigidBody rigidBody(&model);
    engine::Camera camera(35.0f, 0.1f, 10.0f);
    camera.LookAt(glm::vec3(0.0f, 0.0f, 5.0f),   // eye
                  glm::vec3(0.0f, 0.0f, 0.0f),   // center
                  glm::vec3(0.0f, 1.0f, 0.0f));  // up
    engine::Light light(1.0f, 1.0f, 1.0f);
    light.SetPosition(glm::vec3(0.0f, 0.0f, 10.0f));
    // Loop until the user closes the window
    while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
           !glfwWindowShouldClose(window)) {
      // Set the rendering viewport
      int width, height;
      glfwGetFramebufferSize(window, &width, &height);
      glViewport(0, 0, width, height);
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      // Select and setup the projection matrix
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();
      camera.MultProjectionMatrix(width, height);
      // Select and setup the view matrix
      glMatrixMode(GL_MODELVIEW);
      glPushMatrix();
      camera.MultViewMatrix();
      // Rotate and draw rigid body
      rigidBody.Turn(10.0f, glm::vec3(0.0f, 1.0f, 0.0f));  // 10 deg around y axis
      rigidBody.Draw();
      // Prepare for next frame
      glPopMatrix();
      glfwSwapBuffers(window);
      glfwPollEvents();
    }
    // Clean up
    glfwDestroyWindow(window);
    glfwTerminate();
    exit(EXIT_SUCCESS);
  }Grading
The functionality of your code will be graded according to the following point scale:
| 1 | draw a model with vertex only faces and a material | 5 points | 
| 2 | draw a model with vertex and normal faces and an ambient material | 5 points | 
| 3 | draw a model with vertex and normal faces and a diffuse material | 5 points | 
| 4 | draw a model with vertex and normal faces and a specular material | 5 points | 
| 5 | draw a model with vertex and normal faces and a specular shiny material | 5 points | 
| 6 | draw a model with vertex and normal faces and a ambient, diffuse, and specular material | 5 points | 
| 7 | draw a model with multiple different materials | 5 points | 
| 8 | draw a model with default material | 5 points | 
| 9 | draw a model with default material components | 5 points | 
| 10 | draw a model with multiple material libraries | 5 points | 
| 11 | draw a model with the default light | 5 points | 
| 12 | draw a model with a colored light | 5 points | 
| 13 | draw a model with a light with a changed color | 5 points | 
| 14 | draw a model with a spot light | 5 points | 
| 15 | draw a model with a turned spot light | 5 points | 
| 16 | draw a model with an attenuated light | 5 points | 
| 17 | draw a model with an deactivated light | 5 points | 
| 18 | draw a model with multiple lights | 5 points | 
| 19 | draw a model with 9 lights | 5 points | 
| 20 | draw a model after destroying a light and creating 8 lights | 5 points | 
The final grade for this part of the project will be computed as:
const double final_score = fmin(fmax(functionality_score - (days_late / 21.0 * 100.0), 0.0), 125.0);Submission
Submit a .zip file with the following structure and contents:
username
├──camera.cc
├──camera.h
├──game_object.cc
├──game_object.h
├──light.cc
├──light.h
├──model.cc
├──model.h
├──rigid_body.cc
└──rigid_body.hwhere username is your cpsc user name.
Submit your .zip file on Inquire on Friday, April 3rd.