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