labyrinth
diff src/game.c @ 3:45b91185b298
android port
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 01 May 2015 04:36:50 +0300 |
parents | |
children | d3f1f74067b0 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/game.c Fri May 01 04:36:50 2015 +0300 1.3 @@ -0,0 +1,356 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <math.h> 1.7 +#include "opengl.h" 1.8 +#include "game.h" 1.9 +#include "player.h" 1.10 +#include "level.h" 1.11 +#include "noise.h" 1.12 +#include "texture.h" 1.13 +#include "mesh.h" 1.14 + 1.15 +#define PLAYER_EYE_HEIGHT 1.65 1.16 + 1.17 +static void draw_scene(unsigned long msec); 1.18 + 1.19 +static int win_width, win_height; 1.20 +static struct level level; 1.21 +static struct player player; 1.22 +static int mouselook, freelook = 1; 1.23 +static char keystate[256]; 1.24 + 1.25 +static struct mesh *monkey_mesh; 1.26 +static unsigned int envmap; 1.27 +static unsigned int win_tex; 1.28 + 1.29 +static int game_won; 1.30 + 1.31 +static float dbg_cam_dist = 0.0; 1.32 + 1.33 + 1.34 +int game_init(void) 1.35 +{ 1.36 + glEnable(GL_DEPTH_TEST); 1.37 + glEnable(GL_CULL_FACE); 1.38 + glEnable(GL_LIGHTING); 1.39 + glEnable(GL_NORMALIZE); 1.40 + 1.41 + glEnable(GL_LIGHT0); 1.42 + glEnable(GL_LIGHT1); 1.43 + 1.44 + /* set a slightly bluish cold ambient light */ 1.45 + { 1.46 + float ambient[] = {0.08, 0.1, 0.3, 1.0}; 1.47 + glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); 1.48 + } 1.49 + 1.50 + level_init(&level); 1.51 + if(level_load(&level, "data/0.level") == -1) { 1.52 + fprintf(stderr, "level loading failed\n"); 1.53 + return -1; 1.54 + } 1.55 + 1.56 + if(!(level.wall_tex = load_texture("data/wall.ppm"))) { 1.57 + return -1; 1.58 + } 1.59 + if(!(level.floor_tex = load_texture("data/floor.ppm"))) { 1.60 + return -1; 1.61 + } 1.62 + level.floor_tex_scale = 1.0; 1.63 + if(!(level.ceil_tex = load_texture("data/ceil.ppm"))) { 1.64 + return -1; 1.65 + } 1.66 + level.ceil_tex_scale = 2.0; 1.67 + 1.68 + 1.69 + if(!(monkey_mesh = load_mesh("data/monkey.obj"))) { 1.70 + return -1; 1.71 + } 1.72 + if(!(envmap = load_texture("data/refmap.ppm"))) { 1.73 + return -1; 1.74 + } 1.75 + 1.76 + if(!(win_tex = load_texture("data/done.ppm"))) { 1.77 + return -1; 1.78 + } 1.79 + 1.80 + player_init(&player, &level); 1.81 + return 0; 1.82 +} 1.83 + 1.84 +void game_shutdown(void) 1.85 +{ 1.86 +} 1.87 + 1.88 +static void update(unsigned long msec) 1.89 +{ 1.90 + static unsigned long prev_upd; 1.91 + float dfwd = 0.0f; 1.92 + float dright = 0.0f; 1.93 + float walk_speed = 8.0; 1.94 + 1.95 + float dt = (float)(msec - prev_upd) / 1000.0f; 1.96 + prev_upd = msec; 1.97 + 1.98 + if(game_won) return; 1.99 + 1.100 + if(freelook) { 1.101 + if(keystate['w'] || keystate['W']) { 1.102 + dfwd += walk_speed * dt; 1.103 + } 1.104 + if(keystate['s'] || keystate['S']) { 1.105 + dfwd -= walk_speed * dt; 1.106 + } 1.107 + if(keystate['d'] || keystate['D']) { 1.108 + dright += walk_speed * dt * 0.6; 1.109 + } 1.110 + if(keystate['a'] || keystate['A']) { 1.111 + dright -= walk_speed * dt * 0.6; 1.112 + } 1.113 + 1.114 + player_move(&player, dfwd, dright); 1.115 + } 1.116 + 1.117 + if(level_cell_at(&level, player.x, player.y) == 'x') { 1.118 + game_won = 1; 1.119 + } 1.120 +} 1.121 + 1.122 +void game_display(unsigned long msec) 1.123 +{ 1.124 + float flicker = 1.0f; 1.125 + 1.126 + update(msec); 1.127 + 1.128 + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 1.129 + 1.130 + glMatrixMode(GL_MODELVIEW); 1.131 + glLoadIdentity(); 1.132 + glTranslatef(0, 0, -dbg_cam_dist); 1.133 + /* set view matrix according to player pos/rot */ 1.134 + player_setup_view_matrix(&player); 1.135 + glTranslatef(0, -PLAYER_EYE_HEIGHT, 0); 1.136 + 1.137 + /* setup lights */ 1.138 + flicker = fbm1((float)msec / 500.0f, 2) * 0.4 + 0.6; 1.139 + set_light_position(0, player.x, PLAYER_EYE_HEIGHT + 0.2, player.y); 1.140 + set_light_color(0, 1.0 * flicker, 0.6 * flicker, 0.3 * flicker); 1.141 + set_light_attenuation(0, 0.5, 0, 0.04); 1.142 + 1.143 + set_light_position(1, level.goal_pos[0], 0.8, level.goal_pos[1]); 1.144 + set_light_color(1, 0.955, 0.75, 0.06); 1.145 + set_light_attenuation(1, 0.9, 0, 0.05); 1.146 + 1.147 + /* draw the scene */ 1.148 + draw_scene(msec); 1.149 +} 1.150 + 1.151 +void game_reshape(int x, int y) 1.152 +{ 1.153 + win_width = x; 1.154 + win_height = y; 1.155 + glViewport(0, 0, x, y); 1.156 + glMatrixMode(GL_PROJECTION); 1.157 + glLoadIdentity(); 1.158 + gluPerspective(55.0, (float)x / (float)y, 0.5, 500.0); 1.159 +} 1.160 + 1.161 + 1.162 +static void draw_scene(unsigned long msec) 1.163 +{ 1.164 + float x, y; 1.165 + float tsec = (float)msec / 1000.0f; 1.166 + 1.167 + level_draw(&level); 1.168 + 1.169 + /* draw the golden monkey */ 1.170 + if(level_obj_pos(&level, 'x', &x, &y)) { 1.171 + /* TODO: GLES doesn't have tex-gen... recalc manually */ 1.172 +#ifndef GL_MOBILE 1.173 + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 1.174 + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); 1.175 + glEnable(GL_TEXTURE_GEN_S); 1.176 + glEnable(GL_TEXTURE_GEN_T); 1.177 + 1.178 + glBindTexture(GL_TEXTURE_2D, envmap); 1.179 + glEnable(GL_TEXTURE_2D); 1.180 +#endif 1.181 + 1.182 + set_mtl_diffuse(0.1, 0.1, 0.1, 1); 1.183 + set_mtl_specular(0.955, 0.75, 0.06); 1.184 + set_mtl_shininess(80.0); 1.185 + set_mtl_emission(0.955, 0.75 * 0.7, 0.06 * 0.1); 1.186 + 1.187 + glMatrixMode(GL_MODELVIEW); 1.188 + glPushMatrix(); 1.189 + glTranslatef(x, 0.8 + sin(tsec * 2.0) * 0.1, y); 1.190 + glRotatef(tsec * 100.0, 0, 1, 0); 1.191 + glRotatef(sin(tsec * 3.0) * 10.0, 1, 0, 0); 1.192 + glScalef(0.3, 0.3, 0.3); 1.193 + 1.194 + render_mesh(monkey_mesh); 1.195 + 1.196 + glPopMatrix(); 1.197 + 1.198 + set_mtl_emission(0, 0, 0); 1.199 + 1.200 +#ifndef GL_MOBILE 1.201 + glDisable(GL_TEXTURE_2D); 1.202 + 1.203 + glDisable(GL_TEXTURE_GEN_S); 1.204 + glDisable(GL_TEXTURE_GEN_T); 1.205 +#endif 1.206 + } 1.207 + 1.208 + /* draw the win text */ 1.209 + if(game_won) { 1.210 + glMatrixMode(GL_MODELVIEW); 1.211 + glPushMatrix(); 1.212 + glLoadIdentity(); 1.213 + glMatrixMode(GL_PROJECTION); 1.214 + glPushMatrix(); 1.215 + glLoadIdentity(); 1.216 + glScalef((float)win_height / (float)win_width, 1, 1); 1.217 + 1.218 + glBindTexture(GL_TEXTURE_2D, win_tex); 1.219 + glEnable(GL_TEXTURE_2D); 1.220 + 1.221 + glEnable(GL_BLEND); 1.222 + glBlendFunc(GL_ONE, GL_ONE); 1.223 + glDisable(GL_LIGHTING); 1.224 + 1.225 + glBegin(GL_QUADS); 1.226 + glTexCoord2f(0, 1); glVertex2f(-1, -1); 1.227 + glTexCoord2f(1, 1); glVertex2f(1, -1); 1.228 + glTexCoord2f(1, 0); glVertex2f(1, 1); 1.229 + glTexCoord2f(0, 0); glVertex2f(-1, 1); 1.230 + glEnd(); 1.231 + 1.232 + glDisable(GL_BLEND); 1.233 + glDisable(GL_TEXTURE_2D); 1.234 + glEnable(GL_LIGHTING); 1.235 + 1.236 + glPopMatrix(); 1.237 + glMatrixMode(GL_MODELVIEW); 1.238 + glPopMatrix(); 1.239 + } 1.240 +} 1.241 + 1.242 +static int warping_mouse; 1.243 + 1.244 +void game_keyboard(int key, int pressed) 1.245 +{ 1.246 + keystate[key] = pressed; 1.247 + 1.248 + if(!pressed) return; 1.249 + 1.250 + switch(key) { 1.251 + case 27: 1.252 + exit(0); 1.253 + 1.254 + case 'a': 1.255 + if(!freelook && !game_won) { 1.256 + player_turn(&player, -90, 0); 1.257 + } 1.258 + break; 1.259 + 1.260 + case 'd': 1.261 + if(!freelook && !game_won) { 1.262 + player_turn(&player, 90, 0); 1.263 + } 1.264 + break; 1.265 + 1.266 + case 'w': 1.267 + case 's': 1.268 + if(!freelook && !game_won) { 1.269 + float prev_x = player.x; 1.270 + float prev_y = player.y; 1.271 + float sign = key == 'w' ? 1.0 : -1.0; 1.272 + 1.273 + if(!player_move(&player, level.cell_size * sign, 0)) { 1.274 + player.x = prev_x; 1.275 + player.y = prev_y; 1.276 + } 1.277 + } 1.278 + break; 1.279 + 1.280 + case '`': 1.281 + case '~': 1.282 + mouselook = !mouselook; 1.283 + if(mouselook) { 1.284 + warping_mouse = 1; 1.285 + set_mouse_pos(win_width / 2, win_height / 2); 1.286 + set_mouse_cursor(0); 1.287 + } else { 1.288 + set_mouse_cursor(1); 1.289 + } 1.290 + break; 1.291 + 1.292 + case 'b': 1.293 + case 'B': 1.294 + freelook = !freelook; 1.295 + break; 1.296 + 1.297 + case 'r': 1.298 + case 'R': 1.299 + game_won = 0; 1.300 + player_init(&player, &level); 1.301 + break; 1.302 + 1.303 + default: 1.304 + break; 1.305 + } 1.306 +} 1.307 + 1.308 +#define MAX_TOUCH_IDS 16 1.309 +static struct { 1.310 + int bnstate[8]; 1.311 + int prev_x, prev_y; 1.312 +} mstate[MAX_TOUCH_IDS]; 1.313 + 1.314 +void game_mouse_button(int id, int bn, int pressed, int x, int y) 1.315 +{ 1.316 + if(id >= MAX_TOUCH_IDS) return; 1.317 + 1.318 + mstate[id].prev_x = x; 1.319 + mstate[id].prev_y = y; 1.320 + mstate[id].bnstate[bn] = pressed; 1.321 +} 1.322 + 1.323 +void game_mouse_motion(int id, int x, int y) 1.324 +{ 1.325 + int dx, dy, cx, cy; 1.326 + 1.327 + if(id >= MAX_TOUCH_IDS) return; 1.328 + 1.329 + cx = win_width / 2; 1.330 + cy = win_height / 2; 1.331 + 1.332 + if(warping_mouse) { 1.333 + warping_mouse = 0; 1.334 + return; 1.335 + } 1.336 + 1.337 + dx = x - (mouselook ? cx : mstate[id].prev_x); 1.338 + dy = y - (mouselook ? cy : mstate[id].prev_y); 1.339 + mstate[id].prev_x = x; 1.340 + mstate[id].prev_y = y; 1.341 + 1.342 + if(!dx && !dy) return; 1.343 + 1.344 + if(mouselook || mstate[id].bnstate[0]) { 1.345 + player_turn(&player, dx * 0.5, dy * 0.5); 1.346 + } 1.347 + if(mstate[id].bnstate[2]) { 1.348 + dbg_cam_dist += 0.1 * dy; 1.349 + if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0; 1.350 + } 1.351 + 1.352 + if(mouselook) { 1.353 + warping_mouse = 1; 1.354 + set_mouse_pos(cx, cy); 1.355 + mstate[id].prev_x = cx; 1.356 + mstate[id].prev_y = cy; 1.357 + } 1.358 +} 1.359 +