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 +