erebus

annotate src/main.cc @ 40:9d6368850fe1

minor enhancements and bugfixes to the console stuff
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 10 Jun 2014 10:53:19 +0300
parents fd45cf0fc912
children 2e817711d0f6
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@40 577 int len = strlen(line);
nuclear@40 578 if(!len) return;
nuclear@40 579
nuclear@40 580 char *buf = (char*)alloca(len + 1);
nuclear@40 581 memcpy(buf, line, len + 1);
nuclear@37 582
nuclear@39 583 std::vector<char*> args;
nuclear@39 584 char *tok;
nuclear@39 585
nuclear@39 586 while((tok = strtok(buf, " \n\r\v\t"))) {
nuclear@39 587 buf = 0;
nuclear@39 588 args.push_back(tok);
nuclear@39 589 }
nuclear@39 590 args.push_back(0);
nuclear@39 591 int argc = args.size() - 1;
nuclear@39 592
nuclear@40 593 if(!args[0]) return;
nuclear@40 594
nuclear@40 595 if(strcmp(args[0], "exit") == 0 || strcmp(args[0], "quit") == 0) {
nuclear@39 596 exit(0);
nuclear@40 597
nuclear@40 598 } else if(strcmp(args[0], "clear") == 0) {
nuclear@40 599 erb_clear(erb);
nuclear@40 600
nuclear@40 601 } else if(strcmp(args[0], "stop") == 0) {
nuclear@40 602 erb_end_frame(erb);
nuclear@40 603
nuclear@40 604 } else if(strcmp(args[0], "render") == 0) {
nuclear@40 605 long tm = 0;
nuclear@40 606 if(args[1]) {
nuclear@40 607 char *endp;
nuclear@40 608 tm = strtol(args[1], &endp, 10);
nuclear@40 609 if(endp == args[1]) {
nuclear@40 610 con.printf("the argument to render must be a time value in milliseconds\n");
nuclear@40 611 return;
nuclear@40 612 }
nuclear@40 613 }
nuclear@40 614 begin_frame(tm);
nuclear@40 615
nuclear@39 616 } else if(strcmp(args[0], "load") == 0) {
nuclear@39 617 for(int i=1; i<argc; i++) {
nuclear@39 618 if(erb_load_scene(erb, args[i]) == -1) {
nuclear@39 619 con.printf("failed to load scene: %s\n", args[1]);
nuclear@39 620 } else {
nuclear@39 621 begin_frame(0);
nuclear@39 622 }
nuclear@39 623 }
nuclear@39 624
nuclear@40 625 } else if(strcmp(args[0], "add") == 0) {
nuclear@40 626 if(erb_proc_cmd(erb, line + 4) == -1) {
nuclear@40 627 con.puts("invalid add command\n");
nuclear@39 628 } else {
nuclear@39 629 begin_frame(0);
nuclear@39 630 }
nuclear@40 631
nuclear@40 632 } else {
nuclear@40 633 con.printf("unrecognized command: %s\n", args[0]);
nuclear@37 634 }
nuclear@37 635 }