#define GL_GLEXT_PROTOTYPES 1 #include <assert.h> #include <stddef.h> #include <stdlib.h> #include <stdio.h> #include <GL/glut.h> #include <GL/glext.h> typedef float vector4[4]; typedef struct { vector4 position; vector4 colour; } vertex; static GLuint vertices_name; static GLuint triangles[2]; static void init_data() { vertex *data = malloc(4 * sizeof(vertex)); if (data == NULL) abort(); data[0].position[0] = 0.0; data[0].position[1] = 0.0; data[0].position[2] = 0.0; data[0].position[3] = 1.0; data[0].colour[0] = 1.0; data[0].colour[1] = 0.0; data[0].colour[2] = 0.0; data[0].colour[3] = 1.0; data[1].position[0] = 100.0; data[1].position[1] = 0.0; data[1].position[2] = 0.0; data[1].position[3] = 1.0; data[1].colour[0] = 0.0; data[1].colour[1] = 1.0; data[1].colour[2] = 0.0; data[1].colour[3] = 1.0; data[2].position[0] = 100.0; data[2].position[1] = 100.0; data[2].position[2] = 0.0; data[2].position[3] = 1.0; data[2].colour[0] = 0.0; data[2].colour[1] = 0.0; data[2].colour[2] = 1.0; data[2].colour[3] = 1.0; data[3].position[0] = 0.0; data[3].position[1] = 100.0; data[3].position[2] = 0.0; data[3].position[3] = 1.0; data[3].colour[0] = 1.0; data[3].colour[1] = 1.0; data[3].colour[2] = 0.0; data[3].colour[3] = 1.0; glGenBuffers(1, &vertices_name); glBindBuffer(GL_ARRAY_BUFFER, vertices_name); glBufferData(GL_ARRAY_BUFFER, 4 * sizeof(vertex), data, GL_STATIC_DRAW); free(data); glGenBuffers(2, triangles); { unsigned short indices[] = { 0, 1, 2 }; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles[0]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); } { unsigned short indices[] = { 1, 2, 3 }; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles[1]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); } assert(glGetError() == GL_NO_ERROR); } static GLuint shader_vertex; static GLuint shader_fragment; static GLuint shader_program; static const char *shader_vertex_source[] = { "#version 110\n", "\n", "attribute vec4 position_data;\n", "attribute vec4 colour_data;\n", "\n", "void main()\n", "{\n", " gl_Position = gl_ProjectionMatrix * gl_ModelViewMatrix * position_data;\n", " gl_FrontColor = colour_data;\n", "}\n" }; static const char *shader_fragment_source[] = { "#version 110\n", "\n", "void main()\n", "{\n", " gl_FragColor = gl_Color;\n", "}\n" }; static void init_shaders(void) { GLint ok; char shader_log[8192]; /* * Compile vertex shader. */ shader_vertex = glCreateShader(GL_VERTEX_SHADER); glShaderSource( shader_vertex, sizeof(shader_vertex_source) / sizeof(const char *), shader_vertex_source, NULL); glCompileShader(shader_vertex); glGetShaderiv(shader_vertex, GL_COMPILE_STATUS, &ok); if (ok == GL_FALSE) { GLsizei size; glGetShaderInfoLog(shader_vertex, sizeof(shader_log), &size, shader_log); fprintf(stderr, "fatal: vertex shader:\n%s\n", shader_log); exit(1); } /* * Compile fragment shader. */ shader_fragment = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource( shader_fragment, sizeof(shader_fragment_source) / sizeof(const char *), shader_fragment_source, NULL); glCompileShader(shader_fragment); glGetShaderiv(shader_fragment, GL_COMPILE_STATUS, &ok); if (ok == GL_FALSE) { GLsizei size; glGetShaderInfoLog(shader_fragment, sizeof(shader_log), &size, shader_log); fprintf(stderr, "fatal: fragment shader:\n%s\n", shader_log); exit(1); } /* * Link shading program. */ shader_program = glCreateProgram(); glAttachShader(shader_program, shader_vertex); glAttachShader(shader_program, shader_fragment); glLinkProgram(shader_program); glGetProgramiv(shader_program, GL_LINK_STATUS, &ok); if (ok == GL_FALSE) { GLsizei size; glGetShaderInfoLog(shader_program, sizeof(shader_log), &size, shader_log); fprintf(stderr, "fatal: %s\n", shader_log); exit(1); } assert(glGetError() == GL_NO_ERROR); } static void init(void) { init_data(); init_shaders(); } static void reshape(int width, int height) { glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, width, 0, height, -1.0, 100.0); assert(glGetError() == GL_NO_ERROR); } static void display(void) { glClearColor(0.3f, 0.3f, 0.3f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); { const int position_attrib = glGetAttribLocation(shader_program, "position_data"); const int colour_attrib = glGetAttribLocation(shader_program, "colour_data"); assert (position_attrib != -1); assert (colour_attrib != -1); glBindBuffer(GL_ARRAY_BUFFER, vertices_name); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles[0]); glEnableVertexAttribArray(position_attrib); glVertexAttribPointer(position_attrib, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), 0); glEnableVertexAttribArray(colour_attrib); glVertexAttribPointer(colour_attrib, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (void *) offsetof(vertex, colour)); glUseProgram(shader_program); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, (void *) 0); glTranslated(120.0, 120.0, 0.0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangles[1]); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, (void *) 0); glUseProgram(0); glDisableVertexAttribArray(position_attrib); glDisableVertexAttribArray(colour_attrib); } assert(glGetError() == GL_NO_ERROR); glutSwapBuffers(); } int main(int argc, char **argv) { glutInit(&argc, argv); glutCreateWindow("Modern GL triangles"); init(); glutReshapeFunc(reshape); glutDisplayFunc(display); glutIdleFunc(glutPostRedisplay); glutMainLoop(); return 0; }