10 static void calc_primary_ray(struct ray *ray, int x, int y, int w, int h, float aspect);
11 static int ray_trace(struct ray *ray, float *col);
12 static void shade(float *col, struct ray *ray, struct hit *hit);
13 static void background(float *col, struct ray *ray);
14 static int find_intersection(struct ray *ray, struct hit *best);
16 static float ambient[3];
17 static struct camera cam;
18 static csg_object *oblist;
19 static csg_object *plights;
27 csg_view(0, 0, 5, 0, 0, 0);
33 void csg_destroy(void)
36 csg_object *o = oblist;
37 oblist = oblist->ob.next;
43 void csg_view(float x, float y, float z, float tx, float ty, float tz)
53 void csg_fov(float fov)
55 cam.fov = M_PI * fov / 180.0f;
59 int csg_load(const char *fname)
64 int csg_save(const char *fname)
69 void csg_add_object(csg_object *o)
74 if(o->ob.type == OB_NULL && (o->ob.emr > 0.0f || o->ob.emg > 0.0f || o->ob.emb > 0.0f)) {
75 o->ob.plt_next = plights;
80 int csg_remove_object(csg_object *o)
84 dummy.ob.next = oblist;
89 n->ob.next = o->ob.next;
97 void csg_free_object(csg_object *o)
105 static union csg_object *alloc_object(int type)
109 if(!(o = calloc(sizeof *o, 1))) {
113 mat4_identity(o->ob.xform);
114 mat4_identity(o->ob.inv_xform);
116 csg_emission(o, 0, 0, 0);
117 csg_color(o, 1, 1, 1);
124 csg_object *csg_null(float x, float y, float z)
128 if(!(o = alloc_object(OB_NULL))) {
132 mat4_translation(o->ob.xform, x, y, z);
136 csg_object *csg_sphere(float x, float y, float z, float r)
140 if(!(o = alloc_object(OB_SPHERE))) {
145 mat4_translation(o->ob.xform, x, y, z);
146 mat4_copy(o->ob.inv_xform, o->ob.xform);
147 mat4_inverse(o->ob.inv_xform);
151 csg_object *csg_cylinder(float x0, float y0, float z0, float x1, float y1, float z1, float r)
157 if(!(o = alloc_object(OB_CYLINDER))) {
165 if(fabs(dx) > fabs(dy) && fabs(dx) > fabs(dz)) {
167 } else if(fabs(dy) > fabs(dz)) {
174 mat4_lookat(o->ob.xform, x0, y0, z0, x1, y1, z1, 0, major == 2 ? 1 : 0, major == 2 ? 0 : 1);
175 mat4_copy(o->ob.inv_xform, o->ob.xform);
176 mat4_inverse(o->ob.inv_xform);
180 csg_object *csg_plane(float x, float y, float z, float nx, float ny, float nz)
185 if(!(o = alloc_object(OB_PLANE))) {
189 len = sqrt(nx * nx + ny * ny + nz * nz);
191 float s = 1.0f / len;
200 o->plane.d = x * nx + y * ny + z * nz;
204 csg_object *csg_box(float x, float y, float z, float xsz, float ysz, float zsz)
209 csg_object *csg_union(csg_object *a, csg_object *b)
213 if(!(o = alloc_object(OB_UNION))) {
221 csg_object *csg_intersection(csg_object *a, csg_object *b)
225 if(!(o = alloc_object(OB_INTERSECTION))) {
233 csg_object *csg_subtraction(csg_object *a, csg_object *b)
237 if(!(o = alloc_object(OB_SUBTRACTION))) {
245 void csg_ambient(float r, float g, float b)
252 void csg_emission(csg_object *o, float r, float g, float b)
259 void csg_color(csg_object *o, float r, float g, float b)
266 void csg_roughness(csg_object *o, float r)
271 void csg_opacity(csg_object *o, float p)
276 void csg_metallic(csg_object *o, int m)
282 void csg_render_pixel(int x, int y, int width, int height, float aspect, float *color)
286 calc_primary_ray(&ray, x, y, width, height, aspect);
287 ray_trace(&ray, color);
290 void csg_render_image(float *pixels, int width, int height)
293 float aspect = (float)width / (float)height;
295 for(i=0; i<height; i++) {
296 for(j=0; j<width; j++) {
297 csg_render_pixel(j, i, width, height, aspect, pixels);
303 static void calc_primary_ray(struct ray *ray, int x, int y, int w, int h, float aspect)
306 ray->dx = aspect * ((float)x / (float)w * 2.0f - 1.0f);
307 ray->dy = 1.0f - (float)y / (float)h * 2.0f;
308 ray->dz = -1.0f / tan(cam.fov * 0.5f);
315 static int ray_trace(struct ray *ray, float *col)
319 if(!find_intersection(ray, &hit)) {
320 background(col, ray);
324 shade(col, ray, &hit);
328 #define NULLXPOS(o) ((o)->ob.xform[12])
329 #define NULLYPOS(o) ((o)->ob.xform[13])
330 #define NULLZPOS(o) ((o)->ob.xform[14])
332 static void shade(float *col, struct ray *ray, struct hit *hit)
334 float ndotl, ndoth, len, falloff, spec;
335 csg_object *o, *lt = plights;
336 float dcol[3], scol[3] = {0};
337 float ldir[3], lcol[3], hdir[3];
342 dcol[0] = ambient[0];
343 dcol[1] = ambient[1];
344 dcol[2] = ambient[2];
347 ldir[0] = NULLXPOS(lt) - hit->x;
348 ldir[1] = NULLYPOS(lt) - hit->y;
349 ldir[2] = NULLZPOS(lt) - hit->z;
358 if(!find_intersection(&sray, &tmphit) || tmphit.t > 1.0f) {
359 if((len = sqrt(ldir[0] * ldir[0] + ldir[1] * ldir[1] + ldir[2] * ldir[2])) != 0.0f) {
360 float s = 1.0f / len;
365 falloff = 1.0f / (len * len);
367 lcol[0] = lt->ob.emr * falloff;
368 lcol[1] = lt->ob.emg * falloff;
369 lcol[2] = lt->ob.emb * falloff;
371 if((ndotl = hit->nx * ldir[0] + hit->ny * ldir[1] + hit->nz * ldir[2]) < 0.0f) {
375 dcol[0] += o->ob.r * lcol[0] * ndotl;
376 dcol[1] += o->ob.g * lcol[1] * ndotl;
377 dcol[2] += o->ob.b * lcol[2] * ndotl;
379 if(o->ob.roughness < 1.0f) {
380 float gloss = 1.0f - o->ob.roughness;
382 hdir[0] = ldir[0] - ray->dx;
383 hdir[1] = ldir[1] - ray->dy;
384 hdir[2] = ldir[2] - ray->dz;
385 if((len = sqrt(hdir[0] * hdir[0] + hdir[1] * hdir[1] + hdir[2] * hdir[2])) != 0.0f) {
386 float s = 1.0f / len;
392 if((ndoth = hit->nx * hdir[0] + hit->ny * hdir[1] + hit->nz * hdir[2]) < 0.0f) {
395 spec = gloss * pow(ndoth, 100.0f * gloss);
402 scol[0] += lcol[0] * spec;
403 scol[1] += lcol[1] * spec;
404 scol[2] += lcol[2] * spec;
408 lt = lt->ob.plt_next;
411 col[0] = dcol[0] + scol[0];
412 col[1] = dcol[1] + scol[1];
413 col[2] = dcol[2] + scol[2];
416 static void background(float *col, struct ray *ray)
418 col[0] = col[1] = col[2] = 0.0f;
421 static int find_intersection(struct ray *ray, struct hit *best)
425 struct hinterv *hit, *it;
432 if((hit = ray_intersect(ray, o))) {
435 if(it->end[0].t > 1e-6) {
439 if(it->end[1].t > 1e-6) {
446 if(it && it->end[idx].t < best->t) {
447 *best = it->end[idx];