/* * VBO-cube.c * This program demonstrates VBOs for a cube. * $Id: VBO-cube.c,v 1.4 2014/07/28 02:03:24 gl Exp gl $ */ #define DEBUG #define GL_GLEXT_PROTOTYPES #include #include #include #include #include #include #include enum RenderMode { IMMEDIATE_MODE = 0, VERTEX_ARRAY, VERTEX_BUFFER_OBJECT, NUMRENMODES } renMode = VERTEX_ARRAY; enum DerefMethods { DRAWARRAYS = 0, MULTIDRAWARRAYS, ARRAYELEMENT, DRAWELEMENTS, DRAWELEMENTSALL, MULTIDRAWELEMENTS, NUMDEREFMETHODS } derefMethod = DRAWARRAYS; bool useBufferObjects = false; GLfloat vertices[] = { -1.0, -1.0, -1.0, // 0 1.0, -1.0, -1.0, // 1 1.0, 1.0, -1.0, // 2 -1.0, 1.0, -1.0, // 3 -1.0, -1.0, 1.0, // 4 1.0, -1.0, 1.0, // 5 1.0, 1.0, 1.0, // 6 -1.0, 1.0, 1.0 // 7 }; GLfloat colors[] = { 0.0, 0.0, 0.0, // 0 1.0, 0.0, 0.0, // 1 0.0, 1.0, 0.0, // 2 0.0, 0.0, 1.0, // 3 1.0, 1.0, 0.0, // 4 1.0, 0.0, 1.0, // 5 0.0, 1.0, 1.0, // 6 1.0, 1.0, 1.0, // 7 }; GLfloat colorsAndVertices[] = { // Colors 0.0, 0.0, 0.0, // 0 1.0, 0.0, 0.0, // 1 0.0, 1.0, 0.0, // 2 0.0, 0.0, 1.0, // 3 1.0, 1.0, 0.0, // 4 1.0, 0.0, 1.0, // 5 0.0, 1.0, 1.0, // 6 1.0, 1.0, 1.0, // 7 // Vertices 0.0, 0.0, 0.0, // 0 1.0, 0.0, 0.0, // 1 1.0, 1.0, 0.0, // 2 0.0, 1.0, 0.0, // 3 0.0, 0.0, 1.0, // 4 1.0, 0.0, 1.0, // 5 1.0, 1.0, 1.0, // 6 0.0, 1.0, 1.0, // 7 }; GLfloat colorsAndVerticesInterleaved[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, // 0 1.0, 0.0, 0.0, 1.0, 0.0, 0.0, // 1 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, // 2 0.0, 0.0, 1.0, 0.0, 1.0, 0.0, // 3 1.0, 1.0, 0.0, 0.0, 0.0, 1.0, // 4 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, // 5 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, // 6 1.0, 1.0, 1.0, 0.0, 1.0, 1.0, // 7 }; GLfloat verticesQuads[] = { // Front -1.0, -1.0, 1.0, // 4 1.0, -1.0, 1.0, // 5 1.0, 1.0, 1.0, // 6 -1.0, 1.0, 1.0, // 7 // Back -1.0, -1.0, -1.0, // 0 -1.0, 1.0, -1.0, // 3 1.0, 1.0, -1.0, // 2 1.0, -1.0, -1.0, // 1 // Left -1.0, -1.0, -1.0, // 0 -1.0, -1.0, 1.0, // 4 -1.0, 1.0, 1.0, // 7 -1.0, 1.0, -1.0, // 3 // Right 1.0, -1.0, -1.0, // 1 1.0, 1.0, -1.0, // 2 1.0, 1.0, 1.0, // 6 1.0, -1.0, 1.0, // 5 // Bottom -1.0, -1.0, -1.0, // 0 1.0, -1.0, -1.0, // 1 1.0, -1.0, 1.0, // 5 -1.0, -1.0, 1.0, // 4 // Top 1.0, 1.0, -1.0, // 2 -1.0, 1.0, -1.0, // 3 -1.0, 1.0, 1.0, // 7 1.0, 1.0, 1.0, // 6 }; GLfloat colorsQuads[] = { // Front 1.0, 1.0, 0.0, // 4 1.0, 0.0, 1.0, // 5 0.0, 1.0, 1.0, // 6 1.0, 1.0, 1.0, // 7 // Back 0.0, 0.0, 0.0, // 0 0.0, 0.0, 1.0, // 3 0.0, 1.0, 0.0, // 2 1.0, 0.0, 0.0, // 1 // Left 0.0, 0.0, 0.0, // 0 1.0, 1.0, 0.0, // 4 1.0, 1.0, 1.0, // 7 0.0, 0.0, 1.0, // 3 // Right 1.0, 0.0, 0.0, // 1 0.0, 1.0, 0.0, // 2 0.0, 1.0, 1.0, // 6 1.0, 0.0, 1.0, // 5 // Bottom 0.0, 0.0, 0.0, // 0 1.0, 0.0, 0.0, // 1 1.0, 0.0, 1.0, // 5 1.0, 1.0, 0.0, // 4 // Top 0.0, 1.0, 0.0, // 2 0.0, 0.0, 1.0, // 3 1.0, 1.0, 1.0, // 7 0.0, 1.0, 1.0, // 6 }; GLuint indices1DArray[] = { 4, 5, 6, 7, // Front 0, 3, 2, 1, // Back 0, 4, 7, 3, // Left 1, 2, 6, 5, // Right 0, 1, 5, 4, // Bottom 2, 3, 7, 6 // Top }; GLuint indices2DArray[][4] = { { 4, 5, 6, 7 }, // Front { 0, 3, 2, 1 }, // Back { 0, 4, 7, 3 }, // Left { 1, 2, 6, 5 }, // Right { 0, 1, 5, 4 }, // Bottom { 2, 3, 7, 6 } // Top }; GLuint frontIndices[] = { 4, 5, 6, 7 }; GLuint backIndices[] = { 0, 3, 2, 1 }; GLuint leftIndices[] = { 0, 4, 7, 3 }; GLuint rightIndices[] = { 1, 2, 6, 5 }; GLuint bottomIndices[] = { 0, 1, 5, 4 }; GLuint topIndices[] = { 2, 3, 7, 6 }; const GLvoid* indices1DArrayOfArray[] = { frontIndices, backIndices, leftIndices, rightIndices, bottomIndices, topIndices }; GLint indicesFirsts[] = { 0, 4, 8, 12, 16, 20 }; GLsizei indicesCounts[] = { 4, 4, 4, 4, 4, 4 }; const GLvoid* indicesOffsets[] = { (GLvoid*)(0), (GLvoid*)(4 * sizeof(GLuint)), (GLvoid*)(8 * sizeof(GLuint)), (GLvoid*)(12 * sizeof(GLuint)), (GLvoid*)(16 * sizeof(GLuint)), (GLvoid*)(20 * sizeof(GLuint)), }; GLsizei numQuads = 6; #define VERTICES 0 #define VERTICES_QUADS 1 #define COLORS 2 #define COLORS_QUADS 3 #define INDICES 4 #define NUM_BUFFERS 5 GLuint buffers[NUM_BUFFERS]; void checkForGLerrors(int lineno) { GLenum error; while ((error = glGetError()) != GL_NO_ERROR) printf("%d: %s\n", lineno, gluErrorString(error)); } void enableVertexArrays(void) { glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_COLOR_ARRAY); } void disableVertexArrays(void) { glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); } void generateBuffers(void) { glGenBuffers(NUM_BUFFERS, buffers); } void bufferData() { glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES_QUADS]); glBufferData(GL_ARRAY_BUFFER, sizeof(verticesQuads), verticesQuads, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES]); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, buffers[COLORS]); glBufferData(GL_ARRAY_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, buffers[COLORS_QUADS]); glBufferData(GL_ARRAY_BUFFER, sizeof(colorsQuads), colorsQuads, GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[INDICES]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices2DArray), indices2DArray, GL_STATIC_DRAW); } void unBindBuffers() { int buffer; glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &buffer); if (buffer != 0) glBindBuffer(GL_ARRAY_BUFFER, 0); glGetIntegerv(GL_ELEMENT_ARRAY_BUFFER_BINDING, &buffer); if (buffer != 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } /* Immediate mode, vertex at a time */ void renderCubeIM() { int i, j; glBegin(GL_QUADS); for (i = 0; i < numQuads; i++) for (j = 0; j < 4; j++) { glColor3fv(&colors[indices1DArray[i*4+j]*3]); glVertex3fv(&vertices[indices1DArray[i*4+j]*3]); } glEnd(); } /* Use VAs or VBOs */ void renderCubeVAVBO() { int i, j; /* Bind/unbind buffers and set vertex and color array pointers */ switch (derefMethod) { case DRAWARRAYS: case MULTIDRAWARRAYS: if (renMode == VERTEX_ARRAY) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glVertexPointer(3, GL_FLOAT, 0, verticesQuads); glColorPointer(3, GL_FLOAT, 0, colorsQuads); } else if (renMode == VERTEX_BUFFER_OBJECT) { glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES_QUADS]); glVertexPointer(3, GL_FLOAT, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, buffers[COLORS_QUADS]); glColorPointer(3, GL_FLOAT, 0, 0); } break; case ARRAYELEMENT: case DRAWELEMENTS: case DRAWELEMENTSALL: case MULTIDRAWELEMENTS: if (renMode == VERTEX_ARRAY) { glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); glVertexPointer(3, GL_FLOAT, 0, vertices); glColorPointer(3, GL_FLOAT, 0, colors); } if (renMode == VERTEX_BUFFER_OBJECT) { glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTICES]); glVertexPointer(3, GL_FLOAT, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, buffers[COLORS]); glColorPointer(3, GL_FLOAT, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[INDICES]); } break; } /* Render using chosen dereference technique. */ switch (derefMethod) { case DRAWARRAYS: glDrawArrays(GL_QUADS, 0, 24); break; case MULTIDRAWARRAYS: /* Just an example to demonstrate usage - no advantage to use * glMultiDrawArrays for cube as all primitives are quads and same * size so glDrawArrays does the job. */ glMultiDrawArrays(GL_QUADS, indicesFirsts, indicesCounts, numQuads); break; case ARRAYELEMENT: glBegin(GL_QUADS); for (i = 0; i < numQuads; i++) for (j = 0; j < 4; j++) glArrayElement(((GLuint*)indices1DArrayOfArray[i])[j]); glEnd(); break; case DRAWELEMENTS: for (i = 0; i < numQuads; i++) if (renMode == VERTEX_ARRAY) /* Can use either indices1DArray or indices2DArrays */ glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, &indices1DArray[i*4]); else if (renMode == VERTEX_BUFFER_OBJECT) glDrawElements(GL_QUADS, 4, GL_UNSIGNED_INT, indicesOffsets[i]); break; case DRAWELEMENTSALL: if (renMode == VERTEX_ARRAY) glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, indices1DArray); else if (renMode == VERTEX_BUFFER_OBJECT) glDrawElements(GL_QUADS, 24, GL_UNSIGNED_INT, 0); break; case MULTIDRAWELEMENTS: /* Another example just to demonstrate usage. Like * glMultiDrawArrays, no advantage using the 'multi' version for * cube consisting of quads as all same size. */ if (renMode == VERTEX_ARRAY) glMultiDrawElements(GL_QUADS, indicesCounts, GL_UNSIGNED_INT, indices1DArrayOfArray, numQuads); else if (renMode == VERTEX_BUFFER_OBJECT) glMultiDrawElements(GL_QUADS, indicesCounts, GL_UNSIGNED_INT, indicesOffsets, numQuads); break; } } void init(void) { glClearColor(0.0, 0.0, 0.0, 0.0); glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); generateBuffers(); enableVertexArrays(); bufferData(); unBindBuffers(); } void display(void) { #ifdef DEBUG printf("rendering mode: %d\n", renMode); if (renMode != IMMEDIATE_MODE) printf("derefence method: %d\n", derefMethod); #endif glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glLoadIdentity(); /* Oblique view, scale cube */ glRotatef(15.0, 1.0, 0.0, 0.0); glRotatef(-30.0, 0.0, 1.0, 0.0); glScalef(0.5, 0.5, 0.5); if (renMode == IMMEDIATE_MODE) renderCubeIM(); else if (renMode == VERTEX_ARRAY || renMode == VERTEX_BUFFER_OBJECT) renderCubeVAVBO(); checkForGLerrors(__LINE__); glutSwapBuffers(); } void reshape (int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); } void mouse (int button, int state, int x, int y) { switch (button) { case GLUT_LEFT_BUTTON: if (state == GLUT_DOWN) { renMode++; if (renMode >= NUMRENMODES) renMode = 0; glutPostRedisplay(); } break; case GLUT_RIGHT_BUTTON: if (state == GLUT_DOWN) { derefMethod++; if (derefMethod >= NUMDEREFMETHODS) derefMethod = 0; glutPostRedisplay(); } break; default: break; } } void keyboard(unsigned char key, int x, int y) { switch (key) { case 'l': glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glutPostRedisplay(); break; case 'f': glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glutPostRedisplay(); break; case 'c': glShadeModel(GL_FLAT); glutPostRedisplay(); break; case 's': glShadeModel(GL_SMOOTH); glutPostRedisplay(); break; case 27: exit(0); break; } } int main(int argc, char** argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(350, 350); glutInitWindowPosition(100, 100); glutCreateWindow(argv[0]); init(); glutDisplayFunc(display); glutReshapeFunc(reshape); glutMouseFunc(mouse); glutKeyboardFunc(keyboard); glutMainLoop(); return 0; }