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  * shade.cpp - This file contains the functions that perform surface shading.
48  */
49 
50 #include "machine.hpp"
51 #include "types.hpp"
52 #include "macros.hpp"
53 #include "light.hpp"
54 #include "intersect.hpp"
55 #include "vector.hpp"
56 #include "trace.hpp"
57 #include "global.hpp"
58 #include "shade.hpp"
59 
reset_lights(void)60 void reset_lights(void) {
61     numlights = 0;
62 }
63 
add_light(point_light * li)64 void add_light(point_light* li) {
65     lightlist[numlights] = li;
66     numlights++;
67 }
68 
shader(ray * incident)69 color shader(ray* incident) {
70     color col, diffuse, phongcol;
71     vector N, L, hit;
72     ray shadowray;
73     flt inten, t, Llen;
74     object* obj;
75     int numints, i;
76     point_light* li;
77 
78     numints = closest_intersection(&t, &obj, incident->intstruct);
79     /* find the number of intersections */
80     /* and return the closest one.      */
81 
82     if (numints < 1) {
83         /* if there weren't any object intersections then return the */
84         /* background color for the pixel color.                     */
85         return incident->scene->background;
86     }
87 
88     if (obj->tex->islight) { /* if the current object is a light, then we   */
89         return obj->tex->col; /* will only use the objects ambient color    */
90     }
91 
92     RAYPNT(hit, (*incident), t) /* find the point of intersection from t */
93     obj->methods->normal(obj, &hit, incident, &N); /* find the surface normal */
94 
95     /* execute the object's texture function */
96     col = obj->tex->texfunc(&hit, obj->tex, incident);
97 
98     diffuse.r = 0.0;
99     diffuse.g = 0.0;
100     diffuse.b = 0.0;
101     phongcol = diffuse;
102 
103     if ((obj->tex->diffuse > 0.0) || (obj->tex->phong > 0.0)) {
104         for (i = 0; i < numlights; i++) { /* loop for light contributions */
105             li = lightlist[i]; /* set li=to the current light */
106             VSUB(li->ctr, hit, L) /* find the light vector */
107 
108             /* calculate the distance to the light from the hit point */
109             Llen = sqrt(L.x * L.x + L.y * L.y + L.z * L.z) + EPSILON;
110 
111             L.x /= Llen; /* normalize the light direction vector */
112             L.y /= Llen;
113             L.z /= Llen;
114 
115             VDOT(inten, N, L) /* light intensity */
116 
117             /* add in diffuse lighting for this light if we're facing it */
118             if (inten > 0.0) {
119                 /* test for a shadow */
120                 shadowray.intstruct = incident->intstruct;
121                 shadowray.flags = RT_RAY_SHADOW | RT_RAY_BOUNDED;
122                 incident->serial++;
123                 shadowray.serial = incident->serial;
124                 shadowray.mbox = incident->mbox;
125                 shadowray.o = hit;
126                 shadowray.d = L;
127                 shadowray.maxdist = Llen;
128                 shadowray.s = hit;
129                 shadowray.e = li->ctr;
130                 shadowray.scene = incident->scene;
131                 reset_intersection(incident->intstruct);
132                 intersect_objects(&shadowray);
133 
134                 if (!shadow_intersection(incident->intstruct, Llen)) {
135                     /* XXX now that opacity is in the code, have to be more careful */
136                     ColorAddS(&diffuse, &li->tex->col, inten);
137 
138                     /* phong type specular highlights */
139                     if (obj->tex->phong > 0.0) {
140                         flt phongval;
141                         phongval = shade_phong(incident, &hit, &N, &L, obj->tex->phongexp);
142                         if (obj->tex->phongtype)
143                             ColorAddS(&phongcol, &col, phongval);
144                         else
145                             ColorAddS(&phongcol, &(li->tex->col), phongval);
146                     }
147                 }
148             }
149         }
150     }
151 
152     ColorScale(&diffuse, obj->tex->diffuse);
153 
154     col.r *= (diffuse.r + obj->tex->ambient); /* do a product of the */
155     col.g *= (diffuse.g + obj->tex->ambient); /* diffuse intensity with */
156     col.b *= (diffuse.b + obj->tex->ambient); /* object color + ambient */
157 
158     if (obj->tex->phong > 0.0) {
159         ColorAccum(&col, &phongcol);
160     }
161 
162     /* spawn reflection rays if necessary */
163     /* note: this will overwrite the old intersection list */
164     if (obj->tex->specular > 0.0) {
165         color specol;
166         specol = shade_reflection(incident, &hit, &N, obj->tex->specular);
167         ColorAccum(&col, &specol);
168     }
169 
170     /* spawn transmission rays / refraction */
171     /* note: this will overwrite the old intersection list */
172     if (obj->tex->opacity < 1.0) {
173         color transcol;
174         transcol = shade_transmission(incident, &hit, 1.0 - obj->tex->opacity);
175         ColorAccum(&col, &transcol);
176     }
177 
178     return col; /* return the color of the shaded pixel... */
179 }
180 
shade_reflection(ray * incident,vector * hit,vector * N,flt specular)181 color shade_reflection(ray* incident, vector* hit, vector* N, flt specular) {
182     ray specray;
183     color col;
184     vector R;
185 
186     VAddS(-2.0 * (incident->d.x * N->x + incident->d.y * N->y + incident->d.z * N->z),
187           N,
188           &incident->d,
189           &R);
190 
191     specray.intstruct = incident->intstruct; /* what thread are we */
192     specray.depth = incident->depth - 1; /* go up a level in recursion depth */
193     specray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
194     specray.serial = incident->serial + 1; /* next serial number */
195     specray.mbox = incident->mbox;
196     specray.o = *hit;
197     specray.d = R; /* reflect incident ray about normal */
198     specray.o = Raypnt(&specray, EPSILON); /* avoid numerical precision bugs */
199     specray.maxdist = FHUGE; /* take any intersection */
200     specray.scene = incident->scene; /* global scenedef info */
201     col = trace(&specray); /* trace specular reflection ray */
202 
203     incident->serial = specray.serial; /* update the serial number */
204 
205     ColorScale(&col, specular);
206 
207     return col;
208 }
209 
shade_transmission(ray * incident,vector * hit,flt trans)210 color shade_transmission(ray* incident, vector* hit, flt trans) {
211     ray transray;
212     color col;
213 
214     transray.intstruct = incident->intstruct; /* what thread are we   */
215     transray.depth = incident->depth - 1; /* go up a level in recursion depth */
216     transray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
217     transray.serial = incident->serial + 1; /* update serial number */
218     transray.mbox = incident->mbox;
219     transray.o = *hit;
220     transray.d = incident->d; /* ray continues along incident path */
221     transray.o = Raypnt(&transray, EPSILON); /* avoid numerical precision bugs */
222     transray.maxdist = FHUGE; /* take any intersection */
223     transray.scene = incident->scene; /* global scenedef info */
224     col = trace(&transray); /* trace transmission ray */
225 
226     incident->serial = transray.serial;
227 
228     ColorScale(&col, trans);
229 
230     return col;
231 }
232 
shade_phong(ray * incident,vector * hit,vector * N,vector * L,flt specpower)233 flt shade_phong(ray* incident, vector* hit, vector* N, vector* L, flt specpower) {
234     vector H, V;
235     flt inten;
236 
237     V = incident->d;
238     VScale(&V, -1.0);
239     VAdd(&V, L, &H);
240     VScale(&H, 0.5);
241     VNorm(&H);
242     inten = VDot(N, &H);
243     if (inten > 0.0)
244         inten = pow(inten, specpower);
245     else
246         inten = 0.0;
247 
248     return inten;
249 }
250