erebus

annotate liberebus/src/erebus.cc @ 15:20d6c05529f1

debugging the sphere problem
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 25 May 2014 02:00:07 +0300
parents 506e114b7ca2
children e9da2916bc79
rev   line source
nuclear@2 1 #include <string.h>
nuclear@2 2 #include <limits.h>
nuclear@2 3 #include <chrono>
nuclear@2 4 #include <random>
nuclear@2 5 #include "erebus.h"
nuclear@2 6 #include "vmath/vector.h"
nuclear@2 7 #include "image.h"
nuclear@4 8 #include "scene.h"
nuclear@4 9 #include "geomobj.h"
nuclear@5 10 #include "rt.h"
nuclear@2 11
nuclear@8 12 #define INF_SAMPLES (INT_MAX / 2)
nuclear@8 13
nuclear@2 14 using namespace std::chrono;
nuclear@2 15
nuclear@2 16 struct Rect {
nuclear@2 17 int x, y, width, height;
nuclear@2 18
nuclear@2 19 bool operator ==(const Rect &r) { return memcmp(this, &r, sizeof r) == 0; }
nuclear@2 20 bool operator !=(const Rect &r) { return memcmp(this, &r, sizeof r) != 0; }
nuclear@2 21 };
nuclear@2 22
nuclear@2 23 #define INVALID_RECT Rect{0, 0, 0, 0}
nuclear@2 24
nuclear@2 25 struct erebus {
nuclear@4 26 Scene *scn;
nuclear@4 27
nuclear@2 28 Image<float> fbimg;
nuclear@8 29 Image<float> accum; // sample accumulator per pixel
nuclear@2 30 Vector4 options[ERB_NUM_OPTIONS];
nuclear@2 31
nuclear@2 32 // render state
nuclear@2 33 long cur_time;
nuclear@2 34 int cur_pixel_x, cur_pixel_y;
nuclear@2 35 Rect cur_rect;
nuclear@8 36 int cur_sample;
nuclear@9 37
nuclear@9 38 // interactive input
nuclear@9 39 std::vector<bool> keystate;
nuclear@9 40 std::vector<bool> bnstate;
nuclear@9 41 int mouse_pos[2];
nuclear@15 42
nuclear@15 43 // debugging stuff
nuclear@15 44 int dbg_nodesel;
nuclear@2 45 };
nuclear@2 46
nuclear@8 47 static void render_pixel(struct erebus *ctx, int x, int y, int sample);
nuclear@2 48
nuclear@2 49 static std::mt19937 rnd_gen;
nuclear@2 50
nuclear@2 51 extern "C" {
nuclear@2 52
nuclear@2 53 struct erebus *erb_init(void)
nuclear@2 54 {
nuclear@2 55 struct erebus *ctx;
nuclear@2 56 try {
nuclear@2 57 ctx = new struct erebus;
nuclear@2 58 }
nuclear@2 59 catch(...) {
nuclear@2 60 return 0;
nuclear@2 61 }
nuclear@2 62
nuclear@10 63 rnd_gen.seed(time(0));
nuclear@10 64
nuclear@4 65 ctx->scn = 0;
nuclear@2 66 ctx->cur_time = 0;
nuclear@2 67 ctx->cur_rect = INVALID_RECT;
nuclear@8 68
nuclear@8 69 ctx->options[ERB_OPT_MAX_SAMPLES].x = (float)INF_SAMPLES;
nuclear@15 70
nuclear@15 71 ctx->dbg_nodesel = -1;
nuclear@2 72 return ctx;
nuclear@2 73 }
nuclear@2 74
nuclear@2 75 void erb_destroy(struct erebus *ctx)
nuclear@2 76 {
nuclear@2 77 delete ctx;
nuclear@2 78 }
nuclear@2 79
nuclear@2 80 void erb_setopti(struct erebus *ctx, enum erb_option opt, int val)
nuclear@2 81 {
nuclear@2 82 ctx->options[opt].x = val;
nuclear@2 83 }
nuclear@2 84 void erb_setoptf(struct erebus *ctx, enum erb_option opt, float val)
nuclear@2 85 {
nuclear@2 86 ctx->options[opt].x = val;
nuclear@2 87 }
nuclear@2 88 void erb_setoptfv(struct erebus *ctx, enum erb_option opt, float *vec)
nuclear@2 89 {
nuclear@2 90 for(int i=0; i<4; i++) {
nuclear@2 91 ctx->options[opt][i] = vec[i];
nuclear@2 92 }
nuclear@2 93 }
nuclear@2 94
nuclear@2 95 int erb_getopti(struct erebus *ctx, enum erb_option opt)
nuclear@2 96 {
nuclear@2 97 return ctx->options[opt].x;
nuclear@2 98 }
nuclear@2 99 float erb_getoptf(struct erebus *ctx, enum erb_option opt)
nuclear@2 100 {
nuclear@2 101 return ctx->options[opt].x;
nuclear@2 102 }
nuclear@2 103 float *erb_getoptfv(struct erebus *ctx, enum erb_option opt)
nuclear@2 104 {
nuclear@2 105 return &ctx->options[opt].x;
nuclear@2 106 }
nuclear@2 107
nuclear@2 108 float *erb_get_framebuffer(struct erebus *ctx)
nuclear@2 109 {
nuclear@2 110 return ctx->fbimg.get_pixels();
nuclear@2 111 }
nuclear@2 112
nuclear@2 113 void erb_begin_frame(struct erebus *ctx, long ms)
nuclear@2 114 {
nuclear@8 115 printf("starting new frame...\n");
nuclear@2 116 ctx->cur_time = ms;
nuclear@4 117
nuclear@4 118 int xsz = ctx->options[ERB_OPT_WIDTH].x;
nuclear@4 119 int ysz = ctx->options[ERB_OPT_HEIGHT].x;
nuclear@4 120
nuclear@4 121 ctx->fbimg.create(xsz, ysz);
nuclear@8 122 ctx->accum.create(xsz, ysz);
nuclear@15 123
nuclear@15 124 ctx->cur_rect = INVALID_RECT;
nuclear@2 125 }
nuclear@2 126
nuclear@2 127 int erb_render(struct erebus *ctx, long timeout)
nuclear@2 128 {
nuclear@2 129 return erb_render_rect(ctx, 0, 0, ctx->fbimg.get_width(), ctx->fbimg.get_height(), timeout);
nuclear@2 130 }
nuclear@2 131
nuclear@2 132 int erb_render_rect(struct erebus *ctx, int x, int y, int width, int height, long timeout)
nuclear@2 133 {
nuclear@2 134 if(!width || !height) return -1;
nuclear@2 135
nuclear@2 136 Rect rect{x, y, width, height};
nuclear@2 137 if(ctx->cur_rect != rect) {
nuclear@8 138 // starting a new rendering apparently
nuclear@2 139 ctx->cur_rect = rect;
nuclear@2 140 ctx->cur_pixel_x = x;
nuclear@2 141 ctx->cur_pixel_y = y;
nuclear@8 142 ctx->cur_sample = 0;
nuclear@2 143 }
nuclear@2 144
nuclear@4 145 ctx->scn->update();
nuclear@4 146
nuclear@8 147 int max_samples = ctx->options[ERB_OPT_MAX_SAMPLES].x;
nuclear@8 148
nuclear@2 149 if(timeout > 0) {
nuclear@2 150 auto start_time = steady_clock::now();
nuclear@2 151 while(duration_cast<milliseconds>(steady_clock::now() - start_time).count() < timeout) {
nuclear@8 152 render_pixel(ctx, ctx->cur_pixel_x, ctx->cur_pixel_y, ctx->cur_sample);
nuclear@2 153
nuclear@2 154 if(++ctx->cur_pixel_x >= ctx->cur_rect.width) {
nuclear@8 155 ctx->cur_pixel_x = ctx->cur_rect.x;
nuclear@2 156 if(++ctx->cur_pixel_y >= ctx->cur_rect.height) {
nuclear@8 157 ctx->cur_pixel_y = ctx->cur_rect.y;
nuclear@8 158 if(++ctx->cur_sample >= max_samples) {
nuclear@8 159 ctx->cur_rect = INVALID_RECT;
nuclear@8 160 return 0;
nuclear@8 161 }
nuclear@2 162 }
nuclear@2 163 }
nuclear@2 164 }
nuclear@2 165 return 1;
nuclear@2 166 }
nuclear@2 167
nuclear@8 168 if(ctx->options[ERB_OPT_MAX_SAMPLES].x == (float)INF_SAMPLES) {
nuclear@8 169 max_samples = 128;
nuclear@8 170 }
nuclear@8 171
nuclear@2 172 for(int i=0; i<height; i++) {
nuclear@2 173 for(int j=0; j<width; j++) {
nuclear@8 174 for(int k=0; k<max_samples; k++) {
nuclear@8 175 render_pixel(ctx, j, i, k);
nuclear@8 176 }
nuclear@2 177 }
nuclear@2 178 }
nuclear@2 179 return 0;
nuclear@2 180 }
nuclear@2 181
nuclear@2 182 int erb_get_progress(struct erebus *ctx)
nuclear@2 183 {
nuclear@2 184 return 0; // TODO
nuclear@2 185 }
nuclear@2 186
nuclear@2 187 int erb_load_scene(struct erebus *ctx, const char *fname)
nuclear@2 188 {
nuclear@4 189 delete ctx->scn;
nuclear@4 190 ctx->scn = new Scene;
nuclear@2 191
nuclear@4 192 // XXX for now just create a test scene here
nuclear@4 193 Sphere *sph = new Sphere;
nuclear@8 194 sph->mtl.set_attrib("albedo", Color(1.0, 0.3, 0.2));
nuclear@4 195 SceneNode *sph_node = new SceneNode(sph);
nuclear@4 196 ctx->scn->add_object(sph);
nuclear@4 197 ctx->scn->add_node(sph_node);
nuclear@4 198
nuclear@8 199 sph = new Sphere;
nuclear@8 200 sph->mtl.set_attrib("albedo", Color(0.3, 0.4, 1.0));
nuclear@8 201 sph_node = new SceneNode(sph);
nuclear@8 202 sph_node->set_position(Vector3(0, -3.0, 0));
nuclear@8 203 //sph_node->set_scaling(Vector3(4.0, 4.0, 4.0) * 0.3);
nuclear@8 204 ctx->scn->add_object(sph);
nuclear@8 205 ctx->scn->add_node(sph_node);
nuclear@8 206
nuclear@8 207 Sphere *lt = new Sphere;
nuclear@8 208 lt->mtl.set_attrib("emissive", Color(10, 10, 10));
nuclear@8 209 SceneNode *lt_node = new SceneNode(lt);
nuclear@8 210 lt_node->set_position(Vector3(-15, 15, -10));
nuclear@8 211 lt_node->set_scaling(Vector3(5, 5, 5));
nuclear@8 212 ctx->scn->add_object(lt);
nuclear@8 213 ctx->scn->add_node(lt_node);
nuclear@8 214
nuclear@8 215 TargetCamera *cam = new TargetCamera(Vector3(0, 4, -8), Vector3(0, 0, 0));
nuclear@4 216 //ctx->scn->add_object(cam);
nuclear@4 217 ctx->scn->use_camera(cam);
nuclear@4 218
nuclear@4 219 return 0;
nuclear@2 220 }
nuclear@2 221
nuclear@9 222 bool erb_input_keyboard(struct erebus *ctx, int key, bool pressed)
nuclear@9 223 {
nuclear@9 224 if(!ctx) return false;
nuclear@15 225 if((int)ctx->keystate.size() <= key) {
nuclear@15 226 ctx->keystate.resize(key < 256 ? 256 : key + 1);
nuclear@15 227 }
nuclear@9 228
nuclear@9 229 ctx->keystate[key] = pressed;
nuclear@10 230
nuclear@10 231 if(pressed) {
nuclear@10 232 switch(key) {
nuclear@15 233 case '.':
nuclear@15 234 {
nuclear@15 235 int node_count = ctx->scn->get_node_count();
nuclear@15 236 if(node_count && ++ctx->dbg_nodesel >= node_count) {
nuclear@15 237 ctx->dbg_nodesel = 0;
nuclear@15 238 }
nuclear@15 239 printf("selected node: %d\n", ctx->dbg_nodesel);
nuclear@15 240 }
nuclear@15 241 break;
nuclear@15 242
nuclear@15 243 case ',':
nuclear@15 244 {
nuclear@15 245 int node_count = ctx->scn->get_node_count();
nuclear@15 246 if(node_count && --ctx->dbg_nodesel < 0) {
nuclear@15 247 ctx->dbg_nodesel = node_count - 1;
nuclear@15 248 }
nuclear@15 249 printf("selected node: %d\n", ctx->dbg_nodesel);
nuclear@15 250 }
nuclear@15 251 break;
nuclear@15 252
nuclear@10 253 case '=':
nuclear@10 254 case '-':
nuclear@15 255 case '0':
nuclear@15 256 if(ctx->dbg_nodesel != -1) {
nuclear@15 257 SceneNode *node = ctx->scn->get_node(ctx->dbg_nodesel);
nuclear@15 258 Vector3 s = node->get_scaling();
nuclear@15 259 switch(key) {
nuclear@15 260 case '=':
nuclear@15 261 node->set_scaling(s * 1.1);
nuclear@15 262 break;
nuclear@15 263 case '-':
nuclear@15 264 node->set_scaling(s * 0.9);
nuclear@15 265 break;
nuclear@15 266 case '0':
nuclear@15 267 node->set_scaling(Vector3(1, 1, 1));
nuclear@15 268 break;
nuclear@15 269 }
nuclear@15 270 }
nuclear@15 271 erb_begin_frame(ctx, 0);
nuclear@15 272 return true;
nuclear@10 273 }
nuclear@10 274 }
nuclear@9 275 return false;
nuclear@9 276 }
nuclear@9 277
nuclear@9 278 bool erb_input_mouse_button(struct erebus *ctx, int bn, bool pressed, int x, int y)
nuclear@9 279 {
nuclear@9 280 if(!ctx) return false;
nuclear@15 281 if((int)ctx->bnstate.size() <= bn) {
nuclear@15 282 ctx->bnstate.resize(bn < 32 ? 32 : bn + 1);
nuclear@15 283 }
nuclear@9 284
nuclear@9 285 ctx->bnstate[bn] = pressed;
nuclear@9 286 ctx->mouse_pos[0] = x;
nuclear@9 287 ctx->mouse_pos[1] = y;
nuclear@10 288 return false;
nuclear@9 289 }
nuclear@9 290
nuclear@10 291 bool erb_input_mouse_motion(struct erebus *ctx, int x, int y)
nuclear@10 292 {
nuclear@10 293 if(!ctx) return false;
nuclear@10 294
nuclear@10 295 ctx->mouse_pos[0] = x;
nuclear@10 296 ctx->mouse_pos[1] = y;
nuclear@10 297 return false;
nuclear@10 298 }
nuclear@10 299
nuclear@10 300 bool erb_input_6dof_button(struct erebus *ctx, int bn, bool pressed)
nuclear@10 301 {
nuclear@10 302 if(!ctx) return false;
nuclear@10 303 return false;
nuclear@10 304 }
nuclear@10 305
nuclear@10 306 bool erb_input_6dof_motion(struct erebus *ctx, float x, float y, float z)
nuclear@10 307 {
nuclear@10 308 if(!ctx) return false;
nuclear@10 309 return false;
nuclear@10 310 }
nuclear@9 311
nuclear@9 312
nuclear@2 313 } // extern "C"
nuclear@2 314
nuclear@2 315 float randf(float low, float high)
nuclear@2 316 {
nuclear@2 317 std::uniform_real_distribution<float> unirnd(low, high);
nuclear@2 318 return unirnd(rnd_gen);
nuclear@2 319 }
nuclear@2 320
nuclear@8 321 static void render_pixel(struct erebus *ctx, int x, int y, int sample)
nuclear@2 322 {
nuclear@5 323 Camera *cam = ctx->scn->get_active_camera();
nuclear@5 324 if(!cam) return;
nuclear@5 325
nuclear@5 326 int xsz = ctx->fbimg.get_width();
nuclear@5 327 int ysz = ctx->fbimg.get_height();
nuclear@8 328 int offs = (y * xsz + x) * 4;
nuclear@5 329
nuclear@8 330 float *pix = ctx->fbimg.get_pixels() + offs;
nuclear@8 331 float *accum = ctx->accum.get_pixels() + offs;
nuclear@8 332
nuclear@8 333 Ray ray = cam->get_primary_ray(x, y, xsz, ysz, sample);
nuclear@8 334 Color c = ray_trace(ray, ctx->scn, 0);
nuclear@8 335 accum[0] += c.x;
nuclear@8 336 accum[1] += c.y;
nuclear@8 337 accum[2] += c.z;
nuclear@8 338 accum[3] += c.w;
nuclear@8 339
nuclear@8 340 float inv_samples = 1.0f / (float)(sample + 1);
nuclear@8 341 pix[0] = accum[0] * inv_samples;
nuclear@8 342 pix[1] = accum[1] * inv_samples;
nuclear@8 343 pix[2] = accum[2] * inv_samples;
nuclear@8 344 pix[3] = accum[3] * inv_samples;
nuclear@2 345 }