f917836ad449d2a3cfa395b875b1a7ce5ff05f23
[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 int ray_object(const cgm_ray *ray, const struct object *obj, struct rayhit *hit)
21 {
22         struct csghit csghit;
23
24         if(!ray_object_csg(ray, obj, &csghit)) {
25                 return 0;
26         }
27         if(hit) {
28                 *hit = csghit.ivlist[0].a;
29         }
30         return 1;
31 }
32
33 int ray_object_csg(const cgm_ray *ray, const struct object *obj, struct csghit *hit)
34 {
35         int i, res;
36         cgm_ray localray = *ray;
37
38         cgm_rmul_mr(&localray, obj->inv_xform);
39
40         switch(obj->type) {
41         case OBJ_SPHERE:
42                 res = ray_sphere(ray, (const struct sphere*)obj, hit);
43                 break;
44
45         default:
46                 res = 0;
47         }
48
49         if(res && hit) {
50                 for(i=0; i<hit->ivcount; i++) {
51                         cgm_vmul_m4v3(&hit->ivlist[i].a.pos, obj->xform);
52                         cgm_vmul_m3v3(&hit->ivlist[i].a.norm, obj->xform);
53                         cgm_vmul_m4v3(&hit->ivlist[i].b.pos, obj->xform);
54                         cgm_vmul_m3v3(&hit->ivlist[i].b.norm, obj->xform);
55                 }
56         }
57         return res;
58 }
59
60 int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit)
61 {
62         int i;
63         float a, b, c, d, sqrt_d, t1, t2;/*, invrad;*/
64         struct rayhit *rhptr;
65
66         a = cgm_vdot(&ray->dir, &ray->dir);
67         b = 2.0f * ray->dir.x * (ray->origin.x - sph->pos.x) +
68                 2.0f * ray->dir.y * (ray->origin.y - sph->pos.y) +
69                 2.0f * ray->dir.z * (ray->origin.z - sph->pos.z);
70         c = cgm_vdot(&sph->pos, &sph->pos) + cgm_vdot(&ray->origin, &ray->origin) +
71                 cgm_vdot(&sph->pos, &ray->origin) * -2.0f - sph->rad * sph->rad;
72
73         if((d = b * b - 4.0 * a * c) < 0.0) return 0;
74
75         sqrt_d = sqrt(d);
76         t1 = (-b + sqrt_d) / (2.0 * a);
77         t2 = (-b - sqrt_d) / (2.0 * a);
78
79         if((t1 < 1e-6f && t2 < 1e-6f) || (t1 > 1.0f && t2 > 1.0f)) {
80                 return 0;
81         }
82
83         if(hit) {
84                 if(t1 < 1e-6f || t1 > 1.0f) {
85                         t1 = t2;
86                 } else if(t2 < 1e-6f || t2 > 1.0f) {
87                         t2 = t1;
88                 }
89                 if(t2 < t1) {
90                         float tmp = t1;
91                         t1 = t2;
92                         t2 = tmp;
93                 }
94
95                 hit->ivcount = 1;
96                 hit->ivlist[0].a.t = t1;
97                 hit->ivlist[0].b.t = t2;
98                 /*invrad = 1.0f / sph->rad;*/
99
100                 rhptr = &hit->ivlist[0].a;
101                 for(i=0; i<2; i++) {
102                         cgm_raypos(&rhptr->pos, ray, rhptr->t);
103                         rhptr->norm = rhptr->pos;
104                         cgm_vnormalize(&rhptr->norm);
105                         /*rhptr->norm.x = rhptr->pos.x * invrad;
106                         rhptr->norm.y = rhptr->pos.y * invrad;
107                         rhptr->norm.z = rhptr->pos.z * invrad;*/
108                         rhptr->uv.x = (atan2(rhptr->norm.z, rhptr->norm.x) + CGM_PI) / (2.0 * CGM_PI);
109                         rhptr->uv.y = acos(rhptr->norm.y) / CGM_PI;
110                         rhptr->obj = (struct object*)sph;
111                         rhptr = &hit->ivlist[0].b;
112                 }
113         }
114         return 1;
115 }
116
117 int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit)
118 {
119         return 0;
120 }
121
122 float ray_object_dist(const cgm_ray *ray, const struct object *obj)
123 {
124         /*struct rayhit hit;*/
125         cgm_vec3 norm, pvec;
126
127         /*if(ray_object(ray, obj, &hit)) {
128                 return cgm_vdist(&hit.pos, &ray->origin);
129         }*/
130
131         /* if we can't hit the object for some reason, fallback to computing the
132          * distance of obj->pos from the plane perpendicular to the ray at the origin
133          */
134         norm = ray->dir;
135         /*cgm_vnormalize(&norm);*/
136         pvec = obj->pos;
137         cgm_vsub(&pvec, &ray->origin);
138         return cgm_vdot(&pvec, &norm);
139 }