/* * Copyright (C) 1999-2001 Brian Paul All Rights Reserved. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* * This is a port of the infamous "glxgears" demo to straight EGL * Port by Dane Rushton 10 July 2005 * * No command line options. * Program runs for 5 seconds then exits, outputing framerate to console */ #define MAXFRAME 5 #define PFINISH 1 #include #include #include #define GL_GLEXT_PROTOTYPES #include #include static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0; static GLint gear1, gear2, gear3; static GLfloat angle = 0.0; static GLfloat cube_rot = 0.0; static GLuint gears_fbo, gears_tex; static GLuint win_width = 1024; static GLuint win_height = 512; static GLuint frames = 0; static GLuint renderbuffers[3]; static GLuint nrenderbuffers = 0; GLuint generate_simple_fbo(unsigned width, unsigned height) { GLuint fb; GLenum status; unsigned color, stencil, depth, packed; color = stencil = depth = packed = 1; /* texture */ glGenTextures(1, &gears_tex); glBindTexture(GL_TEXTURE_2D, gears_tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glGenFramebuffers(1, &fb); glBindFramebuffer(GL_FRAMEBUFFER, fb); if (color) { #if 0 glGenRenderbuffers(1, &renderbuffers[nrenderbuffers]); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[nrenderbuffers]); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffers[nrenderbuffers]); nrenderbuffers++; #else glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, gears_tex, 0); #endif } if (stencil) { const GLenum format = (packed) ? GL_DEPTH24_STENCIL8 : GL_STENCIL_INDEX8; const GLenum attachment = (packed) ? GL_DEPTH_STENCIL_ATTACHMENT : GL_STENCIL_ATTACHMENT; glGenRenderbuffers(1, &renderbuffers[nrenderbuffers]); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[nrenderbuffers]); glRenderbufferStorage(GL_RENDERBUFFER, format, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, attachment, GL_RENDERBUFFER, renderbuffers[nrenderbuffers]); nrenderbuffers++; } if (!packed && depth) { glGenRenderbuffers(1, &renderbuffers[nrenderbuffers]); glBindRenderbuffer(GL_RENDERBUFFER, renderbuffers[nrenderbuffers]); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderbuffers[nrenderbuffers]); nrenderbuffers++; } status = glGetError(); if (status != GL_NO_ERROR) { fprintf(stderr, "Unexpected GL error: 0x%x\n", status); exit(1); } /* All of the possible combinations that we can generate are required * to be supported by all OpenGL 3.0 implementations, with one * exception. As far as I can tell, implementations are not required * to support separate depth and stencil. That one option is handled * specially. */ status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE && !(status == GL_FRAMEBUFFER_UNSUPPORTED && stencil && !packed)) { fprintf(stderr, "Framebuffer %s color, %s stencil (%s) was not " "complete: 0x%04x\n", color ? "with" : "without", stencil ? "with" : "without", packed ? "packed" : "separate", status); exit(1); } if (status == GL_FRAMEBUFFER_UNSUPPORTED) { glDeleteRenderbuffers(nrenderbuffers, renderbuffers); glDeleteFramebuffers(1, &fb); fprintf(stderr, "Unsupported framebuffer\n"); exit(1); } glBindFramebuffer(GL_FRAMEBUFFER, 0); #if 0 glClearColor(0.2, 0.4, 0.6, 1.0); glClearDepth(0.5); glClearStencil(0x7a); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glFinish(); #endif return fb; } /* * Draw a gear wheel. You'll probably want to call this function when * building a display list since we do a lot of trig here. * * Input: inner_radius - radius of hole at center * outer_radius - radius at center of teeth * width - width of gear * teeth - number of teeth * tooth_depth - depth of tooth */ static void gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width, GLint teeth, GLfloat tooth_depth) { GLint i; GLfloat r0, r1, r2; GLfloat angle, da; GLfloat u, v, len; r0 = inner_radius; r1 = outer_radius - tooth_depth / 2.0; r2 = outer_radius + tooth_depth / 2.0; da = 2.0 * M_PI / teeth / 4.0; glShadeModel(GL_FLAT); glNormal3f(0.0, 0.0, 1.0); /* draw front face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); if (i < teeth) { glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); } } glEnd(); /* draw front sides of teeth */ glBegin(GL_QUADS); da = 2.0 * M_PI / teeth / 4.0; for (i = 0; i < teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); } glEnd(); glNormal3f(0.0, 0.0, -1.0); /* draw back face */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); if (i < teeth) { glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); } } glEnd(); /* draw back sides of teeth */ glBegin(GL_QUADS); da = 2.0 * M_PI / teeth / 4.0; for (i = 0; i < teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); } glEnd(); /* draw outward faces of teeth */ glBegin(GL_QUAD_STRIP); for (i = 0; i < teeth; i++) { angle = i * 2.0 * M_PI / teeth; glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5); glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5); u = r2 * cos(angle + da) - r1 * cos(angle); v = r2 * sin(angle + da) - r1 * sin(angle); len = sqrt(u * u + v * v); u /= len; v /= len; glNormal3f(v, -u, 0.0); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5); glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5); glNormal3f(cos(angle), sin(angle), 0.0); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), width * 0.5); glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da), -width * 0.5); u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da); v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da); glNormal3f(v, -u, 0.0); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), width * 0.5); glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da), -width * 0.5); glNormal3f(cos(angle), sin(angle), 0.0); } glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5); glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5); glEnd(); glShadeModel(GL_SMOOTH); /* draw inside radius cylinder */ glBegin(GL_QUAD_STRIP); for (i = 0; i <= teeth; i++) { angle = i * 2.0 * M_PI / teeth; glNormal3f(-cos(angle), -sin(angle), 0.0); glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5); glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5); } glEnd(); } static void draw_gear(void) { #if PFINISH fprintf(stderr, "EE CLEAR FBO -------------------------------------------------\n"); #endif glBindFramebuffer(GL_FRAMEBUFFER, gears_fbo); glClearColor(0.5, 0.5, 0.8, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #if PFINISH fprintf(stderr, "EE CLEAR FBO _________________________________________________\n"); #endif #if PFINISH fprintf(stderr, "EE DRAW FBO --------------------------------------------------\n"); #endif glPushMatrix(); glRotatef(view_rotx, 1.0, 0.0, 0.0); glRotatef(view_roty, 0.0, 1.0, 0.0); glRotatef(view_rotz, 0.0, 0.0, 1.0); glPushMatrix(); glTranslatef(-3.0, -2.0, 0.0); glRotatef(angle, 0.0, 0.0, 1.0); glCallList(gear1); glPopMatrix(); glPushMatrix(); glTranslatef(3.1, -2.0, 0.0); glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0); glCallList(gear2); glPopMatrix(); glPushMatrix(); glTranslatef(-3.1, 4.2, 0.0); glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0); glCallList(gear3); glPopMatrix(); glPopMatrix(); glBindFramebuffer(GL_FRAMEBUFFER, 0); #if PFINISH fprintf(stderr, "EE DRAW FBO __________________________________________________\n"); #endif } static void draw_cube(void) { static const GLfloat texcoords[4][2] = { { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 } }; static const GLfloat vertices[4][2] = { { -1, -1 }, { 1, -1 }, { 1, 1 }, { -1, 1 } }; static const GLfloat xforms[6][4] = { { 0, 0, 1, 0 }, { 90, 0, 1, 0 }, { 180, 0, 1, 0 }, { 270, 0, 1, 0 }, { 90, 1, 0, 0 }, { -90, 1, 0, 0 } }; static const GLfloat mat[4] = { 1.0, 1.0, 0.5, 1.0 }; float ar; GLint i, j; #if PFINISH fprintf(stderr, "EE CLEAR -----------------------------------------------------\n"); #endif glClearColor(0.8, 0.5, 0.5, 0.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); #if PFINISH fprintf(stderr, "EE CLEAR _____________________________________________________\n"); #endif #if PFINISH fprintf(stderr, "EE DRAW ------------------------------------------------------\n"); #endif ar = (float)win_width / win_height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-ar, ar, -1.0, 1.0, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, gears_tex); glPushMatrix(); glRotatef(view_rotx, 1.0, 0.0, 0.0); glRotatef(15, 1, 0, 0); glRotatef(cube_rot, 0, 1, 0); glScalef(4, 4, 4); for (i = 0; i < 6; i++) { glPushMatrix(); glRotatef(xforms[i][0], xforms[i][1], xforms[i][2], xforms[i][3]); glTranslatef(0, 0, 1.1); glBegin(GL_POLYGON); glNormal3f(0, 0, 1); for (j = 0; j < 4; j++) { glTexCoord2fv(texcoords[j]); glVertex2fv(vertices[j]); } glEnd(); glPopMatrix(); } glPopMatrix(); glDisable(GL_TEXTURE_2D); #if PFINISH fprintf(stderr, "EE DRAW ______________________________________________________\n"); #endif } static void draw(void) { #if PFINISH fprintf(stderr, "EE FRAME -----------------------------------------------------\n"); #endif draw_gear(); draw_cube(); #if PFINISH glFinish(); fprintf(stderr, "EE FRAME _____________________________________________________\n"); #endif glutSwapBuffers(); frames++; if (frames >= MAXFRAME) { exit(0); } } static void idle(void) { static double t0 = -1.; double dt, t; t = glutGet(GLUT_ELAPSED_TIME) / 1000.0; if (t0 < 0.0) t0 = t; dt = t - t0; t0 = t; angle += 70.0 * dt; /* 70 degrees per second */ angle = fmod(angle, 360.0); /* prevents eventual overflow */ cube_rot = fmod(cube_rot + 15.0 * dt, 360.0); /* 15 deg/sec */ glutPostRedisplay(); } /* new window size or exposure */ static void reshape(int width, int height) { GLfloat h = (GLfloat) height / (GLfloat) width; glViewport(0, 0, (GLint) width, (GLint) height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, -40.0); win_width = width; win_height = height; } static void init(void) { static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 }; static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 }; static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 }; static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 }; glLightfv(GL_LIGHT0, GL_POSITION, pos); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); /* make the gears */ gear1 = glGenLists(1); glNewList(gear1, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red); gear(1.0, 4.0, 1.0, 20, 0.7); glEndList(); gear2 = glGenLists(1); glNewList(gear2, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green); gear(0.5, 2.0, 2.0, 10, 0.7); glEndList(); gear3 = glGenLists(1); glNewList(gear3, GL_COMPILE); glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue); gear(1.3, 2.0, 0.5, 10, 0.7); glEndList(); gears_fbo = generate_simple_fbo(512, 512); glEnable(GL_NORMALIZE); } int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | GLUT_STENCIL); glutInitWindowSize(win_width, win_height); glutCreateWindow("glgears"); GLenum err = glewInit(); if (GLEW_OK != err) { fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); return -1; } glutIdleFunc(idle); glutReshapeFunc(reshape); glutDisplayFunc(draw); init(); reshape(win_width, win_height); glutMainLoop(); return 0; }