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