1 /*
2     Copyright (c) 2005-2021 Intel Corporation
3 
4     Licensed under the Apache License, Version 2.0 (the "License");
5     you may not use this file except in compliance with the License.
6     You may obtain a copy of the License at
7 
8         http://www.apache.org/licenses/LICENSE-2.0
9 
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15 */
16 
17 /*
18     The original source for this example is
19     Copyright (c) 1994-2008 John E. Stone
20     All rights reserved.
21 
22     Redistribution and use in source and binary forms, with or without
23     modification, are permitted provided that the following conditions
24     are met:
25     1. Redistributions of source code must retain the above copyright
26        notice, this list of conditions and the following disclaimer.
27     2. Redistributions in binary form must reproduce the above copyright
28        notice, this list of conditions and the following disclaimer in the
29        documentation and/or other materials provided with the distribution.
30     3. The name of the author may not be used to endorse or promote products
31        derived from this software without specific prior written permission.
32 
33     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34     OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36     ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39     OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43     SUCH DAMAGE.
44 */
45 
46 /*
47  * extvol.cpp - Volume rendering helper routines etc.
48  */
49 
50 #include <cstdio>
51 
52 #include "machine.hpp"
53 #include "types.hpp"
54 #include "macros.hpp"
55 #include "vector.hpp"
56 #include "util.hpp"
57 #include "box.hpp"
58 #include "extvol.hpp"
59 #include "trace.hpp"
60 #include "sphere.hpp"
61 #include "light.hpp"
62 #include "shade.hpp"
63 #include "global.hpp"
64 
extvol_bbox(void * obj,vector * min,vector * max)65 int extvol_bbox(void *obj, vector *min, vector *max) {
66     box *b = (box *)obj;
67 
68     *min = b->min;
69     *max = b->max;
70 
71     return 1;
72 }
73 
74 static object_methods extvol_methods = { (void (*)(void *, void *))(box_intersect),
75                                          (void (*)(void *, void *, void *, void *))(box_normal),
76                                          extvol_bbox,
77                                          free };
78 
newextvol(void * voidtex,vector min,vector max,int samples,flt (* evaluator)(flt,flt,flt))79 extvol *newextvol(void *voidtex,
80                   vector min,
81                   vector max,
82                   int samples,
83                   flt (*evaluator)(flt, flt, flt)) {
84     extvol *xvol;
85     texture *tex;
86 
87     tex = (texture *)voidtex;
88 
89     xvol = (extvol *)rt_getmem(sizeof(extvol));
90     memset(xvol, 0, sizeof(extvol));
91 
92     xvol->methods = &extvol_methods;
93 
94     xvol->min = min;
95     xvol->max = max;
96     xvol->evaluator = evaluator;
97     xvol->ambient = tex->ambient;
98     xvol->diffuse = tex->diffuse;
99     xvol->opacity = tex->opacity;
100     xvol->samples = samples;
101 
102     xvol->tex = (texture *)rt_getmem(sizeof(texture));
103     memset(xvol->tex, 0, sizeof(texture));
104 
105     xvol->tex->ctr.x = 0.0;
106     xvol->tex->ctr.y = 0.0;
107     xvol->tex->ctr.z = 0.0;
108     xvol->tex->rot = xvol->tex->ctr;
109     xvol->tex->scale = xvol->tex->ctr;
110     xvol->tex->uaxs = xvol->tex->ctr;
111     xvol->tex->vaxs = xvol->tex->ctr;
112     xvol->tex->islight = 0;
113     xvol->tex->shadowcast = 0;
114 
115     xvol->tex->col = tex->col;
116     xvol->tex->ambient = 1.0;
117     xvol->tex->diffuse = 0.0;
118     xvol->tex->specular = 0.0;
119     xvol->tex->opacity = 1.0;
120     xvol->tex->img = nullptr;
121     xvol->tex->texfunc = (color(*)(void *, void *, void *))(ext_volume_texture);
122     xvol->tex->obj = (void *)xvol; /* XXX hack! */
123 
124     return xvol;
125 }
126 
ExtVoxelColor(flt scalar)127 color ExtVoxelColor(flt scalar) {
128     color col;
129 
130     if (scalar > 1.0)
131         scalar = 1.0;
132 
133     if (scalar < 0.0)
134         scalar = 0.0;
135 
136     if (scalar < 0.5) {
137         col.g = 0.0;
138     }
139     else {
140         col.g = (scalar - 0.5) * 2.0;
141     }
142 
143     col.r = scalar;
144     col.b = 1.0 - (scalar / 2.0);
145 
146     return col;
147 }
148 
ext_volume_texture(vector * hit,texture * tex,ray * ry)149 color ext_volume_texture(vector *hit, texture *tex, ray *ry) {
150     color col, col2;
151     box *bx;
152     extvol *xvol;
153     flt a, tx1, tx2, ty1, ty2, tz1, tz2;
154     flt tnear, tfar;
155     flt t, tdist, dt, ddt, sum, tt;
156     vector pnt, bln;
157     flt scalar, transval;
158     int i;
159     point_light *li;
160     color diffint;
161     vector N, L;
162     flt inten;
163 
164     col.r = 0.0;
165     col.g = 0.0;
166     col.b = 0.0;
167 
168     bx = (box *)tex->obj;
169     xvol = (extvol *)tex->obj;
170 
171     tnear = -FHUGE;
172     tfar = FHUGE;
173 
174     if (ry->d.x == 0.0) {
175         if ((ry->o.x < bx->min.x) || (ry->o.x > bx->max.x))
176             return col;
177     }
178     else {
179         tx1 = (bx->min.x - ry->o.x) / ry->d.x;
180         tx2 = (bx->max.x - ry->o.x) / ry->d.x;
181         if (tx1 > tx2) {
182             a = tx1;
183             tx1 = tx2;
184             tx2 = a;
185         }
186         if (tx1 > tnear)
187             tnear = tx1;
188         if (tx2 < tfar)
189             tfar = tx2;
190     }
191     if (tnear > tfar)
192         return col;
193     if (tfar < 0.0)
194         return col;
195 
196     if (ry->d.y == 0.0) {
197         if ((ry->o.y < bx->min.y) || (ry->o.y > bx->max.y))
198             return col;
199     }
200     else {
201         ty1 = (bx->min.y - ry->o.y) / ry->d.y;
202         ty2 = (bx->max.y - ry->o.y) / ry->d.y;
203         if (ty1 > ty2) {
204             a = ty1;
205             ty1 = ty2;
206             ty2 = a;
207         }
208         if (ty1 > tnear)
209             tnear = ty1;
210         if (ty2 < tfar)
211             tfar = ty2;
212     }
213     if (tnear > tfar)
214         return col;
215     if (tfar < 0.0)
216         return col;
217 
218     if (ry->d.z == 0.0) {
219         if ((ry->o.z < bx->min.z) || (ry->o.z > bx->max.z))
220             return col;
221     }
222     else {
223         tz1 = (bx->min.z - ry->o.z) / ry->d.z;
224         tz2 = (bx->max.z - ry->o.z) / ry->d.z;
225         if (tz1 > tz2) {
226             a = tz1;
227             tz1 = tz2;
228             tz2 = a;
229         }
230         if (tz1 > tnear)
231             tnear = tz1;
232         if (tz2 < tfar)
233             tfar = tz2;
234     }
235     if (tnear > tfar)
236         return col;
237     if (tfar < 0.0)
238         return col;
239 
240     if (tnear < 0.0)
241         tnear = 0.0;
242 
243     tdist = xvol->samples;
244 
245     tt = (xvol->opacity / tdist);
246 
247     bln.x = fabs(bx->min.x - bx->max.x);
248     bln.y = fabs(bx->min.y - bx->max.y);
249     bln.z = fabs(bx->min.z - bx->max.z);
250 
251     dt = 1.0 / tdist;
252     sum = 0.0;
253 
254     /* Accumulate color as the ray passes through the voxels */
255     for (t = tnear; t <= tfar; t += dt) {
256         if (sum < 1.0) {
257             pnt.x = ((ry->o.x + (ry->d.x * t)) - bx->min.x) / bln.x;
258             pnt.y = ((ry->o.y + (ry->d.y * t)) - bx->min.y) / bln.y;
259             pnt.z = ((ry->o.z + (ry->d.z * t)) - bx->min.z) / bln.z;
260 
261             /* call external evaluator assume 0.0 -> 1.0 range.. */
262             scalar = xvol->evaluator(pnt.x, pnt.y, pnt.z);
263 
264             transval = tt * scalar;
265             sum += transval;
266 
267             col2 = ExtVoxelColor(scalar);
268 
269             col.r += transval * col2.r * xvol->ambient;
270             col.g += transval * col2.g * xvol->ambient;
271             col.b += transval * col2.b * xvol->ambient;
272 
273             ddt = dt;
274 
275             /* Add in diffuse shaded light sources (no shadows) */
276             if (xvol->diffuse > 0.0) {
277                 /* Calculate the Volume gradient at the voxel */
278                 N.x = (xvol->evaluator(pnt.x - ddt, pnt.y, pnt.z) -
279                        xvol->evaluator(pnt.x + ddt, pnt.y, pnt.z)) *
280                       8.0 * tt;
281 
282                 N.y = (xvol->evaluator(pnt.x, pnt.y - ddt, pnt.z) -
283                        xvol->evaluator(pnt.x, pnt.y + ddt, pnt.z)) *
284                       8.0 * tt;
285 
286                 N.z = (xvol->evaluator(pnt.x, pnt.y, pnt.z - ddt) -
287                        xvol->evaluator(pnt.x, pnt.y, pnt.z + ddt)) *
288                       8.0 * tt;
289 
290                 /* only light surfaces with enough of a normal.. */
291                 if ((N.x * N.x + N.y * N.y + N.z * N.z) > 0.0) {
292                     diffint.r = 0.0;
293                     diffint.g = 0.0;
294                     diffint.b = 0.0;
295 
296                     /* add the contribution of each of the lights.. */
297                     for (i = 0; i < numlights; i++) {
298                         li = lightlist[i];
299                         VSUB(li->ctr, (*hit), L)
300                         VNorm(&L);
301                         VDOT(inten, N, L)
302 
303                         /* only add light if its from the front of the surface */
304                         /* could add back-lighting if we wanted to later.. */
305                         if (inten > 0.0) {
306                             diffint.r += inten * li->tex->col.r;
307                             diffint.g += inten * li->tex->col.g;
308                             diffint.b += inten * li->tex->col.b;
309                         }
310                     }
311                     col.r += col2.r * diffint.r * xvol->diffuse;
312                     col.g += col2.g * diffint.g * xvol->diffuse;
313                     col.b += col2.b * diffint.b * xvol->diffuse;
314                 }
315             }
316         }
317         else {
318             sum = 1.0;
319         }
320     }
321 
322     /* Add in transmitted ray from outside environment */
323     if (sum < 1.0) { /* spawn transmission rays / refraction */
324         color transcol;
325 
326         transcol = shade_transmission(ry, hit, 1.0 - sum);
327 
328         col.r += transcol.r; /* add the transmitted ray  */
329         col.g += transcol.g; /* to the diffuse and       */
330         col.b += transcol.b; /* transmission total..     */
331     }
332 
333     return col;
334 }
335