/* pyramid.c * * @2011 Kamil Kaminski * * notes: since lighting is enabled, we need to specify normals for * each polygon face so the OpenGL can calculate e.g. how light reflects * * drawing a shadow for the pyramid would require drawing things twice, so on 2nd * pass we would draw with black color and multiply by squished matrix, we should * get to this later with better approach * * so far we have been using immediate mode rendering, we should begin using * display lists / batch processing to reduce overhead, aka compiling commands * * it might be time to split the code, and make a shader version... * */ #include <SDL/SDL.h> #include <SDL/SDL_image.h> #include <GL/glew.h> #include <GL/freeglut.h> #include <sys/time.h> #include "glframe.h" #include "gltools.h" #include "math3d.h" #include "platform.h" #include "window.h" /* function prototypes */ static void keys(SDL_keysym *, const unsigned int *, const int); static void process_events(void); static void platform_init(void); static void platform_destroy(void); static void render(void); /* global */ int program_running = 1; const unsigned int xres = 640; const unsigned int yres = 480; const unsigned int bpp = 32; const char *window_caption = "Textured Pyramid"; const char *window_icon_path = "tux.png"; /* platform struct */ static struct { GLFrame camera; /* display lists identifiers */ GLuint ground_list; GLuint triangle_list; GLfloat xrot; GLfloat yrot; } p; static void keys(SDL_keysym *keysym, const unsigned int *keys_held, const int flag) { if (!flag) { switch (keysym->sym) { case SDLK_ESCAPE: program_running = 0; break; case SDLK_w: p.xrot -= 5.0f; break; case SDLK_s: p.xrot += 5.0f; break; case SDLK_a: p.yrot -= 5.0f; break; case SDLK_d: p.yrot += 5.0f; break; case SDLK_UP: glframe_move_forward(&p.camera, 0.5f); break; case SDLK_DOWN: glframe_move_forward(&p.camera, -0.5f); break; case SDLK_LEFT: glframe_rotate_local_y(&p.camera, 0.1f); break; case SDLK_RIGHT: glframe_rotate_local_y(&p.camera, -0.1f); break; case SDLK_n: glframe_rotate_local_x(&p.camera, 0.1f); break; case SDLK_m: glframe_rotate_local_x(&p.camera, -0.1f); break; default: break; } } else { if (keys_held[SDLK_w]) p.xrot -= 5.0f; if (keys_held[SDLK_s]) p.xrot += 5.0f; if (keys_held[SDLK_a]) p.yrot -= 5.0f; if (keys_held[SDLK_d]) p.yrot += 5.0f; if (keys_held[SDLK_UP]) glframe_move_forward(&p.camera, 0.05f); if (keys_held[SDLK_DOWN]) glframe_move_forward(&p.camera, -0.05f); if (keys_held[SDLK_LEFT]) glframe_rotate_local_y(&p.camera, 0.02f); if (keys_held[SDLK_RIGHT]) glframe_rotate_local_y(&p.camera, -0.02f); if (keys_held[SDLK_n]) glframe_rotate_local_x(&p.camera, 0.02f); if (keys_held[SDLK_m]) glframe_rotate_local_x(&p.camera, -0.02f); } p.xrot = (GLfloat) ((const int) p.xrot % 360); p.yrot = (GLfloat) ((const int) p.yrot % 360); } static void process_events(void) { /* process SDL events */ 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: { window_resize(event.resize.w, event.resize.h); break; } case SDL_QUIT: { program_running = 0; break; } default: break; } } /* below code has to be placed here, check for keys that are being constantly held */ 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] || keys_held[SDLK_n] || keys_held[SDLK_m]) { flag = !flag; keys(NULL, keys_held, flag); } else flag = !flag; } static void platform_init(void) { /* variables used for texture loading */ GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; /* set the camera to <0,0,0> */ glframe_reset(&p.camera); p.xrot = 0; p.yrot = 0; /* 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); /* display list, precompile commands */ p.ground_list = glGenLists(2); p.triangle_list = p.ground_list + 1; glNewList(p.ground_list, GL_COMPILE); gltDrawGround(); glEndList(); glNewList(p.triangle_list, GL_COMPILE); gltDrawTriangle(); glEndList(); } static void platform_destroy(void) { glDeleteLists(p.ground_list, 2); } static void render(void) { /* 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(); /* apply camera transform, and draw the ground */ glframe_apply_camera_transform(&p.camera); glColor3ub(255, 0, 255); glCallList(p.ground_list); glPushMatrix(); /* move object back and do in place rotation */ glTranslatef(0.0f, 0.2f, -3.5f); glRotatef(p.xrot, 1.0f, 0.0f, 0.0f); glRotatef(p.yrot, 0.0f, 1.0f, 0.0f); /* draw the pyramid */ glColor3f(1.0f, 1.0f, 1.0f); glCallList(p.triangle_list); glPopMatrix(); /* draw a snowman */ glTranslatef(0.0f, 0.0f, -7.0f); gltDrawSnowman(); /* restore the matrix state */ glPopMatrix(); /* buffer swap */ SDL_GL_SwapBuffers(); } int main(int argc, char **argv) { setup_sdl(); setup_glew(); setup_opengl(); platform_init(); unsigned int startclock; while (program_running) { startclock = SDL_GetTicks(); process_events(); render(); fps_control(startclock); } platform_destroy(); puts("bye!"); return 0; }