picking and brute force ray intersections
[retroray] / src / rt.c
1 /*
2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include "rt.h"
19
20
21 int ray_object(const cgm_ray *ray, const struct object *obj, struct csghit *hit)
22 {
23         int i, res;
24         cgm_ray localray = *ray;
25
26         cgm_rmul_mr(&localray, obj->inv_xform);
27
28         switch(obj->type) {
29         case OBJ_SPHERE:
30                 res = ray_sphere(ray, (const struct sphere*)obj, hit);
31                 break;
32
33         default:
34                 res = 0;
35         }
36
37         if(res && hit) {
38                 for(i=0; i<hit->ivcount; i++) {
39                         cgm_vmul_m4v3(&hit->ivlist[i].a.pos, obj->xform);
40                         cgm_vmul_m3v3(&hit->ivlist[i].a.norm, obj->xform);
41                         cgm_vmul_m4v3(&hit->ivlist[i].b.pos, obj->xform);
42                         cgm_vmul_m3v3(&hit->ivlist[i].b.norm, obj->xform);
43                 }
44         }
45         return res;
46 }
47
48 int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit)
49 {
50         int i;
51         float a, b, c, d, sqrt_d, t1, t2, invrad;
52         struct rayhit *rhptr;
53
54         a = cgm_vdot(&ray->dir, &ray->dir);
55         b = 2.0f * ray->dir.x * (ray->origin.x - sph->pos.x) +
56                 2.0f * ray->dir.y * (ray->origin.y - sph->pos.y) +
57                 2.0f * ray->dir.z * (ray->origin.z - sph->pos.z);
58         c = cgm_vdot(&sph->pos, &sph->pos) + cgm_vdot(&ray->origin, &ray->origin) +
59                 cgm_vdot(&sph->pos, &ray->origin) * -2.0f - sph->rad * sph->rad;
60
61         if((d = b * b - 4.0 * a * c) < 0.0) return 0;
62
63         sqrt_d = sqrt(d);
64         t1 = (-b + sqrt_d) / (2.0 * a);
65         t2 = (-b - sqrt_d) / (2.0 * a);
66
67         if((t1 < 1e-6f && t2 < 1e-6f) || (t1 > 1.0f && t2 > 1.0f)) {
68                 return 0;
69         }
70
71         if(hit) {
72                 if(t1 < 1e-6f || t1 > 1.0f) {
73                         t1 = t2;
74                 } else if(t2 < 1e-6f || t2 > 1.0f) {
75                         t2 = t1;
76                 }
77                 if(t2 < t1) {
78                         float tmp = t1;
79                         t1 = t2;
80                         t2 = tmp;
81                 }
82
83                 hit->ivcount = 1;
84                 hit->ivlist[0].a.t = t1;
85                 hit->ivlist[0].b.t = t2;
86                 invrad = 1.0f / sph->rad;
87
88                 rhptr = &hit->ivlist[0].a;
89                 for(i=0; i<2; i++) {
90                         cgm_raypos(&rhptr->pos, ray, rhptr->t);
91                         rhptr->norm.x = rhptr->pos.x * invrad;
92                         rhptr->norm.y = rhptr->pos.y * invrad;
93                         rhptr->norm.z = rhptr->pos.z * invrad;
94                         rhptr->uv.x = (atan2(rhptr->norm.z, rhptr->norm.x) + CGM_PI) / (2.0 * CGM_PI);
95                         rhptr->uv.y = acos(rhptr->norm.y) / CGM_PI;
96                         rhptr->obj = (struct object*)sph;
97                         rhptr = &hit->ivlist[0].b;
98                 }
99         }
100         return 1;
101 }
102
103 int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit)
104 {
105         return 0;
106 }