foo
[erebus2020] / liberebus / src / surf.c
1 #include <stdio.h>
2 #include "erebus.h"
3
4 struct sph_data {
5         float rad;
6 };
7 struct box_data {
8         cgm_vec3 sz;
9 };
10
11 static int null_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
12 static void null_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
13 static void null_sample(struct erb_surf *surf, cgm_vec3 *pos);
14 static void null_bbox(struct erb_surf *surf, struct erb_aabb *bb);
15
16 static int sph_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
17 static void sph_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
18 static void sph_sample(struct erb_surf *surf, cgm_vec3 *pos);
19 static void sph_bbox(struct erb_surf *surf, struct erb_aabb *bb);
20
21 static int box_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit);
22 static void box_hitgeom(struct erb_surf *surf, struct erb_hit *hit);
23 static void box_sample(struct erb_surf *surf, cgm_vec3 *pos);
24 static void box_bbox(struct erb_surf *surf, struct erb_aabb *bb);
25
26
27 struct erb_surf *erb_surface(int datasz)
28 {
29         struct erb_surf *surf;
30
31         if(!(surf = calloc(1, sizeof *surf - sizeof surf->data + datasz))) {
32                 fprintf(stderr, "failed to allocate surface\n");
33                 return 0;
34         }
35         surf->isect = null_isect;
36         surf->hitgeom = null_hitgeom;
37         surf->sample = null_sample;
38         surf->calc_bbox = null_bbox;
39         return surf;
40 }
41
42 void erb_free_surface(struct erb_surf *surf)
43 {
44         if(surf->node) {
45                 erb_node_rmsurf(surf->node, surf);
46         }
47         free(surf);
48 }
49
50 struct erb_surf *erb_surf_sphere(float rad)
51 {
52         struct erb_surf *surf;
53         struct sph_data *sdata;
54
55         if(!(surf = erb_surface(sizeof *sdata))) {
56                 return 0;
57         }
58         surf->isect = sph_isect;
59         surf->hitgeom = sph_hitgeom;
60         surf->sample = sph_sample;
61         surf->calc_bbox = sph_bbox;
62         sdata = (struct sph_data*)surf->data;
63         sdata->rad = rad;
64         return surf;
65 }
66
67 struct erb_surf *erb_surf_box(float xsz, float ysz, float zsz)
68 {
69         struct erb_surf *surf;
70         struct box_data *bdata;
71
72         if(!(surf = erb_surface(sizeof *bdata))) {
73                 return 0;
74         }
75         surf->isect = box_isect;
76         surf->hitgeom = box_hitgeom;
77         surf->sample = box_sample;
78         surf->calc_bbox = box_bbox;
79         bdata = (struct box_data*)surf->data;
80         cgm_vcons(&bdata->sz, xsz, ysz, zsz);
81         return surf;
82 }
83
84
85 static int null_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
86 {
87         return 0;
88 }
89
90 static void null_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
91 {
92         fprintf(stderr, "BUG: null_hitgeom called\n");
93 }
94
95 static void null_sample(struct erb_surf *surf, cgm_vec3 *pos)
96 {
97         pos->x = pos->y = pos->z = 0;
98 }
99
100 static void null_bbox(struct erb_surf *surf, struct erb_aabb *bb)
101 {
102         bb->pos.x = bb->pos.y = bb->pos.z = 0;
103         bb->sz.x = bb->sz.y = bb->sz.z = 0;
104 }
105
106 static int sph_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
107 {
108         float a, b, c, d, sqrt_d, q, t, t0, t1;
109         cgm_vec3 org, dir;
110         struct sph_data *sdata = (struct sph_data*)surf->data;
111
112         if(surf->node) {
113                 erb_xform_ray(ray, surf->node->inv_xform, &org, &dir);
114         } else {
115                 org = ray->o;
116                 dir = ray->d;
117         }
118
119         a = cgm_vdot(&dir, &dir);
120         b = 2.0f * cgm_vdot(&org, &dir);
121         c = cgm_vdot(&org, &org) - sdata->rad * sdata->rad;
122
123         d = b * b - 4.0f * a * c;
124         if(d <= 0.0f) return 0;
125
126         sqrt_d = sqrt(d);
127         q = b < 0.0f ? -0.5f * (b - sqrt_d) : -0.5f * (b + sqrt_d);
128
129         t0 = q / a;
130         t1 = c / q;
131         if(t1 < t0) {
132                 float ttmp = t0;
133                 t0 = t1;
134                 t1 = ttmp;
135         }
136
137         if(t0 > ray->tmax || t1 < ray->tmin) {
138                 return 0;
139         }
140         t = t0 < ray->tmin ? t1 : t0;
141         if(t > ray->tmax) {
142                 return 0;
143         }
144
145         if(hit) {
146                 hit->t = t;
147                 hit->err = 5e-4f * t;   /* PBR 3.2.6 */
148                 hit->surf = surf;
149                 hit->pos = ray->o;
150                 cgm_vadd_scaled(&hit->pos, &ray->d, t);
151                 hit->lpos = org;
152                 cgm_vadd_scaled(&hit->lpos, &dir, t);
153                 hit->total_dist = ray->total_dist + t;
154         }
155
156         return 1;
157 }
158
159 static void sph_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
160 {
161         float theta, phi;
162
163         hit->norm = hit->lpos;
164         cgm_vnormalize(&hit->norm);
165
166         cgm_uvec_to_sph(&theta, &phi, &hit->norm);
167
168         hit->u = (theta + M_PI) / (2.0 * M_PI);
169         hit->v = phi / M_PI;
170
171         hit->tang.x = hit->norm.z;
172         hit->tang.y = hit->norm.y;
173         hit->tang.z = -hit->norm.x;
174
175         if(surf->node) {
176                 cgm_vmul_m3v3(&hit->norm, surf->node->xform);
177                 cgm_vmul_m3v3(&hit->tang, surf->node->xform);
178         }
179 }
180
181 static void sph_sample(struct erb_surf *surf, cgm_vec3 *pos)
182 {
183         /* TODO */
184 }
185
186 static void sph_bbox(struct erb_surf *surf, struct erb_aabb *bb)
187 {
188         struct sph_data *sdata = (struct sph_data*)surf->data;
189
190         cgm_vcons(&bb->pos, 0, 0, 0);
191         bb->sz.x = bb->sz.y = bb->sz.z = sdata->rad;
192 }
193
194 /* TODO boxen */
195 static int box_isect(struct erb_surf *surf, struct erb_ray *ray, struct erb_hit *hit)
196 {
197         return 0;
198 }
199
200 static void box_hitgeom(struct erb_surf *surf, struct erb_hit *hit)
201 {
202 }
203
204 static void box_sample(struct erb_surf *surf, cgm_vec3 *pos)
205 {
206 }
207
208 static void box_bbox(struct erb_surf *surf, struct erb_aabb *bb)
209 {
210 }