rev |
line source |
nuclear@2
|
1 #include <stdio.h>
|
nuclear@2
|
2 #include <stdlib.h>
|
nuclear@34
|
3 #include <string.h>
|
nuclear@2
|
4 #include <assert.h>
|
nuclear@29
|
5 #include <signal.h>
|
nuclear@19
|
6 #include <vector>
|
nuclear@26
|
7 #include <chrono>
|
nuclear@29
|
8 #include <imago2.h>
|
nuclear@32
|
9 #include <drawtext.h>
|
nuclear@2
|
10 #include "opengl.h"
|
nuclear@4
|
11 #include "erebus.h"
|
nuclear@37
|
12 #include "console.h"
|
nuclear@2
|
13
|
nuclear@26
|
14 using namespace std::chrono;
|
nuclear@26
|
15
|
nuclear@2
|
16 static bool init();
|
nuclear@2
|
17 static void cleanup();
|
nuclear@32
|
18 static void begin_frame(long tm);
|
nuclear@32
|
19 static void end_frame();
|
nuclear@2
|
20 static void resize_rtarget(int xsz, int ysz);
|
nuclear@2
|
21 static void update_rect(int x, int y, int xsz, int ysz, float *pixels);
|
nuclear@4
|
22 static void idle();
|
nuclear@2
|
23 static void display();
|
nuclear@32
|
24 static void display_statusbar(const erb_render_status &status);
|
nuclear@29
|
25 static void save_image(const char *fname = 0);
|
nuclear@2
|
26 static void reshape(int x, int y);
|
nuclear@2
|
27 static void keyb(unsigned char key, int x, int y);
|
nuclear@9
|
28 static void keyb_up(unsigned char key, int x, int y);
|
nuclear@37
|
29 static void skeyb(int key, int x, int y);
|
nuclear@2
|
30 static void mouse(int bn, int st, int x, int y);
|
nuclear@9
|
31 static void motion(int x, int y);
|
nuclear@9
|
32 static void sball_button(int bn, int st);
|
nuclear@9
|
33 static void sball_motion(int x, int y, int z);
|
nuclear@2
|
34 static int next_pow2(int x);
|
nuclear@29
|
35 static void sighandler(int s);
|
nuclear@32
|
36 static bool parse_args(int argc, char **argv);
|
nuclear@37
|
37 static void con_parse(const char *line);
|
nuclear@2
|
38
|
nuclear@32
|
39 static int win_width, win_height, width, height, rtex_width, rtex_height;
|
nuclear@2
|
40 static unsigned int rtex;
|
nuclear@2
|
41
|
nuclear@32
|
42 static int opt_samples = -1;
|
nuclear@32
|
43 static int opt_iter = -1;
|
nuclear@32
|
44 static int opt_threads = -1;
|
nuclear@32
|
45 static float opt_imgscale = 2.0f;
|
nuclear@32
|
46
|
nuclear@4
|
47 static erebus *erb;
|
nuclear@4
|
48 static bool render_pending;
|
nuclear@32
|
49 static bool show_status = true;
|
nuclear@32
|
50 static steady_clock::time_point start_time;
|
nuclear@4
|
51
|
nuclear@19
|
52 static std::vector<char*> sfiles;
|
nuclear@4
|
53
|
nuclear@37
|
54 #define FONTSZ 22
|
nuclear@32
|
55 static dtx_font *font;
|
nuclear@37
|
56 static Console con;
|
nuclear@32
|
57
|
nuclear@2
|
58 int main(int argc, char **argv)
|
nuclear@2
|
59 {
|
nuclear@2
|
60 glutInitWindowSize(1024, 600);
|
nuclear@2
|
61 glutInit(&argc, argv);
|
nuclear@19
|
62
|
nuclear@32
|
63 if(!parse_args(argc, argv)) {
|
nuclear@32
|
64 return 1;
|
nuclear@19
|
65 }
|
nuclear@19
|
66
|
nuclear@2
|
67 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
|
nuclear@2
|
68 glutCreateWindow("erebus OpenGL frontend");
|
nuclear@2
|
69
|
nuclear@2
|
70 glutDisplayFunc(display);
|
nuclear@2
|
71 glutReshapeFunc(reshape);
|
nuclear@2
|
72 glutKeyboardFunc(keyb);
|
nuclear@9
|
73 glutKeyboardUpFunc(keyb_up);
|
nuclear@37
|
74 glutSpecialFunc(skeyb);
|
nuclear@2
|
75 glutMouseFunc(mouse);
|
nuclear@9
|
76 glutMotionFunc(motion);
|
nuclear@9
|
77 glutSpaceballButtonFunc(sball_button);
|
nuclear@9
|
78 glutSpaceballMotionFunc(sball_motion);
|
nuclear@2
|
79
|
nuclear@2
|
80 if(!init()) {
|
nuclear@2
|
81 return 1;
|
nuclear@2
|
82 }
|
nuclear@2
|
83 atexit(cleanup);
|
nuclear@29
|
84 signal(SIGINT, sighandler);
|
nuclear@29
|
85 signal(SIGSEGV, sighandler);
|
nuclear@29
|
86 signal(SIGILL, sighandler);
|
nuclear@29
|
87 signal(SIGTERM, sighandler);
|
nuclear@29
|
88 signal(SIGFPE, sighandler);
|
nuclear@2
|
89
|
nuclear@2
|
90 glutMainLoop();
|
nuclear@2
|
91 }
|
nuclear@2
|
92
|
nuclear@2
|
93 static bool init()
|
nuclear@2
|
94 {
|
nuclear@32
|
95 width = glutGet(GLUT_WINDOW_WIDTH) / opt_imgscale;
|
nuclear@32
|
96 height = glutGet(GLUT_WINDOW_HEIGHT) / opt_imgscale;
|
nuclear@32
|
97
|
nuclear@37
|
98 //if(!(font = dtx_open_font("/usr/share/fonts/opentype/linux-libertine/LinLibertine_R.otf", FONTSZ))) {
|
nuclear@32
|
99 if(!(font = dtx_open_font_glyphmap("data/serif.glyphmap"))) {
|
nuclear@32
|
100 fprintf(stderr, "warning: failed to load font!\n");
|
nuclear@32
|
101 }
|
nuclear@5
|
102
|
nuclear@37
|
103 //dtx_font *confont = dtx_open_font("/usr/share/fonts/truetype/droid/DroidSansMono.ttf", 14);
|
nuclear@37
|
104 dtx_font *confont = dtx_open_font_glyphmap("data/mono.glyphmap");
|
nuclear@37
|
105 if(confont) {
|
nuclear@37
|
106 con.set_font(confont, 14);
|
nuclear@37
|
107 } else {
|
nuclear@37
|
108 con.set_font(font, FONTSZ);
|
nuclear@37
|
109 }
|
nuclear@37
|
110 con.set_command_func(con_parse);
|
nuclear@37
|
111
|
nuclear@4
|
112 if(!(erb = erb_init())) {
|
nuclear@4
|
113 return false;
|
nuclear@4
|
114 }
|
nuclear@4
|
115 erb_setopti(erb, ERB_OPT_WIDTH, width);
|
nuclear@4
|
116 erb_setopti(erb, ERB_OPT_HEIGHT, height);
|
nuclear@4
|
117
|
nuclear@32
|
118 if(opt_samples != -1) {
|
nuclear@32
|
119 erb_setopti(erb, ERB_OPT_MAX_SAMPLES, opt_samples);
|
nuclear@32
|
120 }
|
nuclear@32
|
121 if(opt_iter != -1) {
|
nuclear@32
|
122 erb_setopti(erb, ERB_OPT_MAX_ITER, opt_iter);
|
nuclear@32
|
123 }
|
nuclear@32
|
124 if(opt_threads != -1) {
|
nuclear@32
|
125 erb_setopti(erb, ERB_OPT_NUM_THREADS, opt_threads);
|
nuclear@32
|
126 }
|
nuclear@32
|
127
|
nuclear@19
|
128 for(size_t i=0; i<sfiles.size(); i++) {
|
nuclear@19
|
129 printf("loading scene file: %s\n", sfiles[i]);
|
nuclear@19
|
130 if(erb_load_scene(erb, sfiles[i]) == -1) {
|
nuclear@19
|
131 return false;
|
nuclear@19
|
132 }
|
nuclear@4
|
133 }
|
nuclear@4
|
134
|
nuclear@21
|
135 if(!sfiles.empty()) {
|
nuclear@32
|
136 begin_frame(0);
|
nuclear@21
|
137 }
|
nuclear@4
|
138
|
nuclear@8
|
139 glEnable(GL_TEXTURE_2D);
|
nuclear@2
|
140 return true;
|
nuclear@2
|
141 }
|
nuclear@2
|
142
|
nuclear@2
|
143 static void cleanup()
|
nuclear@2
|
144 {
|
nuclear@29
|
145 save_image("final.png");
|
nuclear@4
|
146 erb_destroy(erb);
|
nuclear@2
|
147 }
|
nuclear@2
|
148
|
nuclear@32
|
149 static void begin_frame(long tm)
|
nuclear@32
|
150 {
|
nuclear@32
|
151 printf("rendering frame (t=%ld) ... ", tm);
|
nuclear@32
|
152 fflush(stdout);
|
nuclear@32
|
153
|
nuclear@32
|
154 render_pending = true;
|
nuclear@32
|
155 glutIdleFunc(idle);
|
nuclear@32
|
156 erb_begin_frame(erb, 0);
|
nuclear@32
|
157
|
nuclear@32
|
158 start_time = steady_clock::now();
|
nuclear@32
|
159 }
|
nuclear@32
|
160
|
nuclear@32
|
161 static void end_frame()
|
nuclear@32
|
162 {
|
nuclear@32
|
163 if(!render_pending) return;
|
nuclear@32
|
164
|
nuclear@32
|
165 auto dur = steady_clock::now() - start_time;
|
nuclear@32
|
166 long full_msec = duration_cast<milliseconds>(dur).count();
|
nuclear@32
|
167 long msec, sec, min, hr, days;
|
nuclear@32
|
168
|
nuclear@32
|
169 msec = full_msec;
|
nuclear@32
|
170 printf("done in ");
|
nuclear@32
|
171 if((sec = msec / 1000) > 0) {
|
nuclear@32
|
172 msec %= 1000;
|
nuclear@32
|
173 if((min = sec / 60) > 0) {
|
nuclear@32
|
174 sec %= 60;
|
nuclear@32
|
175 if((hr = min / 60) > 0) {
|
nuclear@32
|
176 min %= 60;
|
nuclear@32
|
177 if((days = hr / 24) > 0) {
|
nuclear@32
|
178 hr %= 24;
|
nuclear@32
|
179 printf("%ld days ", days);
|
nuclear@32
|
180 }
|
nuclear@32
|
181 printf("%ld hours ", hr);
|
nuclear@32
|
182 }
|
nuclear@32
|
183 printf("%ld min ", min);
|
nuclear@32
|
184 }
|
nuclear@32
|
185 printf("%ld sec ", sec);
|
nuclear@32
|
186 }
|
nuclear@32
|
187 printf("%ld ms (%ld total msec)\n", msec, full_msec);
|
nuclear@32
|
188
|
nuclear@32
|
189 render_pending = false;
|
nuclear@32
|
190 glutIdleFunc(0);
|
nuclear@32
|
191 }
|
nuclear@32
|
192
|
nuclear@2
|
193 static void resize_rtarget(int xsz, int ysz)
|
nuclear@2
|
194 {
|
nuclear@2
|
195 static unsigned char *defpix;
|
nuclear@2
|
196
|
nuclear@32
|
197 win_width = xsz;
|
nuclear@32
|
198 win_height = ysz;
|
nuclear@32
|
199
|
nuclear@32
|
200 width = xsz / opt_imgscale;
|
nuclear@32
|
201 height = ysz / opt_imgscale;
|
nuclear@2
|
202
|
nuclear@8
|
203 if(width <= rtex_width && height <= rtex_height) {
|
nuclear@2
|
204 return;
|
nuclear@2
|
205 }
|
nuclear@8
|
206 rtex_width = next_pow2(width);
|
nuclear@8
|
207 rtex_height = next_pow2(height);
|
nuclear@2
|
208
|
nuclear@2
|
209 printf("resizing framebuffer texture: %dx%d\n", rtex_width, rtex_height);
|
nuclear@2
|
210
|
nuclear@2
|
211 if(!rtex) {
|
nuclear@2
|
212 glGenTextures(1, &rtex);
|
nuclear@2
|
213 }
|
nuclear@2
|
214
|
nuclear@2
|
215 delete [] defpix;
|
nuclear@2
|
216 defpix = new unsigned char[rtex_width * rtex_height * 4];
|
nuclear@2
|
217 unsigned char *ptr = defpix;
|
nuclear@2
|
218 for(int i=0; i<rtex_height; i++) {
|
nuclear@2
|
219 for(int j=0; j<rtex_width; j++) {
|
nuclear@2
|
220 bool chess = ((i >> 4) & 1) == ((j >> 4) & 1);
|
nuclear@2
|
221
|
nuclear@2
|
222 int val = chess ? 64 : 48;
|
nuclear@2
|
223
|
nuclear@2
|
224 *ptr++ = val;
|
nuclear@2
|
225 *ptr++ = val;
|
nuclear@2
|
226 *ptr++ = val;
|
nuclear@2
|
227 *ptr++ = 255;
|
nuclear@2
|
228 }
|
nuclear@2
|
229 }
|
nuclear@2
|
230
|
nuclear@2
|
231 glBindTexture(GL_TEXTURE_2D, rtex);
|
nuclear@2
|
232 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
nuclear@2
|
233 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
nuclear@2
|
234 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F_ARB, rtex_width, rtex_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, defpix);
|
nuclear@2
|
235 }
|
nuclear@2
|
236
|
nuclear@2
|
237 static void update_rect(int x, int y, int xsz, int ysz, float *pixels)
|
nuclear@2
|
238 {
|
nuclear@2
|
239 glBindTexture(GL_TEXTURE_2D, rtex);
|
nuclear@2
|
240 glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, xsz, ysz, GL_RGBA, GL_FLOAT, pixels);
|
nuclear@2
|
241 }
|
nuclear@2
|
242
|
nuclear@4
|
243 static void idle()
|
nuclear@4
|
244 {
|
nuclear@4
|
245 glutPostRedisplay();
|
nuclear@4
|
246 }
|
nuclear@4
|
247
|
nuclear@2
|
248 static void display()
|
nuclear@2
|
249 {
|
nuclear@32
|
250 static struct erb_render_status status;
|
nuclear@32
|
251
|
nuclear@4
|
252 if(render_pending) {
|
nuclear@8
|
253 if(erb_render(erb, 64) == 0) {
|
nuclear@32
|
254 end_frame();
|
nuclear@4
|
255 }
|
nuclear@4
|
256 update_rect(0, 0, width, height, erb_get_framebuffer(erb));
|
nuclear@32
|
257 erb_get_status(erb, &status);
|
nuclear@4
|
258 }
|
nuclear@4
|
259
|
nuclear@2
|
260 float maxu = (float)width / (float)rtex_width;
|
nuclear@2
|
261 float maxv = (float)height / (float)rtex_height;
|
nuclear@2
|
262
|
nuclear@34
|
263 glEnable(GL_TEXTURE_2D);
|
nuclear@34
|
264 glBindTexture(GL_TEXTURE_2D, rtex);
|
nuclear@34
|
265
|
nuclear@2
|
266 glBegin(GL_QUADS);
|
nuclear@32
|
267 glColor4f(1, 1, 1, 1);
|
nuclear@2
|
268 glTexCoord2f(0, maxv); glVertex2f(-1, -1);
|
nuclear@2
|
269 glTexCoord2f(maxu, maxv); glVertex2f(1, -1);
|
nuclear@2
|
270 glTexCoord2f(maxu, 0); glVertex2f(1, 1);
|
nuclear@2
|
271 glTexCoord2f(0, 0); glVertex2f(-1, 1);
|
nuclear@2
|
272 glEnd();
|
nuclear@2
|
273
|
nuclear@37
|
274 // draw the console
|
nuclear@37
|
275 con.update();
|
nuclear@37
|
276 con.draw();
|
nuclear@37
|
277
|
nuclear@32
|
278 // draw progress information etc...
|
nuclear@32
|
279 if(show_status) {
|
nuclear@32
|
280 display_statusbar(status);
|
nuclear@32
|
281 }
|
nuclear@32
|
282
|
nuclear@2
|
283 glutSwapBuffers();
|
nuclear@2
|
284 assert(glGetError() == GL_NO_ERROR);
|
nuclear@2
|
285 }
|
nuclear@2
|
286
|
nuclear@32
|
287 static void display_statusbar(const erb_render_status &status)
|
nuclear@32
|
288 {
|
nuclear@32
|
289 if(!font) return;
|
nuclear@37
|
290 dtx_use_font(font, FONTSZ);
|
nuclear@32
|
291
|
nuclear@32
|
292 bool show_progress = opt_samples > 0;
|
nuclear@32
|
293
|
nuclear@32
|
294 glDisable(GL_TEXTURE_2D);
|
nuclear@32
|
295
|
nuclear@32
|
296 glMatrixMode(GL_PROJECTION);
|
nuclear@32
|
297 glPushMatrix();
|
nuclear@32
|
298 glLoadIdentity();
|
nuclear@32
|
299 glOrtho(0, win_width, 0, win_height, -1, 1);
|
nuclear@32
|
300
|
nuclear@32
|
301 glMatrixMode(GL_MODELVIEW);
|
nuclear@32
|
302 glPushMatrix();
|
nuclear@32
|
303 glLoadIdentity();
|
nuclear@32
|
304
|
nuclear@34
|
305 dtx_box bbox;
|
nuclear@34
|
306 dtx_glyph_box('Q', &bbox);
|
nuclear@34
|
307
|
nuclear@34
|
308 // draw progress/status bar
|
nuclear@34
|
309 int bar_height = bbox.height + 4;
|
nuclear@32
|
310 int prog_width = show_progress ? status.progress_percent * win_width / 100 : 0;
|
nuclear@32
|
311
|
nuclear@32
|
312 glBegin(GL_QUADS);
|
nuclear@32
|
313 glColor4f(0, 0, 0, 1);
|
nuclear@32
|
314 glVertex2f(prog_width, 0);
|
nuclear@32
|
315 glVertex2f(win_width, 0);
|
nuclear@34
|
316 glVertex2f(win_width, bar_height);
|
nuclear@34
|
317 glVertex2f(prog_width, bar_height);
|
nuclear@32
|
318
|
nuclear@32
|
319 glColor4f(0.25, 0, 0, 1);
|
nuclear@32
|
320 glVertex2f(0, 0);
|
nuclear@32
|
321 glVertex2f(prog_width, 0);
|
nuclear@34
|
322 glVertex2f(prog_width, bar_height);
|
nuclear@34
|
323 glVertex2f(0, bar_height);
|
nuclear@32
|
324 glEnd();
|
nuclear@32
|
325
|
nuclear@34
|
326 // draw the text
|
nuclear@34
|
327 glTranslatef(bbox.x + 2, bbox.y + 2, 0);
|
nuclear@32
|
328
|
nuclear@32
|
329 glColor4f(1, 1, 1, 1);
|
nuclear@32
|
330
|
nuclear@32
|
331 if(opt_samples > 0) {
|
nuclear@34
|
332 dtx_printf("samples: %ld / %ld", status.samples, status.max_samples);
|
nuclear@32
|
333
|
nuclear@34
|
334 glLoadIdentity();
|
nuclear@34
|
335 glTranslatef(win_width - dtx_string_width("progress: 100%") - 2, bbox.y + 2, 0);
|
nuclear@34
|
336 dtx_printf("progress: %ld%%", status.progress_percent);
|
nuclear@32
|
337 } else {
|
nuclear@34
|
338 dtx_printf("samples: %ld", status.samples);
|
nuclear@32
|
339 }
|
nuclear@34
|
340
|
nuclear@34
|
341 // samples/sec display
|
nuclear@34
|
342 static long paths_per_sec, prev_msec, prev_paths;
|
nuclear@34
|
343
|
nuclear@34
|
344 long msec = duration_cast<milliseconds>(steady_clock::now() - start_time).count();
|
nuclear@34
|
345 long dt = msec - prev_msec;
|
nuclear@34
|
346
|
nuclear@34
|
347 if(dt >= 1500) { // average over 1.5 seconds
|
nuclear@34
|
348 long paths = status.samples * width * height;
|
nuclear@34
|
349 if(prev_msec > 0 && prev_paths <= paths) { // check valid interval (not a restart or whatever)
|
nuclear@34
|
350 paths_per_sec = 1000 * (paths - prev_paths) / dt;
|
nuclear@34
|
351 }
|
nuclear@34
|
352 prev_msec = msec;
|
nuclear@34
|
353 prev_paths = paths;
|
nuclear@34
|
354 }
|
nuclear@34
|
355
|
nuclear@34
|
356 glLoadIdentity();
|
nuclear@34
|
357 glTranslatef((win_width - dtx_string_width("paths/s: 999999")) / 2, bbox.y + 2, 0);
|
nuclear@34
|
358 if(paths_per_sec) {
|
nuclear@34
|
359 dtx_printf("paths/s: %ld", paths_per_sec);
|
nuclear@34
|
360 } else {
|
nuclear@34
|
361 dtx_printf("paths/s: ???");
|
nuclear@34
|
362 }
|
nuclear@34
|
363
|
nuclear@32
|
364 glPopMatrix();
|
nuclear@32
|
365 glMatrixMode(GL_PROJECTION);
|
nuclear@32
|
366 glPopMatrix();
|
nuclear@32
|
367 }
|
nuclear@32
|
368
|
nuclear@29
|
369 static void save_image(const char *fname)
|
nuclear@29
|
370 {
|
nuclear@29
|
371 float *fb = erb_get_framebuffer(erb);
|
nuclear@29
|
372
|
nuclear@29
|
373 if(img_save_pixels(fname ? fname : "output.png", fb, width, height, IMG_FMT_RGBAF) == -1) {
|
nuclear@29
|
374 fprintf(stderr, "failed to save image\n");
|
nuclear@29
|
375 }
|
nuclear@29
|
376 }
|
nuclear@29
|
377
|
nuclear@2
|
378 static void reshape(int x, int y)
|
nuclear@2
|
379 {
|
nuclear@2
|
380 glViewport(0, 0, x, y);
|
nuclear@2
|
381 resize_rtarget(x, y);
|
nuclear@4
|
382
|
nuclear@4
|
383 erb_setopti(erb, ERB_OPT_WIDTH, width);
|
nuclear@4
|
384 erb_setopti(erb, ERB_OPT_HEIGHT, height);
|
nuclear@2
|
385 }
|
nuclear@2
|
386
|
nuclear@2
|
387 static void keyb(unsigned char key, int x, int y)
|
nuclear@2
|
388 {
|
nuclear@2
|
389 switch(key) {
|
nuclear@2
|
390 case 27:
|
nuclear@37
|
391 if(con.is_visible()) {
|
nuclear@37
|
392 con.hide();
|
nuclear@37
|
393 glutPostRedisplay();
|
nuclear@37
|
394 } else {
|
nuclear@37
|
395 end_frame();
|
nuclear@37
|
396 exit(0);
|
nuclear@37
|
397 }
|
nuclear@37
|
398 break;
|
nuclear@4
|
399
|
nuclear@4
|
400 case ' ':
|
nuclear@37
|
401 if(!con.is_visible()) {
|
nuclear@37
|
402 begin_frame(0);
|
nuclear@37
|
403 } else {
|
nuclear@37
|
404 con.input_key(' ');
|
nuclear@37
|
405 glutPostRedisplay();
|
nuclear@37
|
406 }
|
nuclear@29
|
407 break;
|
nuclear@32
|
408
|
nuclear@34
|
409 case '`':
|
nuclear@37
|
410 con.set_visible(!con.is_visible());
|
nuclear@37
|
411 glutPostRedisplay();
|
nuclear@37
|
412 break;
|
nuclear@37
|
413
|
nuclear@37
|
414 case '~':
|
nuclear@32
|
415 show_status = !show_status;
|
nuclear@32
|
416 glutPostRedisplay();
|
nuclear@32
|
417 break;
|
nuclear@37
|
418
|
nuclear@37
|
419 default:
|
nuclear@37
|
420 // otherwise if the console is visible, let them through
|
nuclear@37
|
421 if(con.is_visible()) {
|
nuclear@37
|
422 con.input_key(key);
|
nuclear@37
|
423 glutPostRedisplay();
|
nuclear@37
|
424 return; // don't pass anything to the erb input handler
|
nuclear@37
|
425 }
|
nuclear@2
|
426 }
|
nuclear@9
|
427
|
nuclear@10
|
428 if(erb_input_keyboard(erb, key, true)) {
|
nuclear@9
|
429 glutPostRedisplay();
|
nuclear@9
|
430 }
|
nuclear@9
|
431 }
|
nuclear@9
|
432
|
nuclear@9
|
433 static void keyb_up(unsigned char key, int x, int y)
|
nuclear@9
|
434 {
|
nuclear@10
|
435 if(erb_input_keyboard(erb, key, false)) {
|
nuclear@9
|
436 glutPostRedisplay();
|
nuclear@9
|
437 }
|
nuclear@2
|
438 }
|
nuclear@2
|
439
|
nuclear@37
|
440 static void skeyb(int key, int x, int y)
|
nuclear@37
|
441 {
|
nuclear@37
|
442 if(key == GLUT_KEY_F12) {
|
nuclear@37
|
443 printf("saving image...\n");
|
nuclear@37
|
444 save_image();
|
nuclear@37
|
445 return;
|
nuclear@37
|
446 }
|
nuclear@37
|
447
|
nuclear@37
|
448 if(con.is_visible()) {
|
nuclear@37
|
449 switch(key) {
|
nuclear@37
|
450 case GLUT_KEY_F8:
|
nuclear@37
|
451 con.debug();
|
nuclear@37
|
452 return;
|
nuclear@37
|
453
|
nuclear@37
|
454 case GLUT_KEY_LEFT:
|
nuclear@37
|
455 con.input_key(Console::KEY_LEFT);
|
nuclear@37
|
456 break;
|
nuclear@37
|
457 case GLUT_KEY_RIGHT:
|
nuclear@37
|
458 con.input_key(Console::KEY_RIGHT);
|
nuclear@37
|
459 break;
|
nuclear@37
|
460 case GLUT_KEY_UP:
|
nuclear@37
|
461 con.input_key(Console::KEY_UP);
|
nuclear@37
|
462 break;
|
nuclear@37
|
463 case GLUT_KEY_DOWN:
|
nuclear@37
|
464 con.input_key(Console::KEY_DOWN);
|
nuclear@37
|
465 break;
|
nuclear@37
|
466 case GLUT_KEY_HOME:
|
nuclear@37
|
467 con.input_key(Console::KEY_HOME);
|
nuclear@37
|
468 break;
|
nuclear@37
|
469 case GLUT_KEY_END:
|
nuclear@37
|
470 con.input_key(Console::KEY_END);
|
nuclear@37
|
471 break;
|
nuclear@37
|
472 case GLUT_KEY_INSERT:
|
nuclear@37
|
473 con.input_key(Console::KEY_INS);
|
nuclear@37
|
474 break;
|
nuclear@37
|
475 case GLUT_KEY_PAGE_UP:
|
nuclear@37
|
476 con.input_key(Console::KEY_PGUP);
|
nuclear@37
|
477 break;
|
nuclear@37
|
478 case GLUT_KEY_PAGE_DOWN:
|
nuclear@37
|
479 con.input_key(Console::KEY_PGDOWN);
|
nuclear@37
|
480 break;
|
nuclear@37
|
481
|
nuclear@37
|
482 default:
|
nuclear@37
|
483 return;
|
nuclear@37
|
484 }
|
nuclear@37
|
485 glutPostRedisplay();
|
nuclear@37
|
486 }
|
nuclear@37
|
487 }
|
nuclear@37
|
488
|
nuclear@2
|
489 static void mouse(int bn, int st, int x, int y)
|
nuclear@2
|
490 {
|
nuclear@10
|
491 if(erb_input_mouse_button(erb, bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y)) {
|
nuclear@9
|
492 glutPostRedisplay();
|
nuclear@9
|
493 }
|
nuclear@9
|
494 }
|
nuclear@9
|
495
|
nuclear@9
|
496 static void motion(int x, int y)
|
nuclear@9
|
497 {
|
nuclear@15
|
498 if(erb_input_mouse_motion(erb, x, y)) {
|
nuclear@9
|
499 glutPostRedisplay();
|
nuclear@9
|
500 }
|
nuclear@9
|
501 }
|
nuclear@9
|
502
|
nuclear@9
|
503 static void sball_button(int bn, int state)
|
nuclear@9
|
504 {
|
nuclear@10
|
505 if(erb_input_6dof_button(erb, bn, state == GLUT_DOWN)) {
|
nuclear@9
|
506 glutPostRedisplay();
|
nuclear@9
|
507 }
|
nuclear@9
|
508 }
|
nuclear@9
|
509
|
nuclear@9
|
510 static void sball_motion(int x, int y, int z)
|
nuclear@9
|
511 {
|
nuclear@10
|
512 if(erb_input_6dof_motion(erb, x / 65536.0, y / 65536.0, z / 65536.0)) {
|
nuclear@9
|
513 glutPostRedisplay();
|
nuclear@9
|
514 }
|
nuclear@2
|
515 }
|
nuclear@2
|
516
|
nuclear@2
|
517 static int next_pow2(int x)
|
nuclear@2
|
518 {
|
nuclear@2
|
519 int res = 2;
|
nuclear@2
|
520 while(res < x) {
|
nuclear@2
|
521 res <<= 1;
|
nuclear@2
|
522 }
|
nuclear@2
|
523 return res;
|
nuclear@2
|
524 }
|
nuclear@29
|
525
|
nuclear@29
|
526 static void sighandler(int s)
|
nuclear@29
|
527 {
|
nuclear@29
|
528 exit(0);
|
nuclear@29
|
529 }
|
nuclear@32
|
530
|
nuclear@32
|
531 static bool parse_args(int argc, char **argv)
|
nuclear@32
|
532 {
|
nuclear@32
|
533 for(int i=1; i<argc; i++) {
|
nuclear@32
|
534 if(argv[i][0] == '-') {
|
nuclear@32
|
535 if(strcmp(argv[i], "-samples") == 0) {
|
nuclear@32
|
536 opt_samples = atoi(argv[++i]);
|
nuclear@32
|
537 if(opt_samples <= 0) {
|
nuclear@32
|
538 fprintf(stderr, "invalid -samples option: %s\n", argv[i]);
|
nuclear@32
|
539 return false;
|
nuclear@32
|
540 }
|
nuclear@32
|
541
|
nuclear@32
|
542 } else if(strcmp(argv[i], "-iter") == 0) {
|
nuclear@32
|
543 opt_iter = atoi(argv[++i]);
|
nuclear@32
|
544 if(opt_iter <= 0) {
|
nuclear@32
|
545 fprintf(stderr, "invalid -iter option: %s\n", argv[i]);
|
nuclear@32
|
546 return false;
|
nuclear@32
|
547 }
|
nuclear@32
|
548
|
nuclear@32
|
549 } else if(strcmp(argv[i], "-threads") == 0) {
|
nuclear@32
|
550 opt_threads = atoi(argv[++i]);
|
nuclear@32
|
551 if(opt_threads <= 0) {
|
nuclear@32
|
552 fprintf(stderr, "invalid -threads option: %s\n", argv[i]);
|
nuclear@32
|
553 return false;
|
nuclear@32
|
554 }
|
nuclear@32
|
555
|
nuclear@32
|
556 } else if(strcmp(argv[i], "-scale") == 0) {
|
nuclear@32
|
557 opt_imgscale = atof(argv[++i]);
|
nuclear@32
|
558 if(opt_imgscale <= 0.0f) {
|
nuclear@32
|
559 fprintf(stderr, "invalid -scale option: %s\n", argv[i]);
|
nuclear@32
|
560 return false;
|
nuclear@32
|
561 }
|
nuclear@32
|
562
|
nuclear@32
|
563 } else {
|
nuclear@32
|
564 fprintf(stderr, "invalid option: %s\n", argv[i]);
|
nuclear@32
|
565 return false;
|
nuclear@32
|
566 }
|
nuclear@32
|
567 } else {
|
nuclear@32
|
568 sfiles.push_back(argv[i]);
|
nuclear@32
|
569 }
|
nuclear@32
|
570 }
|
nuclear@32
|
571
|
nuclear@32
|
572 return true;
|
nuclear@34
|
573 }
|
nuclear@37
|
574
|
nuclear@37
|
575 static void con_parse(const char *line)
|
nuclear@37
|
576 {
|
nuclear@39
|
577 char *buf = (char*)alloca(strlen(line) + 1);
|
nuclear@39
|
578 strcpy(buf, line);
|
nuclear@37
|
579
|
nuclear@39
|
580 std::vector<char*> args;
|
nuclear@39
|
581 char *tok;
|
nuclear@39
|
582
|
nuclear@39
|
583 while((tok = strtok(buf, " \n\r\v\t"))) {
|
nuclear@39
|
584 buf = 0;
|
nuclear@39
|
585 args.push_back(tok);
|
nuclear@39
|
586 }
|
nuclear@39
|
587 args.push_back(0);
|
nuclear@39
|
588 int argc = args.size() - 1;
|
nuclear@39
|
589
|
nuclear@39
|
590 if(strcmp(args[0], "exit") == 0) {
|
nuclear@39
|
591 exit(0);
|
nuclear@39
|
592 } else if(strcmp(args[0], "load") == 0) {
|
nuclear@39
|
593 for(int i=1; i<argc; i++) {
|
nuclear@39
|
594 if(erb_load_scene(erb, args[i]) == -1) {
|
nuclear@39
|
595 con.printf("failed to load scene: %s\n", args[1]);
|
nuclear@39
|
596 } else {
|
nuclear@39
|
597 begin_frame(0);
|
nuclear@39
|
598 }
|
nuclear@39
|
599 }
|
nuclear@37
|
600 } else {
|
nuclear@39
|
601
|
nuclear@39
|
602 if(erb_proc_cmd(erb, line) == -1) {
|
nuclear@39
|
603 con.puts("invalid command\n");
|
nuclear@39
|
604 } else {
|
nuclear@39
|
605 begin_frame(0);
|
nuclear@39
|
606 }
|
nuclear@37
|
607 }
|
nuclear@37
|
608 }
|