1d86ed7fbStbbdev /*
2*b15aabb3Stbbdev     Copyright (c) 2005-2021 Intel Corporation
3d86ed7fbStbbdev 
4d86ed7fbStbbdev     Licensed under the Apache License, Version 2.0 (the "License");
5d86ed7fbStbbdev     you may not use this file except in compliance with the License.
6d86ed7fbStbbdev     You may obtain a copy of the License at
7d86ed7fbStbbdev 
8d86ed7fbStbbdev         http://www.apache.org/licenses/LICENSE-2.0
9d86ed7fbStbbdev 
10d86ed7fbStbbdev     Unless required by applicable law or agreed to in writing, software
11d86ed7fbStbbdev     distributed under the License is distributed on an "AS IS" BASIS,
12d86ed7fbStbbdev     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13d86ed7fbStbbdev     See the License for the specific language governing permissions and
14d86ed7fbStbbdev     limitations under the License.
15d86ed7fbStbbdev */
16d86ed7fbStbbdev 
17d86ed7fbStbbdev /*
18d86ed7fbStbbdev     The original source for this example is
19d86ed7fbStbbdev     Copyright (c) 1994-2008 John E. Stone
20d86ed7fbStbbdev     All rights reserved.
21d86ed7fbStbbdev 
22d86ed7fbStbbdev     Redistribution and use in source and binary forms, with or without
23d86ed7fbStbbdev     modification, are permitted provided that the following conditions
24d86ed7fbStbbdev     are met:
25d86ed7fbStbbdev     1. Redistributions of source code must retain the above copyright
26d86ed7fbStbbdev        notice, this list of conditions and the following disclaimer.
27d86ed7fbStbbdev     2. Redistributions in binary form must reproduce the above copyright
28d86ed7fbStbbdev        notice, this list of conditions and the following disclaimer in the
29d86ed7fbStbbdev        documentation and/or other materials provided with the distribution.
30d86ed7fbStbbdev     3. The name of the author may not be used to endorse or promote products
31d86ed7fbStbbdev        derived from this software without specific prior written permission.
32d86ed7fbStbbdev 
33d86ed7fbStbbdev     THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
34d86ed7fbStbbdev     OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
35d86ed7fbStbbdev     WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36d86ed7fbStbbdev     ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
37d86ed7fbStbbdev     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
38d86ed7fbStbbdev     DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
39d86ed7fbStbbdev     OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40d86ed7fbStbbdev     HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
41d86ed7fbStbbdev     LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
42d86ed7fbStbbdev     OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
43d86ed7fbStbbdev     SUCH DAMAGE.
44d86ed7fbStbbdev */
45d86ed7fbStbbdev 
46d86ed7fbStbbdev /*
47d86ed7fbStbbdev  * shade.cpp - This file contains the functions that perform surface shading.
48d86ed7fbStbbdev  */
49d86ed7fbStbbdev 
50d86ed7fbStbbdev #include "machine.hpp"
51d86ed7fbStbbdev #include "types.hpp"
52d86ed7fbStbbdev #include "macros.hpp"
53d86ed7fbStbbdev #include "light.hpp"
54d86ed7fbStbbdev #include "intersect.hpp"
55d86ed7fbStbbdev #include "vector.hpp"
56d86ed7fbStbbdev #include "trace.hpp"
57d86ed7fbStbbdev #include "global.hpp"
58d86ed7fbStbbdev #include "shade.hpp"
59d86ed7fbStbbdev 
reset_lights(void)60d86ed7fbStbbdev void reset_lights(void) {
61d86ed7fbStbbdev     numlights = 0;
62d86ed7fbStbbdev }
63d86ed7fbStbbdev 
add_light(point_light * li)64d86ed7fbStbbdev void add_light(point_light* li) {
65d86ed7fbStbbdev     lightlist[numlights] = li;
66d86ed7fbStbbdev     numlights++;
67d86ed7fbStbbdev }
68d86ed7fbStbbdev 
shader(ray * incident)69d86ed7fbStbbdev color shader(ray* incident) {
70d86ed7fbStbbdev     color col, diffuse, phongcol;
71d86ed7fbStbbdev     vector N, L, hit;
72d86ed7fbStbbdev     ray shadowray;
73d86ed7fbStbbdev     flt inten, t, Llen;
74d86ed7fbStbbdev     object* obj;
75d86ed7fbStbbdev     int numints, i;
76d86ed7fbStbbdev     point_light* li;
77d86ed7fbStbbdev 
78d86ed7fbStbbdev     numints = closest_intersection(&t, &obj, incident->intstruct);
79d86ed7fbStbbdev     /* find the number of intersections */
80d86ed7fbStbbdev     /* and return the closest one.      */
81d86ed7fbStbbdev 
82d86ed7fbStbbdev     if (numints < 1) {
83d86ed7fbStbbdev         /* if there weren't any object intersections then return the */
84d86ed7fbStbbdev         /* background color for the pixel color.                     */
85d86ed7fbStbbdev         return incident->scene->background;
86d86ed7fbStbbdev     }
87d86ed7fbStbbdev 
88d86ed7fbStbbdev     if (obj->tex->islight) { /* if the current object is a light, then we   */
89d86ed7fbStbbdev         return obj->tex->col; /* will only use the objects ambient color    */
90d86ed7fbStbbdev     }
91d86ed7fbStbbdev 
92d86ed7fbStbbdev     RAYPNT(hit, (*incident), t) /* find the point of intersection from t */
93d86ed7fbStbbdev     obj->methods->normal(obj, &hit, incident, &N); /* find the surface normal */
94d86ed7fbStbbdev 
95d86ed7fbStbbdev     /* execute the object's texture function */
96d86ed7fbStbbdev     col = obj->tex->texfunc(&hit, obj->tex, incident);
97d86ed7fbStbbdev 
98d86ed7fbStbbdev     diffuse.r = 0.0;
99d86ed7fbStbbdev     diffuse.g = 0.0;
100d86ed7fbStbbdev     diffuse.b = 0.0;
101d86ed7fbStbbdev     phongcol = diffuse;
102d86ed7fbStbbdev 
103d86ed7fbStbbdev     if ((obj->tex->diffuse > 0.0) || (obj->tex->phong > 0.0)) {
104d86ed7fbStbbdev         for (i = 0; i < numlights; i++) { /* loop for light contributions */
105d86ed7fbStbbdev             li = lightlist[i]; /* set li=to the current light */
106d86ed7fbStbbdev             VSUB(li->ctr, hit, L) /* find the light vector */
107d86ed7fbStbbdev 
108d86ed7fbStbbdev             /* calculate the distance to the light from the hit point */
109d86ed7fbStbbdev             Llen = sqrt(L.x * L.x + L.y * L.y + L.z * L.z) + EPSILON;
110d86ed7fbStbbdev 
111d86ed7fbStbbdev             L.x /= Llen; /* normalize the light direction vector */
112d86ed7fbStbbdev             L.y /= Llen;
113d86ed7fbStbbdev             L.z /= Llen;
114d86ed7fbStbbdev 
115d86ed7fbStbbdev             VDOT(inten, N, L) /* light intensity */
116d86ed7fbStbbdev 
117d86ed7fbStbbdev             /* add in diffuse lighting for this light if we're facing it */
118d86ed7fbStbbdev             if (inten > 0.0) {
119d86ed7fbStbbdev                 /* test for a shadow */
120d86ed7fbStbbdev                 shadowray.intstruct = incident->intstruct;
121d86ed7fbStbbdev                 shadowray.flags = RT_RAY_SHADOW | RT_RAY_BOUNDED;
122d86ed7fbStbbdev                 incident->serial++;
123d86ed7fbStbbdev                 shadowray.serial = incident->serial;
124d86ed7fbStbbdev                 shadowray.mbox = incident->mbox;
125d86ed7fbStbbdev                 shadowray.o = hit;
126d86ed7fbStbbdev                 shadowray.d = L;
127d86ed7fbStbbdev                 shadowray.maxdist = Llen;
128d86ed7fbStbbdev                 shadowray.s = hit;
129d86ed7fbStbbdev                 shadowray.e = li->ctr;
130d86ed7fbStbbdev                 shadowray.scene = incident->scene;
131d86ed7fbStbbdev                 reset_intersection(incident->intstruct);
132d86ed7fbStbbdev                 intersect_objects(&shadowray);
133d86ed7fbStbbdev 
134d86ed7fbStbbdev                 if (!shadow_intersection(incident->intstruct, Llen)) {
135d86ed7fbStbbdev                     /* XXX now that opacity is in the code, have to be more careful */
136d86ed7fbStbbdev                     ColorAddS(&diffuse, &li->tex->col, inten);
137d86ed7fbStbbdev 
138d86ed7fbStbbdev                     /* phong type specular highlights */
139d86ed7fbStbbdev                     if (obj->tex->phong > 0.0) {
140d86ed7fbStbbdev                         flt phongval;
141d86ed7fbStbbdev                         phongval = shade_phong(incident, &hit, &N, &L, obj->tex->phongexp);
142d86ed7fbStbbdev                         if (obj->tex->phongtype)
143d86ed7fbStbbdev                             ColorAddS(&phongcol, &col, phongval);
144d86ed7fbStbbdev                         else
145d86ed7fbStbbdev                             ColorAddS(&phongcol, &(li->tex->col), phongval);
146d86ed7fbStbbdev                     }
147d86ed7fbStbbdev                 }
148d86ed7fbStbbdev             }
149d86ed7fbStbbdev         }
150d86ed7fbStbbdev     }
151d86ed7fbStbbdev 
152d86ed7fbStbbdev     ColorScale(&diffuse, obj->tex->diffuse);
153d86ed7fbStbbdev 
154d86ed7fbStbbdev     col.r *= (diffuse.r + obj->tex->ambient); /* do a product of the */
155d86ed7fbStbbdev     col.g *= (diffuse.g + obj->tex->ambient); /* diffuse intensity with */
156d86ed7fbStbbdev     col.b *= (diffuse.b + obj->tex->ambient); /* object color + ambient */
157d86ed7fbStbbdev 
158d86ed7fbStbbdev     if (obj->tex->phong > 0.0) {
159d86ed7fbStbbdev         ColorAccum(&col, &phongcol);
160d86ed7fbStbbdev     }
161d86ed7fbStbbdev 
162d86ed7fbStbbdev     /* spawn reflection rays if necessary */
163d86ed7fbStbbdev     /* note: this will overwrite the old intersection list */
164d86ed7fbStbbdev     if (obj->tex->specular > 0.0) {
165d86ed7fbStbbdev         color specol;
166d86ed7fbStbbdev         specol = shade_reflection(incident, &hit, &N, obj->tex->specular);
167d86ed7fbStbbdev         ColorAccum(&col, &specol);
168d86ed7fbStbbdev     }
169d86ed7fbStbbdev 
170d86ed7fbStbbdev     /* spawn transmission rays / refraction */
171d86ed7fbStbbdev     /* note: this will overwrite the old intersection list */
172d86ed7fbStbbdev     if (obj->tex->opacity < 1.0) {
173d86ed7fbStbbdev         color transcol;
174d86ed7fbStbbdev         transcol = shade_transmission(incident, &hit, 1.0 - obj->tex->opacity);
175d86ed7fbStbbdev         ColorAccum(&col, &transcol);
176d86ed7fbStbbdev     }
177d86ed7fbStbbdev 
178d86ed7fbStbbdev     return col; /* return the color of the shaded pixel... */
179d86ed7fbStbbdev }
180d86ed7fbStbbdev 
shade_reflection(ray * incident,vector * hit,vector * N,flt specular)181d86ed7fbStbbdev color shade_reflection(ray* incident, vector* hit, vector* N, flt specular) {
182d86ed7fbStbbdev     ray specray;
183d86ed7fbStbbdev     color col;
184d86ed7fbStbbdev     vector R;
185d86ed7fbStbbdev 
186d86ed7fbStbbdev     VAddS(-2.0 * (incident->d.x * N->x + incident->d.y * N->y + incident->d.z * N->z),
187d86ed7fbStbbdev           N,
188d86ed7fbStbbdev           &incident->d,
189d86ed7fbStbbdev           &R);
190d86ed7fbStbbdev 
191d86ed7fbStbbdev     specray.intstruct = incident->intstruct; /* what thread are we */
192d86ed7fbStbbdev     specray.depth = incident->depth - 1; /* go up a level in recursion depth */
193d86ed7fbStbbdev     specray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
194d86ed7fbStbbdev     specray.serial = incident->serial + 1; /* next serial number */
195d86ed7fbStbbdev     specray.mbox = incident->mbox;
196d86ed7fbStbbdev     specray.o = *hit;
197d86ed7fbStbbdev     specray.d = R; /* reflect incident ray about normal */
198d86ed7fbStbbdev     specray.o = Raypnt(&specray, EPSILON); /* avoid numerical precision bugs */
199d86ed7fbStbbdev     specray.maxdist = FHUGE; /* take any intersection */
200d86ed7fbStbbdev     specray.scene = incident->scene; /* global scenedef info */
201d86ed7fbStbbdev     col = trace(&specray); /* trace specular reflection ray */
202d86ed7fbStbbdev 
203d86ed7fbStbbdev     incident->serial = specray.serial; /* update the serial number */
204d86ed7fbStbbdev 
205d86ed7fbStbbdev     ColorScale(&col, specular);
206d86ed7fbStbbdev 
207d86ed7fbStbbdev     return col;
208d86ed7fbStbbdev }
209d86ed7fbStbbdev 
shade_transmission(ray * incident,vector * hit,flt trans)210d86ed7fbStbbdev color shade_transmission(ray* incident, vector* hit, flt trans) {
211d86ed7fbStbbdev     ray transray;
212d86ed7fbStbbdev     color col;
213d86ed7fbStbbdev 
214d86ed7fbStbbdev     transray.intstruct = incident->intstruct; /* what thread are we   */
215d86ed7fbStbbdev     transray.depth = incident->depth - 1; /* go up a level in recursion depth */
216d86ed7fbStbbdev     transray.flags = RT_RAY_REGULAR; /* infinite ray, to start with */
217d86ed7fbStbbdev     transray.serial = incident->serial + 1; /* update serial number */
218d86ed7fbStbbdev     transray.mbox = incident->mbox;
219d86ed7fbStbbdev     transray.o = *hit;
220d86ed7fbStbbdev     transray.d = incident->d; /* ray continues along incident path */
221d86ed7fbStbbdev     transray.o = Raypnt(&transray, EPSILON); /* avoid numerical precision bugs */
222d86ed7fbStbbdev     transray.maxdist = FHUGE; /* take any intersection */
223d86ed7fbStbbdev     transray.scene = incident->scene; /* global scenedef info */
224d86ed7fbStbbdev     col = trace(&transray); /* trace transmission ray */
225d86ed7fbStbbdev 
226d86ed7fbStbbdev     incident->serial = transray.serial;
227d86ed7fbStbbdev 
228d86ed7fbStbbdev     ColorScale(&col, trans);
229d86ed7fbStbbdev 
230d86ed7fbStbbdev     return col;
231d86ed7fbStbbdev }
232d86ed7fbStbbdev 
shade_phong(ray * incident,vector * hit,vector * N,vector * L,flt specpower)233d86ed7fbStbbdev flt shade_phong(ray* incident, vector* hit, vector* N, vector* L, flt specpower) {
234d86ed7fbStbbdev     vector H, V;
235d86ed7fbStbbdev     flt inten;
236d86ed7fbStbbdev 
237d86ed7fbStbbdev     V = incident->d;
238d86ed7fbStbbdev     VScale(&V, -1.0);
239d86ed7fbStbbdev     VAdd(&V, L, &H);
240d86ed7fbStbbdev     VScale(&H, 0.5);
241d86ed7fbStbbdev     VNorm(&H);
242d86ed7fbStbbdev     inten = VDot(N, &H);
243d86ed7fbStbbdev     if (inten > 0.0)
244d86ed7fbStbbdev         inten = pow(inten, specpower);
245d86ed7fbStbbdev     else
246d86ed7fbStbbdev         inten = 0.0;
247d86ed7fbStbbdev 
248d86ed7fbStbbdev     return inten;
249d86ed7fbStbbdev }
250