first render
[retroray] / src / geom.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 "geom.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(&localray, (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 #define EPSILON 1e-5
61
62 int ray_sphere(const cgm_ray *ray, const struct sphere *sph, struct csghit *hit)
63 {
64         int i;
65         float a, b, c, d, sqrt_d, t1, t2;/*, invrad;*/
66         struct rayhit *rhptr;
67
68         a = cgm_vdot(&ray->dir, &ray->dir);
69         b = 2.0f * ray->dir.x * ray->origin.x +
70                 2.0f * ray->dir.y * ray->origin.y +
71                 2.0f * ray->dir.z * ray->origin.z;
72         c = cgm_vdot(&ray->origin, &ray->origin) - sph->rad * sph->rad;
73
74         if((d = b * b - 4.0 * a * c) < 0.0) return 0;
75
76         sqrt_d = sqrt(d);
77         t1 = (-b + sqrt_d) / (2.0 * a);
78         t2 = (-b - sqrt_d) / (2.0 * a);
79
80         if((t1 < EPSILON && t2 < EPSILON) || (t1 > 1.0f && t2 > 1.0f)) {
81                 return 0;
82         }
83
84         if(hit) {
85                 if(t1 < EPSILON || t1 > 1.0f) {
86                         t1 = t2;
87                 } else if(t2 < EPSILON || t2 > 1.0f) {
88                         t2 = t1;
89                 }
90                 if(t2 < t1) {
91                         float tmp = t1;
92                         t1 = t2;
93                         t2 = tmp;
94                 }
95
96                 hit->ivcount = 1;
97                 hit->ivlist[0].a.t = t1;
98                 hit->ivlist[0].b.t = t2;
99                 /*invrad = 1.0f / sph->rad;*/
100
101                 rhptr = &hit->ivlist[0].a;
102                 for(i=0; i<2; i++) {
103                         cgm_raypos(&rhptr->pos, ray, rhptr->t);
104                         rhptr->norm = rhptr->pos;
105                         cgm_vnormalize(&rhptr->norm);
106                         /*rhptr->norm.x = rhptr->pos.x * invrad;
107                         rhptr->norm.y = rhptr->pos.y * invrad;
108                         rhptr->norm.z = rhptr->pos.z * invrad;*/
109                         rhptr->uv.x = (atan2(rhptr->norm.z, rhptr->norm.x) + CGM_PI) / (2.0 * CGM_PI);
110                         rhptr->uv.y = acos(rhptr->norm.y) / CGM_PI;
111                         rhptr->obj = (struct object*)sph;
112                         rhptr = &hit->ivlist[0].b;
113                 }
114         }
115         return 1;
116 }
117
118 int ray_csg(const cgm_ray *ray, const struct csgnode *csg, struct csghit *hit)
119 {
120         return 0;
121 }
122
123 float ray_object_dist(const cgm_ray *ray, const struct object *obj)
124 {
125         /*struct rayhit hit;*/
126         cgm_vec3 norm, pvec;
127
128         /*if(ray_object(ray, obj, &hit)) {
129                 return cgm_vdist(&hit.pos, &ray->origin);
130         }*/
131
132         /* if we can't hit the object for some reason, fallback to computing the
133          * distance of obj->pos from the plane perpendicular to the ray at the origin
134          */
135         norm = ray->dir;
136         /*cgm_vnormalize(&norm);*/
137         pvec = obj->pos;
138         cgm_vsub(&pvec, &ray->origin);
139         return cgm_vdot(&pvec, &norm);
140 }