/* pyramid.cpp * */ #include #include /* for some reason order of the headers matters */ #include "lib/gltools.h" #include "lib/math3d.h" #include "lib/glframe.h" #include #define FRAMES_PER_SECOND 300 static GLfloat xRot = 0.0f; static GLfloat yRot = 0.0f; /* global camera used to walk in the scene */ GLFrame frameCamera; static void resize(int w, int h) { printf("window: resizing to %dx%d\n", w, h); GLfloat fAspect = (GLfloat) w / (GLfloat) h; if (h == 0) h = 1; glViewport(0, 0, w, h); /* reset coordinate system */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); /* produce the perspective projection */ gluPerspective(40.0f, fAspect, 1.0, 40.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); /* this needs to be ran again, glut does it for you I suppose */ SDL_SetVideoMode(w, h, 32, SDL_OPENGL | SDL_RESIZABLE); } static void SetupRC() { GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; /* light values and coordinates */ GLfloat whiteLight[] = { 0.05f, 0.05f, 0.05f, 1.0f }; GLfloat sourceLight[] = { 0.75f, 0.75f, 0.75f, 1.0f }; GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f }; glEnable(GL_DEPTH_TEST); /* hidden surface removal */ glFrontFace(GL_CCW); /* counter clock-wise polygons face out */ glEnable(GL_CULL_FACE); /* do not calculate inside of a pyramid */ /* enable lighting */ glEnable(GL_LIGHTING); /* setup and enable light 0 */ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteLight); glLightfv(GL_LIGHT0, GL_AMBIENT, sourceLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, sourceLight); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); glEnable(GL_LIGHT0); /* enable color tracking */ glEnable(GL_COLOR_MATERIAL); /* set Material properties to follow glColor values */ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); /* gray background */ glClearColor(0.5f, 0.5f, 0.5f, 1.0f); /* load texture */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); pBytes = gltLoadTGA("stone.tga", &iWidth, &iHeight, &iComponents, &eFormat); if (!pBytes) fprintf(stderr, "gltLoadTGA: failed to load texture!\n"); /* load texture image */ glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); free(pBytes); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glEnable(GL_TEXTURE_2D); } static void keys(SDL_keysym *keysym, unsigned int *keys_held, int flag) { if (!flag) { switch (keysym->sym) { case SDLK_ESCAPE: exit(0); break; case SDLK_w: xRot -= 1.0f; break; case SDLK_s: xRot += 1.0f; break; case SDLK_a: yRot -= 1.0f; break; case SDLK_d: yRot += 1.0f; break; case SDLK_UP: frameCamera.MoveForward(0.1f); break; case SDLK_DOWN: frameCamera.MoveForward(-0.1f); break; case SDLK_LEFT: frameCamera.RotateLocalY(0.1f); break; case SDLK_RIGHT: frameCamera.RotateLocalY(-0.1f); break; default: break; } } else { if (keys_held[SDLK_w]) xRot -= 1.0f; if (keys_held[SDLK_s]) xRot += 1.0f; if (keys_held[SDLK_a]) yRot -= 1.0f; if (keys_held[SDLK_d]) yRot += 1.0f; if (keys_held[SDLK_UP]) frameCamera.MoveForward(0.01f); if (keys_held[SDLK_DOWN]) frameCamera.MoveForward(-0.01f); if (keys_held[SDLK_LEFT]) frameCamera.RotateLocalY(0.01f); if (keys_held[SDLK_RIGHT]) frameCamera.RotateLocalY(-0.01f); } xRot = (GLfloat) ((const int) xRot % 360); yRot = (GLfloat) ((const int) yRot % 360); } /* process SDL events */ void processEvents() { SDL_Event event; unsigned static int keys_held[323]; SDLKey sym; /* helper flag for keys() */ int flag = 0; while (SDL_PollEvent(&event)) { sym = event.key.keysym.sym; switch (event.type) { case SDL_KEYUP: { /* reset the key to 0 */ keys_held[sym] = 0; break; } case SDL_KEYDOWN: { keys_held[sym] = 1; keys(&event.key.keysym, keys_held, flag); break; } case SDL_VIDEORESIZE: { resize(event.resize.w, event.resize.h); break; } case SDL_QUIT: { printf("status: exiting...\n"); exit(0); break; } default: break; } } /* XXX below code has the be below of the above */ /* check for keys that are being constantly pressed */ if (keys_held[SDLK_w] || keys_held[SDLK_s] || keys_held[SDLK_a] || keys_held[SDLK_d] || keys_held[SDLK_UP] || keys_held[SDLK_DOWN] || keys_held[SDLK_LEFT] || keys_held[SDLK_RIGHT]) { flag = !flag; keys(NULL, keys_held, flag); } else flag = !flag; } static void draw_ground(void) { GLfloat fExtent = 20.0f; GLfloat fStep = 0.5f; GLfloat y = -0.4f; GLfloat iLine; glBegin(GL_LINES); for (iLine = -fExtent; iLine <= fExtent; iLine += fStep) { glVertex3f(iLine, y, fExtent); glVertex3f(iLine, y, -fExtent); glVertex3f(fExtent, y, iLine); glVertex3f(-fExtent, y, iLine); } glEnd(); } static void render(void) { M3DVector3f vNormal; M3DVector3f vCorners[5] = { { 0.0f, 0.6f, 0.0f }, /* top 0 */ { -0.5f, -0.2f, -.50f }, /* back left 1 */ { 0.5f, -0.2f, -0.50f }, /* back right 2 */ { 0.5f, -0.2f, 0.5f }, /* front right 3 */ { -0.5f, -0.2f, 0.5f } /* front left 4 */ }; /* clear the window with current clearing color */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); /* save the matrix state and do the rotations */ glPushMatrix(); frameCamera.ApplyCameraTransform(); draw_ground(); /* move object back and do in place rotation */ glTranslatef(0.0f, 0.2f, -3.5f); glRotatef(xRot, 1.0f, 0.0f, 0.0f); glRotatef(yRot, 0.0f, 1.0f, 0.0f); /* draw the pyramid */ glColor3f(1.0f, 1.0f, 1.0f); glBegin(GL_TRIANGLES); /* bottom section - two triangles */ glNormal3f(0.0f, -1.0f, 0.0f); /* map texture to geometry */ glTexCoord2f(1.0f, 1.0f); glVertex3fv(vCorners[2]); glTexCoord2f(0.0f, 1.0f); glVertex3fv(vCorners[4]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vCorners[1]); glTexCoord2f(1.0f, 1.0f); glVertex3fv(vCorners[2]); glTexCoord2f(1.0f, 0.0f); glVertex3fv(vCorners[3]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vCorners[4]); /* front face */ m3dFindNormal(vNormal, vCorners[0], vCorners[4], vCorners[3]); glNormal3fv(vNormal); glTexCoord2f(0.5f, 1.0f); glVertex3fv(vCorners[0]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vCorners[4]); glTexCoord2f(1.0f, 0.0f); glVertex3fv(vCorners[3]); /* left face */ m3dFindNormal(vNormal, vCorners[0], vCorners[1], vCorners[4]); glNormal3fv(vNormal); glTexCoord2f(0.5f, 1.0f); glVertex3fv(vCorners[0]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vCorners[1]); glTexCoord2f(1.0f, 0.0f); glVertex3fv(vCorners[4]); /* back face */ m3dFindNormal(vNormal, vCorners[0], vCorners[2], vCorners[1]); glNormal3fv(vNormal); glTexCoord2f(0.5f, 1.0f); glVertex3fv(vCorners[0]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vCorners[2]); glTexCoord2f(1.0f, 0.0f); glVertex3fv(vCorners[1]); /* right face */ m3dFindNormal(vNormal, vCorners[0], vCorners[3], vCorners[2]); glNormal3fv(vNormal); glTexCoord2f(0.5f, 1.0f); glVertex3fv(vCorners[0]); glTexCoord2f(0.0f, 0.0f); glVertex3fv(vCorners[3]); glTexCoord2f(1.0f, 0.0f); glVertex3fv(vCorners[2]); glEnd(); /* restore the matrix state */ glPopMatrix(); /* buffer swap */ SDL_GL_SwapBuffers(); } int main(int argc, char **argv) { SDL_Surface *screen; if (SDL_Init(SDL_INIT_VIDEO) < 0 ) { fprintf(stderr, "unable to init SDL: %s\n", SDL_GetError()); exit(-1); } atexit(SDL_Quit); SDL_WM_SetCaption("Textured Pyramid", NULL); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); if ((screen = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | SDL_RESIZABLE)) == NULL) { fprintf(stderr, "unable to set video mode: %s\n", SDL_GetError()); exit(-1); } SDL_EnableUNICODE(1); /* SDL doesn't trigger off a ResizeEvent at startup, but as we need this * for OpenGL, we do this ourselves */ SDL_Event resizeEvent; resizeEvent.type = SDL_VIDEORESIZE; resizeEvent.resize.w = 640; resizeEvent.resize.h = 480; SDL_PushEvent(&resizeEvent); /* initalize glew */ GLenum glewerr = glewInit(); if (GLEW_OK != glewerr) { fprintf(stderr, "error: %s\n", glewGetErrorString(glewerr)); return -1; } else fprintf(stdout, "status: using GLEW %s\n", glewGetString(GLEW_VERSION)); SetupRC(); #ifdef STAT_FPS /* fps counter */ Uint32 startclock = 0; Uint32 deltaclock = 0; Uint32 current_fps = 0; #endif struct timeval m_LastCount; struct timeval lcurrent; for (;;) { gettimeofday(&m_LastCount, 0); #ifdef STAT_FPS startclock = SDL_GetTicks(); #endif processEvents(); render(); gettimeofday(&lcurrent, 0); float fSeconds = (float) (lcurrent.tv_sec - m_LastCount.tv_sec); float fFraction = (float) (lcurrent.tv_usec - m_LastCount.tv_usec) * 0.000001f; float delta = fSeconds + fFraction; if (delta < 1000 / FRAMES_PER_SECOND) SDL_Delay((1000 / FRAMES_PER_SECOND) - delta); #ifdef STAT_FPS deltaclock = SDL_GetTicks() - startclock; if (deltaclock != 0 ) current_fps = 1000 / deltaclock; static char buffer[30] = { 0 }; sprintf(buffer, "Textured Pyramid: %04d fps", current_fps); SDL_WM_SetCaption(buffer, NULL); #endif } return 0; }