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@48
|
106 }
|
nuclear@48
|
107
|
nuclear@41
|
108 rend = new DeferredRenderer();
|
nuclear@42
|
109 if(!cfg.use_deferred || !rend->init(xsz, ysz)) {
|
nuclear@41
|
110 printf("falling back to crappy renderer...\n");
|
nuclear@41
|
111
|
nuclear@41
|
112 rend = new FwdRenderer();
|
nuclear@41
|
113 if(!rend->init(xsz, ysz)) {
|
nuclear@41
|
114 fprintf(stderr, "failed to create renderer\n");
|
nuclear@41
|
115 return false;
|
nuclear@41
|
116 }
|
nuclear@15
|
117 }
|
nuclear@15
|
118
|
nuclear@26
|
119 if(!init_cmdcon()) {
|
nuclear@26
|
120 return false;
|
nuclear@26
|
121 }
|
nuclear@26
|
122
|
nuclear@46
|
123 psys_texture_loader(load_psys_tex, 0, 0);
|
nuclear@46
|
124
|
nuclear@5
|
125 // load a tileset
|
nuclear@5
|
126 tileset = new TileSet;
|
nuclear@18
|
127 printf("loading tileset: %s\n", cfg.tileset_file);
|
nuclear@18
|
128 if(!tileset->load(datafile_path(cfg.tileset_file))) {
|
nuclear@5
|
129 return false;
|
nuclear@5
|
130 }
|
nuclear@5
|
131 set_active_tileset(tileset);
|
nuclear@5
|
132
|
nuclear@1
|
133 level = new Level;
|
nuclear@18
|
134 printf("loading level: %s\n", cfg.level_file);
|
nuclear@18
|
135 if(!level->load(datafile_path(cfg.level_file))) {
|
nuclear@5
|
136 return false;
|
nuclear@1
|
137 }
|
nuclear@1
|
138
|
nuclear@7
|
139 cam.input_move(0, 0.5, 0);
|
nuclear@7
|
140
|
nuclear@5
|
141 return true;
|
nuclear@1
|
142 }
|
nuclear@1
|
143
|
nuclear@15
|
144 void cleanup()
|
nuclear@15
|
145 {
|
nuclear@47
|
146 if(cfg.sound) {
|
nuclear@48
|
147 delete move_sound;
|
nuclear@47
|
148 destroy_audio();
|
nuclear@47
|
149 }
|
nuclear@47
|
150
|
nuclear@15
|
151 delete level;
|
nuclear@15
|
152 delete tileset;
|
nuclear@41
|
153 delete rend;
|
nuclear@26
|
154
|
nuclear@26
|
155 cleanup_cmdcon();
|
nuclear@15
|
156 }
|
nuclear@15
|
157
|
nuclear@7
|
158 void idle()
|
nuclear@7
|
159 {
|
nuclear@7
|
160 glutPostRedisplay();
|
nuclear@7
|
161 }
|
nuclear@7
|
162
|
nuclear@1
|
163 void disp()
|
nuclear@1
|
164 {
|
nuclear@38
|
165 update(get_time_msec());
|
nuclear@7
|
166
|
nuclear@18
|
167 if(cfg.stereo) {
|
nuclear@18
|
168 glDrawBuffer(GL_BACK_LEFT);
|
nuclear@1
|
169
|
nuclear@18
|
170 glMatrixMode(GL_PROJECTION);
|
nuclear@18
|
171 glLoadIdentity();
|
nuclear@18
|
172 proj_matrix(-1);
|
nuclear@18
|
173 glMatrixMode(GL_MODELVIEW);
|
nuclear@18
|
174 glLoadIdentity();
|
nuclear@18
|
175 view_matrix(-1);
|
nuclear@1
|
176
|
nuclear@24
|
177 draw();
|
nuclear@18
|
178
|
nuclear@18
|
179 glDrawBuffer(GL_BACK_RIGHT);
|
nuclear@18
|
180
|
nuclear@18
|
181 glMatrixMode(GL_PROJECTION);
|
nuclear@18
|
182 glLoadIdentity();
|
nuclear@18
|
183 proj_matrix(1);
|
nuclear@18
|
184 glMatrixMode(GL_MODELVIEW);
|
nuclear@18
|
185 glLoadIdentity();
|
nuclear@18
|
186 view_matrix(1);
|
nuclear@18
|
187
|
nuclear@24
|
188 draw();
|
nuclear@18
|
189 } else {
|
nuclear@18
|
190 glMatrixMode(GL_PROJECTION);
|
nuclear@18
|
191 glLoadIdentity();
|
nuclear@18
|
192 proj_matrix(0);
|
nuclear@18
|
193 glMatrixMode(GL_MODELVIEW);
|
nuclear@18
|
194 glLoadIdentity();
|
nuclear@18
|
195 view_matrix(0);
|
nuclear@18
|
196
|
nuclear@24
|
197 draw();
|
nuclear@18
|
198 }
|
nuclear@1
|
199
|
nuclear@1
|
200 glutSwapBuffers();
|
nuclear@1
|
201 assert(glGetError() == GL_NO_ERROR);
|
nuclear@7
|
202 }
|
nuclear@7
|
203
|
nuclear@24
|
204 void draw()
|
nuclear@24
|
205 {
|
nuclear@41
|
206 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@29
|
207
|
nuclear@41
|
208 rend->render(level);
|
nuclear@24
|
209
|
nuclear@24
|
210 if(show_con) {
|
nuclear@24
|
211 draw_cmdcon();
|
nuclear@24
|
212 }
|
nuclear@24
|
213 }
|
nuclear@24
|
214
|
nuclear@18
|
215 void view_matrix(int eye)
|
nuclear@18
|
216 {
|
nuclear@18
|
217 float offs = stereo_eye_sep * eye * 0.5;
|
nuclear@18
|
218 glTranslatef(-offs, 0, 0);
|
nuclear@18
|
219 cam.use_inverse();
|
nuclear@18
|
220 }
|
nuclear@18
|
221
|
nuclear@18
|
222 void proj_matrix(int eye)
|
nuclear@18
|
223 {
|
nuclear@18
|
224 static const float fov = M_PI / 4.0;
|
nuclear@18
|
225 static const float near_clip = 0.1;
|
nuclear@18
|
226 static const float far_clip = 100.0;
|
nuclear@18
|
227
|
nuclear@18
|
228 float top = near_clip * tan(fov * 0.5);
|
nuclear@18
|
229 float right = top * (float)cfg.width / (float)cfg.height;
|
nuclear@18
|
230
|
nuclear@18
|
231 float frust_shift = -(float)eye * (stereo_eye_sep * 0.5 * near_clip / stereo_focus_dist);
|
nuclear@18
|
232 glFrustum(-right + frust_shift, right + frust_shift, -top, top, near_clip, far_clip);
|
nuclear@18
|
233 }
|
nuclear@18
|
234
|
nuclear@18
|
235
|
nuclear@7
|
236 void update(unsigned long msec)
|
nuclear@7
|
237 {
|
nuclear@7
|
238 static unsigned long last_upd;
|
nuclear@7
|
239
|
nuclear@7
|
240 if(last_upd == 0) {
|
nuclear@7
|
241 last_upd = msec;
|
nuclear@7
|
242 }
|
nuclear@7
|
243 float dt = (float)(msec - last_upd) / 1000.0;
|
nuclear@7
|
244
|
nuclear@9
|
245 float offs = 2.5 * dt;
|
nuclear@7
|
246 float dx = 0, dy = 0;
|
nuclear@7
|
247
|
nuclear@7
|
248 // handle key input
|
nuclear@48
|
249 bool did_move = false;
|
nuclear@7
|
250 if(keystate['w'] || keystate['W']) {
|
nuclear@7
|
251 dy -= offs;
|
nuclear@48
|
252 did_move = true;
|
nuclear@7
|
253 }
|
nuclear@7
|
254 if(keystate['s'] || keystate['S']) {
|
nuclear@7
|
255 dy += offs;
|
nuclear@48
|
256 did_move = true;
|
nuclear@7
|
257 }
|
nuclear@7
|
258 if(keystate['d'] || keystate['D']) {
|
nuclear@7
|
259 dx += offs;
|
nuclear@48
|
260 did_move = true;
|
nuclear@7
|
261 }
|
nuclear@7
|
262 if(keystate['a'] || keystate['A']) {
|
nuclear@7
|
263 dx -= offs;
|
nuclear@48
|
264 did_move = true;
|
nuclear@7
|
265 }
|
nuclear@7
|
266
|
nuclear@7
|
267 cam.input_move(dx, 0, dy);
|
nuclear@7
|
268
|
nuclear@46
|
269 tileset->update_tiles(msec);
|
nuclear@49
|
270
|
nuclear@49
|
271 level->set_player_position(cam.get_position());
|
nuclear@38
|
272 level->update(msec, dt);
|
nuclear@38
|
273
|
nuclear@49
|
274 if(cfg.sound) {
|
nuclear@50
|
275 // set the listener matrix
|
nuclear@50
|
276 set_audio_listener(cam.matrix());
|
nuclear@50
|
277
|
nuclear@50
|
278 // play the walking sound if we're walking
|
nuclear@49
|
279 int cellx, celly;
|
nuclear@49
|
280 level->get_cell_coords_at(cam.get_position(), &cellx, &celly);
|
nuclear@48
|
281
|
nuclear@49
|
282 const AudioSample *move_sample;
|
nuclear@49
|
283 if(did_move && (move_sample = level->get_sample(cellx, celly, TILE_SAMPLE_WALK))) {
|
nuclear@49
|
284 if(move_sample != move_sound->get_sample()) {
|
nuclear@49
|
285 move_sound->stop();
|
nuclear@49
|
286 move_sound->set_sample(move_sample);
|
nuclear@49
|
287 move_sound->play();
|
nuclear@49
|
288 }
|
nuclear@49
|
289 } else {
|
nuclear@49
|
290 if(move_sound->get_sample()) {
|
nuclear@49
|
291 move_sound->stop();
|
nuclear@49
|
292 move_sound->set_sample(0);
|
nuclear@49
|
293 }
|
nuclear@48
|
294 }
|
nuclear@48
|
295 }
|
nuclear@48
|
296
|
nuclear@7
|
297 last_upd = msec;
|
nuclear@1
|
298 }
|
nuclear@1
|
299
|
nuclear@1
|
300 void reshape(int x, int y)
|
nuclear@1
|
301 {
|
nuclear@1
|
302 glViewport(0, 0, x, y);
|
nuclear@18
|
303 cfg.width = x;
|
nuclear@18
|
304 cfg.height = y;
|
nuclear@30
|
305
|
nuclear@41
|
306 rend->resize(x, y);
|
nuclear@1
|
307 }
|
nuclear@1
|
308
|
nuclear@18
|
309 static bool stereo_shift_pressed;
|
nuclear@18
|
310
|
nuclear@1
|
311 void keyb(unsigned char key, int x, int y)
|
nuclear@1
|
312 {
|
nuclear@1
|
313 switch(key) {
|
nuclear@1
|
314 case 27:
|
nuclear@1
|
315 exit(0);
|
nuclear@18
|
316
|
nuclear@24
|
317 case '`':
|
nuclear@24
|
318 show_con = true;
|
nuclear@24
|
319 glutKeyboardFunc(keyb_con);
|
nuclear@24
|
320 glutKeyboardUpFunc(0);
|
nuclear@24
|
321 glutPostRedisplay();
|
nuclear@24
|
322 break;
|
nuclear@24
|
323
|
nuclear@18
|
324 case 'z':
|
nuclear@18
|
325 stereo_shift_pressed = true;
|
nuclear@18
|
326 break;
|
nuclear@18
|
327
|
nuclear@48
|
328 case 'p':
|
nuclear@48
|
329 {
|
nuclear@48
|
330 Vector3 pos = cam.get_position();
|
nuclear@48
|
331 int cell_x, cell_y;
|
nuclear@48
|
332 level->get_cell_coords_at(pos, &cell_x, &cell_y);
|
nuclear@48
|
333 printf("Current position: [%.2f %.2f %.2f] cell: [%d %d]\n", pos.x, pos.y, pos.z,
|
nuclear@48
|
334 cell_x, cell_y);
|
nuclear@48
|
335 }
|
nuclear@48
|
336 break;
|
nuclear@48
|
337
|
nuclear@48
|
338 case 'P':
|
nuclear@48
|
339 {
|
nuclear@48
|
340 Vector3 pos = cam.get_position();
|
nuclear@48
|
341 int cell_x, cell_y;
|
nuclear@48
|
342 level->get_cell_coords_at(pos, &cell_x, &cell_y);
|
nuclear@48
|
343 AudioSample *sample = level->get_sample(cell_x, cell_y, TILE_SAMPLE_WALK);
|
nuclear@48
|
344 printf("walk sample: %p\n", (void*)sample);
|
nuclear@48
|
345 }
|
nuclear@48
|
346 break;
|
nuclear@48
|
347
|
nuclear@48
|
348
|
nuclear@18
|
349 case '\n':
|
nuclear@18
|
350 case '\r':
|
nuclear@18
|
351 {
|
nuclear@18
|
352 static bool fullscr;
|
nuclear@18
|
353 if(glutGetModifiers() & GLUT_ACTIVE_ALT) {
|
nuclear@18
|
354 fullscr = !fullscr;
|
nuclear@18
|
355 if(fullscr) {
|
nuclear@18
|
356 glutFullScreen();
|
nuclear@18
|
357 } else {
|
nuclear@18
|
358 glutPositionWindow(20, 20);
|
nuclear@18
|
359 }
|
nuclear@18
|
360 }
|
nuclear@18
|
361 }
|
nuclear@18
|
362 break;
|
nuclear@18
|
363
|
nuclear@18
|
364 default:
|
nuclear@18
|
365 break;
|
nuclear@1
|
366 }
|
nuclear@7
|
367
|
nuclear@7
|
368 keystate[key] = true;
|
nuclear@7
|
369 }
|
nuclear@7
|
370
|
nuclear@7
|
371 void key_release(unsigned char key, int x, int y)
|
nuclear@7
|
372 {
|
nuclear@18
|
373 switch(key) {
|
nuclear@18
|
374 case 'z':
|
nuclear@18
|
375 stereo_shift_pressed = false;
|
nuclear@18
|
376 break;
|
nuclear@18
|
377
|
nuclear@18
|
378 default:
|
nuclear@18
|
379 break;
|
nuclear@18
|
380 }
|
nuclear@18
|
381
|
nuclear@7
|
382 keystate[key] = false;
|
nuclear@1
|
383 }
|
nuclear@1
|
384
|
nuclear@24
|
385 void keyb_con(unsigned char key, int x, int y)
|
nuclear@24
|
386 {
|
nuclear@24
|
387 if(key == '`' || key == 27) {
|
nuclear@24
|
388 show_con = false;
|
nuclear@24
|
389 glutKeyboardFunc(keyb);
|
nuclear@24
|
390 glutKeyboardUpFunc(key_release);
|
nuclear@24
|
391 glutPostRedisplay();
|
nuclear@24
|
392 } else {
|
nuclear@24
|
393 cmdcon_keypress(key);
|
nuclear@24
|
394 }
|
nuclear@24
|
395 }
|
nuclear@24
|
396
|
nuclear@1
|
397 static int prev_x, prev_y;
|
nuclear@1
|
398 static bool bnstate[32];
|
nuclear@1
|
399
|
nuclear@1
|
400 void mouse(int bn, int state, int x, int y)
|
nuclear@1
|
401 {
|
nuclear@1
|
402 prev_x = x;
|
nuclear@1
|
403 prev_y = y;
|
nuclear@1
|
404 bnstate[bn - GLUT_LEFT_BUTTON] = state == GLUT_DOWN;
|
nuclear@1
|
405 }
|
nuclear@1
|
406
|
nuclear@1
|
407 void motion(int x, int y)
|
nuclear@1
|
408 {
|
nuclear@1
|
409 int dx = x - prev_x;
|
nuclear@1
|
410 int dy = y - prev_y;
|
nuclear@1
|
411 prev_x = x;
|
nuclear@1
|
412 prev_y = y;
|
nuclear@1
|
413
|
nuclear@18
|
414 if(stereo_shift_pressed) {
|
nuclear@18
|
415 if(dy != 0) {
|
nuclear@18
|
416 stereo_focus_dist += dy * 0.01;
|
nuclear@18
|
417 stereo_eye_sep = stereo_focus_dist / 30.0;
|
nuclear@18
|
418 printf("foc: %f, sep: %f\n", stereo_focus_dist, stereo_eye_sep);
|
nuclear@18
|
419 glutPostRedisplay();
|
nuclear@18
|
420 }
|
nuclear@18
|
421 return;
|
nuclear@18
|
422 }
|
nuclear@18
|
423
|
nuclear@1
|
424 if(bnstate[0]) {
|
nuclear@7
|
425 cam.input_rotate(dy * 0.01, dx * 0.01, 0);
|
nuclear@1
|
426 glutPostRedisplay();
|
nuclear@1
|
427 }
|
nuclear@1
|
428 if(bnstate[2]) {
|
nuclear@1
|
429 cam.input_zoom(dy * 0.1);
|
nuclear@1
|
430 glutPostRedisplay();
|
nuclear@1
|
431 }
|
nuclear@1
|
432 }
|
nuclear@46
|
433
|
nuclear@46
|
434 unsigned int load_psys_tex(const char *fname, void *cls)
|
nuclear@46
|
435 {
|
nuclear@46
|
436 TextureSet *texset = tileset->get_textures();
|
nuclear@48
|
437 return texset->get(fname);
|
nuclear@46
|
438 }
|