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 }
|