17 #define TACHYON_INTERNAL 1 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)) 36 (
void (*)(
const void *,
const void *,
const void *,
void *))(NULL),
41 object *
newgrid(scenedef * scene,
int xsize,
int ysize,
int zsize, vector min, vector max) {
45 g = (grid *) malloc(
sizeof(grid));
46 memset(g, 0,
sizeof(grid));
55 numcells = ((ptrdiff_t) xsize) * ((ptrdiff_t) ysize) * ((ptrdiff_t) zsize);
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;
65 g->cells = (objectlist **) malloc(numcells *
sizeof(objectlist *));
66 memset(g->cells, 0, numcells *
sizeof(objectlist *));
71 static int grid_bbox(
void * obj, vector * min, vector * max) {
72 grid * g = (grid *) obj;
81 ptrdiff_t i, numvoxels;
82 grid * g = (grid *) v;
85 numvoxels = ((ptrdiff_t) g->xsize) * ((ptrdiff_t) g->ysize) * ((ptrdiff_t) g->zsize);
86 for (i=0; i<numvoxels; i++) {
91 while (lcur != NULL) {
107 static void globalbound(
object ** rootlist, vector * gmin, vector * gmax) {
111 if (*rootlist == NULL)
114 gmin->x = FHUGE; gmin->y = FHUGE; gmin->z = FHUGE;
115 gmax->x = -FHUGE; gmax->y = -FHUGE; gmax->z = -FHUGE;
118 while (cur != NULL) {
119 min.x = -FHUGE; min.y = -FHUGE; min.z = -FHUGE;
120 max.x = FHUGE; max.y = FHUGE; max.z = FHUGE;
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);
127 gmax->x =
MYMAX( gmax->x , max.x);
128 gmax->y =
MYMAX( gmax->y , max.y);
129 gmax->z =
MYMAX( gmax->z , max.z);
137 static ptrdiff_t
cellbound(
const grid *g,
const gridindex *index, vector * cmin, vector * cmax) {
138 vector min, max, cellmin, cellmax;
140 ptrdiff_t numinbounds = 0;
142 cur = g->cells[index->z*((ptrdiff_t) g->xsize)*((ptrdiff_t) g->ysize) +
143 index->y*((ptrdiff_t) g->xsize) +
149 cellmin.x = voxel2x(g, index->x);
150 cellmin.y = voxel2y(g, index->y);
151 cellmin.z = voxel2z(g, index->z);
153 cellmax.x = cellmin.x + g->voxsize.x;
154 cellmax.y = cellmin.y + g->voxsize.y;
155 cellmax.z = cellmin.z + g->voxsize.z;
157 cmin->x = FHUGE; cmin->y = FHUGE; cmin->z = FHUGE;
158 cmax->x = -FHUGE; cmax->y = -FHUGE; cmax->z = -FHUGE;
160 while (cur != NULL) {
161 min.x = -FHUGE; min.y = -FHUGE; min.z = -FHUGE;
162 max.x = FHUGE; max.y = FHUGE; max.z = FHUGE;
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)) {
169 cmin->x =
MYMIN( cmin->x , min.x);
170 cmin->y =
MYMIN( cmin->y , min.y);
171 cmin->z =
MYMIN( cmin->z , min.z);
173 cmax->x =
MYMAX( cmax->x , max.x);
174 cmax->y =
MYMAX( cmax->y , max.y);
175 cmax->z =
MYMAX( cmax->z , max.z);
186 if ((cmax->x - cmin->x) < EPSILON) {
190 if ((cmax->y - cmin->y) < EPSILON) {
194 if ((cmax->z - cmin->z) < EPSILON) {
209 while (cur != NULL) {
216 static void gridstats(
int xs,
int ys,
int zs,
int numobj) {
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));
232 if (scene->objgroup.boundedobj == NULL)
235 numobj =
countobj(scene->objgroup.boundedobj);
237 if (scene->mynode == 0) {
238 sprintf(msgtxt,
"Scene contains %d objects.", numobj);
242 if (numobj > boundthresh) {
243 numcbrt = (int)
cbrt(4*numobj);
245 globalbound(&scene->objgroup.boundedobj, &gmin, &gmax);
246 if (scene->verbosemode && scene->mynode == 0) {
248 sprintf(t,
"Global bounds: %g %g %g -> %g %g %g",
249 gmin.x, gmin.y, gmin.z, gmax.x, gmax.y, gmax.z);
252 sprintf(t,
"Creating top level grid: X:%d Y:%d Z:%d",
253 numcbrt, numcbrt, numcbrt);
257 g = (grid *)
newgrid(scene, numcbrt, numcbrt, numcbrt, gmin, gmax);
259 if (scene->verbosemode && scene->mynode == 0)
260 gridstats(numcbrt, numcbrt, numcbrt, numsucceeded);
262 if (scene->verbosemode && scene->mynode == 0) {
264 numobj =
countobj(scene->objgroup.boundedobj);
265 sprintf(t,
"Scene contains %d non-gridded objects\n", numobj);
271 g->nextobj = scene->objgroup.boundedobj;
272 scene->objgroup.boundedobj = (
object *) g;
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++) {
289 object * cur, * next, **prev;
290 ptrdiff_t numsucceeded = 0;
298 while (cur != NULL) {
305 prev = (
object **) &cur->nextobj;
315 static int engrid_cell(scenedef * scene,
int boundthresh, grid * gold, gridindex *index) {
316 vector gmin, gmax, gsize;
319 int numcbrt, xs, ys, zs;
323 ptrdiff_t numsucceeded;
325 list = &gold->cells[index->z*((ptrdiff_t) gold->xsize)*((ptrdiff_t) gold->ysize) +
326 index->y*((ptrdiff_t) gold->xsize) +
332 numobj =
cellbound(gold, index, &gmin, &gmax);
334 VSub(&gmax, &gmin, &gsize);
335 len = 1.0 / (
MYMAX(
MYMAX(gsize.x, gsize.y), gsize.z ));
340 if (numobj > boundthresh) {
341 numcbrt = (int)
cbrt(2*numobj);
343 xs = (int) ((
flt) numcbrt * gsize.x);
345 ys = (int) ((
flt) numcbrt * gsize.y);
347 zs = (int) ((
flt) numcbrt * gsize.z);
350 g = (grid *)
newgrid(scene, xs, ys, zs, gmin, gmax);
353 if (scene->verbosemode && scene->mynode == 0)
356 newobj = (objectlist *) malloc(
sizeof(objectlist));
357 newobj->obj = (
object *) g;
358 newobj->next = *list;
361 g->nextobj = gold->objects;
362 gold->objects = (
object *) g;
369 objectlist * cur, * next, **prev;
370 ptrdiff_t numsucceeded = 0;
378 while (cur != NULL) {
400 ptrdiff_t zindex, yindex, voxindex;
403 if (obj->methods->bbox(obj, &omin, &omax)) {
420 int voxeloccupancy = (high.x - low.x) * (high.y - low.y) * (high.z - low.z);
421 if (voxeloccupancy > 22000) {
429 obj->nextobj = g->objects;
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];
443 g->cells[voxindex] = tmp;
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);
457 if (index->x == g->xsize)
459 if (index->y == g->ysize)
461 if (index->z == g->zsize)
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)
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)
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;
490 if (ry->flags & RT_RAY_FINISHED)
496 if (ry->maxdist < tnear)
500 #if !defined(DISABLEMBOX) 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);
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--;
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;
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;
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;
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;
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;
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;
572 SY = step.y * ((ptrdiff_t) g->xsize);
573 SZ = step.z * ((ptrdiff_t) g->xsize) * ((ptrdiff_t) g->ysize);
576 voxindex = curvox.z*((ptrdiff_t) g->xsize)*((ptrdiff_t) g->ysize) +
577 curvox.y*((ptrdiff_t) g->xsize) +
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);
590 cur->obj->methods->intersect(cur->obj, ry);
596 while (!(ry->flags & RT_RAY_FINISHED)) {
598 if (tmax.x < tmax.y && tmax.x < tmax.z) {
600 if (ry->maxdist < tmax.x || curvox.x == out.x)
605 else if (tmax.z < tmax.y) {
607 if (ry->maxdist < tmax.z || curvox.z == out.z)
614 if (ry->maxdist < tmax.y || curvox.y == out.y)
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);
629 cur->obj->methods->intersect(cur->obj, ry);
639 flt a, tx1, tx2, ty1, ty2, tz1, tz2;
645 if (ry->d.x == 0.0) {
646 if ((ry->o.x < g->min.x) || (ry->o.x > g->max.x))
return 0;
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;
654 if (tnear > tfar)
return 0;
655 if (tfar < 0.0)
return 0;
657 if (ry->d.y == 0.0) {
658 if ((ry->o.y < g->min.y) || (ry->o.y > g->max.y))
return 0;
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;
666 if (tnear > tfar)
return 0;
667 if (tfar < 0.0)
return 0;
669 if (ry->d.z == 0.0) {
670 if ((ry->o.z < g->min.z) || (ry->o.z > g->max.z))
return 0;
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;
678 if (tnear > tfar)
return 0;
679 if (tfar < 0.0)
return 0;
unsigned int new_objectid(scenedef *scene)
static void globalbound(object **rootlist, vector *gmin, vector *gmax)
static ptrdiff_t cellbound(const grid *g, const gridindex *index, vector *cmin, vector *cmax)
static int pos2grid(grid *g, vector *pos, gridindex *index)
void rt_ui_message(int level, char *msg)
void VSub(apivector *a, apivector *b, apivector *c)
double flt
generic floating point number, using double
static int grid_bounds_intersect(const grid *g, const ray *ry, flt *hitnear, flt *hitfar)
object * newgrid(scenedef *scene, int xsize, int ysize, int zsize, vector min, vector max)
Tachyon cross-platform timers, special math function wrappers, and RNGs.
static int countobj(object *root)
static object_methods grid_methods
int engrid_scene(scenedef *scene, int boundthresh)
void free_objects(object *start)
static int engrid_object(grid *g, object *obj, int addtolist)
static void gridstats(int xs, int ys, int zs, int numobj)
static void grid_free(void *v)
static int engrid_cell(scenedef *scene, int boundthresh, grid *gold, gridindex *index)
static void grid_intersect(const grid *g, ray *ry)
Tachyon public API function prototypes and declarations used to drive the ray tracing engine...
static int engrid_objectlist(grid *g, objectlist **list)
static ptrdiff_t engrid_objlist(grid *g, object **list)
static int grid_bbox(void *obj, vector *min, vector *max)