erebus
diff src/main.cc @ 32:b1fc96c71bcc
- lambert BRDF importance sampling
- UI + commandline arguments
- font rendering for showing status/progress
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 07 Jun 2014 13:36:36 +0300 |
parents | fb20e3855740 |
children | d15ee526daa6 |
line diff
1.1 --- a/src/main.cc Sat Jun 07 09:14:17 2014 +0300 1.2 +++ b/src/main.cc Sat Jun 07 13:36:36 2014 +0300 1.3 @@ -5,19 +5,21 @@ 1.4 #include <vector> 1.5 #include <chrono> 1.6 #include <imago2.h> 1.7 +#include <drawtext.h> 1.8 #include "opengl.h" 1.9 #include "erebus.h" 1.10 1.11 using namespace std::chrono; 1.12 1.13 -#define SCALE 2 1.14 - 1.15 static bool init(); 1.16 static void cleanup(); 1.17 +static void begin_frame(long tm); 1.18 +static void end_frame(); 1.19 static void resize_rtarget(int xsz, int ysz); 1.20 static void update_rect(int x, int y, int xsz, int ysz, float *pixels); 1.21 static void idle(); 1.22 static void display(); 1.23 +static void display_statusbar(const erb_render_status &status); 1.24 static void save_image(const char *fname = 0); 1.25 static void reshape(int x, int y); 1.26 static void keyb(unsigned char key, int x, int y); 1.27 @@ -28,22 +30,32 @@ 1.28 static void sball_motion(int x, int y, int z); 1.29 static int next_pow2(int x); 1.30 static void sighandler(int s); 1.31 +static bool parse_args(int argc, char **argv); 1.32 1.33 -static int width, height, rtex_width, rtex_height; 1.34 +static int win_width, win_height, width, height, rtex_width, rtex_height; 1.35 static unsigned int rtex; 1.36 1.37 +static int opt_samples = -1; 1.38 +static int opt_iter = -1; 1.39 +static int opt_threads = -1; 1.40 +static float opt_imgscale = 2.0f; 1.41 + 1.42 static erebus *erb; 1.43 static bool render_pending; 1.44 +static bool show_status = true; 1.45 +static steady_clock::time_point start_time; 1.46 1.47 static std::vector<char*> sfiles; 1.48 1.49 +static dtx_font *font; 1.50 + 1.51 int main(int argc, char **argv) 1.52 { 1.53 glutInitWindowSize(1024, 600); 1.54 glutInit(&argc, argv); 1.55 1.56 - for(int i=1; i<argc; i++) { 1.57 - sfiles.push_back(argv[i]); 1.58 + if(!parse_args(argc, argv)) { 1.59 + return 1; 1.60 } 1.61 1.62 glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); 1.63 @@ -73,8 +85,13 @@ 1.64 1.65 static bool init() 1.66 { 1.67 - width = glutGet(GLUT_WINDOW_WIDTH) / SCALE; 1.68 - height = glutGet(GLUT_WINDOW_HEIGHT) / SCALE; 1.69 + width = glutGet(GLUT_WINDOW_WIDTH) / opt_imgscale; 1.70 + height = glutGet(GLUT_WINDOW_HEIGHT) / opt_imgscale; 1.71 + 1.72 + if(!(font = dtx_open_font_glyphmap("data/serif.glyphmap"))) { 1.73 + fprintf(stderr, "warning: failed to load font!\n"); 1.74 + } 1.75 + dtx_use_font(font, 24); 1.76 1.77 if(!(erb = erb_init())) { 1.78 return false; 1.79 @@ -82,6 +99,16 @@ 1.80 erb_setopti(erb, ERB_OPT_WIDTH, width); 1.81 erb_setopti(erb, ERB_OPT_HEIGHT, height); 1.82 1.83 + if(opt_samples != -1) { 1.84 + erb_setopti(erb, ERB_OPT_MAX_SAMPLES, opt_samples); 1.85 + } 1.86 + if(opt_iter != -1) { 1.87 + erb_setopti(erb, ERB_OPT_MAX_ITER, opt_iter); 1.88 + } 1.89 + if(opt_threads != -1) { 1.90 + erb_setopti(erb, ERB_OPT_NUM_THREADS, opt_threads); 1.91 + } 1.92 + 1.93 for(size_t i=0; i<sfiles.size(); i++) { 1.94 printf("loading scene file: %s\n", sfiles[i]); 1.95 if(erb_load_scene(erb, sfiles[i]) == -1) { 1.96 @@ -90,10 +117,7 @@ 1.97 } 1.98 1.99 if(!sfiles.empty()) { 1.100 - printf("begin rendering\n"); 1.101 - render_pending = true; 1.102 - glutIdleFunc(idle); 1.103 - erb_begin_frame(erb, 0); 1.104 + begin_frame(0); 1.105 } 1.106 1.107 glEnable(GL_TEXTURE_2D); 1.108 @@ -106,12 +130,59 @@ 1.109 erb_destroy(erb); 1.110 } 1.111 1.112 +static void begin_frame(long tm) 1.113 +{ 1.114 + printf("rendering frame (t=%ld) ... ", tm); 1.115 + fflush(stdout); 1.116 + 1.117 + render_pending = true; 1.118 + glutIdleFunc(idle); 1.119 + erb_begin_frame(erb, 0); 1.120 + 1.121 + start_time = steady_clock::now(); 1.122 +} 1.123 + 1.124 +static void end_frame() 1.125 +{ 1.126 + if(!render_pending) return; 1.127 + 1.128 + auto dur = steady_clock::now() - start_time; 1.129 + long full_msec = duration_cast<milliseconds>(dur).count(); 1.130 + long msec, sec, min, hr, days; 1.131 + 1.132 + msec = full_msec; 1.133 + printf("done in "); 1.134 + if((sec = msec / 1000) > 0) { 1.135 + msec %= 1000; 1.136 + if((min = sec / 60) > 0) { 1.137 + sec %= 60; 1.138 + if((hr = min / 60) > 0) { 1.139 + min %= 60; 1.140 + if((days = hr / 24) > 0) { 1.141 + hr %= 24; 1.142 + printf("%ld days ", days); 1.143 + } 1.144 + printf("%ld hours ", hr); 1.145 + } 1.146 + printf("%ld min ", min); 1.147 + } 1.148 + printf("%ld sec ", sec); 1.149 + } 1.150 + printf("%ld ms (%ld total msec)\n", msec, full_msec); 1.151 + 1.152 + render_pending = false; 1.153 + glutIdleFunc(0); 1.154 +} 1.155 + 1.156 static void resize_rtarget(int xsz, int ysz) 1.157 { 1.158 static unsigned char *defpix; 1.159 1.160 - width = xsz / SCALE; 1.161 - height = ysz / SCALE; 1.162 + win_width = xsz; 1.163 + win_height = ysz; 1.164 + 1.165 + width = xsz / opt_imgscale; 1.166 + height = ysz / opt_imgscale; 1.167 1.168 if(width <= rtex_width && height <= rtex_height) { 1.169 return; 1.170 @@ -160,28 +231,90 @@ 1.171 1.172 static void display() 1.173 { 1.174 + static struct erb_render_status status; 1.175 + 1.176 if(render_pending) { 1.177 if(erb_render(erb, 64) == 0) { 1.178 - render_pending = false; 1.179 - glutIdleFunc(0); 1.180 + end_frame(); 1.181 } 1.182 update_rect(0, 0, width, height, erb_get_framebuffer(erb)); 1.183 + erb_get_status(erb, &status); 1.184 } 1.185 1.186 float maxu = (float)width / (float)rtex_width; 1.187 float maxv = (float)height / (float)rtex_height; 1.188 1.189 glBegin(GL_QUADS); 1.190 + glColor4f(1, 1, 1, 1); 1.191 glTexCoord2f(0, maxv); glVertex2f(-1, -1); 1.192 glTexCoord2f(maxu, maxv); glVertex2f(1, -1); 1.193 glTexCoord2f(maxu, 0); glVertex2f(1, 1); 1.194 glTexCoord2f(0, 0); glVertex2f(-1, 1); 1.195 glEnd(); 1.196 1.197 + // draw progress information etc... 1.198 + if(show_status) { 1.199 + display_statusbar(status); 1.200 + } 1.201 + 1.202 glutSwapBuffers(); 1.203 assert(glGetError() == GL_NO_ERROR); 1.204 } 1.205 1.206 +static void display_statusbar(const erb_render_status &status) 1.207 +{ 1.208 + if(!font) return; 1.209 + 1.210 + bool show_progress = opt_samples > 0; 1.211 + 1.212 + glPushAttrib(GL_ENABLE_BIT); 1.213 + glDisable(GL_TEXTURE_2D); 1.214 + 1.215 + glMatrixMode(GL_PROJECTION); 1.216 + glPushMatrix(); 1.217 + glLoadIdentity(); 1.218 + glOrtho(0, win_width, 0, win_height, -1, 1); 1.219 + 1.220 + glMatrixMode(GL_MODELVIEW); 1.221 + glPushMatrix(); 1.222 + glLoadIdentity(); 1.223 + 1.224 + int font_height = dtx_glyph_height('Q'); 1.225 + int prog_width = show_progress ? status.progress_percent * win_width / 100 : 0; 1.226 + 1.227 + glBegin(GL_QUADS); 1.228 + glColor4f(0, 0, 0, 1); 1.229 + glVertex2f(prog_width, 0); 1.230 + glVertex2f(win_width, 0); 1.231 + glVertex2f(win_width, font_height); 1.232 + glVertex2f(prog_width, font_height); 1.233 + 1.234 + glColor4f(0.25, 0, 0, 1); 1.235 + glVertex2f(0, 0); 1.236 + glVertex2f(prog_width, 0); 1.237 + glVertex2f(prog_width, font_height); 1.238 + glVertex2f(0, font_height); 1.239 + glEnd(); 1.240 + 1.241 + glTranslatef(5, 5, 0); 1.242 + 1.243 + glColor4f(1, 1, 1, 1); 1.244 + 1.245 + if(opt_samples > 0) { 1.246 + dtx_printf("samples: %d / %d\n", status.samples, status.max_samples); 1.247 + 1.248 + glTranslatef(win_width - dtx_string_width("progress: 100%") - 5, 0, 0); 1.249 + dtx_printf("progress: %d%%\n", status.progress_percent); 1.250 + } else { 1.251 + dtx_printf("samples: %d\n", status.samples); 1.252 + } 1.253 + glPopMatrix(); 1.254 + glMatrixMode(GL_PROJECTION); 1.255 + glPopMatrix(); 1.256 + 1.257 + glPopAttrib(); 1.258 +} 1.259 + 1.260 static void save_image(const char *fname) 1.261 { 1.262 float *fb = erb_get_framebuffer(erb); 1.263 @@ -204,19 +337,22 @@ 1.264 { 1.265 switch(key) { 1.266 case 27: 1.267 + end_frame(); 1.268 exit(0); 1.269 1.270 case ' ': 1.271 - printf("begin rendering\n"); 1.272 - render_pending = true; 1.273 - glutIdleFunc(idle); 1.274 - erb_begin_frame(erb, 0); 1.275 + begin_frame(0); 1.276 break; 1.277 1.278 case '`': 1.279 printf("saving image.\n"); 1.280 save_image(); 1.281 break; 1.282 + 1.283 + case 'p': 1.284 + show_status = !show_status; 1.285 + glutPostRedisplay(); 1.286 + break; 1.287 } 1.288 1.289 if(erb_input_keyboard(erb, key, true)) { 1.290 @@ -272,3 +408,47 @@ 1.291 { 1.292 exit(0); 1.293 } 1.294 + 1.295 +static bool parse_args(int argc, char **argv) 1.296 +{ 1.297 + for(int i=1; i<argc; i++) { 1.298 + if(argv[i][0] == '-') { 1.299 + if(strcmp(argv[i], "-samples") == 0) { 1.300 + opt_samples = atoi(argv[++i]); 1.301 + if(opt_samples <= 0) { 1.302 + fprintf(stderr, "invalid -samples option: %s\n", argv[i]); 1.303 + return false; 1.304 + } 1.305 + 1.306 + } else if(strcmp(argv[i], "-iter") == 0) { 1.307 + opt_iter = atoi(argv[++i]); 1.308 + if(opt_iter <= 0) { 1.309 + fprintf(stderr, "invalid -iter option: %s\n", argv[i]); 1.310 + return false; 1.311 + } 1.312 + 1.313 + } else if(strcmp(argv[i], "-threads") == 0) { 1.314 + opt_threads = atoi(argv[++i]); 1.315 + if(opt_threads <= 0) { 1.316 + fprintf(stderr, "invalid -threads option: %s\n", argv[i]); 1.317 + return false; 1.318 + } 1.319 + 1.320 + } else if(strcmp(argv[i], "-scale") == 0) { 1.321 + opt_imgscale = atof(argv[++i]); 1.322 + if(opt_imgscale <= 0.0f) { 1.323 + fprintf(stderr, "invalid -scale option: %s\n", argv[i]); 1.324 + return false; 1.325 + } 1.326 + 1.327 + } else { 1.328 + fprintf(stderr, "invalid option: %s\n", argv[i]); 1.329 + return false; 1.330 + } 1.331 + } else { 1.332 + sfiles.push_back(argv[i]); 1.333 + } 1.334 + } 1.335 + 1.336 + return true; 1.337 +} 1.338 \ No newline at end of file