+#include <stdio.h>
#include "erebus.h"
-int erb_init(void)
+struct erb_rend {
+ int fb_width, fb_height, fb_npix;
+ float *fb_pixels;
+ int *fb_nsamples;
+};
+
+struct erb_rend *erb_create(void)
+{
+ struct erb_rend *erb;
+
+ if(!(erb = calloc(1, sizeof *erb))) {
+ return 0;
+ }
+ return erb;
+}
+
+void erb_destroy(struct erb_rend *erb)
{
+ if(!erb) return;
+ free(erb->fb_pixels);
+ free(erb);
+}
+
+int erb_allocframe(struct erb_rend *erb, int width, int height)
+{
+ float *newfb;
+ int *newns;
+ int npix;
+
+ if(width == erb->fb_width && height == erb->fb_height) {
+ return 0;
+ }
+
+ npix = width * height;
+
+ if(!(newfb = malloc(npix * 3 * sizeof *erb->fb_pixels))) {
+ goto err;
+ }
+ if(!(newns = malloc(npix * sizeof *erb->fb_nsamples))) {
+ free(newfb);
+ goto err;
+ }
+
+ free(erb->fb_pixels);
+ free(erb->fb_nsamples);
+
+ erb->fb_pixels = newfb;
+ erb->fb_nsamples = newns;
+ erb->fb_width = width;
+ erb->fb_height = height;
+ erb->fb_npix = npix;
return 0;
+
+err:
+ fprintf(stderr, "erb_allocframe: failed to allocate %dx%d framebuffer\n", width, height);
+ return -1;
+}
+
+float *erb_getframe(struct erb_rend *erb)
+{
+ return erb->fb_pixels;
}
-void erb_cleanup(void)
+void erb_begin(struct erb_rend *erb)
{
+ memset(erb->fb_pixels, 0, erb->fb_npix * 3 * sizeof *erb->fb_pixels);
+ memset(erb->fb_nsamples, 0, erb->fb_npix * sizeof *erb->fb_nsamples);
+}
+
+float *erb_end(struct erb_rend *erb)
+{
+ int i, n;
+ float s;
+ float *pptr = erb->fb_pixels;
+ int *nptr = erb->fb_nsamples;
+
+ for(i=0; i<erb->fb_npix; i++) {
+ n = *nptr;
+ if(n > 1) {
+ s = 1.0f / n;
+ *pptr++ *= s;
+ *pptr++ *= s;
+ *pptr++ *= s;
+ *nptr++ = 1;
+ } else {
+ pptr += 3;
+ nptr++;
+ }
+ }
+
+ return erb->fb_pixels;
}
#include <cgmath/cgmath.h>
+struct erb_rend;
struct erb_node;
struct erb_surf;
struct erb_ray;
struct erb_aabb;
typedef int (*erb_intersect_func)(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+typedef void (*erb_hitgeom_func)(struct erb_surf *surf, struct erb_hit *hit);
typedef void (*erb_sample_func)(struct erb_surf *surf, cgm_vec3 *pos);
typedef void (*erb_bbox_func)(struct erb_surf *surf, struct erb_aabb *bb);
int bbox_valid;
erb_intersect_func isect; /* intersection routine */
+ erb_hitgeom_func hitgeom; /* calculate derived values of the erb_hit structure */
erb_sample_func sample; /* random sample generation */
erb_bbox_func calc_bbox; /* bounds calculation */
struct erb_hit {
float t, err;
+ cgm_vec3 pos, lpos; /* global and local space hit positions */
struct erb_surf *surf;
+ float total_dist;
+
+ /* derived by calc_hit */
+ cgm_vec3 norm, tang;
+ float u, v;
};
-int erb_init(void);
-void erb_cleanup(void);
+struct erb_rend *erb_create(void);
+void erb_destroy(struct erb_rend *erb);
+
+int erb_allocframe(struct erb_rend *erb, int width, int height);
+float *erb_getframe(struct erb_rend *erb);
+
+/* clears the framebuffer and sample counters to begin rendering a new frame */
+void erb_begin(struct erb_rend *erb);
+/* finalizes the frame, averaging samples (optional) */
+float *erb_end(struct erb_rend *erb);
/* transformation nodes */
struct erb_node *erb_node(void);
int erb_node_addsurf(struct erb_node *n, struct erb_surf *s);
int erb_node_rmsurf(struct erb_node *n, struct erb_surf *s);
+/* sets the transformation matrix and also calculates the inverse */
void erb_node_setxform(struct erb_node *n, float *mat);
-void erb_node_mulxform(struct erb_node *n, float *mat);
-void erb_node_translate(struct erb_node *n, float x, float y, float z);
-/* TODO ... more ... */
/* surfaces */
struct erb_surf *erb_surface(int datasz);
struct erb_surf *erb_surf_box(float xsz, float ysz, float zsz);
/* utility functions */
-void erb_xform_ray(struct erb_ray *ray, float *mat);
+void erb_xform_ray(struct erb_ray *inray, float *mat, cgm_vec3 *org, cgm_vec3 *dir);
#endif /* RENDLIB_H_ */
};
static int null_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+static void null_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
static void null_sample(struct erb_surf *surf, cgm_vec3 *pos);
static void null_bbox(struct erb_surf *surf, struct erb_aabb *bb);
static int sph_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+static void sph_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
static void sph_sample(struct erb_surf *surf, cgm_vec3 *pos);
static void sph_bbox(struct erb_surf *surf, struct erb_aabb *bb);
static int box_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
+static void box_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
static void box_sample(struct erb_surf *surf, cgm_vec3 *pos);
static void box_bbox(struct erb_surf *surf, struct erb_aabb *bb);
return 0;
}
surf->isect = null_isect;
+ surf->hitgeom = null_hitgeom;
surf->sample = null_sample;
surf->calc_bbox = null_bbox;
return surf;
return 0;
}
surf->isect = sph_isect;
+ surf->hitgeom = sph_hitgeom;
surf->sample = sph_sample;
surf->calc_bbox = sph_bbox;
sdata = (struct sph_data*)surf->data;
return 0;
}
surf->isect = box_isect;
+ surf->hitgeom = box_hitgeom;
surf->sample = box_sample;
surf->calc_bbox = box_bbox;
bdata = (struct box_data*)surf->data;
return 0;
}
+static void null_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
+{
+ fprintf(stderr, "BUG: null_hitgeom called\n");
+}
+
static void null_sample(struct erb_surf *surf, cgm_vec3 *pos)
{
pos->x = pos->y = pos->z = 0;
static int sph_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
{
- return 0;
+ float a, b, c, d, sqrt_d, q, t, t0, t1;
+ cgm_vec3 org, dir;
+ struct sph_data *sdata = (struct sph_data*)surf->data;
+
+ if(surf->node) {
+ erb_xform_ray(ray, surf->node->inv_xform, &org, &dir);
+ } else {
+ org = ray->o;
+ dir = ray->d;
+ }
+
+ a = cgm_vdot(&dir, &dir);
+ b = 2.0f * cgm_vdot(&org, &dir);
+ c = cgm_vdot(&org, &org) - sdata->rad * sdata->rad;
+
+ d = b * b - 4.0f * a * c;
+ if(d <= 0.0f) return 0;
+
+ sqrt_d = sqrt(d);
+ q = b < 0.0f ? -0.5f * (b - sqrt_d) : -0.5f * (b + sqrt_d);
+
+ t0 = q / a;
+ t1 = c / q;
+ if(t1 < t0) {
+ float ttmp = t0;
+ t0 = t1;
+ t1 = ttmp;
+ }
+
+ if(t0 > ray->tmax || t1 < ray->tmin) {
+ return 0;
+ }
+ t = t0 < ray->tmin ? t1 : t0;
+ if(t > ray->tmax) {
+ return 0;
+ }
+
+ if(hit) {
+ hit->t = t;
+ hit->err = 5e-4f * t; /* PBR 3.2.6 */
+ hit->surf = surf;
+ hit->pos = ray->o;
+ cgm_vadd_scaled(&hit->pos, &ray->d, t);
+ hit->lpos = org;
+ cgm_vadd_scaled(&hit->lpos, &dir, t);
+ hit->total_dist = ray->total_dist + t;
+ }
+
+ return 1;
+}
+
+static void sph_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
+{
+ float theta, phi;
+
+ hit->norm = hit->lpos;
+ cgm_vnormalize(&hit->norm);
+
+ cgm_uvec_to_sph(&theta, &phi, &hit->norm);
+
+ hit->u = (theta + M_PI) / (2.0 * M_PI);
+ hit->v = phi / M_PI;
+
+ hit->tang.x = hit->norm.z;
+ hit->tang.y = hit->norm.y;
+ hit->tang.z = -hit->norm.x;
+
+ if(surf->node) {
+ cgm_vmul_m3v3(&hit->norm, surf->node->xform);
+ cgm_vmul_m3v3(&hit->tang, surf->node->xform);
+ }
}
static void sph_sample(struct erb_surf *surf, cgm_vec3 *pos)
{
+ /* TODO */
}
static void sph_bbox(struct erb_surf *surf, struct erb_aabb *bb)
{
+ struct sph_data *sdata = (struct sph_data*)surf->data;
+
+ cgm_vcons(&bb->pos, 0, 0, 0);
+ bb->sz.x = bb->sz.y = bb->sz.z = sdata->rad;
}
+/* TODO boxen */
static int box_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
{
return 0;
}
+static void box_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
+{
+}
+
static void box_sample(struct erb_surf *surf, cgm_vec3 *pos)
{
}