Tachyon (current)  Current Main Branch
grid.c
Go to the documentation of this file.
1 /*
2  * grid.c - spatial subdivision efficiency structures
3  *
4  * (C) Copyright 1994-2022 John E. Stone
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * $Id: grid.c,v 1.62 2022/02/18 17:55:28 johns Exp $
8  *
9  */
10 
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 #include <math.h>
15 #include <stddef.h>
16 
17 #define TACHYON_INTERNAL 1
18 #include "tachyon.h"
19 #include "macros.h"
20 #include "vector.h"
21 #include "intersect.h"
22 #include "util.h"
23 #include "ui.h"
24 #include "parallel.h"
25 
26 #define GRID_PRIVATE
27 #include "grid.h"
28 
29 #ifndef cbrt
30 #define cbrt(x) ((x) > 0.0 ? pow((double)(x), 1.0/3.0) : \
31  ((x) < 0.0 ? -pow((double)-(x), 1.0/3.0) : 0.0))
32 #endif
33 
34 static object_methods grid_methods = {
35  (void (*)(const void *, void *))(grid_intersect),
36  (void (*)(const void *, const void *, const void *, void *))(NULL),
37  grid_bbox,
38  grid_free
39 };
40 
41 object * newgrid(scenedef * scene, int xsize, int ysize, int zsize, vector min, vector max) {
42  grid * g;
43  ptrdiff_t numcells;
44 
45  g = (grid *) malloc(sizeof(grid));
46  memset(g, 0, sizeof(grid));
47 
48  g->methods = &grid_methods;
49  g->id = new_objectid(scene);
50 
51  g->xsize = xsize;
52  g->ysize = ysize;
53  g->zsize = zsize;
54 
55  numcells = ((ptrdiff_t) xsize) * ((ptrdiff_t) ysize) * ((ptrdiff_t) zsize);
56 
57  g->min = min;
58  g->max = max;
59 
60  VSub(&g->max, &g->min, &g->voxsize);
61  g->voxsize.x /= (flt) g->xsize;
62  g->voxsize.y /= (flt) g->ysize;
63  g->voxsize.z /= (flt) g->zsize;
64 
65  g->cells = (objectlist **) malloc(numcells * sizeof(objectlist *));
66  memset(g->cells, 0, numcells * sizeof(objectlist *));
67 
68  return (object *) g;
69 }
70 
71 static int grid_bbox(void * obj, vector * min, vector * max) {
72  grid * g = (grid *) obj;
73 
74  *min = g->min;
75  *max = g->max;
76 
77  return 1;
78 }
79 
80 static void grid_free(void * v) {
81  ptrdiff_t i, numvoxels;
82  grid * g = (grid *) v;
83 
84  /* loop through all voxels and free the object lists */
85  numvoxels = ((ptrdiff_t) g->xsize) * ((ptrdiff_t) g->ysize) * ((ptrdiff_t) g->zsize);
86  for (i=0; i<numvoxels; i++) {
87  objectlist * lcur;
88  objectlist * lnext;
89 
90  lcur = g->cells[i];
91  while (lcur != NULL) {
92  lnext = lcur->next;
93  free(lcur);
94  lcur = lnext;
95  }
96  }
97 
98  /* free the grid cells */
99  free(g->cells);
100 
101  /* free all objects on the grid object list */
102  free_objects(g->objects);
103 
104  free(g);
105 }
106 
107 static void globalbound(object ** rootlist, vector * gmin, vector * gmax) {
108  vector min, max;
109  object * cur;
110 
111  if (*rootlist == NULL) /* don't bound non-existant objects */
112  return;
113 
114  gmin->x = FHUGE; gmin->y = FHUGE; gmin->z = FHUGE;
115  gmax->x = -FHUGE; gmax->y = -FHUGE; gmax->z = -FHUGE;
116 
117  cur=*rootlist;
118  while (cur != NULL) { /* Go! */
119  min.x = -FHUGE; min.y = -FHUGE; min.z = -FHUGE;
120  max.x = FHUGE; max.y = FHUGE; max.z = FHUGE;
121 
122  if (cur->methods->bbox((void *) cur, &min, &max)) {
123  gmin->x = MYMIN( gmin->x , min.x);
124  gmin->y = MYMIN( gmin->y , min.y);
125  gmin->z = MYMIN( gmin->z , min.z);
126 
127  gmax->x = MYMAX( gmax->x , max.x);
128  gmax->y = MYMAX( gmax->y , max.y);
129  gmax->z = MYMAX( gmax->z , max.z);
130  }
131 
132  cur=cur->nextobj;
133  }
134 }
135 
136 
137 static ptrdiff_t cellbound(const grid *g, const gridindex *index, vector * cmin, vector * cmax) {
138  vector min, max, cellmin, cellmax;
139  objectlist * cur;
140  ptrdiff_t numinbounds = 0;
141 
142  cur = g->cells[index->z*((ptrdiff_t) g->xsize)*((ptrdiff_t) g->ysize) +
143  index->y*((ptrdiff_t) g->xsize) +
144  index->x];
145 
146  if (cur == NULL) /* don't bound non-existant objects */
147  return 0;
148 
149  cellmin.x = voxel2x(g, index->x);
150  cellmin.y = voxel2y(g, index->y);
151  cellmin.z = voxel2z(g, index->z);
152 
153  cellmax.x = cellmin.x + g->voxsize.x;
154  cellmax.y = cellmin.y + g->voxsize.y;
155  cellmax.z = cellmin.z + g->voxsize.z;
156 
157  cmin->x = FHUGE; cmin->y = FHUGE; cmin->z = FHUGE;
158  cmax->x = -FHUGE; cmax->y = -FHUGE; cmax->z = -FHUGE;
159 
160  while (cur != NULL) { /* Go! */
161  min.x = -FHUGE; min.y = -FHUGE; min.z = -FHUGE;
162  max.x = FHUGE; max.y = FHUGE; max.z = FHUGE;
163 
164  if (cur->obj->methods->bbox((void *) cur->obj, &min, &max)) {
165  if ((min.x >= cellmin.x) && (max.x <= cellmax.x) &&
166  (min.y >= cellmin.y) && (max.y <= cellmax.y) &&
167  (min.z >= cellmin.z) && (max.z <= cellmax.z)) {
168 
169  cmin->x = MYMIN( cmin->x , min.x);
170  cmin->y = MYMIN( cmin->y , min.y);
171  cmin->z = MYMIN( cmin->z , min.z);
172 
173  cmax->x = MYMAX( cmax->x , max.x);
174  cmax->y = MYMAX( cmax->y , max.y);
175  cmax->z = MYMAX( cmax->z , max.z);
176 
177  numinbounds++;
178  }
179  }
180 
181  cur=cur->next;
182  }
183 
184  /* in case we get a 0.0 sized axis on the cell bounds, we'll */
185  /* use the original cell bounds */
186  if ((cmax->x - cmin->x) < EPSILON) {
187  cmax->x += EPSILON;
188  cmin->x -= EPSILON;
189  }
190  if ((cmax->y - cmin->y) < EPSILON) {
191  cmax->y += EPSILON;
192  cmin->y -= EPSILON;
193  }
194  if ((cmax->z - cmin->z) < EPSILON) {
195  cmax->z += EPSILON;
196  cmin->z -= EPSILON;
197  }
198 
199  return numinbounds;
200 }
201 
202 static int countobj(object * root) {
203  object * cur; /* counts the number of objects on a list */
204  int numobj;
205 
206  numobj=0;
207  cur=root;
208 
209  while (cur != NULL) {
210  cur=cur->nextobj;
211  numobj++;
212  }
213  return numobj;
214 }
215 
216 static void gridstats(int xs, int ys, int zs, int numobj) {
217  char t[256]; /* msgtxt */
218  int numcells = xs*ys*zs;
219  sprintf(t, "Grid: X:%3d Y:%3d Z:%3d Cells:%9d Obj:%9d Obj/Cell: %7.3f",
220  xs, ys, zs, numcells, numobj, ((float) numobj) / ((float) numcells));
221  rt_ui_message(MSG_0, t);
222 }
223 
224 int engrid_scene(scenedef * scene, int boundthresh) {
225  grid * g;
226  int numobj, numcbrt;
227  vector gmin={0,0,0};
228  vector gmax={0,0,0};
229  gridindex index;
230  char msgtxt[128];
231  int numsucceeded;
232  if (scene->objgroup.boundedobj == NULL)
233  return 0;
234 
235  numobj = countobj(scene->objgroup.boundedobj);
236 
237  if (scene->mynode == 0) {
238  sprintf(msgtxt, "Scene contains %d objects.", numobj);
239  rt_ui_message(MSG_0, msgtxt);
240  }
241 
242  if (numobj > boundthresh) {
243  numcbrt = (int) cbrt(4*numobj);
244 
245  globalbound(&scene->objgroup.boundedobj, &gmin, &gmax);
246  if (scene->verbosemode && scene->mynode == 0) {
247  char t[256]; /* msgtxt */
248  sprintf(t, "Global bounds: %g %g %g -> %g %g %g",
249  gmin.x, gmin.y, gmin.z, gmax.x, gmax.y, gmax.z);
250  rt_ui_message(MSG_0, t);
251 
252  sprintf(t, "Creating top level grid: X:%d Y:%d Z:%d",
253  numcbrt, numcbrt, numcbrt);
254  rt_ui_message(MSG_0, t);
255  }
256 
257  g = (grid *) newgrid(scene, numcbrt, numcbrt, numcbrt, gmin, gmax);
258  numsucceeded = engrid_objlist(g, &scene->objgroup.boundedobj);
259  if (scene->verbosemode && scene->mynode == 0)
260  gridstats(numcbrt, numcbrt, numcbrt, numsucceeded);
261 
262  if (scene->verbosemode && scene->mynode == 0) {
263  char t[256]; /* msgtxt */
264  numobj = countobj(scene->objgroup.boundedobj);
265  sprintf(t, "Scene contains %d non-gridded objects\n", numobj);
266  rt_ui_message(MSG_0, t);
267  }
268 
269  /* add this grid to the bounded object list removing the objects */
270  /* now contained and managed by the grid */
271  g->nextobj = scene->objgroup.boundedobj;
272  scene->objgroup.boundedobj = (object *) g;
273 
274  /* create subgrids for overfull cell in the top level grid... */
275  for (index.z=0; index.z<g->zsize; index.z++) {
276  for (index.y=0; index.y<g->ysize; index.y++) {
277  for (index.x=0; index.x<g->xsize; index.x++) {
278  engrid_cell(scene, boundthresh, g, &index);
279  }
280  }
281  }
282  }
283 
284  return 1;
285 }
286 
287 
288 static ptrdiff_t engrid_objlist(grid * g, object ** list) {
289  object * cur, * next, **prev;
290  ptrdiff_t numsucceeded = 0;
291 
292  if (*list == NULL)
293  return 0;
294 
295  prev = list;
296  cur = *list;
297 
298  while (cur != NULL) {
299  next = cur->nextobj;
300 
301  if (engrid_object(g, cur, 1)) {
302  *prev = next;
303  numsucceeded++;
304  } else {
305  prev = (object **) &cur->nextobj;
306  }
307 
308  cur = next;
309  }
310 
311  return numsucceeded;
312 }
313 
314 
315 static int engrid_cell(scenedef * scene, int boundthresh, grid * gold, gridindex *index) {
316  vector gmin, gmax, gsize;
317  flt len;
318  ptrdiff_t numobj;
319  int numcbrt, xs, ys, zs;
320  grid * g;
321  objectlist **list;
322  objectlist * newobj;
323  ptrdiff_t numsucceeded;
324 
325  list = &gold->cells[index->z*((ptrdiff_t) gold->xsize)*((ptrdiff_t) gold->ysize) +
326  index->y*((ptrdiff_t) gold->xsize) +
327  index->x];
328 
329  if (*list == NULL)
330  return 0;
331 
332  numobj = cellbound(gold, index, &gmin, &gmax);
333 
334  VSub(&gmax, &gmin, &gsize);
335  len = 1.0 / (MYMAX( MYMAX(gsize.x, gsize.y), gsize.z ));
336  gsize.x *= len;
337  gsize.y *= len;
338  gsize.z *= len;
339 
340  if (numobj > boundthresh) {
341  numcbrt = (int) cbrt(2*numobj);
342 
343  xs = (int) ((flt) numcbrt * gsize.x);
344  if (xs < 1) xs = 1;
345  ys = (int) ((flt) numcbrt * gsize.y);
346  if (ys < 1) ys = 1;
347  zs = (int) ((flt) numcbrt * gsize.z);
348  if (zs < 1) zs = 1;
349 
350  g = (grid *) newgrid(scene, xs, ys, zs, gmin, gmax);
351  numsucceeded = engrid_objectlist(g, list);
352 
353  if (scene->verbosemode && scene->mynode == 0)
354  gridstats(xs, ys, zs, numsucceeded);
355 
356  newobj = (objectlist *) malloc(sizeof(objectlist));
357  newobj->obj = (object *) g;
358  newobj->next = *list;
359  *list = newobj;
360 
361  g->nextobj = gold->objects;
362  gold->objects = (object *) g;
363  }
364 
365  return 1;
366 }
367 
368 static int engrid_objectlist(grid * g, objectlist ** list) {
369  objectlist * cur, * next, **prev;
370  ptrdiff_t numsucceeded = 0;
371 
372  if (*list == NULL)
373  return 0;
374 
375  prev = list;
376  cur = *list;
377 
378  while (cur != NULL) {
379  next = cur->next;
380 
381  if (engrid_object(g, cur->obj, 0)) {
382  *prev = next;
383  free(cur);
384  numsucceeded++;
385  } else {
386  prev = &cur->next;
387  }
388 
389  cur = next;
390  }
391 
392  return numsucceeded;
393 }
394 
395 
396 static int engrid_object(grid * g, object * obj, int addtolist) {
397  vector omin, omax;
398  gridindex low, high;
399  int x, y, z;
400  ptrdiff_t zindex, yindex, voxindex;
401  objectlist * tmp;
402 
403  if (obj->methods->bbox(obj, &omin, &omax)) {
404  if (!pos2grid(g, &omin, &low) || !pos2grid(g, &omax, &high)) {
405  return 0; /* object is not wholly contained in the grid, don't engrid */
406  }
407  } else {
408  return 0; /* object is unbounded, don't engrid this object */
409  }
410 
411 #if 0
412  /* test grid cell occupancy size to see if this object would */
413  /* consume a huge number of grid cells (thus causing problems) */
414  /* in the special case of a top level grid, we could count the */
415  /* number of problematic objects, and if they exceed a maximum */
416  /* percentage or absolute number of these, we should cancel */
417  /* filling the top level grid and rebuild a coarser top level */
418  /* grid instead, to prevent an explosion of memory use. */
419  {
420  int voxeloccupancy = (high.x - low.x) * (high.y - low.y) * (high.z - low.z);
421  if (voxeloccupancy > 22000) {
422  return 0; /* don't engrid this object */
423  }
424  }
425 #endif
426 
427  /* add the object to the complete list of objects in the grid */
428  if (addtolist) {
429  obj->nextobj = g->objects;
430  g->objects = obj;
431  }
432 
433  /* add this object to all voxels it inhabits */
434  for (z=low.z; z<=high.z; z++) {
435  zindex = z * ((ptrdiff_t) g->xsize) * ((ptrdiff_t) g->ysize);
436  for (y=low.y; y<=high.y; y++) {
437  yindex = y * ((ptrdiff_t) g->xsize);
438  for (x=low.x; x<=high.x; x++) {
439  voxindex = x + yindex + zindex;
440  tmp = (objectlist *) malloc(sizeof(objectlist));
441  tmp->next = g->cells[voxindex];
442  tmp->obj = obj;
443  g->cells[voxindex] = tmp;
444  }
445  }
446  }
447 
448  return 1;
449 }
450 
451 
452 static int pos2grid(grid * g, vector * pos, gridindex * index) {
453  index->x = (int) ((flt) (pos->x - g->min.x) / g->voxsize.x);
454  index->y = (int) ((flt) (pos->y - g->min.y) / g->voxsize.y);
455  index->z = (int) ((flt) (pos->z - g->min.z) / g->voxsize.z);
456 
457  if (index->x == g->xsize)
458  index->x--;
459  if (index->y == g->ysize)
460  index->y--;
461  if (index->z == g->zsize)
462  index->z--;
463 
464  if (index->x < 0 || index->x > g->xsize ||
465  index->y < 0 || index->y > g->ysize ||
466  index->z < 0 || index->z > g->zsize)
467  return 0;
468 
469  if (pos->x < g->min.x || pos->x > g->max.x ||
470  pos->y < g->min.y || pos->y > g->max.y ||
471  pos->z < g->min.z || pos->z > g->max.z)
472  return 0;
473 
474  return 1;
475 }
476 
477 
478 /* the real thing */
479 static void grid_intersect(const grid * g, ray * ry) {
480  flt tnear, tfar;
481  vector curpos, tmax, tdelta;
482  gridindex curvox, step, out;
483  ptrdiff_t voxindex, SY, SZ;
484  unsigned long serial;
485 #if !defined(DISABLEMBOX)
486  unsigned long * mbox;
487 #endif
488  objectlist * cur;
489 
490  if (ry->flags & RT_RAY_FINISHED)
491  return;
492 
493  if (!grid_bounds_intersect(g, ry, &tnear, &tfar))
494  return;
495 
496  if (ry->maxdist < tnear)
497  return;
498 
499  serial=ry->serial;
500 #if !defined(DISABLEMBOX)
501  mbox=ry->mbox;
502 #endif
503 
504  /* find the entry point in the grid from the near hit */
505  curpos.x = ry->o.x + (ry->d.x * tnear);
506  curpos.y = ry->o.y + (ry->d.y * tnear);
507  curpos.z = ry->o.z + (ry->d.z * tnear);
508 
509  /* map the entry point to its nearest voxel */
510  curvox.x = (int) ((flt) (curpos.x - g->min.x) / g->voxsize.x);
511  curvox.y = (int) ((flt) (curpos.y - g->min.y) / g->voxsize.y);
512  curvox.z = (int) ((flt) (curpos.z - g->min.z) / g->voxsize.z);
513  if (curvox.x == g->xsize) curvox.x--;
514  if (curvox.y == g->ysize) curvox.y--;
515  if (curvox.z == g->zsize) curvox.z--;
516 
517  /* Setup X iterator stuff */
518  if (ry->d.x < -EPSILON) {
519  tmax.x = tnear + ((voxel2x(g, curvox.x) - curpos.x) / ry->d.x);
520  tdelta.x = g->voxsize.x / - ry->d.x;
521  step.x = -1;
522  out.x = -1;
523  } else if (ry->d.x > EPSILON) {
524  tmax.x = tnear + ((voxel2x(g, curvox.x + 1) - curpos.x) / ry->d.x);
525  tdelta.x = g->voxsize.x / ry->d.x;
526  step.x = 1;
527  out.x = g->xsize;
528  } else {
529  tmax.x = FHUGE;
530  tdelta.x = 0.0;
531  step.x = 0;
532  out.x = 0; /* never goes out of bounds on this axis */
533  }
534 
535  /* Setup Y iterator stuff */
536  if (ry->d.y < -EPSILON) {
537  tmax.y = tnear + ((voxel2y(g, curvox.y) - curpos.y) / ry->d.y);
538  tdelta.y = g->voxsize.y / - ry->d.y;
539  step.y = -1;
540  out.y = -1;
541  } else if (ry->d.y > EPSILON) {
542  tmax.y = tnear + ((voxel2y(g, curvox.y + 1) - curpos.y) / ry->d.y);
543  tdelta.y = g->voxsize.y / ry->d.y;
544  step.y = 1;
545  out.y = g->ysize;
546  } else {
547  tmax.y = FHUGE;
548  tdelta.y = 0.0;
549  step.y = 0;
550  out.y = 0; /* never goes out of bounds on this axis */
551  }
552 
553  /* Setup Z iterator stuff */
554  if (ry->d.z < -EPSILON) {
555  tmax.z = tnear + ((voxel2z(g, curvox.z) - curpos.z) / ry->d.z);
556  tdelta.z = g->voxsize.z / - ry->d.z;
557  step.z = -1;
558  out.z = -1;
559  } else if (ry->d.z > EPSILON) {
560  tmax.z = tnear + ((voxel2z(g, curvox.z + 1) - curpos.z) / ry->d.z);
561  tdelta.z = g->voxsize.z / ry->d.z;
562  step.z = 1;
563  out.z = g->zsize;
564  } else {
565  tmax.z = FHUGE;
566  tdelta.z = 0.0;
567  step.z = 0;
568  out.z = 0; /* never goes out of bounds on this axis */
569  }
570 
571  /* pre-calculate row/column/plane offsets for stepping through grid */
572  SY = step.y * ((ptrdiff_t) g->xsize);
573  SZ = step.z * ((ptrdiff_t) g->xsize) * ((ptrdiff_t) g->ysize);
574 
575  /* first cell we'll be testing */
576  voxindex = curvox.z*((ptrdiff_t) g->xsize)*((ptrdiff_t) g->ysize) +
577  curvox.y*((ptrdiff_t) g->xsize) +
578  curvox.x;
579 
580  /* Unrolled while loop by one... */
581  /* Test all objects in the current cell for intersection */
582  cur = g->cells[voxindex];
583  while (cur != NULL) {
584 #if !defined(DISABLEMBOX)
585  if (mbox[cur->obj->id] != serial) {
586  mbox[cur->obj->id] = serial;
587  cur->obj->methods->intersect(cur->obj, ry);
588  }
589 #else
590  cur->obj->methods->intersect(cur->obj, ry);
591 #endif
592  cur = cur->next;
593  }
594 
595  /* Loop through grid cells until we're done */
596  while (!(ry->flags & RT_RAY_FINISHED)) {
597  /* Walk to next cell */
598  if (tmax.x < tmax.y && tmax.x < tmax.z) {
599  curvox.x += step.x;
600  if (ry->maxdist < tmax.x || curvox.x == out.x)
601  break;
602  tmax.x += tdelta.x;
603  voxindex += step.x;
604  }
605  else if (tmax.z < tmax.y) {
606  curvox.z += step.z;
607  if (ry->maxdist < tmax.z || curvox.z == out.z)
608  break;
609  tmax.z += tdelta.z;
610  voxindex += SZ;
611  }
612  else {
613  curvox.y += step.y;
614  if (ry->maxdist < tmax.y || curvox.y == out.y)
615  break;
616  tmax.y += tdelta.y;
617  voxindex += SY;
618  }
619 
620  /* Test all objects in the current cell for intersection */
621  cur = g->cells[voxindex];
622  while (cur != NULL) {
623 #if !defined(DISABLEMBOX)
624  if (mbox[cur->obj->id] != serial) {
625  mbox[cur->obj->id] = serial;
626  cur->obj->methods->intersect(cur->obj, ry);
627  }
628 #else
629  cur->obj->methods->intersect(cur->obj, ry);
630 #endif
631  cur = cur->next;
632  }
633  }
634 }
635 
636 
637 
638 static int grid_bounds_intersect(const grid * g, const ray * ry, flt *hitnear, flt *hitfar) {
639  flt a, tx1, tx2, ty1, ty2, tz1, tz2;
640  flt tnear, tfar;
641 
642  tnear= -FHUGE;
643  tfar= FHUGE;
644 
645  if (ry->d.x == 0.0) {
646  if ((ry->o.x < g->min.x) || (ry->o.x > g->max.x)) return 0;
647  } else {
648  tx1 = (g->min.x - ry->o.x) / ry->d.x;
649  tx2 = (g->max.x - ry->o.x) / ry->d.x;
650  if (tx1 > tx2) { a=tx1; tx1=tx2; tx2=a; }
651  if (tx1 > tnear) tnear=tx1;
652  if (tx2 < tfar) tfar=tx2;
653  }
654  if (tnear > tfar) return 0;
655  if (tfar < 0.0) return 0;
656 
657  if (ry->d.y == 0.0) {
658  if ((ry->o.y < g->min.y) || (ry->o.y > g->max.y)) return 0;
659  } else {
660  ty1 = (g->min.y - ry->o.y) / ry->d.y;
661  ty2 = (g->max.y - ry->o.y) / ry->d.y;
662  if (ty1 > ty2) { a=ty1; ty1=ty2; ty2=a; }
663  if (ty1 > tnear) tnear=ty1;
664  if (ty2 < tfar) tfar=ty2;
665  }
666  if (tnear > tfar) return 0;
667  if (tfar < 0.0) return 0;
668 
669  if (ry->d.z == 0.0) {
670  if ((ry->o.z < g->min.z) || (ry->o.z > g->max.z)) return 0;
671  } else {
672  tz1 = (g->min.z - ry->o.z) / ry->d.z;
673  tz2 = (g->max.z - ry->o.z) / ry->d.z;
674  if (tz1 > tz2) { a=tz1; tz1=tz2; tz2=a; }
675  if (tz1 > tnear) tnear=tz1;
676  if (tz2 < tfar) tfar=tz2;
677  }
678  if (tnear > tfar) return 0;
679  if (tfar < 0.0) return 0;
680 
681  if (tnear < 0.0) {
682  *hitnear = 0.0;
683  } else {
684  *hitnear = tnear;
685  }
686 
687  *hitfar = tfar;
688  return 1;
689 }
690 
691 
692 
693 
unsigned int new_objectid(scenedef *scene)
Definition: intersect.c:26
static void globalbound(object **rootlist, vector *gmin, vector *gmax)
Definition: grid.c:107
static ptrdiff_t cellbound(const grid *g, const gridindex *index, vector *cmin, vector *cmax)
Definition: grid.c:137
static int pos2grid(grid *g, vector *pos, gridindex *index)
Definition: grid.c:452
void rt_ui_message(int level, char *msg)
Definition: ui.c:31
void VSub(apivector *a, apivector *b, apivector *c)
#define cbrt(x)
Definition: grid.c:30
double flt
generic floating point number, using double
Definition: tachyon.h:47
static int grid_bounds_intersect(const grid *g, const ray *ry, flt *hitnear, flt *hitfar)
Definition: grid.c:638
object * newgrid(scenedef *scene, int xsize, int ysize, int zsize, vector min, vector max)
Definition: grid.c:41
Tachyon cross-platform timers, special math function wrappers, and RNGs.
#define MYMIN(a, b)
Definition: macros.h:13
static int countobj(object *root)
Definition: grid.c:202
static object_methods grid_methods
Definition: grid.c:34
int engrid_scene(scenedef *scene, int boundthresh)
Definition: grid.c:224
void free_objects(object *start)
Definition: intersect.c:34
static int engrid_object(grid *g, object *obj, int addtolist)
Definition: grid.c:396
static void gridstats(int xs, int ys, int zs, int numobj)
Definition: grid.c:216
static void grid_free(void *v)
Definition: grid.c:80
static int engrid_cell(scenedef *scene, int boundthresh, grid *gold, gridindex *index)
Definition: grid.c:315
#define MSG_0
Definition: ui.h:12
static void grid_intersect(const grid *g, ray *ry)
Definition: grid.c:479
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
static int engrid_objectlist(grid *g, objectlist **list)
Definition: grid.c:368
static ptrdiff_t engrid_objlist(grid *g, object **list)
Definition: grid.c:288
#define MYMAX(a, b)
Definition: macros.h:12
static int grid_bbox(void *obj, vector *min, vector *max)
Definition: grid.c:71