Created
March 1, 2012 20:46
-
-
Save Mjiig/1953122 to your computer and use it in GitHub Desktop.
OpenGL cube
This file contains 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
/*stdlibs we need*/ | |
#include <stdio.h> | |
#include <math.h> | |
/*basic allegro functions to give us a window and an OpenGL context*/ | |
#include <allegro5/allegro.h> | |
/*all matrix maths functions*/ | |
#include "matrix.h" | |
/*openggl functions*/ | |
#define GL_GLEXT_PROTOTYPES | |
#include <GL/gl.h> | |
#include <GL/glext.h> | |
/*basic window constants*/ | |
#define FPS 60 | |
#define SCREEN_W 640 | |
#define SCREEN_H 640 | |
struct glinfo | |
{ | |
GLuint program; | |
GLint attribute_coord2d; | |
GLint attribute_colour; | |
GLuint cube_vertices; | |
GLuint cube_colours; | |
GLuint cube_elements; | |
GLint uniform_mvp; | |
GLint uniform_rotation; | |
GLint uniform_translation; | |
}; | |
struct allegroinfo | |
{ | |
ALLEGRO_DISPLAY * display; | |
ALLEGRO_EVENT_QUEUE * event_queue; | |
ALLEGRO_TIMER * timer; | |
ALLEGRO_EVENT ev; | |
}; | |
GLint makeshader ( char * filename, GLenum type ); | |
void print_log ( GLuint object ); | |
int init_resources ( struct glinfo * glpointers ); | |
void draw ( int rotation, struct glinfo * glpointers ); | |
struct allegroinfo * startallegro ( void ); | |
int main ( void ) | |
{ | |
bool redraw = true; | |
struct allegroinfo * alinfo = startallegro(); | |
int rotation = 0; | |
struct glinfo * glpointers = malloc ( sizeof ( struct glinfo ) ); | |
init_resources ( glpointers ); | |
while ( 1 ) | |
{ | |
ALLEGRO_EVENT ev; | |
al_wait_for_event ( alinfo -> event_queue, &ev ); | |
if ( ev.type == ALLEGRO_EVENT_TIMER ) | |
{ | |
redraw = true; | |
rotation++; | |
} | |
else if ( ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE ) | |
{ | |
break; | |
} | |
if ( redraw && al_is_event_queue_empty ( alinfo -> event_queue ) ) | |
{ | |
redraw = false; | |
draw ( rotation, glpointers ); | |
al_flip_display(); | |
} | |
} | |
return 0; | |
} | |
struct allegroinfo * startallegro ( void ) | |
{ | |
struct allegroinfo * retval = malloc ( sizeof ( struct allegroinfo ) ); | |
if ( !al_init() ) | |
{ | |
fprintf ( stderr, "failed to initialise allegro!\n" ); | |
return 0; | |
} | |
retval -> timer = al_create_timer ( 1.0 / FPS ); | |
if ( !retval -> timer ) | |
{ | |
fprintf ( stderr, "failed to create timer!\n" ); | |
return 0; | |
} | |
al_set_new_display_flags ( ALLEGRO_OPENGL ); | |
printf ( "%d\n", al_get_new_display_option ( ALLEGRO_DEPTH_SIZE, NULL ) ); | |
al_set_new_display_option ( ALLEGRO_DEPTH_SIZE, 24, ALLEGRO_SUGGEST ); | |
printf ( "%d\n", al_get_new_display_option ( ALLEGRO_DEPTH_SIZE, NULL ) ); | |
retval -> display = al_create_display ( SCREEN_W , SCREEN_H ); | |
if ( !retval -> display ) | |
{ | |
fprintf ( stderr, "failed to create display!\n" ); | |
return 0; | |
} | |
retval -> event_queue = al_create_event_queue(); | |
if ( !retval -> event_queue ) | |
{ | |
fprintf ( stderr, "failed to create event queue!\n" ); | |
return 0; | |
} | |
al_register_event_source ( retval -> event_queue, al_get_display_event_source ( retval->display ) ); | |
al_register_event_source ( retval -> event_queue, al_get_timer_event_source ( retval->timer ) ); | |
al_start_timer ( retval -> timer ); | |
return retval; | |
} | |
int init_resources ( struct glinfo * glpointers ) | |
{ | |
GLint link_ok = GL_FALSE; | |
GLuint vs; | |
GLuint fs; | |
const char* attribute_name; | |
GLfloat cube_vertices[] = { | |
/* front */ | |
-1.0, -1.0, 1.0, | |
1.0, -1.0, 1.0, | |
1.0, 1.0, 1.0, | |
-1.0, 1.0, 1.0, | |
/* back */ | |
-1.0, -1.0, -1.0, | |
1.0, -1.0, -1.0, | |
1.0, 1.0, -1.0, | |
-1.0, 1.0, -1.0, | |
}; | |
GLfloat cube_colours[] = { | |
/*front colors*/ | |
1.0, 0.0, 0.0, | |
0.0, 1.0, 0.0, | |
0.0, 0.0, 1.0, | |
1.0, 1.0, 1.0, | |
/* back colors*/ | |
1.0, 0.0, 0.0, | |
0.0, 1.0, 0.0, | |
0.0, 0.0, 1.0, | |
1.0, 1.0, 1.0, | |
}; | |
GLushort cube_elements[] = { | |
/*front*/ | |
0, 1, 2, | |
2, 3, 0, | |
/*top*/ | |
1, 5, 6, | |
6, 2, 1, | |
/*back*/ | |
7, 6, 5, | |
5, 4, 7, | |
/*bottom*/ | |
4, 0, 3, | |
3, 7, 4, | |
/*left*/ | |
4, 5, 1, | |
1, 0, 4, | |
/*right*/ | |
3, 2, 6, | |
6, 7, 3 | |
}; | |
glEnable ( GL_BLEND ); | |
glEnable ( GL_DEPTH_TEST ); | |
glBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); | |
glGenBuffers ( 1, & ( glpointers -> cube_vertices ) ); | |
glBindBuffer ( GL_ARRAY_BUFFER, glpointers -> cube_vertices ); | |
glBufferData ( GL_ARRAY_BUFFER, sizeof ( cube_vertices ), cube_vertices, GL_STATIC_DRAW ); | |
glGenBuffers ( 1, & ( glpointers -> cube_colours ) ); | |
glBindBuffer ( GL_ARRAY_BUFFER, glpointers -> cube_colours ); | |
glBufferData ( GL_ARRAY_BUFFER, sizeof ( cube_colours ), cube_colours, GL_STATIC_DRAW ); | |
glGenBuffers ( 1, & ( glpointers -> cube_elements ) ); | |
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, glpointers -> cube_elements ); | |
glBufferData ( GL_ELEMENT_ARRAY_BUFFER, sizeof ( cube_elements ), cube_elements, GL_STATIC_DRAW ); | |
glBindBuffer ( GL_ARRAY_BUFFER, 0 ); | |
if ( ( vs = makeshader ( "vertex.v.glsl", GL_VERTEX_SHADER ) ) == 0 ) | |
return 0; | |
if ( ( fs = makeshader ( "fragment.f.glsl", GL_FRAGMENT_SHADER ) ) == 0 ) | |
return 0; | |
glpointers -> program = glCreateProgram(); | |
glAttachShader ( glpointers -> program, vs ); | |
glAttachShader ( glpointers -> program, fs ); | |
glLinkProgram ( glpointers -> program ); | |
glGetProgramiv ( glpointers -> program, GL_LINK_STATUS, &link_ok ); | |
if ( !link_ok ) | |
{ | |
fprintf ( stderr, "glLinkProgram:" ); | |
print_log ( glpointers -> program ); | |
return 0; | |
} | |
attribute_name = "coord2d"; | |
glpointers -> attribute_coord2d = glGetAttribLocation ( glpointers -> program, attribute_name ); | |
if ( glpointers -> attribute_coord2d == -1 ) { | |
fprintf ( stderr, "Could not bind attribute %s\n", attribute_name ); | |
return 0; | |
} | |
attribute_name = "v_colour"; | |
glpointers -> attribute_colour = glGetAttribLocation ( glpointers -> program, attribute_name ); | |
if ( glpointers -> attribute_colour == -1 ) | |
{ | |
fprintf ( stderr, "Could not bind attribute %s\n", attribute_name ); | |
return 0; | |
} | |
attribute_name = "mvp"; | |
glpointers -> uniform_mvp = glGetUniformLocation ( glpointers -> program, attribute_name ); | |
if ( glpointers -> uniform_mvp == -1 ) | |
{ | |
fprintf ( stderr, "Could not bind uniform %s\n", attribute_name ); | |
return 0; | |
} | |
return 1; | |
} | |
void draw ( int rotation, struct glinfo * glpointers ) | |
{ | |
int size; | |
float r[4][4]; /*holds a rotation, to be applied before m, so multiplied in before it*/ | |
float m[4][4]; /*holds a translation to move the cube away from the scree */ | |
float v[4][4]; /*holds the view matrix output by lookat() */ | |
float p[4][4]; /*holds the projection matrix we get from perspective */ | |
float mvp[4][4];/*holds the final matrix equal to p * v * m * r */ | |
float temp[4][4]; | |
float temp2[4][4]; | |
perspective ( 45.0, SCREEN_W / ( float ) SCREEN_H, 0.1, 100, p ); | |
translate ( 0.0, 0.0, -4.0, m ); | |
lookat ( 0, 2, 0, 0, 0, -4, 0, 1, 0, v ); | |
rotate ( rotation, 0.0, 1.0, 0.0, r ); | |
if ( rotation % 360 == 0 ) | |
{ | |
printf ( "Full turn!\n" ); | |
} | |
multmatrix ( p, v, temp ); | |
multmatrix ( temp, m, temp2 ); | |
multmatrix ( temp2, r, mvp ); | |
/* Clear the background as white */ | |
glClearColor ( 1.0, 1.0, 1.0, 1.0 ); | |
glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); | |
glUseProgram ( glpointers -> program ); | |
glUniformMatrix4fv ( glpointers -> uniform_mvp, 1, GL_FALSE, ( GLfloat * ) mvp ); | |
glBindBuffer ( GL_ARRAY_BUFFER, glpointers -> cube_vertices ); | |
glEnableVertexAttribArray ( glpointers -> attribute_coord2d ); | |
/* Describe our vertices array to OpenGL (it can't guess its format automatically) */ | |
glVertexAttribPointer ( | |
glpointers -> attribute_coord2d, /* attribute */ | |
3, /* number of elements per vertex, here (x,y,z) */ | |
GL_FLOAT, /* the type of each element */ | |
GL_FALSE, /* take our values as-is */ | |
0, /*stride */ | |
0 /* offset of first element */ | |
); | |
glBindBuffer ( GL_ARRAY_BUFFER, glpointers -> cube_colours ); | |
glEnableVertexAttribArray ( glpointers -> attribute_colour ); | |
glVertexAttribPointer ( | |
glpointers -> attribute_colour, | |
3, | |
GL_FLOAT, | |
GL_FALSE, | |
0, | |
0 | |
); | |
/* Push each element in buffer_vertices to the vertex shader */ | |
glBindBuffer ( GL_ELEMENT_ARRAY_BUFFER, glpointers -> cube_elements ); | |
glGetBufferParameteriv ( GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size ); | |
glDrawElements ( GL_TRIANGLES, size / sizeof ( GLushort ), GL_UNSIGNED_SHORT, 0 ); | |
glDisableVertexAttribArray ( glpointers -> attribute_coord2d ); | |
glDisableVertexAttribArray ( glpointers -> attribute_colour ); | |
} | |
#define BLOCKSIZE 512 | |
#define BLOCK (BLOCKSIZE*sizeof(char)) | |
char * readfile ( char * filename ) | |
{ | |
int size; | |
int read = 0; /*total we've read*/ | |
char * retval = malloc ( size = ( BLOCK ) ); | |
char * temp; | |
FILE * in = fopen ( filename, "r" ); | |
if ( !retval ) | |
{ | |
printf ( "Memory allocation failure in readfile\n" ); | |
return NULL; | |
} | |
if ( ! in ) | |
{ | |
printf ( "%s\n", strerror ( errno ) ); | |
} | |
read += fread ( retval, sizeof ( char ), BLOCKSIZE, in ); | |
while ( !feof ( in ) ) | |
{ | |
temp = realloc ( retval, size += BLOCK ); | |
if ( temp ) | |
{ | |
retval = temp; | |
} | |
else | |
{ | |
printf ( "Memory allocation failure in readfile\n" ); | |
return NULL; | |
} | |
read += fread ( retval + read, sizeof ( char ), BLOCK, in ); | |
} | |
retval = realloc ( retval, read + 1 ); | |
retval[read] = '\0'; | |
return retval; | |
} | |
/* | |
* Display compilation errors from the OpenGL shader compiler | |
*/ | |
void print_log ( GLuint object ) | |
{ | |
GLint log_length = 0; | |
char *log; | |
if ( glIsShader ( object ) ) | |
glGetShaderiv ( object, GL_INFO_LOG_LENGTH, &log_length ); | |
else if ( glIsProgram ( object ) ) | |
glGetProgramiv ( object, GL_INFO_LOG_LENGTH, &log_length ); | |
else | |
{ | |
fprintf ( stderr, "printlog: Not a shader or a program\n" ); | |
return; | |
} | |
log = ( char* ) malloc ( log_length ); | |
if ( glIsShader ( object ) ) | |
glGetShaderInfoLog ( object, log_length, NULL, log ); | |
else if ( glIsProgram ( object ) ) | |
glGetProgramInfoLog ( object, log_length, NULL, log ); | |
fprintf ( stderr, "%s", log ); | |
free ( log ); | |
} | |
GLint makeshader ( char * filename, GLenum type ) | |
{ | |
const GLchar * source = readfile ( filename ); | |
GLuint shader = glCreateShader ( type ); | |
GLint compile_ok = GL_FALSE; | |
if ( source == NULL ) | |
{ | |
printf ( "Failure reading file\n" ); | |
return 0; | |
} | |
glShaderSource ( shader, 1, &source, NULL ); | |
free ( ( void * ) source ); | |
glCompileShader ( shader ); | |
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compile_ok ); | |
if ( !compile_ok ) | |
{ | |
fprintf ( stderr, "%s", filename ); | |
print_log ( shader ); | |
glDeleteShader ( shader ); | |
return 0; | |
} | |
return shader; | |
} |
This file contains 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
#version 120 | |
varying vec3 f_colour; | |
void main(void) { | |
gl_FragColor = vec4(f_colour.x, f_colour.y, f_colour.z, 1.0); | |
} |
This file contains 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
/*since these fucntions use each other, make sure they're declared before they're defined*/ | |
#include "matrix.h" | |
/*can't make matrices without using some maths*/ | |
#include <math.h> | |
void normalise ( float vec[4] ) | |
{ | |
float x = vec[0] / vec[3]; | |
float y = vec[1] / vec[3]; | |
float z = vec[2] / vec[3]; | |
float length = sqrtf ( x * x + y * y + z * z ); | |
vec[0] = x / length; | |
vec[1] = y / length; | |
vec[2] = z / length; | |
vec[3] = 1; | |
} | |
void crossproduct ( float a[4], float b[4], float result[4] ) | |
{ | |
result[0] = ( a[1] * b[2] ) - ( a[2] * b[1] ); | |
result[1] = ( a[2] * b[0] ) - ( a[0] * b[2] ); | |
result[2] = ( a[0] * b[1] ) - ( a[1] * b[0] ); | |
result[3] = 1; | |
} | |
void multmatrix ( float a[4][4], float b[4][4], float result[4][4] ) | |
{ | |
int i; | |
int j; | |
int k; | |
float total; | |
for ( i = 0; i < 4; i++ ) | |
for ( j = 0; j < 4; j++ ) | |
{ | |
total = 0; | |
for ( k = 0; k < 4; k++ ) | |
total += a[k][i] * b[j][k]; | |
result[j][i] = total; | |
} | |
} | |
void translate ( float x, float y, float z, float result[4][4] ) | |
{ | |
result[0][0] = 1; | |
result[0][1] = 0; | |
result[0][2] = 0; | |
result[0][3] = 0; | |
result[1][0] = 0; | |
result[1][1] = 1; | |
result[1][2] = 0; | |
result[1][3] = 0; | |
result[2][0] = 0; | |
result[2][1] = 0; | |
result[2][2] = 1; | |
result[2][3] = 0; | |
result[3][0] = x; | |
result[3][1] = y; | |
result[3][2] = z; | |
result[3][3] = 1; | |
} | |
void rotate ( float angle, float x, float y, float z, float result[4][4] ) | |
{ | |
float vec[4] = {x, y, z, 1}; | |
float c = cosf ( angle * M_PI / 180); | |
float s = sinf ( angle * M_PI / 180); | |
normalise ( vec ); | |
result[0][0] = vec[0] * vec[0] * ( 1 - c ) + c; | |
result[0][1] = vec[1] * vec[0] * ( 1 - c ) + vec[2] * s; | |
result[0][2] = vec[2] * vec[0] * ( 1 - c ) - vec[1] * s; | |
result[0][3] = 0; | |
result[1][0] = vec[0] * vec[1] * ( 1 - c ) - vec[2] * s; | |
result[1][1] = vec[1] * vec[1] * ( 1 - c ) + c; | |
result[1][2] = vec[2] * vec[1] * ( 1 - c ) + vec[0] * s; | |
result[1][3] = 0; | |
result[2][0] = vec[0] * vec[2] * ( 1 - c ) + vec[1] * s; | |
result[2][1] = vec[1] * vec[2] * ( 1 - c ) - vec[0] * s; | |
result[2][2] = vec[2] * vec[2] * ( 1 - c ) + c; | |
result[2][3] = 0; | |
result[3][0] = 0; | |
result[3][1] = 0; | |
result[3][2] = 0; | |
result[3][3] = 1; | |
} | |
void lookat ( float eyeX, float eyeY, float eyeZ, float centreX, float centreY, float centreZ, float upX, float upY, float upZ, float result[4][4] ) | |
{ | |
float f[4] = {centreX - eyeX, centreY - eyeY, centreZ - eyeZ, 1}; | |
float u[4] = {upX, upY, upZ, 1}; | |
float s[4]; | |
float temp[4][4]; | |
float temp2[4][4]; | |
normalise ( f ); | |
normalise ( u ); | |
crossproduct ( f, u, s ); | |
normalise ( s ); | |
crossproduct ( s, f, u ); | |
temp[0][0] = s[0]; | |
temp[1][0] = s[1]; | |
temp[2][0] = s[2]; | |
temp[3][0] = 0; | |
temp[0][1] = u[0]; | |
temp[1][1] = u[1]; | |
temp[2][1] = u[2]; | |
temp[3][1] = 0; | |
temp[0][2] = -f[0]; | |
temp[1][2] = -f[1]; | |
temp[2][2] = -f[2]; | |
temp[3][2] = 0; | |
temp[0][3] = 0; | |
temp[1][3] = 0; | |
temp[2][3] = 0; | |
temp[3][3] = 1; | |
translate ( -eyeX, -eyeY, -eyeZ, temp2 ); | |
multmatrix ( temp, temp2, result ); | |
} | |
void perspective ( float fovy, float aspect, float zNear, float zFar, float result[4][4] ) | |
{ | |
float f = 1 / tanf ( fovy * M_PI / 360 ); | |
result[0][0] = f / aspect; | |
result[0][1] = 0; | |
result[0][2] = 0; | |
result[0][3] = 0; | |
result[1][0] = 0; | |
result[1][1] = f; | |
result[1][2] = 0; | |
result[1][3] = 0; | |
result[2][0] = 0; | |
result[2][1] = 0; | |
result[2][2] = ( zFar + zNear ) / ( zNear - zFar ); | |
result[2][3] = -1; | |
result[3][0] = 0; | |
result[3][1] = 0; | |
result[3][2] = ( 2 * zNear * zFar ) / ( zNear - zFar ); | |
result[3][3] = 0; | |
} |
This file contains 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
#ifndef MATRIX_H | |
#define MATRIX_H | |
//define M_PI to something sensible since we're using c99 which doens't define it for whatever reason | |
#define M_PI 3.14159265358979323846264338327 | |
void normalise ( float vec[4] ); | |
void crossproduct ( float a[4], float b[4], float result[4] ); | |
void multmatrix ( float a[4][4], float b[4][4], float result[4][4] ); | |
void rotate ( float angle, float x, float y, float z, float result[4][4] ); | |
void translate ( float x, float y, float z, float result[4][4] ); | |
void lookat ( float eyeX, float eyeY, float eyeZ, float centreX, float centreY, float centreZ, float upX, float upY, float upZ, float result[4][4] ); | |
void perspective ( float fovy, float aspect, float zNear, float zFar, float result[4][4] ); | |
#endif |
This file contains 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
#version 120 | |
attribute vec3 coord2d; | |
attribute vec3 v_colour; | |
varying vec3 f_colour; | |
uniform mat4 mvp; | |
void main(void) { | |
gl_Position = mvp * vec4(coord2d, 1.0); | |
f_colour=v_colour; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment