Esempio n. 1
0
int main () {
	GLFWwindow* window = NULL;
	const GLubyte* renderer;
	const GLubyte* version;
	GLuint shader_programme;
	GLuint vao;

	//
	// Start OpenGL using helper libraries
	// --------------------------------------------------------------------------
	if (!glfwInit ()) {
		fprintf (stderr, "ERROR: could not start GLFW3\n");
		return 1;
	}

	/* change to 3.2 if on Apple OS X
	glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 0);
	glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); */

	window = glfwCreateWindow (gl_width, gl_height, "Spinning Cube", NULL, NULL);
	if (!window) {
		fprintf (stderr, "ERROR: opening OS window\n");
		return 1;
	}
	glfwMakeContextCurrent (window);

	glewExperimental = GL_TRUE;
	glewInit ();

	/* get version info */
	renderer = glGetString (GL_RENDERER); /* get renderer string */
	version = glGetString (GL_VERSION); /* version as a string */
	printf ("Renderer: %s\n", renderer);
	printf ("OpenGL version supported %s\n", version);

	int point_count = 0;
	//
	// Set up vertex buffers and vertex array object
	// --------------------------------------------------------------------------
	{
		GLfloat* vp = NULL; // array of vertex points
		GLfloat* vn = NULL; // array of vertex normals (we haven't used these yet)
		GLfloat* vt = NULL; // array of texture coordinates (or these)
		assert (load_obj_file ("cube.obj", vp, vt, vn, point_count));


		GLuint points_vbo, texcoord_vbo;
		glGenBuffers (1, &points_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
		// copy our points from the header file into our VBO on graphics hardware
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 3 * point_count,
			vp, GL_STATIC_DRAW);
		// and grab the normals
		glGenBuffers (1, &texcoord_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, texcoord_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 2 * point_count,
			vt, GL_STATIC_DRAW);

		glGenVertexArrays (1, &vao);
		glBindVertexArray (vao);
		glEnableVertexAttribArray (0);
		glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
		glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		glEnableVertexAttribArray (1);
		glBindBuffer (GL_ARRAY_BUFFER, texcoord_vbo);
		glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, NULL);

		free (vp);
		free (vn);
		free (vt);
	}
	//
	// Load shaders from files
	// --------------------------------------------------------------------------
	{
		char* vertex_shader_str;
		char* fragment_shader_str;

		// allocate some memory to store shader strings
		vertex_shader_str = (char*)malloc (81920);
		fragment_shader_str = (char*)malloc (81920);
		// load shader strings from text files
		assert (parse_file_into_str ("teapot.vert", vertex_shader_str, 81920));
		assert (parse_file_into_str ("teapot.frag", fragment_shader_str, 81920));
		GLuint vs, fs;
		vs = glCreateShader (GL_VERTEX_SHADER);
		fs = glCreateShader (GL_FRAGMENT_SHADER);
		glShaderSource (vs, 1, (const char**)&vertex_shader_str, NULL);
		glShaderSource (fs, 1, (const char**)&fragment_shader_str, NULL);
		// free memory
		free (vertex_shader_str);
		free (fragment_shader_str);
		glCompileShader (vs);
		glCompileShader (fs);
		shader_programme = glCreateProgram ();
		glAttachShader (shader_programme, fs);
		glAttachShader (shader_programme, vs);
		glLinkProgram (shader_programme);
		/* TODO NOTE: you should check for errors and print logs after compiling and also linking shaders */
	}

	//
	// Create some matrices
	// --------------------------------------------------------------------------

	mat4 M, V, P;
	M = identity_mat4 ();//scale (identity_mat4 (), vec3 (0.05, 0.05, 0.05));
	vec3 cam_pos (0.0, 0.0, 5.0);
	vec3 targ_pos (0.0, 0.0, 0.0);
	vec3 up (0.0, 1.0, 0.0);
	V = look_at (cam_pos, targ_pos, up);
	P = perspective (67.0f, (float)gl_width / (float)gl_height, 0.1, 1000.0);

	int M_loc = glGetUniformLocation (shader_programme, "M");
	int V_loc = glGetUniformLocation (shader_programme, "V");
	int P_loc = glGetUniformLocation (shader_programme, "P");
	// send matrix values to shader immediately
	glUseProgram (shader_programme);
	glUniformMatrix4fv (M_loc, 1, GL_FALSE, M.m);
	glUniformMatrix4fv (V_loc, 1, GL_FALSE, V.m);
	glUniformMatrix4fv (P_loc, 1, GL_FALSE, P.m);

	int dt_pixel_c = 16 * 16;
	char* dt_data = (char*)malloc (4 * dt_pixel_c);
	if (!dt_data) {
		fprintf (stderr, "ERROR: out of memory. malloc default texture\n");
		return 1;
	}

	for (int i = 0; i < dt_pixel_c * 4; i += 4) {
		int sq_ac = i / 16;
		if ((sq_ac / 2) * 2 == sq_ac) {
			dt_data[i] = 0;
			dt_data[i + 1] = 0;
			dt_data[i + 2] = 0;
			dt_data[i + 3] = (char)255;
		} else {
			dt_data[i] = (char)255;
			dt_data[i + 1] = 0;
			dt_data[i + 2] = (char)255;
			dt_data[i + 3] = (char)255;
		}
		int sq_dn = i / (16 * 16);
		if ((sq_dn / 2) * 2 == sq_dn) {
			dt_data[i] = (char)255 - dt_data[i];
			dt_data[i + 2] = (char)255 - dt_data[i + 2];
		}
	}

	GLuint tex;
	glGenTextures (1, &tex);
	glActiveTexture (GL_TEXTURE0);
	glBindTexture (GL_TEXTURE_2D, tex);

	int x,y,n;
	unsigned char *data = stbi_load ("move_me.png", &x, &y, &n, 4);
	if (!data) {
		fprintf (stderr, "ERROR: could not load image 'move_me.png'. using default texture\n");
		glTexImage2D (
			GL_TEXTURE_2D,
			0,
			GL_RGBA,
			16,
			16,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			dt_data
		);
	} else {
		glTexImage2D (
			GL_TEXTURE_2D,
			0,
			GL_RGBA,
			x,
			y,
			0,
			GL_RGBA,
			GL_UNSIGNED_BYTE,
			data
		);
		stbi_image_free(data);
		data = NULL;
		printf ("loaded image with [%i,%i] res and %i chans\n", x, y, n);
	}
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);


	free (dt_data);
	dt_data = NULL;


//	*/

	//
	// Start rendering
	// --------------------------------------------------------------------------
	// tell GL to only draw onto a pixel if the fragment is closer to the viewer
	glEnable (GL_DEPTH_TEST); // enable depth-testing
	glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
	glClearColor (0.01, 0.01, 0.25, 1.0);

	float a = 0.0f;
	double prev = glfwGetTime ();
	while (!glfwWindowShouldClose (window)) {
		glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		// just the default viewport, covering the whole render area
		glViewport (0, 0, gl_width, gl_height);

		double curr = glfwGetTime ();
		double elapsed = curr - prev;
		prev = curr;

		glUseProgram (shader_programme);
		glBindVertexArray (vao);

		a += sinf (elapsed * 50.0f);
		M = rotate_y_deg (identity_mat4 (), a);
		glUniformMatrix4fv (M_loc, 1, GL_FALSE, M.m);

		glDrawArrays (GL_TRIANGLES, 0, point_count);

		/* this just updates window events and keyboard input events (not used yet) */
		glfwPollEvents ();
		glfwSwapBuffers (window);
	}

	return 0;
}
Esempio n. 2
0
int main () {
	GLFWwindow* window = NULL;
	const GLubyte* renderer;
	const GLubyte* version;
	GLuint shader_programme;
	GLuint vao;

	//
	// Start OpenGL using helper libraries
	// --------------------------------------------------------------------------
	if (!glfwInit ()) {
		fprintf (stderr, "ERROR: could not start GLFW3\n");
		return 1;
	} 

	// change to 3.2 if on Apple OS X
	glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 2);
	glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); 
	glfwWindowHint (GLFW_SAMPLES, msaa);
	window = glfwCreateWindow (gl_width, gl_height, "Textured Mesh", NULL, NULL);
	if (!window) {
		fprintf (stderr, "ERROR: opening OS window\n");
		return 1;
	}
	glfwMakeContextCurrent (window);
	
	

	glewExperimental = GL_TRUE;
	glewInit ();

	/* get version info */
	renderer = glGetString (GL_RENDERER); /* get renderer string */
	version = glGetString (GL_VERSION); /* version as a string */
	printf ("Renderer: %s\n", renderer);
	printf ("OpenGL version supported %s\n", version);

	int point_count = 0;
	//
	// Set up vertex buffers and vertex array object
	// --------------------------------------------------------------------------
	{
		GLfloat* vp = NULL; // array of vertex points
		GLfloat* vn = NULL; // array of vertex normals (we haven't used these yet)
		GLfloat* vt = NULL; // array of texture coordinates (or these)
		//assert (load_obj_file ("cube.obj", vp, vt, vn, point_count));
		assert (load_obj_file ("monkey.obj", vp, vt, vn, point_count));
		
	
		GLuint points_vbo, texcoord_vbo, normal_vbo;
		glGenBuffers (1, &points_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 3 * point_count,
			vp, GL_STATIC_DRAW);
		glGenBuffers (1, &texcoord_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, texcoord_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 2 * point_count,
			vt, GL_STATIC_DRAW);
		glGenBuffers (1, &normal_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, normal_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 3 * point_count,
			vn, GL_STATIC_DRAW);
	
		glGenVertexArrays (1, &vao);
		glBindVertexArray (vao);
		glEnableVertexAttribArray (0);
		glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
		glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		glEnableVertexAttribArray (1);
		glBindBuffer (GL_ARRAY_BUFFER, texcoord_vbo);
		glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
		glEnableVertexAttribArray (2);
		glBindBuffer (GL_ARRAY_BUFFER, normal_vbo);
		glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		
		free (vp);
		free (vn);
		free (vt);
	}
	//
	// Load shaders from files
	// --------------------------------------------------------------------------
	{
		char* vertex_shader_str;
		char* fragment_shader_str;
		
		// allocate some memory to store shader strings
		vertex_shader_str = (char*)malloc (81920);
		fragment_shader_str = (char*)malloc (81920);
		// load shader strings from text files
		assert (parse_file_into_str ("teapot.vert", vertex_shader_str, 81920));
		assert (parse_file_into_str ("teapot.frag", fragment_shader_str, 81920));
		GLuint vs, fs;
		vs = glCreateShader (GL_VERTEX_SHADER);
		fs = glCreateShader (GL_FRAGMENT_SHADER);
		glShaderSource (vs, 1, (const char**)&vertex_shader_str, NULL);
		glShaderSource (fs, 1, (const char**)&fragment_shader_str, NULL);
		// free memory
		free (vertex_shader_str);
		free (fragment_shader_str);
		int params = -1;
		glCompileShader (vs);
		glGetShaderiv (vs, GL_COMPILE_STATUS, &params);
		if (GL_TRUE != params) {
			printf ("ERROR: GL shader index %i (teapot.vert) did not compile\n", vs);
			int max_length = 2048;
			int actual_length = 0;
			char log[2048];
			glGetShaderInfoLog (vs, max_length, &actual_length, log);
			printf ("shader info log for GL index %u\n%s\n", vs, log);
		}
		glCompileShader (fs);
		glGetShaderiv (fs, GL_COMPILE_STATUS, &params);
		if (GL_TRUE != params) {
			printf ("ERROR: GL shader index %i (teapot.frag) did not compile\n", fs);
			int max_length = 2048;
			int actual_length = 0;
			char log[2048];
			glGetShaderInfoLog (fs, max_length, &actual_length, log);
			printf ("shader info log for GL index %u\n%s\n", vs, log);
		}
		shader_programme = glCreateProgram ();
		glAttachShader (shader_programme, fs);
		glAttachShader (shader_programme, vs);
		glBindAttribLocation (shader_programme, 0, "vp");
		glBindAttribLocation (shader_programme, 1, "vt");
		glBindAttribLocation (shader_programme, 2, "vn");
		glLinkProgram (shader_programme);
		glGetProgramiv (shader_programme, GL_LINK_STATUS, &params);
		if (GL_TRUE != params) {
			printf ("ERROR: could not link shader programme GL index %u\n", shader_programme);
			int max_length = 2048;
		int actual_length = 0;
		char log[2048];
		glGetProgramInfoLog (shader_programme, max_length, &actual_length, log);
		printf ("program info log for GL index %u\n%s\n", shader_programme, log);
		}
		/* TODO NOTE: you should check for errors and print logs after compiling and also linking shaders */
	}
	
	//
	// Create some matrices
	// --------------------------------------------------------------------------
		
	mat4 M, V, P;
	M = identity_mat4 ();//scale (identity_mat4 (), vec3 (0.05, 0.05, 0.05));
	vec3 cam_pos (0.0, 5.0, 5.0);
	vec3 targ_pos (0.0, 0.0, 0.0);
	vec3 up = normalise (vec3 (0.0, 1.0, -1.0));
	V = look_at (cam_pos, targ_pos, up);
	P = perspective (67.0f, (float)gl_width / (float)gl_height, 0.1, 10.0);
	
	int M_loc = glGetUniformLocation (shader_programme, "M");
	int V_loc = glGetUniformLocation (shader_programme, "V");
	int P_loc = glGetUniformLocation (shader_programme, "P");
	int ol_loc = glGetUniformLocation (shader_programme, "ol_mode");
	int sm_loc = glGetUniformLocation (shader_programme, "sm_shaded");
	// send matrix values to shader immediately
	glUseProgram (shader_programme);
	glUniformMatrix4fv (M_loc, 1, GL_FALSE, M.m);
	glUniformMatrix4fv (V_loc, 1, GL_FALSE, V.m);
	glUniformMatrix4fv (P_loc, 1, GL_FALSE, P.m);
	glUniform1f (ol_loc, 0.0f);
	glUniform1f (sm_loc, 0.0f);
	
	//
	// Start rendering
	// --------------------------------------------------------------------------
	// tell GL to only draw onto a pixel if the fragment is closer to the viewer
	glEnable (GL_DEPTH_TEST); // enable depth-testing
	glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
	glDepthFunc (GL_LESS); // depth-testing is to use a "less than" function
	glEnable (GL_CULL_FACE); // enable culling of faces
	glCullFace (GL_BACK);
	glFrontFace (GL_CCW);
	glClearColor (0.04, 0.04, 0.75, 1.0);

	bool multi_pass = true;

	GLuint fb, c_tex, d_tex;;
	{
		// fb
		
		glGenFramebuffers (1, &fb);
		glBindFramebuffer (GL_FRAMEBUFFER, fb);
		glGenTextures (1, &c_tex);
		glGenTextures (1, &d_tex);
		glActiveTexture (GL_TEXTURE0);
		glBindTexture (GL_TEXTURE_2D, c_tex);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, gl_width, gl_height, 0, GL_RGBA,
			GL_UNSIGNED_BYTE, NULL);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	  glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
			c_tex, 0);
		glBindTexture (GL_TEXTURE_2D, d_tex);
		glTexImage2D (GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, gl_width, gl_height, 0,
			GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
		glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
	  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	  glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
		glFramebufferTexture2D (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D,
			d_tex, 0);
		glBindFramebuffer (GL_FRAMEBUFFER, 0);
	}

	GLuint quad_vao;
	{
		float quad_pts[] = {-1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0};
		GLuint quad_vbo;
		glGenBuffers (1, &quad_vbo);
		glGenVertexArrays (1, &quad_vao);
		glBindVertexArray (quad_vao);
		glEnableVertexAttribArray (0);
		glBindBuffer (GL_ARRAY_BUFFER, quad_vbo);
		glBufferData (GL_ARRAY_BUFFER, 8 * sizeof (float), quad_pts, GL_STATIC_DRAW);
		glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
	}

	GLuint post_sp;
	{
		char* vertex_shader_str;
		char* fragment_shader_str;
		
		// allocate some memory to store shader strings
		vertex_shader_str = (char*)malloc (81920);
		fragment_shader_str = (char*)malloc (81920);
		// load shader strings from text files
		assert (parse_file_into_str ("post.vert", vertex_shader_str, 81920));
		assert (parse_file_into_str ("post.frag", fragment_shader_str, 81920));
		GLuint vs, fs;
		vs = glCreateShader (GL_VERTEX_SHADER);
		fs = glCreateShader (GL_FRAGMENT_SHADER);
		glShaderSource (vs, 1, (const char**)&vertex_shader_str, NULL);
		glShaderSource (fs, 1, (const char**)&fragment_shader_str, NULL);
		// free memory
		free (vertex_shader_str);
		free (fragment_shader_str);
		int params = -1;
		glCompileShader (vs);
		glGetShaderiv (vs, GL_COMPILE_STATUS, &params);
		if (GL_TRUE != params) {
			printf ("ERROR: GL shader index %i (post.vert) did not compile\n", vs);
			int max_length = 2048;
			int actual_length = 0;
			char log[2048];
			glGetShaderInfoLog (vs, max_length, &actual_length, log);
			printf ("shader info log for GL index %u\n%s\n", vs, log);
		}
		glCompileShader (fs);
		glGetShaderiv (fs, GL_COMPILE_STATUS, &params);
		if (GL_TRUE != params) {
			printf ("ERROR: GL shader index %i (post.frag) did not compile\n", fs);
			int max_length = 2048;
			int actual_length = 0;
			char log[2048];
			glGetShaderInfoLog (fs, max_length, &actual_length, log);
			printf ("shader info log for GL index %u\n%s\n", vs, log);
		}
		post_sp = glCreateProgram ();
		glAttachShader (post_sp, fs);
		glAttachShader (post_sp, vs);
		glBindAttribLocation (post_sp, 0, "vp");
		glLinkProgram (post_sp);
		glGetProgramiv (post_sp, GL_LINK_STATUS, &params);
		if (GL_TRUE != params) {
			printf ("ERROR: could not link shader programme GL index %u\n", post_sp);
			int max_length = 2048;
		int actual_length = 0;
		char log[2048];
		glGetProgramInfoLog (post_sp, max_length, &actual_length, log);
		printf ("program info log for GL index %u\n%s\n", post_sp, log);
		}
	}

	double a = 0.0f;
	double prev = glfwGetTime ();
	while (!glfwWindowShouldClose (window)) {
		if (multi_pass) {
			glBindFramebuffer (GL_FRAMEBUFFER, fb);
		}
		glViewport (0, 0, gl_width, gl_height);
		glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glActiveTexture (GL_TEXTURE0);
		glBindTexture (GL_TEXTURE_2D, 0);

		double curr = glfwGetTime ();
		double elapsed = curr - prev;
		prev = curr;
		
		glUseProgram (shader_programme);
		glBindVertexArray (vao);
		
		a += elapsed  * 50.0f;
		//float ang = (float)sin (a);
		M = rotate_y_deg (identity_mat4 (), a);
		glUniformMatrix4fv (M_loc, 1, GL_FALSE, M.m);
		glUniform1f (sm_loc, 1.0f); // smooth shaded or not (exception is flat-shaded, they might not be great
		// if non-cube anyway due to scaling)

		if (!multi_pass) {
			glFrontFace (GL_CW);
			glUniform1f (ol_loc, 1.0f);
			glDrawArrays (GL_TRIANGLES, 0, point_count);
		}
		glFrontFace (GL_CCW);
		glUniform1f (ol_loc, 0.0f);
		glDrawArrays (GL_TRIANGLES, 0, point_count);
		/* this just updates window events and keyboard input events (not used yet) */

		if (multi_pass) {
			glFlush ();
			glFinish ();
			glBindFramebuffer (GL_FRAMEBUFFER, 0);
			glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glViewport (0, 0, gl_width, gl_height);
			glUseProgram (post_sp);
			glActiveTexture (GL_TEXTURE0);
			glBindTexture (GL_TEXTURE_2D, d_tex);
			glBindVertexArray (quad_vao);
			glDrawArrays (GL_TRIANGLE_STRIP, 0, 4);
		}
		glfwPollEvents ();
		glfwSwapBuffers (window);
	}

	return 0;
}
Esempio n. 3
0
int main () {
	GLFWwindow* window = NULL;
	const GLubyte* renderer;
	const GLubyte* version;
	GLuint cube_sp, knot_sp;
	GLuint vao;

	//
	// Start OpenGL using helper libraries
	// --------------------------------------------------------------------------
	if (!glfwInit ()) {
		fprintf (stderr, "ERROR: could not start GLFW3\n");
		return 1;
	} 

	/* change to 3.2 if on Apple OS X
	glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 4);
	glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 0);
	glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
	glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); */
	glfwWindowHint (GLFW_SAMPLES, msaa);
	window = glfwCreateWindow (gl_width, gl_height, "{quadratic bezier}", NULL, NULL);
	if (!window) {
		fprintf (stderr, "ERROR: opening OS window\n");
		return 1;
	}
	glfwMakeContextCurrent (window);
	
	

	glewExperimental = GL_TRUE;
	glewInit ();

	/* get version info */
	renderer = glGetString (GL_RENDERER); /* get renderer string */
	version = glGetString (GL_VERSION); /* version as a string */
	printf ("Renderer: %s\n", renderer);
	printf ("OpenGL version supported %s\n", version);

	int point_count = 0;
	//
	// Set up vertex buffers and vertex array object
	// --------------------------------------------------------------------------
	{
		GLfloat* vp = NULL; // array of vertex points
		GLfloat* vn = NULL; // array of vertex normals (we haven't used these yet)
		GLfloat* vt = NULL; // array of texture coordinates (or these)
		assert (load_obj_file ("smcube.obj", vp, vt, vn, point_count));
		
	
		GLuint points_vbo, texcoord_vbo, normal_vbo;
		glGenBuffers (1, &points_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 3 * point_count,
			vp, GL_STATIC_DRAW);
		glGenBuffers (1, &texcoord_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, texcoord_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 2 * point_count,
			vt, GL_STATIC_DRAW);
		glGenBuffers (1, &normal_vbo);
		glBindBuffer (GL_ARRAY_BUFFER, normal_vbo);
		glBufferData (GL_ARRAY_BUFFER, sizeof (float) * 3 * point_count,
			vn, GL_STATIC_DRAW);
	
		glGenVertexArrays (1, &vao);
		glBindVertexArray (vao);
		glEnableVertexAttribArray (0);
		glBindBuffer (GL_ARRAY_BUFFER, points_vbo);
		glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		glEnableVertexAttribArray (1);
		glBindBuffer (GL_ARRAY_BUFFER, texcoord_vbo);
		glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, NULL);
		glEnableVertexAttribArray (2);
		glBindBuffer (GL_ARRAY_BUFFER, normal_vbo);
		glVertexAttribPointer (2, 3, GL_FLOAT, GL_FALSE, 0, NULL);
		
		free (vp);
		free (vn);
		free (vt);
	}
	//
	// Load shaders from files
	// --------------------------------------------------------------------------
	{
		char* vertex_shader_str;
		char* fragment_shader_str;
		
		// allocate some memory to store shader strings
		vertex_shader_str = (char*)malloc (81920);
		fragment_shader_str = (char*)malloc (81920);
		// load shader strings from text files
		assert (parse_file_into_str ("cube.vert", vertex_shader_str, 81920));
		assert (parse_file_into_str ("cube.frag", fragment_shader_str, 81920));
		GLuint vs, fs;
		vs = glCreateShader (GL_VERTEX_SHADER);
		fs = glCreateShader (GL_FRAGMENT_SHADER);
		glShaderSource (vs, 1, (const char**)&vertex_shader_str, NULL);
		glShaderSource (fs, 1, (const char**)&fragment_shader_str, NULL);
		// free memory
		free (vertex_shader_str);
		free (fragment_shader_str);
		glCompileShader (vs);
		glCompileShader (fs);
		cube_sp = glCreateProgram ();
		glAttachShader (cube_sp, fs);
		glAttachShader (cube_sp, vs);
		glBindAttribLocation (cube_sp, 0, "vp");
		glBindAttribLocation (cube_sp, 1, "vt");
		glBindAttribLocation (cube_sp, 2, "vn");
		glLinkProgram (cube_sp);
	}
	{
		char* vertex_shader_str;
		char* fragment_shader_str;
		
		// allocate some memory to store shader strings
		vertex_shader_str = (char*)malloc (81920);
		fragment_shader_str = (char*)malloc (81920);
		// load shader strings from text files
		assert (parse_file_into_str ("knot.vert", vertex_shader_str, 81920));
		assert (parse_file_into_str ("knot.frag", fragment_shader_str, 81920));
		GLuint vs, fs;
		vs = glCreateShader (GL_VERTEX_SHADER);
		fs = glCreateShader (GL_FRAGMENT_SHADER);
		glShaderSource (vs, 1, (const char**)&vertex_shader_str, NULL);
		glShaderSource (fs, 1, (const char**)&fragment_shader_str, NULL);
		// free memory
		free (vertex_shader_str);
		free (fragment_shader_str);
		glCompileShader (vs);
		glCompileShader (fs);
		
		knot_sp = glCreateProgram ();
		glAttachShader (knot_sp, fs);
		glAttachShader (knot_sp, vs);
		glLinkProgram (knot_sp);
	}
	
	//
	// Create some matrices
	// --------------------------------------------------------------------------
		
	mat4 M, V, P;
	M = identity_mat4 ();//scale (identity_mat4 (), vec3 (0.05, 0.05, 0.05));
	vec3 cam_pos (0.0, 0.0, 15.0);
	vec3 targ_pos (0.0, 0.0, 0.0);
	vec3 up = normalise (vec3 (0.0, 1.0, 0.0));
	V = look_at (cam_pos, targ_pos, up);
	P = perspective (67.0f, (float)gl_width / (float)gl_height, 0.1, 1000.0);
	
	int M_loc = glGetUniformLocation (cube_sp, "M");
	int V_loc = glGetUniformLocation (cube_sp, "V");
	int P_loc = glGetUniformLocation (cube_sp, "P");
	int A_loc = glGetUniformLocation (cube_sp, "A");
	int B_loc = glGetUniformLocation (cube_sp, "B");
	int C_loc = glGetUniformLocation (cube_sp, "C");
	int t_loc = glGetUniformLocation (cube_sp, "t");
	// send matrix values to shader immediately
	glUseProgram (cube_sp);
	glUniformMatrix4fv (M_loc, 1, GL_FALSE, M.m);
	glUniformMatrix4fv (V_loc, 1, GL_FALSE, V.m);
	glUniformMatrix4fv (P_loc, 1, GL_FALSE, P.m);
	
	//
	// specific knots for bezier here A, C are start, end, B is control point
	//
	vec3 A = vec3 (-7.0f, -5.0f, 0.0f);
	vec3 B = vec3 (0.0f, 8.0f, 0.0f);
	vec3 C = vec3 (7.0f, -5.0f, 0.0f);
	glUniform3fv (A_loc, 1, A.v);
	glUniform3fv (B_loc, 1, B.v);
	glUniform3fv (C_loc, 1, C.v);
	
	int knot_loc = glGetUniformLocation (knot_sp, "pos");
	int knotP_loc = glGetUniformLocation (knot_sp, "P");
	int knotV_loc = glGetUniformLocation (knot_sp, "V");
	glUseProgram (knot_sp);
	glUniformMatrix4fv (knotV_loc, 1, GL_FALSE, V.m);
	glUniformMatrix4fv (knotP_loc, 1, GL_FALSE, P.m);
	
	//
	// Start rendering
	// --------------------------------------------------------------------------
	// tell GL to only draw onto a pixel if the fragment is closer to the viewer
	glEnable (GL_DEPTH_TEST); // enable depth-testing
	glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
	glDepthFunc (GL_LESS); // depth-testing is to use a "less than" function
	glEnable (GL_CULL_FACE); // enable culling of faces
	glCullFace (GL_BACK);
	glFrontFace (GL_CCW);
	glClearColor (0.04, 0.04, 0.75, 1.0);
	
	/* Render Points, allow resize in vertex shader */
	glEnable (GL_PROGRAM_POINT_SIZE);
	glPointParameteri (GL_POINT_SPRITE_COORD_ORIGIN, GL_LOWER_LEFT);

	float t = 0.0f;
	float speed = 0.5f;
	double prev = glfwGetTime ();
	while (!glfwWindowShouldClose (window)) {
		glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		// just the default viewport, covering the whole render area
		glViewport (0, 0, gl_width, gl_height);
		
		double curr = glfwGetTime ();
		double elapsed = curr - prev;
		prev = curr;
		
		//
		// move along spline
		if (GLFW_PRESS == glfwGetKey (window, GLFW_KEY_LEFT)) {
			t -= elapsed * speed;
			if (t < 0.0f) {
				t = 0.0f;
			}
		}
		if (GLFW_PRESS == glfwGetKey (window, GLFW_KEY_RIGHT)) {
			t += elapsed * speed;
			if (t > 1.0f) {
				t = 1.0f;
			}
		}
		
		//
		// render 3 knots
		glEnable (GL_PROGRAM_POINT_SIZE);
		glUseProgram (knot_sp);
		glUniform3fv (knot_loc, 1, A.v);
		glDrawArrays (GL_POINTS, 0, 1);
		glUseProgram (knot_sp);
		glUniform3fv (knot_loc, 1, B.v);
		glDrawArrays (GL_POINTS, 0, 1);
		glUseProgram (knot_sp);
		glUniform3fv (knot_loc, 1, C.v);
		glDrawArrays (GL_POINTS, 0, 1);
		glDisable (GL_PROGRAM_POINT_SIZE);
		
		glUseProgram (cube_sp);
		glBindVertexArray (vao);
		
		M = identity_mat4 ();//rotate_y_deg (identity_mat4 (), a);
		glUniformMatrix4fv (M_loc, 1, GL_FALSE, M.m);
		glUniform1f (t_loc, t);
		
		glDrawArrays (GL_TRIANGLES, 0, point_count);

		/* this just updates window events and keyboard input events (not used yet) */
		glfwPollEvents ();
		glfwSwapBuffers (window);
	}

	return 0;
}
int main () {
	/* initialise GL context and window */
	assert (restart_gl_log ());
	assert (start_gl ());
	/* initialise framebuffer and G-buffer */
	assert (init_fb ());
	/* load pre-pass shaders that write to the g-buffer */
	g_first_pass_sp = create_programme_from_files (
		FIRST_PASS_VS, FIRST_PASS_FS);
	g_first_pass_P_loc = glGetUniformLocation (g_first_pass_sp, "P");
	g_first_pass_V_loc = glGetUniformLocation (g_first_pass_sp, "V");
	g_first_pass_M_loc = glGetUniformLocation (g_first_pass_sp, "M");
	/* load screen-space pass shaders that read from the g-buffer */
	g_second_pass_sp = create_programme_from_files (
		SECOND_PASS_VS, SECOND_PASS_FS);
	g_second_pass_P_loc = glGetUniformLocation (g_second_pass_sp, "P");
	g_second_pass_V_loc = glGetUniformLocation (g_second_pass_sp, "V");
	g_second_pass_M_loc = glGetUniformLocation (g_second_pass_sp, "M");
	g_second_pass_L_p_loc = glGetUniformLocation (g_second_pass_sp, "lp");
	g_second_pass_L_d_loc = glGetUniformLocation (g_second_pass_sp, "ld");
	g_second_pass_L_s_loc = glGetUniformLocation (g_second_pass_sp, "ls");
	g_second_pass_p_tex_loc = glGetUniformLocation (g_second_pass_sp, "p_tex");
	g_second_pass_n_tex_loc = glGetUniformLocation (g_second_pass_sp, "n_tex");
	glUseProgram (g_second_pass_sp);
	glUniform1i (g_second_pass_p_tex_loc, 0);
	glUniform1i (g_second_pass_n_tex_loc, 1);
	
	/* object positions and matrices */
	assert (load_plane ());
	g_plane_M = scale (identity_mat4 (), vec3 (200.0f, 1.0f, 200.0f));
	g_plane_M = translate (g_plane_M, vec3 (0.0f, -2.0f, 0.0f));
	
	/* load sphere mesh */
	assert (load_sphere ());
	/* light positions and matrices */
	for (int i = 0; i < NUM_LIGHTS; i++) {
		float x = -sinf ((float)i * 0.5f) * 25.0f; // between +- 10 x
		float y = 2.0f;
		float z = (float)-i * 2.0f + 10.0; // 1 light every 2 meters away on z
		g_L_p[i] = vec3 (x, y, z);
	}
	
	float light_radius = 10.0f;
	int redi = 0;
	int bluei = 1;
	int greeni = 2;
	for (int i = 0; i < NUM_LIGHTS; i++) {
		g_L_M[i] = scale (identity_mat4 (),
			vec3 (light_radius, light_radius, light_radius));
		g_L_M[i] = translate (g_L_M[i], g_L_p[i]);
		/* cycle different colours for each of the lights */
		g_L_d[i] = vec3 (
			(float)((redi + 1) / 3),
			(float)((greeni + 1) / 3),
			(float)((bluei + 1) / 3)
		);
		g_L_s[i] = vec3 (1.0, 1.0, 1.0);
		redi = (redi + 1) % 3;
		bluei = (bluei + 1) % 3;
		greeni = (greeni + 1) % 3;
	}
	
	/* set up virtual camera */
	float aspect = (float)g_gl_width / (float)g_gl_height;
	float near = 0.1f;
	float far = 1000.0f;
	float fovy = 67.0f;
	g_P = perspective (fovy, aspect, near, far);
	vec3 up (0.0f, 1.0f, 0.0f);
	vec3 targ_pos (0.0f, 0.0f, 0.0f);
	vec3 cam_pos (0.0f, 30.0f, 30.0f);
	g_V = look_at (cam_pos, targ_pos, up);
	
	glViewport (0, 0, g_gl_width, g_gl_height);
	glEnable (GL_CULL_FACE); // cull face
	glCullFace (GL_BACK); // cull back face
	glFrontFace (GL_CCW); // GL_CCW for counter clock-wise
	while (!glfwWindowShouldClose (g_window)) {
		_update_fps_counter (g_window);
		draw_first_pass ();
		draw_second_pass ();
		
		glfwSwapBuffers (g_window);
		glfwPollEvents ();
		if (GLFW_PRESS == glfwGetKey (g_window, GLFW_KEY_ESCAPE)) {
			glfwSetWindowShouldClose (g_window, 1);
		}
	}
	
	/* close GL context and any other GLFW resources */
	glfwTerminate();
	return 0;
}