multithreaded render
authorJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 21 Jun 2021 03:10:38 +0000 (06:10 +0300)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Mon, 21 Jun 2021 03:10:38 +0000 (06:10 +0300)
src/game.c [new file with mode: 0644]
src/game.h [new file with mode: 0644]
src/geom.c
src/level.c
src/main.c
src/rt.c

diff --git a/src/game.c b/src/game.c
new file mode 100644 (file)
index 0000000..b314e49
--- /dev/null
@@ -0,0 +1,3 @@
+#include "game.h"
+
+struct level lvl;
diff --git a/src/game.h b/src/game.h
new file mode 100644 (file)
index 0000000..0e263bf
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef GAME_H_
+#define GAME_H_
+
+#include "level.h"
+
+extern struct level lvl;
+
+#endif /* GAME_H_ */
index ba61e87..3751286 100644 (file)
@@ -20,7 +20,7 @@ void free_bvh_tree(struct bvhnode *tree)
 int ray_triangle(cgm_ray *ray, struct triangle *tri, float tmax, struct rayhit *hit)
 {
        float t, ndotdir;
-       cgm_vec3 vdir, bc;
+       cgm_vec3 vdir, bc, pos;
 
        if(fabs(ndotdir = cgm_vdot(&ray->dir, &tri->norm)) <= 1e-6) {
                return 0;
@@ -29,17 +29,23 @@ int ray_triangle(cgm_ray *ray, struct triangle *tri, float tmax, struct rayhit *
        vdir = tri->v[0].pos;
        cgm_vsub(&vdir, &ray->origin);
 
-       if((t = cgm_vdot(&ray->dir, &vdir) / ndotdir) <= 1e-6 || t > tmax) {
+       if((t = cgm_vdot(&tri->norm, &vdir) / ndotdir) <= 1e-6 || t > tmax) {
                return 0;
        }
 
+       cgm_raypos(&pos, ray, t);
+       cgm_bary(&bc, &tri->v[0].pos, &tri->v[1].pos, &tri->v[2].pos, &pos);
+
+       if(bc.x < 0.0f || bc.x > 1.0f) return 0;
+       if(bc.y < 0.0f || bc.y > 1.0f) return 0;
+       if(bc.z < 0.0f || bc.z > 1.0f) return 0;
+
        if(hit) {
                hit->t = t;
                hit->ray = *ray;
                hit->mtl = tri->mtl;
 
-               cgm_raypos(&hit->v.pos, ray, t);
-               cgm_bary(&bc, &tri->v[0].pos, &tri->v[1].pos, &tri->v[2].pos, &hit->v.pos);
+               hit->v.pos = pos;
 
                hit->v.norm.x = tri->v[0].norm.x * bc.x + tri->v[1].norm.x * bc.y + tri->v[2].norm.x * bc.z;
                hit->v.norm.y = tri->v[0].norm.y * bc.x + tri->v[1].norm.y * bc.y + tri->v[2].norm.y * bc.z;
index 1bd1c19..fcdc405 100644 (file)
@@ -86,6 +86,29 @@ void destroy_level(struct level *lvl)
 
 int ray_level(cgm_ray *ray, struct level *lvl, float tmax, struct rayhit *hit)
 {
+       int found = 0;
+       struct rayhit hit0;
+
+       if(!hit) {
+               if(ray_bvhnode(ray, lvl->st_root, tmax, 0)) return 1;
+               if(ray_bvhnode(ray, lvl->dyn_root, tmax, 0)) return 1;
+               return 0;
+       }
+
+       hit0.t = FLT_MAX;
+       if(ray_bvhnode(ray, lvl->st_root, tmax, hit)) {
+               hit0 = *hit;
+               found = 1;
+       }
+       if(ray_bvhnode(ray, lvl->dyn_root, tmax, hit) && hit->t < hit0.t) {
+               hit0 = *hit;
+               found = 1;
+       }
+
+       if(found) {
+               *hit = hit0;
+               return 1;
+       }
        return 0;
 }
 
index d49c311..d2240e0 100644 (file)
@@ -3,6 +3,7 @@
 #include <assert.h>
 #include <cgmath/cgmath.h>
 #include "miniglut.h"
+#include "game.h"
 #include "level.h"
 #include "rt.h"
 
@@ -63,8 +64,6 @@ static int keymap[NUM_INPUTS][2] = {
        {' ', 0}
 };
 
-static struct level lvl;
-
 static unsigned int tex;
 static int tex_width, tex_height;
 static int tex_intfmt;
index 0ad8a7c..18b7f17 100644 (file)
--- a/src/rt.c
+++ b/src/rt.c
@@ -1,4 +1,14 @@
+#include <float.h>
 #include "rt.h"
+#include "game.h"
+
+#define TILESZ 32
+
+struct tile {
+       int x, y, width, height;
+       int sample;
+       cgm_vec3 *fbptr;
+};
 
 struct framebuffer fb;
 struct thread_pool *tpool;
@@ -6,48 +16,102 @@ float view_xform[16];
 float vfov = M_PI / 4;
 
 static float aspect;
+static struct tile *tiles;
+static int num_tiles;
 
+static void render_tile(struct tile *tile);
 static void ray_trace(cgm_vec3 *color, cgm_ray *ray);
+static void bgcolor(cgm_vec3 *color, cgm_ray *ray);
 static void primary_ray(cgm_ray *ray, int x, int y, int sample);
 
 int fbsize(int width, int height)
 {
-       void *tmp;
+       int i, j, x, y, xtiles, ytiles;
+       cgm_vec3 *fbptr;
+       struct tile *tileptr;
 
-       if(!(tmp = malloc(width * height * sizeof *fb.pixels))) {
+       if(!(fbptr = malloc(width * height * sizeof *fb.pixels))) {
+               return -1;
+       }
+       xtiles = width / TILESZ;
+       ytiles = height / TILESZ;
+       if(!(tileptr = malloc(xtiles * ytiles * sizeof *tiles))) {
+               free(fbptr);
                return -1;
        }
 
        free(fb.pixels);
-       fb.pixels = tmp;
+       fb.pixels = fbptr;
        fb.width = width;
        fb.height = height;
 
+       free(tiles);
+       tiles = tileptr;
+       num_tiles = xtiles * ytiles;
+
        aspect = (float)fb.width / (float)fb.height;
 
+       y = 0;
+       for(i=0; i<ytiles; i++) {
+               x = 0;
+               for(j=0; j<xtiles; j++) {
+                       tileptr->x = x;
+                       tileptr->y = y;
+                       tileptr->width = width - x < TILESZ ? width - x : TILESZ;
+                       tileptr->height = height - y < TILESZ ? height - y : TILESZ;
+                       tileptr->fbptr = fbptr + x;
+                       tileptr++;
+
+                       x += TILESZ;
+               }
+               fbptr += width * TILESZ;
+               y += TILESZ;
+       }
+
        return 0;
 }
 
 void render(void)
 {
+       int i;
+
+       for(i=0; i<num_tiles; i++) {
+               tpool_enqueue(tpool, tiles + i, (tpool_callback)render_tile, 0);
+       }
+       tpool_wait(tpool);
+}
+
+static void render_tile(struct tile *tile)
+{
        int i, j;
        cgm_ray ray;
-       cgm_vec3 *fbptr = fb.pixels;
+       cgm_vec3 *fbptr = tile->fbptr;
 
-       for(i=0; i<fb.height; i++) {
-               for(j=0; j<fb.width; j++) {
-                       primary_ray(&ray, j, i, 0);
-                       ray_trace(fbptr, &ray);
-                       fbptr++;
+       for(i=0; i<tile->height; i++) {
+               for(j=0; j<tile->width; j++) {
+                       primary_ray(&ray, tile->x + j, tile->y + i, tile->sample);
+                       ray_trace(fbptr + j, &ray);
                }
+               fbptr += fb.width;
        }
 }
 
 static void ray_trace(cgm_vec3 *color, cgm_ray *ray)
 {
-       color->x = ray->dir.x * 0.5f + 0.5f;
-       color->y = ray->dir.y * 0.5f + 0.5f;
-       color->z = 0.0f;
+       struct rayhit hit;
+
+       if(ray_level(ray, &lvl, FLT_MAX, &hit)) {
+               color->x = hit.v.norm.x * 0.5 + 0.5;
+               color->y = hit.v.norm.y * 0.5 + 0.5;
+               color->z = hit.v.norm.z * 0.5 + 0.5;
+       } else {
+               bgcolor(color, ray);
+       }
+}
+
+static void bgcolor(cgm_vec3 *color, cgm_ray *ray)
+{
+       color->x = color->y = color->z = 1.0f;
 }
 
 static void primary_ray(cgm_ray *ray, int x, int y, int sample)