rev |
line source |
nuclear@1
|
1 #include <stdio.h>
|
nuclear@1
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <assert.h>
|
nuclear@7
|
4 #include <unistd.h>
|
nuclear@1
|
5 #include "opengl.h"
|
nuclear@46
|
6 #include "psys/psys.h"
|
nuclear@1
|
7 #include "level.h"
|
nuclear@48
|
8 #include "texture.h"
|
nuclear@1
|
9 #include "camera.h"
|
nuclear@5
|
10 #include "datapath.h"
|
nuclear@5
|
11 #include "tileset.h"
|
nuclear@15
|
12 #include "renderer.h"
|
nuclear@41
|
13 #include "renderer_deferred.h"
|
nuclear@24
|
14 #include "cmdcon.h"
|
nuclear@18
|
15 #include "cfg.h"
|
nuclear@38
|
16 #include "timer.h"
|
nuclear@48
|
17 #include "audio/audio.h"
|
nuclear@48
|
18 #include "audio/source.h"
|
nuclear@1
|
19
|
nuclear@17
|
20 bool init(int xsz, int ysz);
|
nuclear@5
|
21 void cleanup();
|
nuclear@7
|
22 void idle();
|
nuclear@1
|
23 void disp();
|
nuclear@15
|
24 void draw();
|
nuclear@18
|
25 void view_matrix(int eye);
|
nuclear@18
|
26 void proj_matrix(int eye);
|
nuclear@7
|
27 void update(unsigned long msec);
|
nuclear@1
|
28 void reshape(int x, int y);
|
nuclear@1
|
29 void keyb(unsigned char key, int x, int y);
|
nuclear@7
|
30 void key_release(unsigned char key, int x, int y);
|
nuclear@24
|
31 void keyb_con(unsigned char key, int x, int y);
|
nuclear@1
|
32 void mouse(int bn, int state, int x, int y);
|
nuclear@1
|
33 void motion(int x, int y);
|
nuclear@46
|
34 unsigned int load_psys_tex(const char *fname, void *cls);
|
nuclear@1
|
35
|
nuclear@5
|
36 static TileSet *tileset;
|
nuclear@1
|
37 static Level *level;
|
nuclear@7
|
38
|
nuclear@7
|
39 static FpsCamera cam;
|
nuclear@7
|
40 static bool keystate[256];
|
nuclear@1
|
41
|
nuclear@18
|
42 static float stereo_focus_dist = 0.25;
|
nuclear@18
|
43 static float stereo_eye_sep = stereo_focus_dist / 30.0;
|
nuclear@18
|
44
|
nuclear@24
|
45 static bool show_con;
|
nuclear@5
|
46
|
nuclear@48
|
47 static AudioSource *move_sound;
|
nuclear@48
|
48
|
nuclear@1
|
49 int main(int argc, char **argv)
|
nuclear@1
|
50 {
|
nuclear@1
|
51 glutInit(&argc, argv);
|
nuclear@5
|
52
|
nuclear@18
|
53 if(!cfg.parse_args(argc, argv)) {
|
nuclear@18
|
54 return 1;
|
nuclear@5
|
55 }
|
nuclear@5
|
56
|
nuclear@18
|
57 glutInitWindowSize(cfg.width, cfg.height);
|
nuclear@18
|
58 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE | (cfg.stereo ? GLUT_STEREO : 0));
|
nuclear@18
|
59 glutCreateWindow("dungeon crawler prototype");
|
nuclear@1
|
60
|
nuclear@7
|
61 glutIdleFunc(idle);
|
nuclear@1
|
62 glutDisplayFunc(disp);
|
nuclear@1
|
63 glutReshapeFunc(reshape);
|
nuclear@1
|
64 glutKeyboardFunc(keyb);
|
nuclear@7
|
65 glutKeyboardUpFunc(key_release);
|
nuclear@1
|
66 glutMouseFunc(mouse);
|
nuclear@1
|
67 glutMotionFunc(motion);
|
nuclear@1
|
68
|
nuclear@1
|
69 glewInit();
|
nuclear@1
|
70
|
nuclear@18
|
71 if(!init(cfg.width, cfg.height)) {
|
nuclear@5
|
72 return 1;
|
nuclear@5
|
73 }
|
nuclear@39
|
74 atexit(cleanup);
|
nuclear@5
|
75
|
nuclear@5
|
76 glutMainLoop();
|
nuclear@5
|
77 }
|
nuclear@5
|
78
|
nuclear@17
|
79 bool init(int xsz, int ysz)
|
nuclear@5
|
80 {
|
nuclear@41
|
81 // backup light for the forward crappy renderer
|
nuclear@1
|
82 glEnable(GL_LIGHTING);
|
nuclear@1
|
83 glEnable(GL_LIGHT0);
|
nuclear@41
|
84
|
nuclear@41
|
85 float ldir[] = {0, 0, -0.5, 1};
|
nuclear@1
|
86 glLightfv(GL_LIGHT0, GL_POSITION, ldir);
|
nuclear@41
|
87 float lcol[] = {1, 1, 1, 1};
|
nuclear@41
|
88 glLightfv(GL_LIGHT0, GL_DIFFUSE, lcol);
|
nuclear@41
|
89 glLightfv(GL_LIGHT0, GL_SPECULAR, lcol);
|
nuclear@1
|
90
|
nuclear@1
|
91 glEnable(GL_DEPTH_TEST);
|
nuclear@1
|
92 glEnable(GL_CULL_FACE);
|
nuclear@1
|
93 glEnable(GL_MULTISAMPLE);
|
nuclear@1
|
94
|
nuclear@25
|
95 add_data_path(".");
|
nuclear@5
|
96 add_data_path("data");
|
nuclear@48
|
97 add_data_path("data/audio");
|
nuclear@16
|
98 add_data_path("sdr");
|
nuclear@5
|
99
|
nuclear@48
|
100 if(cfg.sound && !init_audio()) {
|
nuclear@48
|
101 fprintf(stderr, "failed to initialize audio, continuing silently\n");
|
nuclear@48
|
102 cfg.sound = false;
|
nuclear@48
|
103 }
|
nuclear@48
|
104 if(cfg.sound) {
|
nuclear@48
|
105 move_sound = new AudioSource;
|
nuclear@52
|
106 move_sound->set_volume(0.4);
|
nuclear@48
|
107 }
|
nuclear@48
|
108
|
nuclear@41
|
109 rend = new DeferredRenderer();
|
nuclear@42
|
110 if(!cfg.use_deferred || !rend->init(xsz, ysz)) {
|
nuclear@41
|
111 printf("falling back to crappy renderer...\n");
|
nuclear@41
|
112
|
nuclear@41
|
113 rend = new FwdRenderer();
|
nuclear@41
|
114 if(!rend->init(xsz, ysz)) {
|
nuclear@41
|
115 fprintf(stderr, "failed to create renderer\n");
|
nuclear@41
|
116 return false;
|
nuclear@41
|
117 }
|
nuclear@15
|
118 }
|
nuclear@15
|
119
|
nuclear@26
|
120 if(!init_cmdcon()) {
|
nuclear@26
|
121 return false;
|
nuclear@26
|
122 }
|
nuclear@26
|
123
|
nuclear@46
|
124 psys_texture_loader(load_psys_tex, 0, 0);
|
nuclear@46
|
125
|
nuclear@5
|
126 // load a tileset
|
nuclear@5
|
127 tileset = new TileSet;
|
nuclear@18
|
128 printf("loading tileset: %s\n", cfg.tileset_file);
|
nuclear@18
|
129 if(!tileset->load(datafile_path(cfg.tileset_file))) {
|
nuclear@5
|
130 return false;
|
nuclear@5
|
131 }
|
nuclear@5
|
132 set_active_tileset(tileset);
|
nuclear@5
|
133
|
nuclear@1
|
134 level = new Level;
|
nuclear@18
|
135 printf("loading level: %s\n", cfg.level_file);
|
nuclear@18
|
136 if(!level->load(datafile_path(cfg.level_file))) {
|
nuclear@5
|
137 return false;
|
nuclear@1
|
138 }
|
nuclear@1
|
139
|
nuclear@7
|
140 cam.input_move(0, 0.5, 0);
|
nuclear@7
|
141
|
nuclear@5
|
142 return true;
|
nuclear@1
|
143 }
|
nuclear@1
|
144
|
nuclear@15
|
145 void cleanup()
|
nuclear@15
|
146 {
|
nuclear@15
|
147 delete level;
|
nuclear@15
|
148 delete tileset;
|
nuclear@41
|
149 delete rend;
|
nuclear@26
|
150
|
nuclear@26
|
151 cleanup_cmdcon();
|
nuclear@51
|
152
|
nuclear@51
|
153 if(cfg.sound) {
|
nuclear@51
|
154 delete move_sound;
|
nuclear@51
|
155 destroy_audio();
|
nuclear@51
|
156 }
|
nuclear@15
|
157 }
|
nuclear@15
|
158
|
nuclear@7
|
159 void idle()
|
nuclear@7
|
160 {
|
nuclear@7
|
161 glutPostRedisplay();
|
nuclear@7
|
162 }
|
nuclear@7
|
163
|
nuclear@1
|
164 void disp()
|
nuclear@1
|
165 {
|
nuclear@38
|
166 update(get_time_msec());
|
nuclear@7
|
167
|
nuclear@18
|
168 if(cfg.stereo) {
|
nuclear@18
|
169 glDrawBuffer(GL_BACK_LEFT);
|
nuclear@1
|
170
|
nuclear@18
|
171 glMatrixMode(GL_PROJECTION);
|
nuclear@18
|
172 glLoadIdentity();
|
nuclear@18
|
173 proj_matrix(-1);
|
nuclear@18
|
174 glMatrixMode(GL_MODELVIEW);
|
nuclear@18
|
175 glLoadIdentity();
|
nuclear@18
|
176 view_matrix(-1);
|
nuclear@1
|
177
|
nuclear@24
|
178 draw();
|
nuclear@18
|
179
|
nuclear@18
|
180 glDrawBuffer(GL_BACK_RIGHT);
|
nuclear@18
|
181
|
nuclear@18
|
182 glMatrixMode(GL_PROJECTION);
|
nuclear@18
|
183 glLoadIdentity();
|
nuclear@18
|
184 proj_matrix(1);
|
nuclear@18
|
185 glMatrixMode(GL_MODELVIEW);
|
nuclear@18
|
186 glLoadIdentity();
|
nuclear@18
|
187 view_matrix(1);
|
nuclear@18
|
188
|
nuclear@24
|
189 draw();
|
nuclear@18
|
190 } else {
|
nuclear@18
|
191 glMatrixMode(GL_PROJECTION);
|
nuclear@18
|
192 glLoadIdentity();
|
nuclear@18
|
193 proj_matrix(0);
|
nuclear@18
|
194 glMatrixMode(GL_MODELVIEW);
|
nuclear@18
|
195 glLoadIdentity();
|
nuclear@18
|
196 view_matrix(0);
|
nuclear@18
|
197
|
nuclear@24
|
198 draw();
|
nuclear@18
|
199 }
|
nuclear@1
|
200
|
nuclear@1
|
201 glutSwapBuffers();
|
nuclear@1
|
202 assert(glGetError() == GL_NO_ERROR);
|
nuclear@7
|
203 }
|
nuclear@7
|
204
|
nuclear@24
|
205 void draw()
|
nuclear@24
|
206 {
|
nuclear@41
|
207 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@29
|
208
|
nuclear@41
|
209 rend->render(level);
|
nuclear@24
|
210
|
nuclear@24
|
211 if(show_con) {
|
nuclear@24
|
212 draw_cmdcon();
|
nuclear@24
|
213 }
|
nuclear@24
|
214 }
|
nuclear@24
|
215
|
nuclear@18
|
216 void view_matrix(int eye)
|
nuclear@18
|
217 {
|
nuclear@18
|
218 float offs = stereo_eye_sep * eye * 0.5;
|
nuclear@18
|
219 glTranslatef(-offs, 0, 0);
|
nuclear@18
|
220 cam.use_inverse();
|
nuclear@18
|
221 }
|
nuclear@18
|
222
|
nuclear@18
|
223 void proj_matrix(int eye)
|
nuclear@18
|
224 {
|
nuclear@18
|
225 static const float fov = M_PI / 4.0;
|
nuclear@18
|
226 static const float near_clip = 0.1;
|
nuclear@18
|
227 static const float far_clip = 100.0;
|
nuclear@18
|
228
|
nuclear@18
|
229 float top = near_clip * tan(fov * 0.5);
|
nuclear@18
|
230 float right = top * (float)cfg.width / (float)cfg.height;
|
nuclear@18
|
231
|
nuclear@18
|
232 float frust_shift = -(float)eye * (stereo_eye_sep * 0.5 * near_clip / stereo_focus_dist);
|
nuclear@18
|
233 glFrustum(-right + frust_shift, right + frust_shift, -top, top, near_clip, far_clip);
|
nuclear@18
|
234 }
|
nuclear@18
|
235
|
nuclear@18
|
236
|
nuclear@7
|
237 void update(unsigned long msec)
|
nuclear@7
|
238 {
|
nuclear@7
|
239 static unsigned long last_upd;
|
nuclear@7
|
240
|
nuclear@7
|
241 if(last_upd == 0) {
|
nuclear@7
|
242 last_upd = msec;
|
nuclear@7
|
243 }
|
nuclear@7
|
244 float dt = (float)(msec - last_upd) / 1000.0;
|
nuclear@7
|
245
|
nuclear@9
|
246 float offs = 2.5 * dt;
|
nuclear@7
|
247 float dx = 0, dy = 0;
|
nuclear@7
|
248
|
nuclear@7
|
249 // handle key input
|
nuclear@48
|
250 bool did_move = false;
|
nuclear@7
|
251 if(keystate['w'] || keystate['W']) {
|
nuclear@7
|
252 dy -= offs;
|
nuclear@48
|
253 did_move = true;
|
nuclear@7
|
254 }
|
nuclear@7
|
255 if(keystate['s'] || keystate['S']) {
|
nuclear@7
|
256 dy += offs;
|
nuclear@48
|
257 did_move = true;
|
nuclear@7
|
258 }
|
nuclear@7
|
259 if(keystate['d'] || keystate['D']) {
|
nuclear@7
|
260 dx += offs;
|
nuclear@48
|
261 did_move = true;
|
nuclear@7
|
262 }
|
nuclear@7
|
263 if(keystate['a'] || keystate['A']) {
|
nuclear@7
|
264 dx -= offs;
|
nuclear@48
|
265 did_move = true;
|
nuclear@7
|
266 }
|
nuclear@7
|
267
|
nuclear@7
|
268 cam.input_move(dx, 0, dy);
|
nuclear@7
|
269
|
nuclear@46
|
270 tileset->update_tiles(msec);
|
nuclear@49
|
271
|
nuclear@49
|
272 level->set_player_position(cam.get_position());
|
nuclear@38
|
273 level->update(msec, dt);
|
nuclear@38
|
274
|
nuclear@49
|
275 if(cfg.sound) {
|
nuclear@50
|
276 // set the listener matrix
|
nuclear@50
|
277 set_audio_listener(cam.matrix());
|
nuclear@50
|
278
|
nuclear@50
|
279 // play the walking sound if we're walking
|
nuclear@49
|
280 int cellx, celly;
|
nuclear@49
|
281 level->get_cell_coords_at(cam.get_position(), &cellx, &celly);
|
nuclear@48
|
282
|
nuclear@49
|
283 const AudioSample *move_sample;
|
nuclear@49
|
284 if(did_move && (move_sample = level->get_sample(cellx, celly, TILE_SAMPLE_WALK))) {
|
nuclear@49
|
285 if(move_sample != move_sound->get_sample()) {
|
nuclear@49
|
286 move_sound->stop();
|
nuclear@49
|
287 move_sound->set_sample(move_sample);
|
nuclear@49
|
288 move_sound->play();
|
nuclear@49
|
289 }
|
nuclear@49
|
290 } else {
|
nuclear@49
|
291 if(move_sound->get_sample()) {
|
nuclear@49
|
292 move_sound->stop();
|
nuclear@49
|
293 move_sound->set_sample(0);
|
nuclear@49
|
294 }
|
nuclear@48
|
295 }
|
nuclear@48
|
296 }
|
nuclear@48
|
297
|
nuclear@7
|
298 last_upd = msec;
|
nuclear@1
|
299 }
|
nuclear@1
|
300
|
nuclear@1
|
301 void reshape(int x, int y)
|
nuclear@1
|
302 {
|
nuclear@1
|
303 glViewport(0, 0, x, y);
|
nuclear@18
|
304 cfg.width = x;
|
nuclear@18
|
305 cfg.height = y;
|
nuclear@30
|
306
|
nuclear@41
|
307 rend->resize(x, y);
|
nuclear@1
|
308 }
|
nuclear@1
|
309
|
nuclear@18
|
310 static bool stereo_shift_pressed;
|
nuclear@18
|
311
|
nuclear@1
|
312 void keyb(unsigned char key, int x, int y)
|
nuclear@1
|
313 {
|
nuclear@1
|
314 switch(key) {
|
nuclear@1
|
315 case 27:
|
nuclear@1
|
316 exit(0);
|
nuclear@18
|
317
|
nuclear@24
|
318 case '`':
|
nuclear@24
|
319 show_con = true;
|
nuclear@24
|
320 glutKeyboardFunc(keyb_con);
|
nuclear@24
|
321 glutKeyboardUpFunc(0);
|
nuclear@24
|
322 glutPostRedisplay();
|
nuclear@24
|
323 break;
|
nuclear@24
|
324
|
nuclear@18
|
325 case 'z':
|
nuclear@18
|
326 stereo_shift_pressed = true;
|
nuclear@18
|
327 break;
|
nuclear@18
|
328
|
nuclear@48
|
329 case 'p':
|
nuclear@48
|
330 {
|
nuclear@48
|
331 Vector3 pos = cam.get_position();
|
nuclear@48
|
332 int cell_x, cell_y;
|
nuclear@48
|
333 level->get_cell_coords_at(pos, &cell_x, &cell_y);
|
nuclear@48
|
334 printf("Current position: [%.2f %.2f %.2f] cell: [%d %d]\n", pos.x, pos.y, pos.z,
|
nuclear@48
|
335 cell_x, cell_y);
|
nuclear@48
|
336 }
|
nuclear@48
|
337 break;
|
nuclear@48
|
338
|
nuclear@48
|
339 case 'P':
|
nuclear@48
|
340 {
|
nuclear@48
|
341 Vector3 pos = cam.get_position();
|
nuclear@48
|
342 int cell_x, cell_y;
|
nuclear@48
|
343 level->get_cell_coords_at(pos, &cell_x, &cell_y);
|
nuclear@48
|
344 AudioSample *sample = level->get_sample(cell_x, cell_y, TILE_SAMPLE_WALK);
|
nuclear@48
|
345 printf("walk sample: %p\n", (void*)sample);
|
nuclear@48
|
346 }
|
nuclear@48
|
347 break;
|
nuclear@48
|
348
|
nuclear@48
|
349
|
nuclear@18
|
350 case '\n':
|
nuclear@18
|
351 case '\r':
|
nuclear@18
|
352 {
|
nuclear@18
|
353 static bool fullscr;
|
nuclear@18
|
354 if(glutGetModifiers() & GLUT_ACTIVE_ALT) {
|
nuclear@18
|
355 fullscr = !fullscr;
|
nuclear@18
|
356 if(fullscr) {
|
nuclear@18
|
357 glutFullScreen();
|
nuclear@18
|
358 } else {
|
nuclear@18
|
359 glutPositionWindow(20, 20);
|
nuclear@18
|
360 }
|
nuclear@18
|
361 }
|
nuclear@18
|
362 }
|
nuclear@18
|
363 break;
|
nuclear@18
|
364
|
nuclear@18
|
365 default:
|
nuclear@18
|
366 break;
|
nuclear@1
|
367 }
|
nuclear@7
|
368
|
nuclear@7
|
369 keystate[key] = true;
|
nuclear@7
|
370 }
|
nuclear@7
|
371
|
nuclear@7
|
372 void key_release(unsigned char key, int x, int y)
|
nuclear@7
|
373 {
|
nuclear@18
|
374 switch(key) {
|
nuclear@18
|
375 case 'z':
|
nuclear@18
|
376 stereo_shift_pressed = false;
|
nuclear@18
|
377 break;
|
nuclear@18
|
378
|
nuclear@18
|
379 default:
|
nuclear@18
|
380 break;
|
nuclear@18
|
381 }
|
nuclear@18
|
382
|
nuclear@7
|
383 keystate[key] = false;
|
nuclear@1
|
384 }
|
nuclear@1
|
385
|
nuclear@24
|
386 void keyb_con(unsigned char key, int x, int y)
|
nuclear@24
|
387 {
|
nuclear@24
|
388 if(key == '`' || key == 27) {
|
nuclear@24
|
389 show_con = false;
|
nuclear@24
|
390 glutKeyboardFunc(keyb);
|
nuclear@24
|
391 glutKeyboardUpFunc(key_release);
|
nuclear@24
|
392 glutPostRedisplay();
|
nuclear@24
|
393 } else {
|
nuclear@24
|
394 cmdcon_keypress(key);
|
nuclear@24
|
395 }
|
nuclear@24
|
396 }
|
nuclear@24
|
397
|
nuclear@1
|
398 static int prev_x, prev_y;
|
nuclear@1
|
399 static bool bnstate[32];
|
nuclear@1
|
400
|
nuclear@1
|
401 void mouse(int bn, int state, int x, int y)
|
nuclear@1
|
402 {
|
nuclear@1
|
403 prev_x = x;
|
nuclear@1
|
404 prev_y = y;
|
nuclear@1
|
405 bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN;
|
nuclear@1
|
406 }
|
nuclear@1
|
407
|
nuclear@1
|
408 void motion(int x, int y)
|
nuclear@1
|
409 {
|
nuclear@1
|
410 int dx = x - prev_x;
|
nuclear@1
|
411 int dy = y - prev_y;
|
nuclear@1
|
412 prev_x = x;
|
nuclear@1
|
413 prev_y = y;
|
nuclear@1
|
414
|
nuclear@18
|
415 if(stereo_shift_pressed) {
|
nuclear@18
|
416 if(dy != 0) {
|
nuclear@18
|
417 stereo_focus_dist += dy * 0.01;
|
nuclear@18
|
418 stereo_eye_sep = stereo_focus_dist / 30.0;
|
nuclear@18
|
419 printf("foc: %f, sep: %f\n", stereo_focus_dist, stereo_eye_sep);
|
nuclear@18
|
420 glutPostRedisplay();
|
nuclear@18
|
421 }
|
nuclear@18
|
422 return;
|
nuclear@18
|
423 }
|
nuclear@18
|
424
|
nuclear@1
|
425 if(bnstate[0]) {
|
nuclear@7
|
426 cam.input_rotate(dy * 0.01, dx * 0.01, 0);
|
nuclear@1
|
427 glutPostRedisplay();
|
nuclear@1
|
428 }
|
nuclear@1
|
429 if(bnstate[2]) {
|
nuclear@1
|
430 cam.input_zoom(dy * 0.1);
|
nuclear@1
|
431 glutPostRedisplay();
|
nuclear@1
|
432 }
|
nuclear@1
|
433 }
|
nuclear@46
|
434
|
nuclear@46
|
435 unsigned int load_psys_tex(const char *fname, void *cls)
|
nuclear@46
|
436 {
|
nuclear@46
|
437 TextureSet *texset = tileset->get_textures();
|
nuclear@48
|
438 return texset->get(fname);
|
nuclear@46
|
439 }
|