Skip to content

Instantly share code, notes, and snippets.

@realModusOperandi
Created April 20, 2013 04:33
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save realModusOperandi/5424758 to your computer and use it in GitHub Desktop.
Save realModusOperandi/5424758 to your computer and use it in GitHub Desktop.
A cube.
#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