Skip to content

Instantly share code, notes, and snippets.

@Mjiig
Created March 1, 2012 20:46
Show Gist options
  • Save Mjiig/1953122 to your computer and use it in GitHub Desktop.
Save Mjiig/1953122 to your computer and use it in GitHub Desktop.
OpenGL cube
/*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;
}
#version 120
varying vec3 f_colour;
void main(void) {
gl_FragColor = vec4(f_colour.x, f_colour.y, f_colour.z, 1.0);
}
/*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;
}
#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
#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