erebus

annotate liberebus/src/erebus.cc @ 8:e2d9bf168a41

semi-works ...
author John Tsiombikas <nuclear@member.fsf.org>
date Sat, 24 May 2014 06:12:57 +0300
parents 9621beb22694
children d38e13d6063c
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@2 37 };
nuclear@2 38
nuclear@8 39 static void render_pixel(struct erebus *ctx, int x, int y, int sample);
nuclear@2 40
nuclear@2 41 static std::mt19937 rnd_gen;
nuclear@2 42
nuclear@2 43 extern "C" {
nuclear@2 44
nuclear@2 45 struct erebus *erb_init(void)
nuclear@2 46 {
nuclear@2 47 struct erebus *ctx;
nuclear@2 48 try {
nuclear@2 49 ctx = new struct erebus;
nuclear@2 50 }
nuclear@2 51 catch(...) {
nuclear@2 52 return 0;
nuclear@2 53 }
nuclear@2 54
nuclear@4 55 ctx->scn = 0;
nuclear@2 56 ctx->cur_time = 0;
nuclear@2 57 ctx->cur_rect = INVALID_RECT;
nuclear@8 58
nuclear@8 59 ctx->options[ERB_OPT_MAX_SAMPLES].x = (float)INF_SAMPLES;
nuclear@2 60 return ctx;
nuclear@2 61 }
nuclear@2 62
nuclear@2 63 void erb_destroy(struct erebus *ctx)
nuclear@2 64 {
nuclear@2 65 delete ctx;
nuclear@2 66 }
nuclear@2 67
nuclear@2 68 void erb_setopti(struct erebus *ctx, enum erb_option opt, int val)
nuclear@2 69 {
nuclear@2 70 ctx->options[opt].x = val;
nuclear@2 71 }
nuclear@2 72 void erb_setoptf(struct erebus *ctx, enum erb_option opt, float val)
nuclear@2 73 {
nuclear@2 74 ctx->options[opt].x = val;
nuclear@2 75 }
nuclear@2 76 void erb_setoptfv(struct erebus *ctx, enum erb_option opt, float *vec)
nuclear@2 77 {
nuclear@2 78 for(int i=0; i<4; i++) {
nuclear@2 79 ctx->options[opt][i] = vec[i];
nuclear@2 80 }
nuclear@2 81 }
nuclear@2 82
nuclear@2 83 int erb_getopti(struct erebus *ctx, enum erb_option opt)
nuclear@2 84 {
nuclear@2 85 return ctx->options[opt].x;
nuclear@2 86 }
nuclear@2 87 float erb_getoptf(struct erebus *ctx, enum erb_option opt)
nuclear@2 88 {
nuclear@2 89 return ctx->options[opt].x;
nuclear@2 90 }
nuclear@2 91 float *erb_getoptfv(struct erebus *ctx, enum erb_option opt)
nuclear@2 92 {
nuclear@2 93 return &ctx->options[opt].x;
nuclear@2 94 }
nuclear@2 95
nuclear@2 96 float *erb_get_framebuffer(struct erebus *ctx)
nuclear@2 97 {
nuclear@2 98 return ctx->fbimg.get_pixels();
nuclear@2 99 }
nuclear@2 100
nuclear@2 101 void erb_begin_frame(struct erebus *ctx, long ms)
nuclear@2 102 {
nuclear@8 103 printf("starting new frame...\n");
nuclear@2 104 ctx->cur_time = ms;
nuclear@4 105
nuclear@4 106 int xsz = ctx->options[ERB_OPT_WIDTH].x;
nuclear@4 107 int ysz = ctx->options[ERB_OPT_HEIGHT].x;
nuclear@4 108
nuclear@4 109 ctx->fbimg.create(xsz, ysz);
nuclear@8 110 ctx->accum.create(xsz, ysz);
nuclear@2 111 }
nuclear@2 112
nuclear@2 113 int erb_render(struct erebus *ctx, long timeout)
nuclear@2 114 {
nuclear@2 115 return erb_render_rect(ctx, 0, 0, ctx->fbimg.get_width(), ctx->fbimg.get_height(), timeout);
nuclear@2 116 }
nuclear@2 117
nuclear@2 118 int erb_render_rect(struct erebus *ctx, int x, int y, int width, int height, long timeout)
nuclear@2 119 {
nuclear@2 120 if(!width || !height) return -1;
nuclear@2 121
nuclear@2 122 Rect rect{x, y, width, height};
nuclear@2 123 if(ctx->cur_rect != rect) {
nuclear@8 124 // starting a new rendering apparently
nuclear@2 125 ctx->cur_rect = rect;
nuclear@2 126 ctx->cur_pixel_x = x;
nuclear@2 127 ctx->cur_pixel_y = y;
nuclear@8 128 ctx->cur_sample = 0;
nuclear@2 129 }
nuclear@2 130
nuclear@4 131 ctx->scn->update();
nuclear@4 132
nuclear@8 133 int max_samples = ctx->options[ERB_OPT_MAX_SAMPLES].x;
nuclear@8 134
nuclear@2 135 if(timeout > 0) {
nuclear@2 136 auto start_time = steady_clock::now();
nuclear@2 137 while(duration_cast<milliseconds>(steady_clock::now() - start_time).count() < timeout) {
nuclear@8 138 render_pixel(ctx, ctx->cur_pixel_x, ctx->cur_pixel_y, ctx->cur_sample);
nuclear@2 139
nuclear@2 140 if(++ctx->cur_pixel_x >= ctx->cur_rect.width) {
nuclear@8 141 ctx->cur_pixel_x = ctx->cur_rect.x;
nuclear@2 142 if(++ctx->cur_pixel_y >= ctx->cur_rect.height) {
nuclear@8 143 ctx->cur_pixel_y = ctx->cur_rect.y;
nuclear@8 144 if(++ctx->cur_sample >= max_samples) {
nuclear@8 145 ctx->cur_rect = INVALID_RECT;
nuclear@8 146 return 0;
nuclear@8 147 }
nuclear@2 148 }
nuclear@2 149 }
nuclear@2 150 }
nuclear@2 151 return 1;
nuclear@2 152 }
nuclear@2 153
nuclear@8 154 if(ctx->options[ERB_OPT_MAX_SAMPLES].x == (float)INF_SAMPLES) {
nuclear@8 155 max_samples = 128;
nuclear@8 156 }
nuclear@8 157
nuclear@2 158 for(int i=0; i<height; i++) {
nuclear@2 159 for(int j=0; j<width; j++) {
nuclear@8 160 for(int k=0; k<max_samples; k++) {
nuclear@8 161 render_pixel(ctx, j, i, k);
nuclear@8 162 }
nuclear@2 163 }
nuclear@2 164 }
nuclear@2 165 return 0;
nuclear@2 166 }
nuclear@2 167
nuclear@2 168 int erb_get_progress(struct erebus *ctx)
nuclear@2 169 {
nuclear@2 170 return 0; // TODO
nuclear@2 171 }
nuclear@2 172
nuclear@2 173 int erb_load_scene(struct erebus *ctx, const char *fname)
nuclear@2 174 {
nuclear@4 175 delete ctx->scn;
nuclear@4 176 ctx->scn = new Scene;
nuclear@2 177
nuclear@4 178 // XXX for now just create a test scene here
nuclear@4 179 Sphere *sph = new Sphere;
nuclear@8 180 sph->mtl.set_attrib("albedo", Color(1.0, 0.3, 0.2));
nuclear@4 181 SceneNode *sph_node = new SceneNode(sph);
nuclear@4 182 ctx->scn->add_object(sph);
nuclear@4 183 ctx->scn->add_node(sph_node);
nuclear@4 184
nuclear@8 185 sph = new Sphere;
nuclear@8 186 sph->mtl.set_attrib("albedo", Color(0.3, 0.4, 1.0));
nuclear@8 187 sph_node = new SceneNode(sph);
nuclear@8 188 sph_node->set_position(Vector3(0, -3.0, 0));
nuclear@8 189 //sph_node->set_scaling(Vector3(4.0, 4.0, 4.0) * 0.3);
nuclear@8 190 ctx->scn->add_object(sph);
nuclear@8 191 ctx->scn->add_node(sph_node);
nuclear@8 192
nuclear@8 193 Sphere *lt = new Sphere;
nuclear@8 194 lt->mtl.set_attrib("emissive", Color(10, 10, 10));
nuclear@8 195 SceneNode *lt_node = new SceneNode(lt);
nuclear@8 196 lt_node->set_position(Vector3(-15, 15, -10));
nuclear@8 197 lt_node->set_scaling(Vector3(5, 5, 5));
nuclear@8 198 ctx->scn->add_object(lt);
nuclear@8 199 ctx->scn->add_node(lt_node);
nuclear@8 200
nuclear@8 201 TargetCamera *cam = new TargetCamera(Vector3(0, 4, -8), Vector3(0, 0, 0));
nuclear@4 202 //ctx->scn->add_object(cam);
nuclear@4 203 ctx->scn->use_camera(cam);
nuclear@4 204
nuclear@4 205 return 0;
nuclear@2 206 }
nuclear@2 207
nuclear@2 208 } // extern "C"
nuclear@2 209
nuclear@2 210 float randf(float low, float high)
nuclear@2 211 {
nuclear@2 212 std::uniform_real_distribution<float> unirnd(low, high);
nuclear@2 213 return unirnd(rnd_gen);
nuclear@2 214 }
nuclear@2 215
nuclear@8 216 static void render_pixel(struct erebus *ctx, int x, int y, int sample)
nuclear@2 217 {
nuclear@5 218 Camera *cam = ctx->scn->get_active_camera();
nuclear@5 219 if(!cam) return;
nuclear@5 220
nuclear@5 221 int xsz = ctx->fbimg.get_width();
nuclear@5 222 int ysz = ctx->fbimg.get_height();
nuclear@8 223 int offs = (y * xsz + x) * 4;
nuclear@5 224
nuclear@8 225 float *pix = ctx->fbimg.get_pixels() + offs;
nuclear@8 226 float *accum = ctx->accum.get_pixels() + offs;
nuclear@8 227
nuclear@8 228 Ray ray = cam->get_primary_ray(x, y, xsz, ysz, sample);
nuclear@8 229 Color c = ray_trace(ray, ctx->scn, 0);
nuclear@8 230 accum[0] += c.x;
nuclear@8 231 accum[1] += c.y;
nuclear@8 232 accum[2] += c.z;
nuclear@8 233 accum[3] += c.w;
nuclear@8 234
nuclear@8 235 float inv_samples = 1.0f / (float)(sample + 1);
nuclear@8 236 pix[0] = accum[0] * inv_samples;
nuclear@8 237 pix[1] = accum[1] * inv_samples;
nuclear@8 238 pix[2] = accum[2] * inv_samples;
nuclear@8 239 pix[3] = accum[3] * inv_samples;
nuclear@2 240 }