Index: .gitignore
===================================================================
--- .gitignore	(revision 49756cbc360e89ed36ddedbcedeb7ad5a5f43c24)
+++ .gitignore	(revision 9e81839edff77dc59eb5269483c3d2c2edaf631d)
@@ -1,4 +1,5 @@
 newgame
-game
+pong
+mygame
 demo
 
Index: makefile
===================================================================
--- makefile	(revision 49756cbc360e89ed36ddedbcedeb7ad5a5f43c24)
+++ makefile	(revision 9e81839edff77dc59eb5269483c3d2c2edaf631d)
@@ -13,4 +13,7 @@
 	$(CC) $? $(DEP) $(CFLAGS) -o $@
 
+pong: pong.cpp logger.cpp
+	$(CC) $? $(DEP) $(CFLAGS) -o $@
+
 mygame: mygame.cpp common/shader.cpp common/texture.cpp common/controls-new.cpp
 	$(CC) $? $(DEP) $(CFLAGS) -o $@
@@ -21,4 +24,5 @@
 clean:
 	rm -f newgame
+	rm -f pong
 	rm -f mygame
 	rm -f demo
Index: pong.cpp
===================================================================
--- pong.cpp	(revision 9e81839edff77dc59eb5269483c3d2c2edaf631d)
+++ pong.cpp	(revision 9e81839edff77dc59eb5269483c3d2c2edaf631d)
@@ -0,0 +1,223 @@
+#include "logger.h"
+
+#include <GL/glew.h>
+#include <GLFW/glfw3.h>
+
+#include <cstdio>
+#include <iostream>
+#include <fstream>
+#include <cmath>
+
+using namespace std;
+
+GLuint loadShader(GLenum type, string file);
+GLuint createDataBuffer(size_t size, GLfloat* data);
+GLuint createArrayBuffer(GLuint points_vbo, GLuint colors_vbo);
+
+const bool FULLSCREEN = false;
+
+void glfw_error_callback(int error, const char* description) {
+   gl_log_err("GLFW ERROR: code %i msg: %s\n", error, description);
+}
+
+int main(int argc, char* argv[]) {
+   cout << "New OpenGL Game" << endl;
+
+   if (!restart_gl_log()) {}
+   gl_log("starting GLFW\n%s\n", glfwGetVersionString());
+
+   glfwSetErrorCallback(glfw_error_callback);
+   if (!glfwInit()) {
+      fprintf(stderr, "ERROR: could not start GLFW3\n");
+      return 1;
+   }
+
+#ifdef __APPLE__
+   glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+   glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+   glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+   glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+#endif
+
+   glfwWindowHint(GLFW_SAMPLES, 4);
+
+   GLFWwindow* window = NULL;
+
+   int width = 640;
+   int height = 480;
+
+   if (FULLSCREEN) {
+      GLFWmonitor* mon = glfwGetPrimaryMonitor();
+      const GLFWvidmode* vmode = glfwGetVideoMode(mon);
+
+      cout << "Fullscreen resolution " << vmode->width << "x" << vmode->height << endl;
+      window = glfwCreateWindow(vmode->width, vmode->height, "Extended GL Init", mon, NULL);
+
+      width = vmode->width;
+      height = vmode->height;
+   } else {
+      window = glfwCreateWindow(width, height, "Hello Triangle", NULL, NULL);
+   }
+
+   if (!window) {
+      fprintf(stderr, "ERROR: could not open window with GLFW3\n");
+      glfwTerminate();
+      return 1;
+   }
+   glfwMakeContextCurrent(window);
+   glewExperimental = GL_TRUE;
+   glewInit();
+
+   // glViewport(0, 0, width*2, height*2);
+
+   const GLubyte* renderer = glGetString(GL_RENDERER);
+   const GLubyte* version = glGetString(GL_VERSION);
+   printf("Renderer: %s\n", renderer);
+   printf("OpenGL version supported %s\n", version);
+
+   glEnable(GL_DEPTH_TEST);
+   glDepthFunc(GL_LESS);
+
+   glEnable(GL_CULL_FACE);
+   // glCullFace(GL_BACK);
+   // glFrontFace(GL_CW);
+
+   GLfloat points[] = {
+       0.0f,  0.5f,  0.5f,
+      -0.5f, -0.5f,  0.5f,
+       0.5f, -0.5f,  0.5f,
+   };
+
+   GLfloat colors[] = {
+      1.0, 0.0, 0.0,
+      0.0, 0.0, 1.0,
+      0.0, 1.0, 0.0,
+   };
+
+   GLfloat points_paddle[] = {
+       0.0f, -0.5f,  0.0f,
+       0.5f,  0.5f,  0.0f,
+      -0.5f,  0.5f,  0.0f,
+   };
+
+   GLfloat colors_paddle[] = {
+      1.0, 0.0, 0.0,
+      0.0, 0.0, 1.0,
+      0.0, 1.0, 0.0,
+   };
+
+   GLfloat model[] = {
+     1.0f, 0.0f, 0.0f, 0.0f, // column 1
+     0.0f, 1.0f, 0.0f, 0.0f, // column 2
+     0.0f, 0.0f, 1.0f, 0.0f, // column 3
+     0.5f, 0.0f, 0.0f, 1.0f, // column 4
+   };
+
+   GLuint ball_points_vbo = createDataBuffer(sizeof(points), points);
+   GLuint ball_colors_vbo = createDataBuffer(sizeof(colors), colors);
+   GLuint ball_vao = createArrayBuffer(ball_points_vbo, ball_colors_vbo);
+
+   GLuint paddle_points_vbo = createDataBuffer(sizeof(points_paddle), points_paddle);
+   GLuint paddle_colors_vbo = createDataBuffer(sizeof(colors_paddle), colors_paddle);
+   GLuint paddle_vao = createArrayBuffer(paddle_points_vbo, paddle_colors_vbo);
+
+   GLuint vs = loadShader(GL_VERTEX_SHADER, "./test.vert");
+   GLuint fs = loadShader(GL_FRAGMENT_SHADER, "./test.frag");
+
+   GLuint shader_program = glCreateProgram();
+   glAttachShader(shader_program, vs);
+   glAttachShader(shader_program, fs);
+
+   glLinkProgram(shader_program);
+
+   GLint location = glGetUniformLocation(shader_program, "model");
+
+   float speed = 1.0f;
+   float last_position = 0.0f;
+
+   double previous_seconds = glfwGetTime();
+   while (!glfwWindowShouldClose(window)) {
+      double current_seconds = glfwGetTime();
+      double elapsed_seconds = current_seconds - previous_seconds;
+      previous_seconds = current_seconds;
+
+      if (fabs(last_position) > 1.0f) {
+         speed = -speed;
+      }
+
+      model[12] = last_position + speed*elapsed_seconds;
+      last_position = model[12];
+      glUseProgram(shader_program);
+      glUniformMatrix4fv(location, 1, GL_FALSE, model);
+
+      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+      glBindVertexArray(ball_vao);
+      glEnableVertexAttribArray(0);
+      glEnableVertexAttribArray(1);
+
+      glDrawArrays(GL_TRIANGLES, 0, 3);
+
+      glBindVertexArray(paddle_vao);
+      glEnableVertexAttribArray(0);
+      glEnableVertexAttribArray(1);
+
+      glDrawArrays(GL_TRIANGLES, 0, 3);
+
+      glfwPollEvents();
+      glfwSwapBuffers(window);
+
+      if (GLFW_PRESS == glfwGetKey(window, GLFW_KEY_ESCAPE)) {
+         glfwSetWindowShouldClose(window, 1);
+      }
+   }
+
+   glfwTerminate();
+   return 0;
+}
+
+GLuint loadShader(GLenum type, string file) {
+  cout << "Loading shader from file " << file << endl;
+
+  ifstream shaderFile(file);
+  GLuint shaderId = 0;
+
+  if (shaderFile.is_open()) {
+    string line, shaderString;
+
+    while(getline(shaderFile, line)) {
+      shaderString += line + "\n";
+    }
+    shaderFile.close();
+    const char* shaderCString = shaderString.c_str();
+
+    shaderId = glCreateShader(type);
+    glShaderSource(shaderId, 1, &shaderCString, NULL);
+    glCompileShader(shaderId);
+
+    cout << "Loaded successfully" << endl;
+  } else {
+    cout << "Failed to loade the file" << endl;
+  }
+
+  return shaderId;
+}
+
+GLuint createDataBuffer(size_t size, GLfloat* data) {
+   GLuint vbo = 0;
+   glGenBuffers(1, &vbo);
+   glBindBuffer(GL_ARRAY_BUFFER, vbo);
+   glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
+   return vbo;
+}
+
+GLuint createArrayBuffer(GLuint points_vbo, GLuint colors_vbo) {
+   GLuint vao = 0;
+   glGenVertexArrays(1, &vao);
+   glBindVertexArray(vao);
+   glBindBuffer(GL_ARRAY_BUFFER, points_vbo);
+   glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
+   glBindBuffer(GL_ARRAY_BUFFER, colors_vbo);
+   glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
+   return vao;
+}
