nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@0: #include "opengl.h" nuclear@0: #include "player.h" nuclear@0: #include "level.h" nuclear@0: #include "noise.h" nuclear@0: #include "texture.h" nuclear@0: #include "mesh.h" nuclear@0: nuclear@0: #define PLAYER_EYE_HEIGHT 1.65 nuclear@0: nuclear@0: static int init(void); nuclear@0: static void update(unsigned int msec); nuclear@0: static void display(void); nuclear@0: static void draw_scene(unsigned int msec); nuclear@0: static void idle(void); nuclear@0: static void reshape(int x, int y); nuclear@0: static void key_down(unsigned char key, int x, int y); nuclear@0: static void key_up(unsigned char key, int x, int y); nuclear@0: static void mouse(int bn, int state, int x, int y); nuclear@0: static void motion(int x, int y); nuclear@0: nuclear@0: static int win_width, win_height; nuclear@0: static struct level level; nuclear@0: static struct player player; nuclear@0: static int mouselook, freelook = 1; nuclear@0: static char keystate[256]; nuclear@0: nuclear@0: static struct mesh *monkey_mesh; nuclear@0: static unsigned int envmap; nuclear@0: static unsigned int win_tex; nuclear@0: nuclear@0: static int game_won; nuclear@0: nuclear@0: static float dbg_cam_dist = 0.0; nuclear@0: nuclear@0: int main(int argc, char **argv) nuclear@0: { nuclear@0: glutInit(&argc, argv); nuclear@0: glutInitWindowSize(1280, 800); nuclear@0: glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE); nuclear@0: glutCreateWindow("labyrinth game example"); nuclear@0: nuclear@0: glutDisplayFunc(display); nuclear@0: glutIdleFunc(idle); nuclear@0: glutReshapeFunc(reshape); nuclear@0: glutKeyboardFunc(key_down); nuclear@0: glutKeyboardUpFunc(key_up); nuclear@0: glutMouseFunc(mouse); nuclear@0: glutMotionFunc(motion); nuclear@0: nuclear@0: if(init() == -1) { nuclear@0: return 1; nuclear@0: } nuclear@0: glutMainLoop(); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: nuclear@0: static int init(void) nuclear@0: { nuclear@0: glEnable(GL_DEPTH_TEST); nuclear@0: glEnable(GL_CULL_FACE); nuclear@0: glEnable(GL_LIGHTING); nuclear@0: glEnable(GL_NORMALIZE); nuclear@0: nuclear@0: glEnable(GL_LIGHT0); nuclear@0: glEnable(GL_LIGHT1); nuclear@0: nuclear@0: /* set a slightly bluish cold ambient light */ nuclear@0: { nuclear@0: float ambient[] = {0.08, 0.1, 0.3, 1.0}; nuclear@0: glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); nuclear@0: } nuclear@0: nuclear@0: level_init(&level); nuclear@0: if(level_load(&level, "data/0.level") == -1) { nuclear@0: fprintf(stderr, "level loading failed\n"); nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: if(!(level.wall_tex = load_texture("data/wall.ppm"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: if(!(level.floor_tex = load_texture("data/floor.ppm"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: level.floor_tex_scale = 1.0; nuclear@0: if(!(level.ceil_tex = load_texture("data/ceil.ppm"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: level.ceil_tex_scale = 2.0; nuclear@0: nuclear@0: nuclear@0: if(!(monkey_mesh = load_mesh("data/monkey.obj"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: if(!(envmap = load_texture("data/refmap.ppm"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: if(!(win_tex = load_texture("data/done.ppm"))) { nuclear@0: return -1; nuclear@0: } nuclear@0: nuclear@0: player_init(&player, &level); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@0: static void update(unsigned int msec) nuclear@0: { nuclear@0: static unsigned int prev_upd; nuclear@0: float dfwd = 0.0f; nuclear@0: float dright = 0.0f; nuclear@0: float walk_speed = 8.0; nuclear@0: nuclear@0: float dt = (float)(msec - prev_upd) / 1000.0f; nuclear@0: prev_upd = msec; nuclear@0: nuclear@0: if(game_won) return; nuclear@0: nuclear@0: if(freelook) { nuclear@0: if(keystate['w'] || keystate['W']) { nuclear@0: dfwd += walk_speed * dt; nuclear@0: } nuclear@0: if(keystate['s'] || keystate['S']) { nuclear@0: dfwd -= walk_speed * dt; nuclear@0: } nuclear@0: if(keystate['d'] || keystate['D']) { nuclear@0: dright += walk_speed * dt * 0.6; nuclear@0: } nuclear@0: if(keystate['a'] || keystate['A']) { nuclear@0: dright -= walk_speed * dt * 0.6; nuclear@0: } nuclear@0: nuclear@0: player_move(&player, dfwd, dright); nuclear@0: } nuclear@0: nuclear@0: if(level_cell_at(&level, player.x, player.y) == 'x') { nuclear@0: game_won = 1; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void display(void) nuclear@0: { nuclear@0: float flicker = 1.0f; nuclear@0: unsigned int msec = glutGet(GLUT_ELAPSED_TIME); nuclear@0: nuclear@0: update(msec); nuclear@0: nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glLoadIdentity(); nuclear@0: glTranslatef(0, 0, -dbg_cam_dist); nuclear@0: /* set view matrix according to player pos/rot */ nuclear@0: player_setup_view_matrix(&player); nuclear@0: glTranslatef(0, -PLAYER_EYE_HEIGHT, 0); nuclear@0: nuclear@0: /* setup lights */ nuclear@0: flicker = fbm1((float)msec / 500.0f, 2) * 0.4 + 0.6; nuclear@0: set_light_position(0, player.x, PLAYER_EYE_HEIGHT + 0.2, player.y); nuclear@0: set_light_color(0, 1.0 * flicker, 0.6 * flicker, 0.3 * flicker); nuclear@0: set_light_attenuation(0, 0.5, 0, 0.04); nuclear@0: nuclear@0: set_light_position(1, level.goal_pos[0], 0.8, level.goal_pos[1]); nuclear@0: set_light_color(1, 0.955, 0.75, 0.06); nuclear@0: set_light_attenuation(1, 0.9, 0, 0.05); nuclear@0: nuclear@0: /* draw the scene */ nuclear@0: draw_scene(msec); nuclear@0: nuclear@0: glutSwapBuffers(); nuclear@0: assert(glGetError() == GL_NO_ERROR); nuclear@0: } nuclear@0: nuclear@0: static void draw_scene(unsigned int msec) nuclear@0: { nuclear@0: float x, y; nuclear@0: float tsec = (float)msec / 1000.0f; nuclear@0: nuclear@0: level_draw(&level); nuclear@0: nuclear@0: /* draw the golden monkey */ nuclear@0: if(level_obj_pos(&level, 'x', &x, &y)) { nuclear@0: glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); nuclear@0: glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); nuclear@0: glEnable(GL_TEXTURE_GEN_S); nuclear@0: glEnable(GL_TEXTURE_GEN_T); nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, envmap); nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: nuclear@0: set_mtl_diffuse(0.1, 0.1, 0.1, 1); nuclear@0: set_mtl_specular(0.955, 0.75, 0.06); nuclear@0: set_mtl_shininess(80.0); nuclear@0: set_mtl_emission(0.955, 0.75 * 0.7, 0.06 * 0.1); nuclear@0: nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPushMatrix(); nuclear@0: glTranslatef(x, 0.8 + sin(tsec * 2.0) * 0.1, y); nuclear@0: glRotatef(tsec * 100.0, 0, 1, 0); nuclear@0: glRotatef(sin(tsec * 3.0) * 10.0, 1, 0, 0); nuclear@0: glScalef(0.3, 0.3, 0.3); nuclear@0: nuclear@0: render_mesh(monkey_mesh); nuclear@0: nuclear@0: glPopMatrix(); nuclear@0: nuclear@0: set_mtl_emission(0, 0, 0); nuclear@0: nuclear@0: glDisable(GL_TEXTURE_2D); nuclear@0: nuclear@0: glDisable(GL_TEXTURE_GEN_S); nuclear@0: glDisable(GL_TEXTURE_GEN_T); nuclear@0: } nuclear@0: nuclear@0: /* draw the win text */ nuclear@0: if(game_won) { nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPushMatrix(); nuclear@0: glLoadIdentity(); nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glPushMatrix(); nuclear@0: glLoadIdentity(); nuclear@0: glScalef((float)win_height / (float)win_width, 1, 1); nuclear@0: nuclear@0: glBindTexture(GL_TEXTURE_2D, win_tex); nuclear@0: glEnable(GL_TEXTURE_2D); nuclear@0: nuclear@0: glEnable(GL_BLEND); nuclear@0: glBlendFunc(GL_ONE, GL_ONE); nuclear@0: glDisable(GL_LIGHTING); nuclear@0: nuclear@0: glBegin(GL_QUADS); nuclear@0: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@0: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@0: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@0: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@0: glEnd(); nuclear@0: nuclear@0: glDisable(GL_BLEND); nuclear@0: glDisable(GL_TEXTURE_2D); nuclear@0: glEnable(GL_LIGHTING); nuclear@0: nuclear@0: glPopMatrix(); nuclear@0: glMatrixMode(GL_MODELVIEW); nuclear@0: glPopMatrix(); nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void idle(void) nuclear@0: { nuclear@0: glutPostRedisplay(); nuclear@0: } nuclear@0: nuclear@0: static void reshape(int x, int y) nuclear@0: { nuclear@0: win_width = x; nuclear@0: win_height = y; nuclear@0: glViewport(0, 0, x, y); nuclear@0: glMatrixMode(GL_PROJECTION); nuclear@0: glLoadIdentity(); nuclear@0: gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); nuclear@0: } nuclear@0: nuclear@0: static int warping_mouse; nuclear@0: nuclear@0: static void key_down(unsigned char key, int x, int y) nuclear@0: { nuclear@0: keystate[key] = 1; nuclear@0: nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@0: nuclear@0: case 'a': nuclear@0: if(!freelook && !game_won) { nuclear@0: player_turn(&player, -90, 0); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case 'd': nuclear@0: if(!freelook && !game_won) { nuclear@0: player_turn(&player, 90, 0); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case 'w': nuclear@0: case 's': nuclear@0: if(!freelook && !game_won) { nuclear@0: float prev_x = player.x; nuclear@0: float prev_y = player.y; nuclear@0: float sign = key == 'w' ? 1.0 : -1.0; nuclear@0: nuclear@0: if(!player_move(&player, level.cell_size * sign, 0)) { nuclear@0: player.x = prev_x; nuclear@0: player.y = prev_y; nuclear@0: } nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case '`': nuclear@0: case '~': nuclear@0: mouselook = !mouselook; nuclear@0: if(mouselook) { nuclear@0: warping_mouse = 1; nuclear@0: glutWarpPointer(win_width / 2, win_height / 2); nuclear@0: glutPassiveMotionFunc(motion); nuclear@0: glutSetCursor(GLUT_CURSOR_NONE); nuclear@0: } else { nuclear@0: glutPassiveMotionFunc(0); nuclear@0: glutSetCursor(GLUT_CURSOR_INHERIT); nuclear@0: } nuclear@0: break; nuclear@0: nuclear@0: case 'b': nuclear@0: case 'B': nuclear@0: freelook = !freelook; nuclear@0: break; nuclear@0: nuclear@0: case 'r': nuclear@0: case 'R': nuclear@0: game_won = 0; nuclear@0: player_init(&player, &level); nuclear@0: break; nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: static void key_up(unsigned char key, int x, int y) nuclear@0: { nuclear@0: keystate[key] = 0; nuclear@0: } nuclear@0: nuclear@0: static int bnstate[16]; nuclear@0: static int prev_x, prev_y; nuclear@0: nuclear@0: static void mouse(int bn, int state, int x, int y) nuclear@0: { nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN ? 1 : 0; nuclear@0: } nuclear@0: nuclear@0: static void motion(int x, int y) nuclear@0: { nuclear@0: int dx, dy; nuclear@0: int cx = win_width / 2; nuclear@0: int cy = win_height / 2; nuclear@0: nuclear@0: if(warping_mouse) { nuclear@0: warping_mouse = 0; nuclear@0: return; nuclear@0: } nuclear@0: nuclear@0: dx = x - (mouselook ? cx : prev_x); nuclear@0: dy = y - (mouselook ? cy : prev_y); nuclear@0: prev_x = x; nuclear@0: prev_y = y; nuclear@0: nuclear@0: if(!dx && !dy) return; nuclear@0: nuclear@0: if(mouselook || bnstate[0]) { nuclear@0: player_turn(&player, dx * 0.5, dy * 0.5); nuclear@0: } nuclear@0: if(bnstate[2]) { nuclear@0: dbg_cam_dist += 0.1 * dy; nuclear@0: if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0; nuclear@0: } nuclear@0: nuclear@0: if(mouselook) { nuclear@0: warping_mouse = 1; nuclear@0: glutWarpPointer(cx, cy); nuclear@0: prev_x = cx; nuclear@0: prev_y = cy; nuclear@0: } nuclear@0: }