2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023 John Tsiombikas <nuclear@mutantstargoat.com>
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.
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.
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/>.
25 static int calc_light(const struct rayhit *hit, const struct light *lt,
26 const cgm_vec3 *vdir, cgm_vec3 *dcol, cgm_vec3 *scol);
28 struct img_pixmap renderbuf;
33 static int rx, ry, rwidth, rheight;
35 static int xstep, ystep;
36 static int pan_x, pan_y;
38 static struct light def_light = {0, {0, 0, 0}, {1, 1, 1}};
45 cgm_vcons(&ambient, 0.05, 0.05, 0.05);
47 rx = ry = rwidth = rheight = roffs = 0;
54 void rend_destroy(void)
56 img_destroy(&renderbuf);
59 void rend_size(int xsz, int ysz)
61 if(xsz != renderbuf.width || ysz != renderbuf.height) {
62 img_set_pixels(&renderbuf, xsz, ysz, IMG_FMT_RGBA32, 0);
66 void rend_pan(int xoffs, int yoffs)
72 void rend_begin(int x, int y, int w, int h)
77 if(w == 0 || h == 0) {
79 rwidth = renderbuf.width;
80 rheight = renderbuf.height;
87 roffs = ry * renderbuf.width + rx;
92 ptr = (uint32_t*)renderbuf.pixels + roffs;
93 for(i=0; i<rheight; i++) {
94 memset(ptr, 0, rwidth * sizeof *ptr);
95 ptr += renderbuf.width;
99 static void fillrect(uint32_t *fb, int x, int y, int w, int h, uint32_t c)
103 fb += y * renderbuf.width + x;
108 fb += renderbuf.width;
112 int render(uint32_t *fb)
114 int i, j, w, h, offs, r, g, b;
115 uint32_t *dest, pcol;
119 dest = (uint32_t*)renderbuf.pixels + roffs;
124 if(xstep < 1) xstep = 1;
125 if(ystep < 1) ystep = 1;
127 if(scn_num_lights(scn) == 0) {
128 primray(&ray, renderbuf.width / 2, renderbuf.height / 2);
129 def_light.pos = ray.origin;
132 for(i=0; i<rheight; i+=ystep) {
134 if(i + h > rheight) h = rheight - i;
136 for(j=0; j<rwidth; j+=xstep) {
137 primray(&ray, rx + j + pan_x, ry + i + pan_y);
138 ray_trace(&ray, max_ray_depth, &color);
140 if(color.x > 1.0f) color.x = 1.0f;
141 if(color.y > 1.0f) color.y = 1.0f;
142 if(color.z > 1.0f) color.z = 1.0f;
143 r = cround64(color.x * 255.0f);
144 g = cround64(color.y * 255.0f);
145 b = cround64(color.z * 255.0f);
146 pcol = PACK_RGB32(r, g, b);
148 offs = i * renderbuf.width + j;
153 if(j + w > rwidth) w = rwidth - j;
155 fillrect(fb, j, i, w, h, pcol);
163 if((xstep | ystep) >= 1) {
169 int ray_trace(const cgm_ray *ray, int maxiter, cgm_vec3 *res)
173 if(!scn_intersect(scn, ray, &hit)) {
178 *res = shade(ray, &hit, maxiter);
182 cgm_vec3 bgcolor(const cgm_ray *ray)
184 return cgm_vvec(0, 0, 0);
187 cgm_vec3 shade(const cgm_ray *ray, const struct rayhit *hit, int maxiter)
190 cgm_vec3 color, dcol, scol, texel, vdir;
191 struct material *mtl;
195 cgm_vcons(&scol, 0, 0, 0);
201 cgm_vnormalize(&vdir);
203 if(!(num_lights = scn_num_lights(scn))) {
204 calc_light(hit, &def_light, &vdir, &dcol, &scol);
206 for(i=0; i<num_lights; i++) {
208 calc_light(hit, lt, &vdir, &dcol, &scol);
212 texel = mtl->texmap->lookup(mtl->texmap, hit);
213 cgm_vmul(&dcol, &texel);
217 cgm_vadd(&color, &scol);
221 static int calc_light(const struct rayhit *hit, const struct light *lt,
222 const cgm_vec3 *vdir, cgm_vec3 *dcol, cgm_vec3 *scol)
224 float ndotl, ndoth, spec;
227 struct material *mtl = hit->obj->mtl;
230 cgm_vsub(&ldir, &hit->pos);
232 ray.origin = hit->pos;
235 if(scn_intersect(scn, &ray, 0)) {
236 return 0; /* in shadow */
239 cgm_vnormalize(&ldir);
242 cgm_vadd(&hdir, &ldir);
243 cgm_vnormalize(&hdir);
245 ndotl = cgm_vdot(&hit->norm, &ldir);
246 if(ndotl < 0.0f) ndotl = 0.0f;
247 ndoth = cgm_vdot(&hit->norm, &hdir);
248 if(ndoth < 0.0f) ndoth = 0.0f;
250 spec = pow(ndoth, mtl->shin);
252 dcol->x += mtl->kd.x * ndotl * lt->color.x;
253 dcol->y += mtl->kd.y * ndotl * lt->color.y;
254 dcol->z += mtl->kd.z * ndotl * lt->color.z;
256 scol->x += mtl->ks.x * spec * lt->color.x;
257 scol->y += mtl->ks.y * spec * lt->color.y;
258 scol->z += mtl->ks.z * spec * lt->color.z;