erebus
view liberebus/src/erebus.cc @ 30:e78f68d03ae9
another missing <algorithm> include broke windows build
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Sat, 07 Jun 2014 06:10:21 +0300 |
parents | c8a6fb04fefa |
children | 53a98c148bf8 |
line source
1 #include <string.h>
2 #include <limits.h>
3 #include <algorithm>
4 #include <chrono>
5 #include <random>
6 #include "erebus.h"
7 #include "erebus_impl.h"
8 #include "scene.h"
9 #include "geomobj.h"
10 #include "rt.h"
12 #define INF_SAMPLES (INT_MAX / 2)
14 using namespace std::chrono;
16 static void render_block(struct erebus *ctx, Block blk);
17 static void render_pixel(struct erebus *ctx, int x, int y, int sample);
19 static std::mt19937 rnd_gen;
21 extern "C" {
23 struct erebus *erb_init(void)
24 {
25 struct erebus *ctx;
26 try {
27 ctx = new struct erebus;
28 }
29 catch(...) {
30 return 0;
31 }
33 rnd_gen.seed(time(0));
35 ctx->scn = 0;
36 ctx->cur_time = 0;
37 ctx->cur_frame = 0;
39 erb_setoptf(ctx, ERB_OPT_GAMMA, 2.2);
40 erb_setopti(ctx, ERB_OPT_MAX_ITER, 6);
41 erb_setopti(ctx, ERB_OPT_MAX_SAMPLES, INF_SAMPLES);
42 erb_setopti(ctx, ERB_OPT_NUM_THREADS, -1);
44 ctx->dbg_nodesel = -1;
45 return ctx;
46 }
48 void erb_destroy(struct erebus *ctx)
49 {
50 delete ctx;
51 }
53 void erb_setopti(struct erebus *ctx, enum erb_option opt, int val)
54 {
55 ctx->options[opt].ival = val;
56 ctx->options[opt].type = Option::Type::INT;
57 }
59 void erb_setoptf(struct erebus *ctx, enum erb_option opt, float val)
60 {
61 ctx->options[opt].fval = val;
62 ctx->options[opt].type = Option::Type::FLOAT;
63 }
65 void erb_setoptfv(struct erebus *ctx, enum erb_option opt, float *vec)
66 {
67 for(int i=0; i<4; i++) {
68 ctx->options[opt].vval[i] = vec[i];
69 }
70 ctx->options[opt].type = Option::Type::VEC;
71 }
73 int erb_getopti(struct erebus *ctx, enum erb_option opt)
74 {
75 switch(ctx->options[opt].type) {
76 case Option::Type::INT:
77 return ctx->options[opt].ival;
78 case Option::Type::FLOAT:
79 return (int)ctx->options[opt].fval;
80 case Option::Type::VEC:
81 return (int)ctx->options[opt].vval.x;
82 }
83 return 0; // can't happen
84 }
86 float erb_getoptf(struct erebus *ctx, enum erb_option opt)
87 {
88 switch(ctx->options[opt].type) {
89 case Option::Type::INT:
90 return (float)ctx->options[opt].ival;
91 case Option::Type::FLOAT:
92 return ctx->options[opt].fval;
93 case Option::Type::VEC:
94 return ctx->options[opt].vval.x;
95 }
96 return 0.0f; // can't happen
97 }
99 float *erb_getoptfv(struct erebus *ctx, enum erb_option opt)
100 {
101 switch(ctx->options[opt].type) {
102 case Option::Type::INT:
103 {
104 int ival = ctx->options[opt].ival;
105 ctx->options[opt].vval = Vector4(ival, ival, ival, ival);
106 }
107 break;
108 case Option::Type::FLOAT:
109 {
110 float fval = ctx->options[opt].fval;
111 ctx->options[opt].vval = Vector4(fval, fval, fval, fval);
112 }
113 default:
114 break;
115 }
117 return &ctx->options[opt].vval.x;
118 }
120 float *erb_get_framebuffer(struct erebus *ctx)
121 {
122 return ctx->fbimg.get_pixels();
123 }
125 void erb_begin_frame(struct erebus *ctx, long ms)
126 {
127 printf("starting new frame...\n");
128 ++ctx->cur_frame;
129 ctx->cur_sample = 0;
130 ctx->cur_time = ms;
132 int xsz = erb_getopti(ctx, ERB_OPT_WIDTH);
133 int ysz = erb_getopti(ctx, ERB_OPT_HEIGHT);
135 if(!ctx->fbimg.get_pixels() || ctx->fbimg.get_width() != xsz || ctx->fbimg.get_height() < ysz) {
136 ctx->fbimg.create(xsz, ysz);
137 ctx->accum.create(xsz, ysz);
138 } else {
139 ctx->fbimg.clear();
140 ctx->accum.clear();
141 }
143 ctx->inv_gamma = 1.0f / erb_getoptf(ctx, ERB_OPT_GAMMA);
145 ctx->scn->update(ctx->cur_time);
146 }
148 int erb_render(struct erebus *ctx, long timeout)
149 {
150 return erb_render_rect(ctx, 0, 0, ctx->fbimg.get_width(), ctx->fbimg.get_height(), timeout);
151 }
153 #define BLKSZ 32
155 int erb_render_rect(struct erebus *ctx, int x, int y, int width, int height, long timeout)
156 {
157 while(ctx->tpool.pending()) {
158 if(timeout > 0) {
159 long wait_interval = ctx->tpool.wait(timeout);
160 timeout -= wait_interval;
161 } else {
162 return 1;
163 }
164 }
166 if(!width || !height) return -1;
168 int startx = x;
169 int endx = x + width;
170 int endy = y + height;
172 while(y < endy) {
173 x = startx;
174 while(x < endx) {
175 Block blk;
176 blk.x = x;
177 blk.y = y;
178 blk.width = std::min(BLKSZ, endx - x);
179 blk.height = std::min(BLKSZ, endy - y);
180 blk.sample = ctx->cur_sample;
181 blk.frame = ctx->cur_frame;
183 ctx->tpool.add_work(std::bind(render_block, ctx, blk));
185 x += BLKSZ;
186 }
187 y += BLKSZ;
188 }
190 ++ctx->cur_sample;
191 ctx->tpool.wait(timeout); // wait for completion
192 return ctx->cur_sample > erb_getopti(ctx, ERB_OPT_MAX_SAMPLES) ? 0 : 1;
193 }
196 int erb_get_progress(struct erebus *ctx)
197 {
198 return 0; // TODO
199 }
201 int erb_load_scene(struct erebus *ctx, const char *fname)
202 {
203 delete ctx->scn;
204 ctx->scn = new Scene;
206 if(!ctx->scn->load(fname)) {
207 return -1;
208 }
209 return 0;
210 }
212 bool erb_input_keyboard(struct erebus *ctx, int key, bool pressed)
213 {
214 if(!ctx) return false;
215 if((int)ctx->keystate.size() <= key) {
216 ctx->keystate.resize(key < 256 ? 256 : key + 1);
217 }
219 ctx->keystate[key] = pressed;
221 if(pressed) {
222 switch(key) {
223 case '.':
224 {
225 int node_count = ctx->scn->get_node_count();
226 if(node_count && ++ctx->dbg_nodesel >= node_count) {
227 ctx->dbg_nodesel = 0;
228 }
229 printf("selected node: %d\n", ctx->dbg_nodesel);
230 }
231 break;
233 case ',':
234 {
235 int node_count = ctx->scn->get_node_count();
236 if(node_count && --ctx->dbg_nodesel < 0) {
237 ctx->dbg_nodesel = node_count - 1;
238 }
239 printf("selected node: %d\n", ctx->dbg_nodesel);
240 }
241 break;
243 case '=':
244 case '-':
245 case '0':
246 if(ctx->dbg_nodesel != -1) {
247 SceneNode *node = ctx->scn->get_node(ctx->dbg_nodesel);
248 Vector3 s = node->get_scaling();
249 switch(key) {
250 case '=':
251 node->set_scaling(s * 1.1);
252 break;
253 case '-':
254 node->set_scaling(s * 0.9);
255 break;
256 case '0':
257 node->set_scaling(Vector3(1, 1, 1));
258 break;
259 }
260 }
261 erb_begin_frame(ctx, 0);
262 return true;
263 }
264 }
265 return false;
266 }
268 bool erb_input_mouse_button(struct erebus *ctx, int bn, bool pressed, int x, int y)
269 {
270 if(!ctx) return false;
271 if((int)ctx->bnstate.size() <= bn) {
272 ctx->bnstate.resize(bn < 32 ? 32 : bn + 1);
273 }
275 ctx->bnstate[bn] = pressed;
276 ctx->mouse_pos[0] = x;
277 ctx->mouse_pos[1] = y;
278 return false;
279 }
281 bool erb_input_mouse_motion(struct erebus *ctx, int x, int y)
282 {
283 bool res = false;
285 if(!ctx) return res;
287 int dx = x - ctx->mouse_pos[0];
288 int dy = y - ctx->mouse_pos[1];
290 if(dx || dy) {
291 TargetCamera *cam = (TargetCamera*)ctx->scn->get_active_camera();
292 if(cam && ctx->bnstate[0]) {
293 Vector3 cpos = cam->get_position();
294 float mag = cpos.length();
296 float theta = atan2(cpos.z / mag, cpos.x / mag) - DEG_TO_RAD(dx * 0.5);
297 float phi = acos(cpos.y / mag) - DEG_TO_RAD(dy * 0.5);
299 if(phi < 0) phi = 0;
300 if(phi > M_PI) phi = M_PI;
302 cpos.x = cos(theta) * sin(phi) * mag;
303 cpos.y = cos(phi) * mag;
304 cpos.z = sin(theta) * sin(phi) * mag;
305 cam->set_position(cpos);
307 erb_begin_frame(ctx, 0);
308 res = true;
309 }
310 }
312 ctx->mouse_pos[0] = x;
313 ctx->mouse_pos[1] = y;
314 return res;
315 }
317 bool erb_input_6dof_button(struct erebus *ctx, int bn, bool pressed)
318 {
319 if(!ctx) return false;
320 return false;
321 }
323 bool erb_input_6dof_motion(struct erebus *ctx, float x, float y, float z)
324 {
325 if(!ctx) return false;
326 return false;
327 }
330 } // extern "C"
332 float randf(float low, float high)
333 {
334 std::uniform_real_distribution<float> unirnd(low, high);
335 return unirnd(rnd_gen);
336 }
338 static void render_block(struct erebus *ctx, Block blk)
339 {
340 if(blk.frame < ctx->cur_frame) {
341 return; // skip stale blocks
342 }
344 for(int i=0; i<blk.height; i++) {
345 for(int j=0; j<blk.width; j++) {
346 render_pixel(ctx, blk.x + j, blk.y + i, blk.sample);
347 }
348 }
349 }
351 static void render_pixel(struct erebus *ctx, int x, int y, int sample)
352 {
353 Camera *cam = ctx->scn->get_active_camera();
354 if(!cam) return;
356 int xsz = ctx->fbimg.get_width();
357 int ysz = ctx->fbimg.get_height();
358 int offs = (y * xsz + x) * 4;
360 float *pix = ctx->fbimg.get_pixels() + offs;
361 float *accum = ctx->accum.get_pixels() + offs;
363 Ray ray = cam->get_primary_ray(x, y, xsz, ysz, sample);
364 Color c = ray_trace(ctx, ray, 0);
365 accum[0] += c.x;
366 accum[1] += c.y;
367 accum[2] += c.z;
368 accum[3] += c.w;
370 float inv_samples = 1.0f / (float)(sample + 1);
371 pix[0] = pow(accum[0] * inv_samples, ctx->inv_gamma);
372 pix[1] = pow(accum[1] * inv_samples, ctx->inv_gamma);
373 pix[2] = pow(accum[2] * inv_samples, ctx->inv_gamma);
374 pix[3] = accum[3] * inv_samples;
375 }