Index: color.frag
===================================================================
--- color.frag	(revision d9f99b2bd20ab9dfaaeeb06cf3ea011c3142f431)
+++ color.frag	(revision 9dd2eb7b9fc69fc00d38e477a9530e48cc6ccf0e)
@@ -1,9 +1,37 @@
 #version 410
 
-in vec3 color;
+in vec3 position_eye, normal_eye, color, light_position_eye;
 
 out vec4 frag_color;
 
+// fixed point light properties
+vec3 Ls = vec3(1.0, 1.0, 1.0); // white specular colour
+vec3 Ld = vec3(0.7, 0.7, 0.7); // dull white diffuse light colour
+vec3 La = vec3(0.2, 0.2, 0.2); // grey ambient colour
+
+// surface reflectance
+vec3 Ks = vec3(1.0, 1.0, 1.0); // fully reflect specular light
+vec3 Kd = vec3(1.0, 0.5, 0.0); // orange diffuse surface reflectance
+vec3 Ka = vec3(0.2, 0.2, 0.2); // fully reflect ambient light
+float specular_exponent = 100.0; // specular 'power'
+
 void main() {
-  frag_color = vec4(color, 1.0);
+  // ambient intensity
+  vec3 Ia = La * Ka;
+
+  vec3 direction_to_light_eye = normalize(light_position_eye - position_eye);
+  float dot_prod = max(dot(direction_to_light_eye, normal_eye), 0.0);
+
+  // diffuse intensity
+  vec3 Id = Ls * color * dot_prod;
+
+  vec3 reflection_eye = reflect(-direction_to_light_eye, normal_eye);
+  vec3 surface_to_viewer_eye = normalize(-position_eye);
+  float dot_prod_specular = max(dot(reflection_eye, surface_to_viewer_eye), 0.0);
+  float specular_factor = pow(dot_prod_specular, specular_exponent);
+
+  // specular intensity
+  vec3 Is = Ls * Ks * specular_factor;
+
+  frag_color = vec4(Is + Id + Ia, 1.0);
 }
Index: color.vert
===================================================================
--- color.vert	(revision d9f99b2bd20ab9dfaaeeb06cf3ea011c3142f431)
+++ color.vert	(revision 9dd2eb7b9fc69fc00d38e477a9530e48cc6ccf0e)
@@ -5,9 +5,17 @@
 layout(location = 0) in vec3 vertex_position;
 layout(location = 1) in vec3 vertex_color;
+layout(location = 2) in vec3 vertex_normal;
 
-out vec3 color;
+out vec3 position_eye, normal_eye, color, light_position_eye;
+
+// fixed point light position
+vec3 light_position_world = vec3(0.0, 0.0, 2.0);
 
 void main() {
+  position_eye = vec3(view * model * vec4(vertex_position, 1.0));
+  normal_eye = vec3(view * model * vec4 (vertex_normal, 0.0));
   color = vertex_color;
-  gl_Position = proj * view * model * vec4(vertex_position, 1.0);
+  light_position_eye = vec3(view * vec4(light_position_world, 1.0));
+
+  gl_Position = proj * vec4(position_eye, 1.0);
 }
Index: new-game.cpp
===================================================================
--- new-game.cpp	(revision d9f99b2bd20ab9dfaaeeb06cf3ea011c3142f431)
+++ new-game.cpp	(revision 9dd2eb7b9fc69fc00d38e477a9530e48cc6ccf0e)
@@ -40,4 +40,5 @@
    vector<GLfloat> colors;
    vector<GLfloat> texcoords;
+   vector<GLfloat> normals;
    vector<GLfloat> selected_colors;
 };
@@ -240,4 +241,12 @@
       1.0f, 0.0f
    };
+   objects[0].normals = {
+       0.0f,  0.0f,  1.0f,
+       0.0f,  0.0f,  1.0f,
+       0.0f,  0.0f,  1.0f,
+       0.0f,  0.0f, -1.0f,
+       0.0f,  0.0f, -1.0f,
+       0.0f,  0.0f, -1.0f,
+   };
    objects[0].selected_colors = {
       0.0f, 1.0f, 0.0f,
@@ -284,4 +293,12 @@
       1.0f, 0.0f
    };
+   objects[1].normals = {
+      0.0f,  0.0f,  1.0f,
+      0.0f,  0.0f,  1.0f,
+      0.0f,  0.0f,  1.0f,
+      0.0f,  0.0f,  1.0f,
+      0.0f,  0.0f,  1.0f,
+      0.0f,  0.0f,  1.0f,
+   };
    objects[1].selected_colors = {
       0.0f, 0.9f, 0.9f,
@@ -353,4 +370,15 @@
    }
 
+   GLuint normals_vbo = 0;
+   glGenBuffers(1, &normals_vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
+   glBufferData(GL_ARRAY_BUFFER, points_buffer_size, NULL, GL_DYNAMIC_DRAW);
+
+   offset = 0;
+   for (obj_it = objects.begin(); obj_it != objects.end(); obj_it++) {
+      glBufferSubData(GL_ARRAY_BUFFER, offset, obj_it->normals.size() * sizeof(GLfloat), &obj_it->normals[0]);
+      offset += obj_it->normals.size() * sizeof(GLfloat);
+   }
+
    GLuint vao = 0;
    glGenVertexArrays(1, &vao);
@@ -359,4 +387,5 @@
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
+   glEnableVertexAttribArray(2);
 
    GLuint vao2 = 0;
@@ -366,4 +395,5 @@
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
+   glEnableVertexAttribArray(2);
 
    // I can create a vbo to store all points for all models,
@@ -459,4 +489,7 @@
    double previous_seconds = glfwGetTime();
 
+   // This draws wireframes. Useful for seeing separate faces and occluded objects.
+   //glPolygonMode(GL_FRONT, GL_LINE);
+
    while (!glfwWindowShouldClose(window)) {
       double current_seconds = glfwGetTime();
@@ -535,4 +568,7 @@
          glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, objects[*it].vertex_vbo_offset);
 
+         glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
+         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, objects[*it].vertex_vbo_offset);
+
          glDrawArrays(GL_TRIANGLES, 0, objects[*it].num_points);
       }
@@ -549,4 +585,7 @@
          glBindBuffer(GL_ARRAY_BUFFER, texcoords_vbo);
          glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, objects[*it].texture_vbo_offset);
+
+         glBindBuffer(GL_ARRAY_BUFFER, normals_vbo);
+         glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, objects[*it].vertex_vbo_offset);
 
          glDrawArrays(GL_TRIANGLES, 0, objects[*it].num_points);
Index: opengl-notes.txt
===================================================================
--- opengl-notes.txt	(revision d9f99b2bd20ab9dfaaeeb06cf3ea011c3142f431)
+++ opengl-notes.txt	(revision 9dd2eb7b9fc69fc00d38e477a9530e48cc6ccf0e)
@@ -1,5 +1,5 @@
 Default bounds
 
-           1   1
+           1   -1
           |   /
           |  /
@@ -11,5 +11,5 @@
        /  |
       /   |
-     -1   -1
+     1    -1
 
 Matrices
Index: texture.frag
===================================================================
--- texture.frag	(revision d9f99b2bd20ab9dfaaeeb06cf3ea011c3142f431)
+++ texture.frag	(revision 9dd2eb7b9fc69fc00d38e477a9530e48cc6ccf0e)
@@ -4,9 +4,39 @@
 
 in vec2 texture_coordinates;
+in vec3 position_eye, normal_eye, light_position_eye;
 
 out vec4 frag_color;
 
+// fixed point light properties
+vec3 Ls = vec3(1.0, 1.0, 1.0); // white specular colour
+vec3 Ld = vec3(0.7, 0.7, 0.7); // dull white diffuse light colour
+vec3 La = vec3(0.2, 0.2, 0.2); // grey ambient colour
+
+// surface reflectance
+vec3 Ks = vec3(1.0, 1.0, 1.0); // fully reflect specular light
+vec3 Kd = vec3(1.0, 0.5, 0.0); // orange diffuse surface reflectance
+vec3 Ka = vec3(0.2, 0.2, 0.2); // fully reflect ambient light
+float specular_exponent = 100.0; // specular 'power'
+
 void main() {
   vec4 texel = texture(basic_texture, texture_coordinates);
-  frag_color = texel;
+
+  // ambient intensity
+  vec3 Ia = La * Ka;
+
+  vec3 direction_to_light_eye = normalize(light_position_eye - position_eye);
+  float dot_prod = max(dot(direction_to_light_eye, normal_eye), 0.0);
+
+  // diffuse intensity
+  vec3 Id = Ls * vec3(texel) * dot_prod;
+
+  vec3 reflection_eye = reflect(-direction_to_light_eye, normal_eye);
+  vec3 surface_to_viewer_eye = normalize(-position_eye);
+  float dot_prod_specular = max(dot(reflection_eye, surface_to_viewer_eye), 0.0);
+  float specular_factor = pow(dot_prod_specular, specular_exponent);
+
+  // specular intensity
+  vec3 Is = Ls * Ks * specular_factor;
+
+  frag_color = vec4(Is + Id + Ia, 1.0);
 }
Index: texture.vert
===================================================================
--- texture.vert	(revision d9f99b2bd20ab9dfaaeeb06cf3ea011c3142f431)
+++ texture.vert	(revision 9dd2eb7b9fc69fc00d38e477a9530e48cc6ccf0e)
@@ -5,9 +5,18 @@
 layout(location = 0) in vec3 vertex_position;
 layout(location = 1) in vec2 vt;
+layout(location = 2) in vec3 vertex_normal;
 
 out vec2 texture_coordinates;
+out vec3 position_eye, normal_eye, light_position_eye;
+
+// fixed point light position
+vec3 light_position_world = vec3(0.0, 0.0, 2.0);
 
 void main() {
+  position_eye = vec3(view * model * vec4(vertex_position, 1.0));
+  normal_eye = vec3(view * model * vec4 (vertex_normal, 0.0));
   texture_coordinates = vt;
-  gl_Position = proj * view * model * vec4(vertex_position, 1.0);
+  light_position_eye = vec3(view * vec4(light_position_world, 1.0));
+
+  gl_Position = proj * vec4(position_eye, 1.0);
 }
