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  * grid.cpp - spatial subdivision efficiency structures
48d86ed7fbStbbdev  */
49d86ed7fbStbbdev 
50d86ed7fbStbbdev #include "machine.hpp"
51d86ed7fbStbbdev #include "types.hpp"
52d86ed7fbStbbdev #include "macros.hpp"
53d86ed7fbStbbdev #include "vector.hpp"
54d86ed7fbStbbdev #include "intersect.hpp"
55d86ed7fbStbbdev #include "util.hpp"
56d86ed7fbStbbdev 
57d86ed7fbStbbdev #define GRID_PRIVATE
58d86ed7fbStbbdev #include "grid.hpp"
59d86ed7fbStbbdev 
60d86ed7fbStbbdev #ifndef cbrt
61d86ed7fbStbbdev #define cbrt(x) \
62d86ed7fbStbbdev     ((x) > 0.0 ? pow((double)(x), 1.0 / 3.0) : ((x) < 0.0 ? -pow((double)-(x), 1.0 / 3.0) : 0.0))
63d86ed7fbStbbdev 
64d86ed7fbStbbdev #define qbrt(x) \
65d86ed7fbStbbdev     ((x) > 0.0 ? pow((double)(x), 1.0 / 4.0) : ((x) < 0.0 ? -pow((double)-(x), 1.0 / 4.0) : 0.0))
66d86ed7fbStbbdev 
67d86ed7fbStbbdev #endif
68d86ed7fbStbbdev 
69d86ed7fbStbbdev static object_methods grid_methods = { (void (*)(void *, void *))(grid_intersect),
70d86ed7fbStbbdev                                        (void (*)(void *, void *, void *, void *))(nullptr),
71d86ed7fbStbbdev                                        grid_bbox,
72d86ed7fbStbbdev                                        grid_free };
73d86ed7fbStbbdev 
74d86ed7fbStbbdev extern bool silent_mode;
75d86ed7fbStbbdev 
newgrid(int xsize,int ysize,int zsize,vector min,vector max)76d86ed7fbStbbdev object *newgrid(int xsize, int ysize, int zsize, vector min, vector max) {
77d86ed7fbStbbdev     grid *g;
78d86ed7fbStbbdev 
79d86ed7fbStbbdev     g = (grid *)rt_getmem(sizeof(grid));
80d86ed7fbStbbdev     memset(g, 0, sizeof(grid));
81d86ed7fbStbbdev 
82d86ed7fbStbbdev     g->methods = &grid_methods;
83d86ed7fbStbbdev     g->id = new_objectid();
84d86ed7fbStbbdev 
85d86ed7fbStbbdev     g->xsize = xsize;
86d86ed7fbStbbdev     g->ysize = ysize;
87d86ed7fbStbbdev     g->zsize = zsize;
88d86ed7fbStbbdev 
89d86ed7fbStbbdev     g->min = min;
90d86ed7fbStbbdev     g->max = max;
91d86ed7fbStbbdev 
92d86ed7fbStbbdev     VSub(&g->max, &g->min, &g->voxsize);
93d86ed7fbStbbdev     g->voxsize.x /= (flt)g->xsize;
94d86ed7fbStbbdev     g->voxsize.y /= (flt)g->ysize;
95d86ed7fbStbbdev     g->voxsize.z /= (flt)g->zsize;
96d86ed7fbStbbdev 
97d86ed7fbStbbdev     g->cells = (objectlist **)rt_getmem(xsize * ysize * zsize * sizeof(objectlist *));
98d86ed7fbStbbdev     memset(g->cells, 0, xsize * ysize * zsize * sizeof(objectlist *));
99d86ed7fbStbbdev 
100d86ed7fbStbbdev     /* fprintf(stderr, "New grid, size: %8d %8d %8d\n", g->xsize, g->ysize, g->zsize); */
101d86ed7fbStbbdev 
102d86ed7fbStbbdev     return (object *)g;
103d86ed7fbStbbdev }
104d86ed7fbStbbdev 
grid_bbox(void * obj,vector * min,vector * max)105d86ed7fbStbbdev static int grid_bbox(void *obj, vector *min, vector *max) {
106d86ed7fbStbbdev     grid *g = (grid *)obj;
107d86ed7fbStbbdev 
108d86ed7fbStbbdev     *min = g->min;
109d86ed7fbStbbdev     *max = g->max;
110d86ed7fbStbbdev 
111d86ed7fbStbbdev     return 1;
112d86ed7fbStbbdev }
113d86ed7fbStbbdev 
grid_free(void * v)114d86ed7fbStbbdev static void grid_free(void *v) {
115d86ed7fbStbbdev     int i, numvoxels;
116d86ed7fbStbbdev     grid *g = (grid *)v;
117d86ed7fbStbbdev 
118d86ed7fbStbbdev     /* loop through all voxels and free the object lists */
119d86ed7fbStbbdev     numvoxels = g->xsize * g->ysize * g->zsize;
120d86ed7fbStbbdev     for (i = 0; i < numvoxels; i++) {
121d86ed7fbStbbdev         objectlist *lcur, *lnext;
122d86ed7fbStbbdev 
123d86ed7fbStbbdev         lcur = g->cells[i];
124d86ed7fbStbbdev         while (lcur != nullptr) {
125d86ed7fbStbbdev             lnext = lcur->next;
126d86ed7fbStbbdev             free(lcur);
127d86ed7fbStbbdev         }
128d86ed7fbStbbdev     }
129d86ed7fbStbbdev 
130d86ed7fbStbbdev     /* free the grid cells */
131d86ed7fbStbbdev     free(g->cells);
132d86ed7fbStbbdev 
133d86ed7fbStbbdev     /* free all objects on the grid object list */
134d86ed7fbStbbdev     free_objects(g->objects);
135d86ed7fbStbbdev 
136d86ed7fbStbbdev     free(g);
137d86ed7fbStbbdev }
138d86ed7fbStbbdev 
globalbound(object ** rootlist,vector * gmin,vector * gmax)139d86ed7fbStbbdev static void globalbound(object **rootlist, vector *gmin, vector *gmax) {
140d86ed7fbStbbdev     vector min, max;
141d86ed7fbStbbdev     object *cur;
142d86ed7fbStbbdev 
143d86ed7fbStbbdev     if (*rootlist == nullptr) /* don't bound non-existent objects */
144d86ed7fbStbbdev         return;
145d86ed7fbStbbdev 
146d86ed7fbStbbdev     gmin->x = FHUGE;
147d86ed7fbStbbdev     gmin->y = FHUGE;
148d86ed7fbStbbdev     gmin->z = FHUGE;
149d86ed7fbStbbdev     gmax->x = -FHUGE;
150d86ed7fbStbbdev     gmax->y = -FHUGE;
151d86ed7fbStbbdev     gmax->z = -FHUGE;
152d86ed7fbStbbdev 
153d86ed7fbStbbdev     cur = *rootlist;
154d86ed7fbStbbdev     while (cur != nullptr) { /* Go! */
155d86ed7fbStbbdev         min.x = -FHUGE;
156d86ed7fbStbbdev         min.y = -FHUGE;
157d86ed7fbStbbdev         min.z = -FHUGE;
158d86ed7fbStbbdev         max.x = FHUGE;
159d86ed7fbStbbdev         max.y = FHUGE;
160d86ed7fbStbbdev         max.z = FHUGE;
161d86ed7fbStbbdev 
162d86ed7fbStbbdev         if (cur->methods->bbox((void *)cur, &min, &max)) {
163d86ed7fbStbbdev             gmin->x = MYMIN(gmin->x, min.x);
164d86ed7fbStbbdev             gmin->y = MYMIN(gmin->y, min.y);
165d86ed7fbStbbdev             gmin->z = MYMIN(gmin->z, min.z);
166d86ed7fbStbbdev 
167d86ed7fbStbbdev             gmax->x = MYMAX(gmax->x, max.x);
168d86ed7fbStbbdev             gmax->y = MYMAX(gmax->y, max.y);
169d86ed7fbStbbdev             gmax->z = MYMAX(gmax->z, max.z);
170d86ed7fbStbbdev         }
171d86ed7fbStbbdev 
172d86ed7fbStbbdev         cur = (object *)cur->nextobj;
173d86ed7fbStbbdev     }
174d86ed7fbStbbdev }
175d86ed7fbStbbdev 
cellbound(grid * g,gridindex * index,vector * cmin,vector * cmax)176d86ed7fbStbbdev static int cellbound(grid *g, gridindex *index, vector *cmin, vector *cmax) {
177d86ed7fbStbbdev     vector min, max, cellmin, cellmax;
178d86ed7fbStbbdev     objectlist *cur;
179d86ed7fbStbbdev     int numinbounds = 0;
180d86ed7fbStbbdev 
181d86ed7fbStbbdev     cur = g->cells[index->z * g->xsize * g->ysize + index->y * g->xsize + index->x];
182d86ed7fbStbbdev 
183d86ed7fbStbbdev     if (cur == nullptr) /* don't bound non-existent objects */
184d86ed7fbStbbdev         return 0;
185d86ed7fbStbbdev 
186d86ed7fbStbbdev     cellmin.x = voxel2x(g, index->x);
187d86ed7fbStbbdev     cellmin.y = voxel2y(g, index->y);
188d86ed7fbStbbdev     cellmin.z = voxel2z(g, index->z);
189d86ed7fbStbbdev 
190d86ed7fbStbbdev     cellmax.x = cellmin.x + g->voxsize.x;
191d86ed7fbStbbdev     cellmax.y = cellmin.y + g->voxsize.y;
192d86ed7fbStbbdev     cellmax.z = cellmin.z + g->voxsize.z;
193d86ed7fbStbbdev 
194d86ed7fbStbbdev     cmin->x = FHUGE;
195d86ed7fbStbbdev     cmin->y = FHUGE;
196d86ed7fbStbbdev     cmin->z = FHUGE;
197d86ed7fbStbbdev     cmax->x = -FHUGE;
198d86ed7fbStbbdev     cmax->y = -FHUGE;
199d86ed7fbStbbdev     cmax->z = -FHUGE;
200d86ed7fbStbbdev 
201d86ed7fbStbbdev     while (cur != nullptr) { /* Go! */
202d86ed7fbStbbdev         min.x = -FHUGE;
203d86ed7fbStbbdev         min.y = -FHUGE;
204d86ed7fbStbbdev         min.z = -FHUGE;
205d86ed7fbStbbdev         max.x = FHUGE;
206d86ed7fbStbbdev         max.y = FHUGE;
207d86ed7fbStbbdev         max.z = FHUGE;
208d86ed7fbStbbdev 
209d86ed7fbStbbdev         if (cur->obj->methods->bbox((void *)cur->obj, &min, &max)) {
210d86ed7fbStbbdev             if ((min.x >= cellmin.x) && (max.x <= cellmax.x) && (min.y >= cellmin.y) &&
211d86ed7fbStbbdev                 (max.y <= cellmax.y) && (min.z >= cellmin.z) && (max.z <= cellmax.z)) {
212d86ed7fbStbbdev                 cmin->x = MYMIN(cmin->x, min.x);
213d86ed7fbStbbdev                 cmin->y = MYMIN(cmin->y, min.y);
214d86ed7fbStbbdev                 cmin->z = MYMIN(cmin->z, min.z);
215d86ed7fbStbbdev 
216d86ed7fbStbbdev                 cmax->x = MYMAX(cmax->x, max.x);
217d86ed7fbStbbdev                 cmax->y = MYMAX(cmax->y, max.y);
218d86ed7fbStbbdev                 cmax->z = MYMAX(cmax->z, max.z);
219d86ed7fbStbbdev 
220d86ed7fbStbbdev                 numinbounds++;
221d86ed7fbStbbdev             }
222d86ed7fbStbbdev         }
223d86ed7fbStbbdev 
224d86ed7fbStbbdev         cur = cur->next;
225d86ed7fbStbbdev     }
226d86ed7fbStbbdev 
227d86ed7fbStbbdev     /* in case we get a 0.0 sized axis on the cell bounds, we'll */
228d86ed7fbStbbdev     /* use the original cell bounds */
229d86ed7fbStbbdev     if ((cmax->x - cmin->x) < EPSILON) {
230d86ed7fbStbbdev         cmax->x += EPSILON;
231d86ed7fbStbbdev         cmin->x -= EPSILON;
232d86ed7fbStbbdev     }
233d86ed7fbStbbdev     if ((cmax->y - cmin->y) < EPSILON) {
234d86ed7fbStbbdev         cmax->y += EPSILON;
235d86ed7fbStbbdev         cmin->y -= EPSILON;
236d86ed7fbStbbdev     }
237d86ed7fbStbbdev     if ((cmax->z - cmin->z) < EPSILON) {
238d86ed7fbStbbdev         cmax->z += EPSILON;
239d86ed7fbStbbdev         cmin->z -= EPSILON;
240d86ed7fbStbbdev     }
241d86ed7fbStbbdev 
242d86ed7fbStbbdev     return numinbounds;
243d86ed7fbStbbdev }
244d86ed7fbStbbdev 
countobj(object * root)245d86ed7fbStbbdev static int countobj(object *root) {
246d86ed7fbStbbdev     object *cur; /* counts the number of objects on a list */
247d86ed7fbStbbdev     int numobj;
248d86ed7fbStbbdev 
249d86ed7fbStbbdev     numobj = 0;
250d86ed7fbStbbdev     cur = root;
251d86ed7fbStbbdev 
252d86ed7fbStbbdev     while (cur != nullptr) {
253d86ed7fbStbbdev         cur = (object *)cur->nextobj;
254d86ed7fbStbbdev         numobj++;
255d86ed7fbStbbdev     }
256d86ed7fbStbbdev     return numobj;
257d86ed7fbStbbdev }
258d86ed7fbStbbdev 
countobjlist(objectlist * root)259d86ed7fbStbbdev static int countobjlist(objectlist *root) {
260d86ed7fbStbbdev     objectlist *cur;
261d86ed7fbStbbdev     int numobj;
262d86ed7fbStbbdev 
263d86ed7fbStbbdev     numobj = 0;
264d86ed7fbStbbdev     cur = root;
265d86ed7fbStbbdev 
266d86ed7fbStbbdev     while (cur != nullptr) {
267d86ed7fbStbbdev         cur = cur->next;
268d86ed7fbStbbdev         numobj++;
269d86ed7fbStbbdev     }
270d86ed7fbStbbdev     return numobj;
271d86ed7fbStbbdev }
272d86ed7fbStbbdev 
engrid_scene(object ** list)273d86ed7fbStbbdev int engrid_scene(object **list) {
274d86ed7fbStbbdev     grid *g;
275d86ed7fbStbbdev     int numobj, numcbrt;
276d86ed7fbStbbdev     vector gmin, gmax;
277d86ed7fbStbbdev     gridindex index;
278d86ed7fbStbbdev 
279d86ed7fbStbbdev     if (*list == nullptr)
280d86ed7fbStbbdev         return 0;
281d86ed7fbStbbdev 
282d86ed7fbStbbdev     numobj = countobj(*list);
283d86ed7fbStbbdev 
284d86ed7fbStbbdev     if (!silent_mode)
285d86ed7fbStbbdev         fprintf(stderr, "Scene contains %d bounded objects.\n", numobj);
286d86ed7fbStbbdev 
287d86ed7fbStbbdev     if (numobj > 16) {
288d86ed7fbStbbdev         numcbrt = (int)cbrt(4 * numobj);
289d86ed7fbStbbdev         globalbound(list, &gmin, &gmax);
290d86ed7fbStbbdev 
291d86ed7fbStbbdev         g = (grid *)newgrid(numcbrt, numcbrt, numcbrt, gmin, gmax);
292d86ed7fbStbbdev         engrid_objlist(g, list);
293d86ed7fbStbbdev 
294d86ed7fbStbbdev         numobj = countobj(*list);
295d86ed7fbStbbdev         g->nextobj = *list;
296d86ed7fbStbbdev         *list = (object *)g;
297d86ed7fbStbbdev 
298d86ed7fbStbbdev         /* now create subgrids.. */
299d86ed7fbStbbdev         for (index.z = 0; index.z < g->zsize; index.z++) {
300d86ed7fbStbbdev             for (index.y = 0; index.y < g->ysize; index.y++) {
301d86ed7fbStbbdev                 for (index.x = 0; index.x < g->xsize; index.x++) {
302d86ed7fbStbbdev                     engrid_cell(g, &index);
303d86ed7fbStbbdev                 }
304d86ed7fbStbbdev             }
305d86ed7fbStbbdev         }
306d86ed7fbStbbdev     }
307d86ed7fbStbbdev 
308d86ed7fbStbbdev     return 1;
309d86ed7fbStbbdev }
310d86ed7fbStbbdev 
engrid_objlist(grid * g,object ** list)311d86ed7fbStbbdev void engrid_objlist(grid *g, object **list) {
312d86ed7fbStbbdev     object *cur, *next, **prev;
313d86ed7fbStbbdev 
314d86ed7fbStbbdev     if (*list == nullptr)
315d86ed7fbStbbdev         return;
316d86ed7fbStbbdev 
317d86ed7fbStbbdev     prev = list;
318d86ed7fbStbbdev     cur = *list;
319d86ed7fbStbbdev 
320d86ed7fbStbbdev     while (cur != nullptr) {
321d86ed7fbStbbdev         next = (object *)cur->nextobj;
322d86ed7fbStbbdev 
323d86ed7fbStbbdev         if (engrid_object(g, cur))
324d86ed7fbStbbdev             *prev = next;
325d86ed7fbStbbdev         else
326d86ed7fbStbbdev             prev = (object **)&cur->nextobj;
327d86ed7fbStbbdev 
328d86ed7fbStbbdev         cur = next;
329d86ed7fbStbbdev     }
330d86ed7fbStbbdev }
331d86ed7fbStbbdev 
engrid_cell(grid * gold,gridindex * index)332d86ed7fbStbbdev static int engrid_cell(grid *gold, gridindex *index) {
333d86ed7fbStbbdev     vector gmin, gmax, gsize;
334d86ed7fbStbbdev     flt len;
335d86ed7fbStbbdev     int numobj, numcbrt, xs, ys, zs;
336d86ed7fbStbbdev     grid *g;
337d86ed7fbStbbdev     objectlist **list;
338d86ed7fbStbbdev     objectlist *newobj;
339d86ed7fbStbbdev 
340d86ed7fbStbbdev     list = &gold->cells[index->z * gold->xsize * gold->ysize + index->y * gold->xsize + index->x];
341d86ed7fbStbbdev 
342d86ed7fbStbbdev     if (*list == nullptr)
343d86ed7fbStbbdev         return 0;
344d86ed7fbStbbdev 
345d86ed7fbStbbdev     numobj = cellbound(gold, index, &gmin, &gmax);
346d86ed7fbStbbdev 
347d86ed7fbStbbdev     VSub(&gmax, &gmin, &gsize);
348d86ed7fbStbbdev     len = 1.0 / (MYMAX(MYMAX(gsize.x, gsize.y), gsize.z));
349d86ed7fbStbbdev     gsize.x *= len;
350d86ed7fbStbbdev     gsize.y *= len;
351d86ed7fbStbbdev     gsize.z *= len;
352d86ed7fbStbbdev 
353d86ed7fbStbbdev     if (numobj > 16) {
354d86ed7fbStbbdev         numcbrt = (int)cbrt(2 * numobj);
355d86ed7fbStbbdev 
356d86ed7fbStbbdev         xs = (int)((flt)numcbrt * gsize.x);
357d86ed7fbStbbdev         if (xs < 1)
358d86ed7fbStbbdev             xs = 1;
359d86ed7fbStbbdev         ys = (int)((flt)numcbrt * gsize.y);
360d86ed7fbStbbdev         if (ys < 1)
361d86ed7fbStbbdev             ys = 1;
362d86ed7fbStbbdev         zs = (int)((flt)numcbrt * gsize.z);
363d86ed7fbStbbdev         if (zs < 1)
364d86ed7fbStbbdev             zs = 1;
365d86ed7fbStbbdev 
366d86ed7fbStbbdev         g = (grid *)newgrid(xs, ys, zs, gmin, gmax);
367d86ed7fbStbbdev         engrid_objectlist(g, list);
368d86ed7fbStbbdev 
369d86ed7fbStbbdev         newobj = (objectlist *)rt_getmem(sizeof(objectlist));
370d86ed7fbStbbdev         newobj->obj = (object *)g;
371d86ed7fbStbbdev         newobj->next = *list;
372d86ed7fbStbbdev         *list = newobj;
373d86ed7fbStbbdev 
374d86ed7fbStbbdev         g->nextobj = gold->objects;
375d86ed7fbStbbdev         gold->objects = (object *)g;
376d86ed7fbStbbdev     }
377d86ed7fbStbbdev 
378d86ed7fbStbbdev     return 1;
379d86ed7fbStbbdev }
380d86ed7fbStbbdev 
engrid_objectlist(grid * g,objectlist ** list)381d86ed7fbStbbdev static int engrid_objectlist(grid *g, objectlist **list) {
382d86ed7fbStbbdev     objectlist *cur, *next, **prev;
383d86ed7fbStbbdev     int numsucceeded = 0;
384d86ed7fbStbbdev 
385d86ed7fbStbbdev     if (*list == nullptr)
386d86ed7fbStbbdev         return 0;
387d86ed7fbStbbdev 
388d86ed7fbStbbdev     prev = list;
389d86ed7fbStbbdev     cur = *list;
390d86ed7fbStbbdev 
391d86ed7fbStbbdev     while (cur != nullptr) {
392d86ed7fbStbbdev         next = cur->next;
393d86ed7fbStbbdev 
394d86ed7fbStbbdev         if (engrid_object(g, cur->obj)) {
395d86ed7fbStbbdev             *prev = next;
396d86ed7fbStbbdev             free(cur);
397d86ed7fbStbbdev             numsucceeded++;
398d86ed7fbStbbdev         }
399d86ed7fbStbbdev         else {
400d86ed7fbStbbdev             prev = &cur->next;
401d86ed7fbStbbdev         }
402d86ed7fbStbbdev 
403d86ed7fbStbbdev         cur = next;
404d86ed7fbStbbdev     }
405d86ed7fbStbbdev 
406d86ed7fbStbbdev     return numsucceeded;
407d86ed7fbStbbdev }
408d86ed7fbStbbdev 
engrid_object(grid * g,object * obj)409d86ed7fbStbbdev static int engrid_object(grid *g, object *obj) {
410d86ed7fbStbbdev     vector omin, omax;
411d86ed7fbStbbdev     gridindex low, high;
412d86ed7fbStbbdev     int x, y, z, zindex, yindex, voxindex;
413d86ed7fbStbbdev     objectlist *tmp;
414d86ed7fbStbbdev 
415d86ed7fbStbbdev     if (obj->methods->bbox(obj, &omin, &omax)) {
416d86ed7fbStbbdev         if (!pos2grid(g, &omin, &low) || !pos2grid(g, &omax, &high)) {
417d86ed7fbStbbdev             return 0; /* object is not wholly contained in the grid */
418d86ed7fbStbbdev         }
419d86ed7fbStbbdev     }
420d86ed7fbStbbdev     else {
421d86ed7fbStbbdev         return 0; /* object is unbounded */
422d86ed7fbStbbdev     }
423d86ed7fbStbbdev 
424d86ed7fbStbbdev     /* add the object to the complete list of objects in the grid */
425d86ed7fbStbbdev     obj->nextobj = g->objects;
426d86ed7fbStbbdev     g->objects = obj;
427d86ed7fbStbbdev 
428d86ed7fbStbbdev     /* add this object to all voxels it inhabits */
429d86ed7fbStbbdev     for (z = low.z; z <= high.z; z++) {
430d86ed7fbStbbdev         zindex = z * g->xsize * g->ysize;
431d86ed7fbStbbdev         for (y = low.y; y <= high.y; y++) {
432d86ed7fbStbbdev             yindex = y * g->xsize;
433d86ed7fbStbbdev             for (x = low.x; x <= high.x; x++) {
434d86ed7fbStbbdev                 voxindex = x + yindex + zindex;
435d86ed7fbStbbdev                 tmp = (objectlist *)rt_getmem(sizeof(objectlist));
436d86ed7fbStbbdev                 tmp->next = g->cells[voxindex];
437d86ed7fbStbbdev                 tmp->obj = obj;
438d86ed7fbStbbdev                 g->cells[voxindex] = tmp;
439d86ed7fbStbbdev             }
440d86ed7fbStbbdev         }
441d86ed7fbStbbdev     }
442d86ed7fbStbbdev 
443d86ed7fbStbbdev     return 1;
444d86ed7fbStbbdev }
445d86ed7fbStbbdev 
pos2grid(grid * g,vector * pos,gridindex * index)446d86ed7fbStbbdev static int pos2grid(grid *g, vector *pos, gridindex *index) {
447d86ed7fbStbbdev     index->x = (int)((pos->x - g->min.x) / g->voxsize.x);
448d86ed7fbStbbdev     index->y = (int)((pos->y - g->min.y) / g->voxsize.y);
449d86ed7fbStbbdev     index->z = (int)((pos->z - g->min.z) / g->voxsize.z);
450d86ed7fbStbbdev 
451d86ed7fbStbbdev     if (index->x == g->xsize)
452d86ed7fbStbbdev         index->x--;
453d86ed7fbStbbdev     if (index->y == g->ysize)
454d86ed7fbStbbdev         index->y--;
455d86ed7fbStbbdev     if (index->z == g->zsize)
456d86ed7fbStbbdev         index->z--;
457d86ed7fbStbbdev 
458d86ed7fbStbbdev     if (index->x < 0 || index->x > g->xsize || index->y < 0 || index->y > g->ysize ||
459d86ed7fbStbbdev         index->z < 0 || index->z > g->zsize)
460d86ed7fbStbbdev         return 0;
461d86ed7fbStbbdev 
462d86ed7fbStbbdev     if (pos->x < g->min.x || pos->x > g->max.x || pos->y < g->min.y || pos->y > g->max.y ||
463d86ed7fbStbbdev         pos->z < g->min.z || pos->z > g->max.z)
464d86ed7fbStbbdev         return 0;
465d86ed7fbStbbdev 
466d86ed7fbStbbdev     return 1;
467d86ed7fbStbbdev }
468d86ed7fbStbbdev 
469d86ed7fbStbbdev /* the real thing */
grid_intersect(grid * g,ray * ry)470d86ed7fbStbbdev static void grid_intersect(grid *g, ray *ry) {
471d86ed7fbStbbdev     flt tnear, tfar, offset;
472d86ed7fbStbbdev     vector curpos, tmax, tdelta, pdeltaX, pdeltaY, pdeltaZ, nXp, nYp, nZp;
473d86ed7fbStbbdev     gridindex curvox, step, out;
474d86ed7fbStbbdev     int voxindex;
475d86ed7fbStbbdev     objectlist *cur;
476d86ed7fbStbbdev 
477d86ed7fbStbbdev     if (ry->flags & RT_RAY_FINISHED)
478d86ed7fbStbbdev         return;
479d86ed7fbStbbdev 
480d86ed7fbStbbdev     if (!grid_bounds_intersect(g, ry, &tnear, &tfar))
481d86ed7fbStbbdev         return;
482d86ed7fbStbbdev 
483d86ed7fbStbbdev     if (ry->maxdist < tnear)
484d86ed7fbStbbdev         return;
485d86ed7fbStbbdev 
486d86ed7fbStbbdev     curpos = Raypnt(ry, tnear);
487d86ed7fbStbbdev     pos2grid(g, &curpos, &curvox);
488d86ed7fbStbbdev     offset = tnear;
489d86ed7fbStbbdev 
490d86ed7fbStbbdev     /* Setup X iterator stuff */
491d86ed7fbStbbdev     if (fabs(ry->d.x) < EPSILON) {
492d86ed7fbStbbdev         tmax.x = FHUGE;
493d86ed7fbStbbdev         tdelta.x = 0.0;
494d86ed7fbStbbdev         step.x = 0;
495d86ed7fbStbbdev         out.x = 0; /* never goes out of bounds on this axis */
496d86ed7fbStbbdev     }
497d86ed7fbStbbdev     else if (ry->d.x < 0.0) {
498d86ed7fbStbbdev         tmax.x = offset + ((voxel2x(g, curvox.x) - curpos.x) / ry->d.x);
499d86ed7fbStbbdev         tdelta.x = g->voxsize.x / -ry->d.x;
500d86ed7fbStbbdev         step.x = out.x = -1;
501d86ed7fbStbbdev     }
502d86ed7fbStbbdev     else {
503d86ed7fbStbbdev         tmax.x = offset + ((voxel2x(g, curvox.x + 1) - curpos.x) / ry->d.x);
504d86ed7fbStbbdev         tdelta.x = g->voxsize.x / ry->d.x;
505d86ed7fbStbbdev         step.x = 1;
506d86ed7fbStbbdev         out.x = g->xsize;
507d86ed7fbStbbdev     }
508d86ed7fbStbbdev 
509d86ed7fbStbbdev     /* Setup Y iterator stuff */
510d86ed7fbStbbdev     if (fabs(ry->d.y) < EPSILON) {
511d86ed7fbStbbdev         tmax.y = FHUGE;
512d86ed7fbStbbdev         tdelta.y = 0.0;
513d86ed7fbStbbdev         step.y = 0;
514d86ed7fbStbbdev         out.y = 0; /* never goes out of bounds on this axis */
515d86ed7fbStbbdev     }
516d86ed7fbStbbdev     else if (ry->d.y < 0.0) {
517d86ed7fbStbbdev         tmax.y = offset + ((voxel2y(g, curvox.y) - curpos.y) / ry->d.y);
518d86ed7fbStbbdev         tdelta.y = g->voxsize.y / -ry->d.y;
519d86ed7fbStbbdev         step.y = out.y = -1;
520d86ed7fbStbbdev     }
521d86ed7fbStbbdev     else {
522d86ed7fbStbbdev         tmax.y = offset + ((voxel2y(g, curvox.y + 1) - curpos.y) / ry->d.y);
523d86ed7fbStbbdev         tdelta.y = g->voxsize.y / ry->d.y;
524d86ed7fbStbbdev         step.y = 1;
525d86ed7fbStbbdev         out.y = g->ysize;
526d86ed7fbStbbdev     }
527d86ed7fbStbbdev 
528d86ed7fbStbbdev     /* Setup Z iterator stuff */
529d86ed7fbStbbdev     if (fabs(ry->d.z) < EPSILON) {
530d86ed7fbStbbdev         tmax.z = FHUGE;
531d86ed7fbStbbdev         tdelta.z = 0.0;
532d86ed7fbStbbdev         step.z = 0;
533d86ed7fbStbbdev         out.z = 0; /* never goes out of bounds on this axis */
534d86ed7fbStbbdev     }
535d86ed7fbStbbdev     else if (ry->d.z < 0.0) {
536d86ed7fbStbbdev         tmax.z = offset + ((voxel2z(g, curvox.z) - curpos.z) / ry->d.z);
537d86ed7fbStbbdev         tdelta.z = g->voxsize.z / -ry->d.z;
538d86ed7fbStbbdev         step.z = out.z = -1;
539d86ed7fbStbbdev     }
540d86ed7fbStbbdev     else {
541d86ed7fbStbbdev         tmax.z = offset + ((voxel2z(g, curvox.z + 1) - curpos.z) / ry->d.z);
542d86ed7fbStbbdev         tdelta.z = g->voxsize.z / ry->d.z;
543d86ed7fbStbbdev         step.z = 1;
544d86ed7fbStbbdev         out.z = g->zsize;
545d86ed7fbStbbdev     }
546d86ed7fbStbbdev 
547d86ed7fbStbbdev     pdeltaX = ry->d;
548d86ed7fbStbbdev     VScale(&pdeltaX, tdelta.x);
549d86ed7fbStbbdev     pdeltaY = ry->d;
550d86ed7fbStbbdev     VScale(&pdeltaY, tdelta.y);
551d86ed7fbStbbdev     pdeltaZ = ry->d;
552d86ed7fbStbbdev     VScale(&pdeltaZ, tdelta.z);
553d86ed7fbStbbdev 
554d86ed7fbStbbdev     nXp = Raypnt(ry, tmax.x);
555d86ed7fbStbbdev     nYp = Raypnt(ry, tmax.y);
556d86ed7fbStbbdev     nZp = Raypnt(ry, tmax.z);
557d86ed7fbStbbdev 
558d86ed7fbStbbdev     voxindex = curvox.z * g->xsize * g->ysize + curvox.y * g->xsize + curvox.x;
559d86ed7fbStbbdev     while (1) {
560d86ed7fbStbbdev         if (tmax.x < tmax.y && tmax.x < tmax.z) {
561d86ed7fbStbbdev             cur = g->cells[voxindex];
562d86ed7fbStbbdev             while (cur != nullptr) {
563d86ed7fbStbbdev                 if (ry->mbox[cur->obj->id] != ry->serial) {
564d86ed7fbStbbdev                     ry->mbox[cur->obj->id] = ry->serial;
565d86ed7fbStbbdev                     cur->obj->methods->intersect(cur->obj, ry);
566d86ed7fbStbbdev                 }
567d86ed7fbStbbdev                 cur = cur->next;
568d86ed7fbStbbdev             }
569d86ed7fbStbbdev             curvox.x += step.x;
570d86ed7fbStbbdev             if (ry->maxdist < tmax.x || curvox.x == out.x)
571d86ed7fbStbbdev                 break;
572d86ed7fbStbbdev             voxindex += step.x;
573d86ed7fbStbbdev             tmax.x += tdelta.x;
574d86ed7fbStbbdev             curpos = nXp;
575d86ed7fbStbbdev             nXp.x += pdeltaX.x;
576d86ed7fbStbbdev             nXp.y += pdeltaX.y;
577d86ed7fbStbbdev             nXp.z += pdeltaX.z;
578d86ed7fbStbbdev         }
579d86ed7fbStbbdev         else if (tmax.z < tmax.y) {
580d86ed7fbStbbdev             cur = g->cells[voxindex];
581d86ed7fbStbbdev             while (cur != nullptr) {
582d86ed7fbStbbdev                 if (ry->mbox[cur->obj->id] != ry->serial) {
583d86ed7fbStbbdev                     ry->mbox[cur->obj->id] = ry->serial;
584d86ed7fbStbbdev                     cur->obj->methods->intersect(cur->obj, ry);
585d86ed7fbStbbdev                 }
586d86ed7fbStbbdev                 cur = cur->next;
587d86ed7fbStbbdev             }
588d86ed7fbStbbdev             curvox.z += step.z;
589d86ed7fbStbbdev             if (ry->maxdist < tmax.z || curvox.z == out.z)
590d86ed7fbStbbdev                 break;
591d86ed7fbStbbdev             voxindex += step.z * g->xsize * g->ysize;
592d86ed7fbStbbdev             tmax.z += tdelta.z;
593d86ed7fbStbbdev             curpos = nZp;
594d86ed7fbStbbdev             nZp.x += pdeltaZ.x;
595d86ed7fbStbbdev             nZp.y += pdeltaZ.y;
596d86ed7fbStbbdev             nZp.z += pdeltaZ.z;
597d86ed7fbStbbdev         }
598d86ed7fbStbbdev         else {
599d86ed7fbStbbdev             cur = g->cells[voxindex];
600d86ed7fbStbbdev             while (cur != nullptr) {
601d86ed7fbStbbdev                 if (ry->mbox[cur->obj->id] != ry->serial) {
602d86ed7fbStbbdev                     ry->mbox[cur->obj->id] = ry->serial;
603d86ed7fbStbbdev                     cur->obj->methods->intersect(cur->obj, ry);
604d86ed7fbStbbdev                 }
605d86ed7fbStbbdev                 cur = cur->next;
606d86ed7fbStbbdev             }
607d86ed7fbStbbdev             curvox.y += step.y;
608d86ed7fbStbbdev             if (ry->maxdist < tmax.y || curvox.y == out.y)
609d86ed7fbStbbdev                 break;
610d86ed7fbStbbdev             voxindex += step.y * g->xsize;
611d86ed7fbStbbdev             tmax.y += tdelta.y;
612d86ed7fbStbbdev             curpos = nYp;
613d86ed7fbStbbdev             nYp.x += pdeltaY.x;
614d86ed7fbStbbdev             nYp.y += pdeltaY.y;
615d86ed7fbStbbdev             nYp.z += pdeltaY.z;
616d86ed7fbStbbdev         }
617d86ed7fbStbbdev 
618d86ed7fbStbbdev         if (ry->flags & RT_RAY_FINISHED)
619d86ed7fbStbbdev             break;
620d86ed7fbStbbdev     }
621d86ed7fbStbbdev }
622d86ed7fbStbbdev 
voxel_intersect(grid * g,ray * ry,int voxindex)623d86ed7fbStbbdev static void voxel_intersect(grid *g, ray *ry, int voxindex) {
624d86ed7fbStbbdev     objectlist *cur;
625d86ed7fbStbbdev 
626d86ed7fbStbbdev     cur = g->cells[voxindex];
627d86ed7fbStbbdev     while (cur != nullptr) {
628d86ed7fbStbbdev         cur->obj->methods->intersect(cur->obj, ry);
629d86ed7fbStbbdev         cur = cur->next;
630d86ed7fbStbbdev     }
631d86ed7fbStbbdev }
632d86ed7fbStbbdev 
grid_bounds_intersect(grid * g,ray * ry,flt * nr,flt * fr)633d86ed7fbStbbdev static int grid_bounds_intersect(grid *g, ray *ry, flt *nr, flt *fr) {
634d86ed7fbStbbdev     flt a, tx1, tx2, ty1, ty2, tz1, tz2;
635d86ed7fbStbbdev     flt tnear, tfar;
636d86ed7fbStbbdev 
637d86ed7fbStbbdev     tnear = -FHUGE;
638d86ed7fbStbbdev     tfar = FHUGE;
639d86ed7fbStbbdev 
640d86ed7fbStbbdev     if (ry->d.x == 0.0) {
641d86ed7fbStbbdev         if ((ry->o.x < g->min.x) || (ry->o.x > g->max.x))
642d86ed7fbStbbdev             return 0;
643d86ed7fbStbbdev     }
644d86ed7fbStbbdev     else {
645d86ed7fbStbbdev         tx1 = (g->min.x - ry->o.x) / ry->d.x;
646d86ed7fbStbbdev         tx2 = (g->max.x - ry->o.x) / ry->d.x;
647d86ed7fbStbbdev         if (tx1 > tx2) {
648d86ed7fbStbbdev             a = tx1;
649d86ed7fbStbbdev             tx1 = tx2;
650d86ed7fbStbbdev             tx2 = a;
651d86ed7fbStbbdev         }
652d86ed7fbStbbdev         if (tx1 > tnear)
653d86ed7fbStbbdev             tnear = tx1;
654d86ed7fbStbbdev         if (tx2 < tfar)
655d86ed7fbStbbdev             tfar = tx2;
656d86ed7fbStbbdev     }
657d86ed7fbStbbdev     if (tnear > tfar)
658d86ed7fbStbbdev         return 0;
659d86ed7fbStbbdev     if (tfar < 0.0)
660d86ed7fbStbbdev         return 0;
661d86ed7fbStbbdev 
662d86ed7fbStbbdev     if (ry->d.y == 0.0) {
663d86ed7fbStbbdev         if ((ry->o.y < g->min.y) || (ry->o.y > g->max.y))
664d86ed7fbStbbdev             return 0;
665d86ed7fbStbbdev     }
666d86ed7fbStbbdev     else {
667d86ed7fbStbbdev         ty1 = (g->min.y - ry->o.y) / ry->d.y;
668d86ed7fbStbbdev         ty2 = (g->max.y - ry->o.y) / ry->d.y;
669d86ed7fbStbbdev         if (ty1 > ty2) {
670d86ed7fbStbbdev             a = ty1;
671d86ed7fbStbbdev             ty1 = ty2;
672d86ed7fbStbbdev             ty2 = a;
673d86ed7fbStbbdev         }
674d86ed7fbStbbdev         if (ty1 > tnear)
675d86ed7fbStbbdev             tnear = ty1;
676d86ed7fbStbbdev         if (ty2 < tfar)
677d86ed7fbStbbdev             tfar = ty2;
678d86ed7fbStbbdev     }
679d86ed7fbStbbdev     if (tnear > tfar)
680d86ed7fbStbbdev         return 0;
681d86ed7fbStbbdev     if (tfar < 0.0)
682d86ed7fbStbbdev         return 0;
683d86ed7fbStbbdev 
684d86ed7fbStbbdev     if (ry->d.z == 0.0) {
685d86ed7fbStbbdev         if ((ry->o.z < g->min.z) || (ry->o.z > g->max.z))
686d86ed7fbStbbdev             return 0;
687d86ed7fbStbbdev     }
688d86ed7fbStbbdev     else {
689d86ed7fbStbbdev         tz1 = (g->min.z - ry->o.z) / ry->d.z;
690d86ed7fbStbbdev         tz2 = (g->max.z - ry->o.z) / ry->d.z;
691d86ed7fbStbbdev         if (tz1 > tz2) {
692d86ed7fbStbbdev             a = tz1;
693d86ed7fbStbbdev             tz1 = tz2;
694d86ed7fbStbbdev             tz2 = a;
695d86ed7fbStbbdev         }
696d86ed7fbStbbdev         if (tz1 > tnear)
697d86ed7fbStbbdev             tnear = tz1;
698d86ed7fbStbbdev         if (tz2 < tfar)
699d86ed7fbStbbdev             tfar = tz2;
700d86ed7fbStbbdev     }
701d86ed7fbStbbdev     if (tnear > tfar)
702d86ed7fbStbbdev         return 0;
703d86ed7fbStbbdev     if (tfar < 0.0)
704d86ed7fbStbbdev         return 0;
705d86ed7fbStbbdev 
706d86ed7fbStbbdev     *nr = tnear;
707d86ed7fbStbbdev     *fr = tfar;
708d86ed7fbStbbdev     return 1;
709d86ed7fbStbbdev }
710