Created
April 20, 2013 04:33
-
-
Save realModusOperandi/5424758 to your computer and use it in GitHub Desktop.
A cube.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <stdio.h> | |
#include <stdlib.h> | |
#include <GL/glfw.h> | |
#include <math.h> | |
// The basic idea of a vertex shader is that it takes in vertices, which have attributes | |
// like position and color, and does the operations specified in the shader's main method on them. | |
// It then passes the results of that on to the fragment shader. | |
// Holds the position and color of each vertex which will comprise the two triangles. | |
typedef struct { | |
float position[3]; | |
float color[4]; | |
float normal[3]; | |
} Vertex; | |
Vertex Vertices[] = { | |
// Front | |
{{0.5, -0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, 1}}, | |
{{0.5, 0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, 1}}, | |
{{-0.5, 0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, 1}}, | |
{{-0.5, -0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, 1}}, | |
// Back | |
{{0.5, 0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, -1}}, | |
{{-0.5, -0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, -1}}, | |
{{0.5, -0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, -1}}, | |
{{-0.5, 0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, 0, -1}}, | |
// Left | |
{{-0.5, -0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {1, 0, 0}}, | |
{{-0.5, 0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {1, 0, 0}}, | |
{{-0.5, 0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {1, 0, 0}}, | |
{{-0.5, -0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {1, 0, 0}}, | |
// Right | |
{{0.5, -0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {-1, 0, 0}}, | |
{{0.5, 0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {-1, 0, 0}}, | |
{{0.5, 0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {-1, 0, 0}}, | |
{{0.5, -0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {-1, 0, 0}}, | |
// Top | |
{{0.5, 0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, 1, 0}}, | |
{{0.5, 0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, 1, 0}}, | |
{{-0.5, 0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, 1, 0}}, | |
{{-0.5, 0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, 1, 0}}, | |
// Bottom | |
{{0.5, -0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, -1, 0}}, | |
{{0.5, -0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, -1, 0}}, | |
{{-0.5, -0.5, 0.5}, {0.5, 0.5, 0.5, 1}, {0, -1, 0}}, | |
{{-0.5, -0.5, -0.5}, {0.5, 0.5, 0.5, 1}, {0, -1, 0}} | |
}; | |
const GLubyte Indices[] = { | |
// Front | |
0, 1, 2, | |
2, 3, 0, | |
// Back | |
6, 5, 4, | |
4, 5, 7, | |
// Left | |
8, 9, 10, | |
10, 11, 8, | |
// Right | |
12, 13, 14, | |
14, 15, 12, | |
// Top | |
16, 17, 18, | |
18, 19, 16, | |
// Bottom | |
22, 21, 20, | |
20, 23, 22 | |
}; | |
// The vertex shader itself. Vertex shaders take in attribute and uniform variables, | |
// and write out varying variables as well as gl_Position, the actual position of each vertices. | |
// Varying literally means we want the values here interpolated between vertices. This is what | |
// makes the rainbow. | |
const GLchar* vertex_shader_src = | |
"#version 120\n" | |
"attribute vec4 Position;\n" | |
"attribute vec4 SourceColor;\n" | |
"attribute vec4 Normal;\n" | |
"\n" | |
"varying vec4 DestinationColor;\n" | |
"varying float DiffuseColor;\n" | |
"\n" | |
"uniform mat4 ModelView;\n" | |
"uniform mat4 Rotation;\n" | |
"uniform mat4 NormalMatrix;\n" | |
"uniform vec3 LightDirection;\n" | |
"uniform float DiffuseFactor;\n" | |
"void main(void) {\n" | |
" vec4 ec_normal = NormalMatrix * Normal;\n" | |
" DiffuseColor = max(dot(vec3(ec_normal), LightDirection), 0.0);\n" | |
" DestinationColor = SourceColor;\n" | |
" gl_Position = ModelView * Rotation * Position;\n" | |
"}\n"; | |
// Fragment shaders work on individual pixels; they are also known as pixel shaders. | |
// gl_FragColor is the color of the pixel currently being considered. | |
// The fragment shader automatically interpolates between the colors of various vertices to arrive | |
// at the destination color for a given fragment. | |
const GLchar* fragment_shader_src = | |
"#version 120\n" | |
"varying vec4 DestinationColor;\n" | |
"varying float DiffuseColor;\n" | |
"\n" | |
"uniform vec4 Ambient;\n" | |
"uniform float DiffuseFactor;\n" | |
"void main(void) {\n" | |
" gl_FragColor = DestinationColor * ((DiffuseColor * DiffuseFactor) + Ambient);\n" | |
"}\n"; | |
// This function compiles and installs a shader passed in as a parameter. | |
// It's used twice in main: once for the vertex shader, and once for the fragment. | |
GLint simple_shader(GLint shader_type, const GLchar* shader_src) | |
{ | |
// Status variable. | |
GLint compile_success = 0; | |
// Tell OpenGl to create a new shader and return the index of it. | |
int shader_id = glCreateShader(shader_type); | |
// Tell OpenGL that the shader that was created will have the source code | |
// passed in as a string. | |
glShaderSource(shader_id, 1, &shader_src, 0); | |
// Tell OpenGl to actually compile the shader that's been installed. | |
glCompileShader(shader_id); | |
//Get the status of compilation | |
glGetShaderiv(shader_id, GL_COMPILE_STATUS, &compile_success); | |
// If there was an issue and compilation failed: | |
if (compile_success == GL_FALSE) { | |
// Get the information about the failure and print it, then die. | |
GLchar message[256]; | |
glGetShaderInfoLog(shader_id, sizeof(message), 0, &message[0]); | |
printf("glCompileShader Error: %s\n", message); | |
exit(1); | |
} | |
// Return the index of the newly created shader. | |
return shader_id; | |
} | |
// This will link everything together after all the shaders have been created. | |
int simple_program() | |
{ | |
// Again, a status variable. | |
GLint link_success = 0; | |
// Tell OpenGL to create a new program, and keep the index of it. | |
GLint program_id = glCreateProgram(); | |
// Install and compile the vertex shader. | |
GLint vertex_shader = simple_shader(GL_VERTEX_SHADER, vertex_shader_src); | |
// Same but fragment shader. | |
GLint fragment_shader = simple_shader(GL_FRAGMENT_SHADER, fragment_shader_src); | |
// Tell the program to use the shaders. | |
glAttachShader(program_id, vertex_shader); | |
glAttachShader(program_id, fragment_shader); | |
// Put everything together. | |
glLinkProgram(program_id); | |
// As with the shader compilation, need to find out if everything went well. | |
// And if not, why not. | |
glGetProgramiv(program_id, GL_LINK_STATUS, &link_success); | |
if (link_success == GL_FALSE) { | |
GLchar message[256]; | |
glGetProgramInfoLog(program_id, sizeof(message), 0, &message[0]); | |
printf("glLinkProgram Error: %s\n", message); | |
exit(1); | |
} | |
return program_id; | |
} | |
// Let's rock. | |
int main(void) | |
{ | |
// Indices of the program and two variables in the vertex shader. | |
GLint program_id, position_slot, color_slot, normal_slot; | |
// The buffer OpenGL uses to store the vertices we want it to render. | |
GLuint vertex_buffer; | |
// OpenGL's buffer of the indices into the above array of vertices. | |
GLuint index_buffer; | |
// Initialize GLFW library | |
if (!glfwInit()) | |
return -1; | |
// Create and open a window | |
if (!glfwOpenWindow(600, // width | |
600, // height | |
8, // red | |
8, // green | |
8, // blue | |
0, // alpha | |
24, // depth | |
0, // stencil | |
GLFW_WINDOW)) //mode | |
return -1; | |
// Build dat program | |
program_id = simple_program(); | |
glUseProgram(program_id); | |
// Where the Position variable from the vertex shader is referenced | |
position_slot = glGetAttribLocation(program_id, "Position"); | |
// Same but with colors | |
color_slot = glGetAttribLocation(program_id, "SourceColor"); | |
// And now for the normal | |
normal_slot = glGetAttribLocation(program_id, "Normal"); | |
// Enable them as arrays of attributes defining vertices | |
glEnableVertexAttribArray(position_slot); | |
glEnableVertexAttribArray(color_slot); | |
glEnableVertexAttribArray(normal_slot); | |
// Create Buffer | |
glGenBuffers(1, &vertex_buffer); | |
// Map GL_ARRAY_BUFFER to this buffer | |
glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer); | |
// Send the data, this is where Position and SourceColor get their data | |
glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW); | |
// Repeat, to map the indices in the above array to the two triangles | |
glGenBuffers(1, &index_buffer); | |
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer); | |
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW); | |
//float r = 600.0/600.0; | |
//calculate_normals(Vertices, Indices); | |
// The model view. Just an identity right now. | |
float modelView[16] = { | |
1, 0, 0, 0, | |
0, 1, 0, 0, | |
0, 0, 1, 0, | |
0, 0, 0, 1 | |
}; | |
glUniformMatrix4fv(glGetUniformLocation(program_id, "ModelView"), 1, 0, &modelView[0]); | |
// Starting angle of the cube, in degrees. | |
float angle = 45; | |
// This makes the light face down. Will investigate later. | |
float lightDirection[3] = {0, 1, 0}; | |
glUniform3fv(glGetUniformLocation(program_id, "LightDirection"), 1, &lightDirection[0]); | |
float ambient[4] = {0.15, 0.15, 0.15, 1.0}; | |
glUniform4fv(glGetUniformLocation(program_id, "Ambient"), 1, &ambient[0]); | |
float diffuse = 0.7; | |
glUniform1fv(glGetUniformLocation(program_id, "DiffuseFactor"), 1, &diffuse); | |
// To prevent graphical anomalies, this tells OpenGL to draw back to front, | |
// and not to draw shapes that are facing away (vertices wound clockwise). | |
glEnable(GL_CULL_FACE); | |
glEnable(GL_DEPTH_TEST); | |
// While the user hasn't mashed "Close" to get back to their LoL sesh. | |
while (glfwGetWindowParam(GLFW_OPENED)) { | |
// Set the background to a muted purple, then clear the screen to that color. | |
glClearColor(0/255.0, 104.0/255.0, 55.0/255.0, 1.0); | |
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
// Rotate the cube about its center on the XY axis. | |
// Placing it here allows the cube to animate. | |
float radians = angle * 3.14159f / 180.0f; | |
angle += 1; | |
if (angle > 359) angle = 0; | |
float s = sinf(radians); | |
float c = cosf(radians); | |
float zRotation[16] = { | |
s, 0, c, 0, | |
s*c, c, -s*s, 0, | |
c*c, -s, -c*s, 0, | |
0, 0, 0, 1 | |
}; | |
GLint rotationUniform = glGetUniformLocation(program_id, "Rotation"); | |
glUniformMatrix4fv(rotationUniform, 1, 0, &zRotation[0]); | |
// Because only rotation is used, the normals may be transformed by the same matrix. | |
glUniformMatrix4fv(glGetUniformLocation(program_id, "NormalMatrix"), 1, 0, &zRotation[0]); | |
// How big the window that was created in GLFW was. | |
glViewport(0, 0, 600, 600); | |
// Point OpenGL at the vertices' positions. | |
glVertexAttribPointer(position_slot, | |
3, | |
GL_FLOAT, | |
GL_FALSE, | |
sizeof(Vertex), | |
0); | |
// Point OpenGl at the vertices' colors. | |
glVertexAttribPointer(color_slot, | |
4, | |
GL_FLOAT, | |
GL_FALSE, | |
sizeof(Vertex), | |
(GLvoid*) (sizeof(float) * 3)); | |
// Point at the vertices' normal vectors | |
glVertexAttribPointer(normal_slot, | |
3, | |
GL_FLOAT, | |
GL_FALSE, | |
sizeof(Vertex), | |
(GLvoid*) (sizeof(float) * 7)); | |
// Consider the vertices as parts of triangles. | |
glDrawElements(GL_TRIANGLES, | |
sizeof(Indices) / sizeof(GLubyte), | |
GL_UNSIGNED_BYTE, 0); | |
// Display dat shit. | |
glfwSwapBuffers(); | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment