labyrinth

annotate src/main.c @ 0:8ba79034e8a6

labyrinth example initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 15 Jan 2015 14:59:38 +0200
parents
children e3b9707504df
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <math.h>
nuclear@0 4 #include <assert.h>
nuclear@0 5 #include "opengl.h"
nuclear@0 6 #include "player.h"
nuclear@0 7 #include "level.h"
nuclear@0 8 #include "noise.h"
nuclear@0 9 #include "texture.h"
nuclear@0 10 #include "mesh.h"
nuclear@0 11
nuclear@0 12 #define PLAYER_EYE_HEIGHT 1.65
nuclear@0 13
nuclear@0 14 static int init(void);
nuclear@0 15 static void update(unsigned int msec);
nuclear@0 16 static void display(void);
nuclear@0 17 static void draw_scene(unsigned int msec);
nuclear@0 18 static void idle(void);
nuclear@0 19 static void reshape(int x, int y);
nuclear@0 20 static void key_down(unsigned char key, int x, int y);
nuclear@0 21 static void key_up(unsigned char key, int x, int y);
nuclear@0 22 static void mouse(int bn, int state, int x, int y);
nuclear@0 23 static void motion(int x, int y);
nuclear@0 24
nuclear@0 25 static int win_width, win_height;
nuclear@0 26 static struct level level;
nuclear@0 27 static struct player player;
nuclear@0 28 static int mouselook, freelook = 1;
nuclear@0 29 static char keystate[256];
nuclear@0 30
nuclear@0 31 static struct mesh *monkey_mesh;
nuclear@0 32 static unsigned int envmap;
nuclear@0 33 static unsigned int win_tex;
nuclear@0 34
nuclear@0 35 static int game_won;
nuclear@0 36
nuclear@0 37 static float dbg_cam_dist = 0.0;
nuclear@0 38
nuclear@0 39 int main(int argc, char **argv)
nuclear@0 40 {
nuclear@0 41 glutInit(&argc, argv);
nuclear@0 42 glutInitWindowSize(1280, 800);
nuclear@0 43 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
nuclear@0 44 glutCreateWindow("labyrinth game example");
nuclear@0 45
nuclear@0 46 glutDisplayFunc(display);
nuclear@0 47 glutIdleFunc(idle);
nuclear@0 48 glutReshapeFunc(reshape);
nuclear@0 49 glutKeyboardFunc(key_down);
nuclear@0 50 glutKeyboardUpFunc(key_up);
nuclear@0 51 glutMouseFunc(mouse);
nuclear@0 52 glutMotionFunc(motion);
nuclear@0 53
nuclear@0 54 if(init() == -1) {
nuclear@0 55 return 1;
nuclear@0 56 }
nuclear@0 57 glutMainLoop();
nuclear@0 58 return 0;
nuclear@0 59 }
nuclear@0 60
nuclear@0 61
nuclear@0 62 static int init(void)
nuclear@0 63 {
nuclear@0 64 glEnable(GL_DEPTH_TEST);
nuclear@0 65 glEnable(GL_CULL_FACE);
nuclear@0 66 glEnable(GL_LIGHTING);
nuclear@0 67 glEnable(GL_NORMALIZE);
nuclear@0 68
nuclear@0 69 glEnable(GL_LIGHT0);
nuclear@0 70 glEnable(GL_LIGHT1);
nuclear@0 71
nuclear@0 72 /* set a slightly bluish cold ambient light */
nuclear@0 73 {
nuclear@0 74 float ambient[] = {0.08, 0.1, 0.3, 1.0};
nuclear@0 75 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
nuclear@0 76 }
nuclear@0 77
nuclear@0 78 level_init(&level);
nuclear@0 79 if(level_load(&level, "data/0.level") == -1) {
nuclear@0 80 fprintf(stderr, "level loading failed\n");
nuclear@0 81 return -1;
nuclear@0 82 }
nuclear@0 83
nuclear@0 84 if(!(level.wall_tex = load_texture("data/wall.ppm"))) {
nuclear@0 85 return -1;
nuclear@0 86 }
nuclear@0 87 if(!(level.floor_tex = load_texture("data/floor.ppm"))) {
nuclear@0 88 return -1;
nuclear@0 89 }
nuclear@0 90 level.floor_tex_scale = 1.0;
nuclear@0 91 if(!(level.ceil_tex = load_texture("data/ceil.ppm"))) {
nuclear@0 92 return -1;
nuclear@0 93 }
nuclear@0 94 level.ceil_tex_scale = 2.0;
nuclear@0 95
nuclear@0 96
nuclear@0 97 if(!(monkey_mesh = load_mesh("data/monkey.obj"))) {
nuclear@0 98 return -1;
nuclear@0 99 }
nuclear@0 100 if(!(envmap = load_texture("data/refmap.ppm"))) {
nuclear@0 101 return -1;
nuclear@0 102 }
nuclear@0 103
nuclear@0 104 if(!(win_tex = load_texture("data/done.ppm"))) {
nuclear@0 105 return -1;
nuclear@0 106 }
nuclear@0 107
nuclear@0 108 player_init(&player, &level);
nuclear@0 109 return 0;
nuclear@0 110 }
nuclear@0 111
nuclear@0 112 static void update(unsigned int msec)
nuclear@0 113 {
nuclear@0 114 static unsigned int prev_upd;
nuclear@0 115 float dfwd = 0.0f;
nuclear@0 116 float dright = 0.0f;
nuclear@0 117 float walk_speed = 8.0;
nuclear@0 118
nuclear@0 119 float dt = (float)(msec - prev_upd) / 1000.0f;
nuclear@0 120 prev_upd = msec;
nuclear@0 121
nuclear@0 122 if(game_won) return;
nuclear@0 123
nuclear@0 124 if(freelook) {
nuclear@0 125 if(keystate['w'] || keystate['W']) {
nuclear@0 126 dfwd += walk_speed * dt;
nuclear@0 127 }
nuclear@0 128 if(keystate['s'] || keystate['S']) {
nuclear@0 129 dfwd -= walk_speed * dt;
nuclear@0 130 }
nuclear@0 131 if(keystate['d'] || keystate['D']) {
nuclear@0 132 dright += walk_speed * dt * 0.6;
nuclear@0 133 }
nuclear@0 134 if(keystate['a'] || keystate['A']) {
nuclear@0 135 dright -= walk_speed * dt * 0.6;
nuclear@0 136 }
nuclear@0 137
nuclear@0 138 player_move(&player, dfwd, dright);
nuclear@0 139 }
nuclear@0 140
nuclear@0 141 if(level_cell_at(&level, player.x, player.y) == 'x') {
nuclear@0 142 game_won = 1;
nuclear@0 143 }
nuclear@0 144 }
nuclear@0 145
nuclear@0 146 static void display(void)
nuclear@0 147 {
nuclear@0 148 float flicker = 1.0f;
nuclear@0 149 unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
nuclear@0 150
nuclear@0 151 update(msec);
nuclear@0 152
nuclear@0 153 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
nuclear@0 154
nuclear@0 155 glMatrixMode(GL_MODELVIEW);
nuclear@0 156 glLoadIdentity();
nuclear@0 157 glTranslatef(0, 0, -dbg_cam_dist);
nuclear@0 158 /* set view matrix according to player pos/rot */
nuclear@0 159 player_setup_view_matrix(&player);
nuclear@0 160 glTranslatef(0, -PLAYER_EYE_HEIGHT, 0);
nuclear@0 161
nuclear@0 162 /* setup lights */
nuclear@0 163 flicker = fbm1((float)msec / 500.0f, 2) * 0.4 + 0.6;
nuclear@0 164 set_light_position(0, player.x, PLAYER_EYE_HEIGHT + 0.2, player.y);
nuclear@0 165 set_light_color(0, 1.0 * flicker, 0.6 * flicker, 0.3 * flicker);
nuclear@0 166 set_light_attenuation(0, 0.5, 0, 0.04);
nuclear@0 167
nuclear@0 168 set_light_position(1, level.goal_pos[0], 0.8, level.goal_pos[1]);
nuclear@0 169 set_light_color(1, 0.955, 0.75, 0.06);
nuclear@0 170 set_light_attenuation(1, 0.9, 0, 0.05);
nuclear@0 171
nuclear@0 172 /* draw the scene */
nuclear@0 173 draw_scene(msec);
nuclear@0 174
nuclear@0 175 glutSwapBuffers();
nuclear@0 176 assert(glGetError() == GL_NO_ERROR);
nuclear@0 177 }
nuclear@0 178
nuclear@0 179 static void draw_scene(unsigned int msec)
nuclear@0 180 {
nuclear@0 181 float x, y;
nuclear@0 182 float tsec = (float)msec / 1000.0f;
nuclear@0 183
nuclear@0 184 level_draw(&level);
nuclear@0 185
nuclear@0 186 /* draw the golden monkey */
nuclear@0 187 if(level_obj_pos(&level, 'x', &x, &y)) {
nuclear@0 188 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
nuclear@0 189 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
nuclear@0 190 glEnable(GL_TEXTURE_GEN_S);
nuclear@0 191 glEnable(GL_TEXTURE_GEN_T);
nuclear@0 192
nuclear@0 193 glBindTexture(GL_TEXTURE_2D, envmap);
nuclear@0 194 glEnable(GL_TEXTURE_2D);
nuclear@0 195
nuclear@0 196 set_mtl_diffuse(0.1, 0.1, 0.1, 1);
nuclear@0 197 set_mtl_specular(0.955, 0.75, 0.06);
nuclear@0 198 set_mtl_shininess(80.0);
nuclear@0 199 set_mtl_emission(0.955, 0.75 * 0.7, 0.06 * 0.1);
nuclear@0 200
nuclear@0 201 glMatrixMode(GL_MODELVIEW);
nuclear@0 202 glPushMatrix();
nuclear@0 203 glTranslatef(x, 0.8 + sin(tsec * 2.0) * 0.1, y);
nuclear@0 204 glRotatef(tsec * 100.0, 0, 1, 0);
nuclear@0 205 glRotatef(sin(tsec * 3.0) * 10.0, 1, 0, 0);
nuclear@0 206 glScalef(0.3, 0.3, 0.3);
nuclear@0 207
nuclear@0 208 render_mesh(monkey_mesh);
nuclear@0 209
nuclear@0 210 glPopMatrix();
nuclear@0 211
nuclear@0 212 set_mtl_emission(0, 0, 0);
nuclear@0 213
nuclear@0 214 glDisable(GL_TEXTURE_2D);
nuclear@0 215
nuclear@0 216 glDisable(GL_TEXTURE_GEN_S);
nuclear@0 217 glDisable(GL_TEXTURE_GEN_T);
nuclear@0 218 }
nuclear@0 219
nuclear@0 220 /* draw the win text */
nuclear@0 221 if(game_won) {
nuclear@0 222 glMatrixMode(GL_MODELVIEW);
nuclear@0 223 glPushMatrix();
nuclear@0 224 glLoadIdentity();
nuclear@0 225 glMatrixMode(GL_PROJECTION);
nuclear@0 226 glPushMatrix();
nuclear@0 227 glLoadIdentity();
nuclear@0 228 glScalef((float)win_height / (float)win_width, 1, 1);
nuclear@0 229
nuclear@0 230 glBindTexture(GL_TEXTURE_2D, win_tex);
nuclear@0 231 glEnable(GL_TEXTURE_2D);
nuclear@0 232
nuclear@0 233 glEnable(GL_BLEND);
nuclear@0 234 glBlendFunc(GL_ONE, GL_ONE);
nuclear@0 235 glDisable(GL_LIGHTING);
nuclear@0 236
nuclear@0 237 glBegin(GL_QUADS);
nuclear@0 238 glTexCoord2f(0, 1); glVertex2f(-1, -1);
nuclear@0 239 glTexCoord2f(1, 1); glVertex2f(1, -1);
nuclear@0 240 glTexCoord2f(1, 0); glVertex2f(1, 1);
nuclear@0 241 glTexCoord2f(0, 0); glVertex2f(-1, 1);
nuclear@0 242 glEnd();
nuclear@0 243
nuclear@0 244 glDisable(GL_BLEND);
nuclear@0 245 glDisable(GL_TEXTURE_2D);
nuclear@0 246 glEnable(GL_LIGHTING);
nuclear@0 247
nuclear@0 248 glPopMatrix();
nuclear@0 249 glMatrixMode(GL_MODELVIEW);
nuclear@0 250 glPopMatrix();
nuclear@0 251 }
nuclear@0 252 }
nuclear@0 253
nuclear@0 254 static void idle(void)
nuclear@0 255 {
nuclear@0 256 glutPostRedisplay();
nuclear@0 257 }
nuclear@0 258
nuclear@0 259 static void reshape(int x, int y)
nuclear@0 260 {
nuclear@0 261 win_width = x;
nuclear@0 262 win_height = y;
nuclear@0 263 glViewport(0, 0, x, y);
nuclear@0 264 glMatrixMode(GL_PROJECTION);
nuclear@0 265 glLoadIdentity();
nuclear@0 266 gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
nuclear@0 267 }
nuclear@0 268
nuclear@0 269 static int warping_mouse;
nuclear@0 270
nuclear@0 271 static void key_down(unsigned char key, int x, int y)
nuclear@0 272 {
nuclear@0 273 keystate[key] = 1;
nuclear@0 274
nuclear@0 275 switch(key) {
nuclear@0 276 case 27:
nuclear@0 277 exit(0);
nuclear@0 278
nuclear@0 279 case 'a':
nuclear@0 280 if(!freelook && !game_won) {
nuclear@0 281 player_turn(&player, -90, 0);
nuclear@0 282 }
nuclear@0 283 break;
nuclear@0 284
nuclear@0 285 case 'd':
nuclear@0 286 if(!freelook && !game_won) {
nuclear@0 287 player_turn(&player, 90, 0);
nuclear@0 288 }
nuclear@0 289 break;
nuclear@0 290
nuclear@0 291 case 'w':
nuclear@0 292 case 's':
nuclear@0 293 if(!freelook && !game_won) {
nuclear@0 294 float prev_x = player.x;
nuclear@0 295 float prev_y = player.y;
nuclear@0 296 float sign = key == 'w' ? 1.0 : -1.0;
nuclear@0 297
nuclear@0 298 if(!player_move(&player, level.cell_size * sign, 0)) {
nuclear@0 299 player.x = prev_x;
nuclear@0 300 player.y = prev_y;
nuclear@0 301 }
nuclear@0 302 }
nuclear@0 303 break;
nuclear@0 304
nuclear@0 305 case '`':
nuclear@0 306 case '~':
nuclear@0 307 mouselook = !mouselook;
nuclear@0 308 if(mouselook) {
nuclear@0 309 warping_mouse = 1;
nuclear@0 310 glutWarpPointer(win_width / 2, win_height / 2);
nuclear@0 311 glutPassiveMotionFunc(motion);
nuclear@0 312 glutSetCursor(GLUT_CURSOR_NONE);
nuclear@0 313 } else {
nuclear@0 314 glutPassiveMotionFunc(0);
nuclear@0 315 glutSetCursor(GLUT_CURSOR_INHERIT);
nuclear@0 316 }
nuclear@0 317 break;
nuclear@0 318
nuclear@0 319 case 'b':
nuclear@0 320 case 'B':
nuclear@0 321 freelook = !freelook;
nuclear@0 322 break;
nuclear@0 323
nuclear@0 324 case 'r':
nuclear@0 325 case 'R':
nuclear@0 326 game_won = 0;
nuclear@0 327 player_init(&player, &level);
nuclear@0 328 break;
nuclear@0 329
nuclear@0 330 default:
nuclear@0 331 break;
nuclear@0 332 }
nuclear@0 333 }
nuclear@0 334
nuclear@0 335 static void key_up(unsigned char key, int x, int y)
nuclear@0 336 {
nuclear@0 337 keystate[key] = 0;
nuclear@0 338 }
nuclear@0 339
nuclear@0 340 static int bnstate[16];
nuclear@0 341 static int prev_x, prev_y;
nuclear@0 342
nuclear@0 343 static void mouse(int bn, int state, int x, int y)
nuclear@0 344 {
nuclear@0 345 prev_x = x;
nuclear@0 346 prev_y = y;
nuclear@0 347 bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN ? 1 : 0;
nuclear@0 348 }
nuclear@0 349
nuclear@0 350 static void motion(int x, int y)
nuclear@0 351 {
nuclear@0 352 int dx, dy;
nuclear@0 353 int cx = win_width / 2;
nuclear@0 354 int cy = win_height / 2;
nuclear@0 355
nuclear@0 356 if(warping_mouse) {
nuclear@0 357 warping_mouse = 0;
nuclear@0 358 return;
nuclear@0 359 }
nuclear@0 360
nuclear@0 361 dx = x - (mouselook ? cx : prev_x);
nuclear@0 362 dy = y - (mouselook ? cy : prev_y);
nuclear@0 363 prev_x = x;
nuclear@0 364 prev_y = y;
nuclear@0 365
nuclear@0 366 if(!dx && !dy) return;
nuclear@0 367
nuclear@0 368 if(mouselook || bnstate[0]) {
nuclear@0 369 player_turn(&player, dx * 0.5, dy * 0.5);
nuclear@0 370 }
nuclear@0 371 if(bnstate[2]) {
nuclear@0 372 dbg_cam_dist += 0.1 * dy;
nuclear@0 373 if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0;
nuclear@0 374 }
nuclear@0 375
nuclear@0 376 if(mouselook) {
nuclear@0 377 warping_mouse = 1;
nuclear@0 378 glutWarpPointer(cx, cy);
nuclear@0 379 prev_x = cx;
nuclear@0 380 prev_y = cy;
nuclear@0 381 }
nuclear@0 382 }