/* 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 #include #include #include #include #include "gldraw.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); GLuint gltLoadTGATexture(const char *); /* 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; /* pyramid texture handle */ GLuint textures[2]; 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; } /* mipmapping enabled by default */ GLuint gltLoadTGATexture(const char *fname) { GLuint handle; /* variables used for texture loading */ GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; glGenTextures(1, &handle); glBindTexture(GL_TEXTURE_2D, handle); /* load texture */ glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); pBytes = gltLoadTGA(fname, &iWidth, &iHeight, &iComponents, &eFormat); if (!pBytes) fprintf(stderr, "gltLoadTGA: failed to load texture!\n"); glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat, GL_UNSIGNED_BYTE, pBytes); free(pBytes); /* seems like mipmapping only applies to MIN_FILTER since mipmapping divides * current texture into smaller and smaller pieces */ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); /* GL_LINEAR to disable mipmapping */ 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); return handle; } static void platform_init(void) { memset(&p, 0, sizeof(p)); /* set the camera to <0,0,0> */ glframe_reset(&p.camera); p.textures[0] = gltLoadTGATexture("stone.tga"); p.textures[1] = gltLoadTGATexture("grass.tga"); /* display list, precompile commands */ p.ground_list = glGenLists(2); p.triangle_list = p.ground_list + 1; /* a ground with grass drawn using magneta lines */ glNewList(p.ground_list, GL_COMPILE); //glBindTexture(GL_TEXTURE_2D, p.textures[1]); glColor3ub(255, 0, 255); glDrawGround(); glEndList(); /* a triangle with a texture */ glNewList(p.triangle_list, GL_COMPILE); glBindTexture(GL_TEXTURE_2D, p.textures[0]); glColor3f(1.0f, 1.0f, 1.0f); glDrawTriangle(); glEndList(); } static void platform_destroy(void) { glDeleteTextures(2, p.textures); 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, 1); 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 */ glCallList(p.triangle_list); glPopMatrix(); /* draw a snowman */ glTranslatef(0.0f, 0.0f, -7.0f); glDrawSnowman(); /* restore the matrix state */ glPopMatrix(); /* buffer swap */ SDL_GL_SwapBuffers(); } int main(int argc, char **argv) { setup_sdl(); setup_glew(); setup_opengl(); platform_init(); gltErrorCheck(); unsigned int startclock; while (program_running) { startclock = SDL_GetTicks(); process_events(); render(); fps_control(startclock); /* need some sort of a timer to trigger this */ /* gl_frame_normalize(&p.camera); */ } platform_destroy(); puts("bye!"); return 0; }