nuclear@3: #include nuclear@3: #include nuclear@3: #include nuclear@3: #include "opengl.h" nuclear@3: #include "game.h" nuclear@3: #include "player.h" nuclear@3: #include "level.h" nuclear@3: #include "noise.h" nuclear@3: #include "texture.h" nuclear@3: #include "mesh.h" nuclear@3: nuclear@3: #define PLAYER_EYE_HEIGHT 1.65 nuclear@3: nuclear@3: static void draw_scene(unsigned long msec); nuclear@3: nuclear@3: static int win_width, win_height; nuclear@3: static struct level level; nuclear@3: static struct player player; nuclear@3: static int mouselook, freelook = 1; nuclear@3: static char keystate[256]; nuclear@3: nuclear@3: static struct mesh *monkey_mesh; nuclear@3: static unsigned int envmap; nuclear@3: static unsigned int win_tex; nuclear@3: nuclear@3: static int game_won; nuclear@3: nuclear@3: static float dbg_cam_dist = 0.0; nuclear@3: nuclear@3: nuclear@3: int game_init(void) nuclear@3: { nuclear@3: glEnable(GL_DEPTH_TEST); nuclear@3: glEnable(GL_CULL_FACE); nuclear@3: glEnable(GL_LIGHTING); nuclear@3: glEnable(GL_NORMALIZE); nuclear@3: nuclear@3: glEnable(GL_LIGHT0); nuclear@3: glEnable(GL_LIGHT1); nuclear@3: nuclear@3: /* set a slightly bluish cold ambient light */ nuclear@3: { nuclear@3: float ambient[] = {0.08, 0.1, 0.3, 1.0}; nuclear@3: glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); nuclear@3: } nuclear@3: nuclear@3: level_init(&level); nuclear@3: if(level_load(&level, "data/0.level") == -1) { nuclear@3: fprintf(stderr, "level loading failed\n"); nuclear@3: return -1; nuclear@3: } nuclear@3: nuclear@3: if(!(level.wall_tex = load_texture("data/wall.ppm"))) { nuclear@3: return -1; nuclear@3: } nuclear@3: if(!(level.floor_tex = load_texture("data/floor.ppm"))) { nuclear@3: return -1; nuclear@3: } nuclear@3: level.floor_tex_scale = 1.0; nuclear@3: if(!(level.ceil_tex = load_texture("data/ceil.ppm"))) { nuclear@3: return -1; nuclear@3: } nuclear@3: level.ceil_tex_scale = 2.0; nuclear@3: nuclear@3: nuclear@3: if(!(monkey_mesh = load_mesh("data/monkey.obj"))) { nuclear@3: return -1; nuclear@3: } nuclear@3: if(!(envmap = load_texture("data/refmap.ppm"))) { nuclear@3: return -1; nuclear@3: } nuclear@3: nuclear@3: if(!(win_tex = load_texture("data/done.ppm"))) { nuclear@3: return -1; nuclear@3: } nuclear@3: nuclear@3: player_init(&player, &level); nuclear@3: return 0; nuclear@3: } nuclear@3: nuclear@3: void game_shutdown(void) nuclear@3: { nuclear@3: } nuclear@3: nuclear@3: static void update(unsigned long msec) nuclear@3: { nuclear@3: static unsigned long prev_upd; nuclear@3: float dfwd = 0.0f; nuclear@3: float dright = 0.0f; nuclear@3: float walk_speed = 8.0; nuclear@3: nuclear@3: float dt = (float)(msec - prev_upd) / 1000.0f; nuclear@3: prev_upd = msec; nuclear@3: nuclear@3: if(game_won) return; nuclear@3: nuclear@3: if(freelook) { nuclear@3: if(keystate['w'] || keystate['W']) { nuclear@3: dfwd += walk_speed * dt; nuclear@3: } nuclear@3: if(keystate['s'] || keystate['S']) { nuclear@3: dfwd -= walk_speed * dt; nuclear@3: } nuclear@3: if(keystate['d'] || keystate['D']) { nuclear@3: dright += walk_speed * dt * 0.6; nuclear@3: } nuclear@3: if(keystate['a'] || keystate['A']) { nuclear@3: dright -= walk_speed * dt * 0.6; nuclear@3: } nuclear@3: nuclear@3: player_move(&player, dfwd, dright); nuclear@3: } nuclear@3: nuclear@3: if(level_cell_at(&level, player.x, player.y) == 'x') { nuclear@3: game_won = 1; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: void game_display(unsigned long msec) nuclear@3: { nuclear@3: float flicker = 1.0f; nuclear@3: nuclear@3: update(msec); nuclear@3: nuclear@3: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@3: nuclear@3: glMatrixMode(GL_MODELVIEW); nuclear@3: glLoadIdentity(); nuclear@3: glTranslatef(0, 0, -dbg_cam_dist); nuclear@3: /* set view matrix according to player pos/rot */ nuclear@3: player_setup_view_matrix(&player); nuclear@3: glTranslatef(0, -PLAYER_EYE_HEIGHT, 0); nuclear@3: nuclear@3: /* setup lights */ nuclear@3: flicker = fbm1((float)msec / 500.0f, 2) * 0.4 + 0.6; nuclear@3: set_light_position(0, player.x, PLAYER_EYE_HEIGHT + 0.2, player.y); nuclear@3: set_light_color(0, 1.0 * flicker, 0.6 * flicker, 0.3 * flicker); nuclear@3: set_light_attenuation(0, 0.5, 0, 0.04); nuclear@3: nuclear@3: set_light_position(1, level.goal_pos[0], 0.8, level.goal_pos[1]); nuclear@3: set_light_color(1, 0.955, 0.75, 0.06); nuclear@3: set_light_attenuation(1, 0.9, 0, 0.05); nuclear@3: nuclear@3: /* draw the scene */ nuclear@3: draw_scene(msec); nuclear@3: } nuclear@3: nuclear@3: void game_reshape(int x, int y) nuclear@3: { nuclear@3: win_width = x; nuclear@3: win_height = y; nuclear@3: glViewport(0, 0, x, y); nuclear@3: glMatrixMode(GL_PROJECTION); nuclear@3: glLoadIdentity(); nuclear@3: gluPerspective(55.0, (float)x / (float)y, 0.5, 500.0); nuclear@3: } nuclear@3: nuclear@3: nuclear@3: static void draw_scene(unsigned long msec) nuclear@3: { nuclear@3: float x, y; nuclear@3: float tsec = (float)msec / 1000.0f; nuclear@3: nuclear@3: level_draw(&level); nuclear@3: nuclear@3: /* draw the golden monkey */ nuclear@3: if(level_obj_pos(&level, 'x', &x, &y)) { nuclear@3: /* TODO: GLES doesn't have tex-gen... recalc manually */ nuclear@3: #ifndef GL_MOBILE nuclear@3: glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); nuclear@3: glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); nuclear@3: glEnable(GL_TEXTURE_GEN_S); nuclear@3: glEnable(GL_TEXTURE_GEN_T); nuclear@3: nuclear@3: glBindTexture(GL_TEXTURE_2D, envmap); nuclear@3: glEnable(GL_TEXTURE_2D); nuclear@3: #endif nuclear@3: nuclear@3: set_mtl_diffuse(0.1, 0.1, 0.1, 1); nuclear@3: set_mtl_specular(0.955, 0.75, 0.06); nuclear@3: set_mtl_shininess(80.0); nuclear@3: set_mtl_emission(0.955, 0.75 * 0.7, 0.06 * 0.1); nuclear@3: nuclear@3: glMatrixMode(GL_MODELVIEW); nuclear@3: glPushMatrix(); nuclear@3: glTranslatef(x, 0.8 + sin(tsec * 2.0) * 0.1, y); nuclear@3: glRotatef(tsec * 100.0, 0, 1, 0); nuclear@3: glRotatef(sin(tsec * 3.0) * 10.0, 1, 0, 0); nuclear@3: glScalef(0.3, 0.3, 0.3); nuclear@3: nuclear@3: render_mesh(monkey_mesh); nuclear@3: nuclear@3: glPopMatrix(); nuclear@3: nuclear@3: set_mtl_emission(0, 0, 0); nuclear@3: nuclear@3: #ifndef GL_MOBILE nuclear@3: glDisable(GL_TEXTURE_2D); nuclear@3: nuclear@3: glDisable(GL_TEXTURE_GEN_S); nuclear@3: glDisable(GL_TEXTURE_GEN_T); nuclear@3: #endif nuclear@3: } nuclear@3: nuclear@3: /* draw the win text */ nuclear@3: if(game_won) { nuclear@3: glMatrixMode(GL_MODELVIEW); nuclear@3: glPushMatrix(); nuclear@3: glLoadIdentity(); nuclear@3: glMatrixMode(GL_PROJECTION); nuclear@3: glPushMatrix(); nuclear@3: glLoadIdentity(); nuclear@3: glScalef((float)win_height / (float)win_width, 1, 1); nuclear@3: nuclear@3: glBindTexture(GL_TEXTURE_2D, win_tex); nuclear@3: glEnable(GL_TEXTURE_2D); nuclear@3: nuclear@3: glEnable(GL_BLEND); nuclear@3: glBlendFunc(GL_ONE, GL_ONE); nuclear@3: glDisable(GL_LIGHTING); nuclear@3: nuclear@3: glBegin(GL_QUADS); nuclear@3: glTexCoord2f(0, 1); glVertex2f(-1, -1); nuclear@3: glTexCoord2f(1, 1); glVertex2f(1, -1); nuclear@3: glTexCoord2f(1, 0); glVertex2f(1, 1); nuclear@3: glTexCoord2f(0, 0); glVertex2f(-1, 1); nuclear@3: glEnd(); nuclear@3: nuclear@3: glDisable(GL_BLEND); nuclear@3: glDisable(GL_TEXTURE_2D); nuclear@3: glEnable(GL_LIGHTING); nuclear@3: nuclear@3: glPopMatrix(); nuclear@3: glMatrixMode(GL_MODELVIEW); nuclear@3: glPopMatrix(); nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: static int warping_mouse; nuclear@3: nuclear@3: void game_keyboard(int key, int pressed) nuclear@3: { nuclear@3: keystate[key] = pressed; nuclear@3: nuclear@3: if(!pressed) return; nuclear@3: nuclear@3: switch(key) { nuclear@3: case 27: nuclear@3: exit(0); nuclear@3: nuclear@3: case 'a': nuclear@3: if(!freelook && !game_won) { nuclear@3: player_turn(&player, -90, 0); nuclear@3: } nuclear@3: break; nuclear@3: nuclear@3: case 'd': nuclear@3: if(!freelook && !game_won) { nuclear@3: player_turn(&player, 90, 0); nuclear@3: } nuclear@3: break; nuclear@3: nuclear@3: case 'w': nuclear@3: case 's': nuclear@3: if(!freelook && !game_won) { nuclear@3: float prev_x = player.x; nuclear@3: float prev_y = player.y; nuclear@3: float sign = key == 'w' ? 1.0 : -1.0; nuclear@3: nuclear@3: if(!player_move(&player, level.cell_size * sign, 0)) { nuclear@3: player.x = prev_x; nuclear@3: player.y = prev_y; nuclear@3: } nuclear@3: } nuclear@3: break; nuclear@3: nuclear@3: case '`': nuclear@3: case '~': nuclear@3: mouselook = !mouselook; nuclear@3: if(mouselook) { nuclear@3: warping_mouse = 1; nuclear@3: set_mouse_pos(win_width / 2, win_height / 2); nuclear@3: set_mouse_cursor(0); nuclear@3: } else { nuclear@3: set_mouse_cursor(1); nuclear@3: } nuclear@3: break; nuclear@3: nuclear@3: case 'b': nuclear@3: case 'B': nuclear@3: freelook = !freelook; nuclear@3: break; nuclear@3: nuclear@3: case 'r': nuclear@3: case 'R': nuclear@3: game_won = 0; nuclear@3: player_init(&player, &level); nuclear@3: break; nuclear@3: nuclear@3: default: nuclear@3: break; nuclear@3: } nuclear@3: } nuclear@3: nuclear@3: #define MAX_TOUCH_IDS 16 nuclear@3: static struct { nuclear@3: int bnstate[8]; nuclear@3: int prev_x, prev_y; nuclear@3: } mstate[MAX_TOUCH_IDS]; nuclear@3: nuclear@3: void game_mouse_button(int id, int bn, int pressed, int x, int y) nuclear@3: { nuclear@3: if(id >= MAX_TOUCH_IDS) return; nuclear@3: nuclear@3: mstate[id].prev_x = x; nuclear@3: mstate[id].prev_y = y; nuclear@3: mstate[id].bnstate[bn] = pressed; nuclear@3: } nuclear@3: nuclear@3: void game_mouse_motion(int id, int x, int y) nuclear@3: { nuclear@3: int dx, dy, cx, cy; nuclear@3: nuclear@3: if(id >= MAX_TOUCH_IDS) return; nuclear@3: nuclear@3: cx = win_width / 2; nuclear@3: cy = win_height / 2; nuclear@3: nuclear@3: if(warping_mouse) { nuclear@3: warping_mouse = 0; nuclear@3: return; nuclear@3: } nuclear@3: nuclear@3: dx = x - (mouselook ? cx : mstate[id].prev_x); nuclear@3: dy = y - (mouselook ? cy : mstate[id].prev_y); nuclear@3: mstate[id].prev_x = x; nuclear@3: mstate[id].prev_y = y; nuclear@3: nuclear@3: if(!dx && !dy) return; nuclear@3: nuclear@3: if(mouselook || mstate[id].bnstate[0]) { nuclear@3: player_turn(&player, dx * 0.5, dy * 0.5); nuclear@3: } nuclear@3: if(mstate[id].bnstate[2]) { nuclear@3: dbg_cam_dist += 0.1 * dy; nuclear@3: if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0; nuclear@3: } nuclear@3: nuclear@3: if(mouselook) { nuclear@3: warping_mouse = 1; nuclear@3: set_mouse_pos(cx, cy); nuclear@3: mstate[id].prev_x = cx; nuclear@3: mstate[id].prev_y = cy; nuclear@3: } nuclear@3: } nuclear@3: