blob: e106bfbd14b23f94114093b54204171721128945 [file] [log] [blame]
/*! \file Grid.hxx defines a recursive grid (should probably rename to RecursiveGrid.hxx ... */
#ifndef RTTL_RECURSIVEGRID_HXX
#define RTTL_RECURSIVEGRID_HXX
#include "../common/RTInclude.hxx"
#include "../common/RTBox.hxx"
#include "../common/RTRay.hxx"
#include "../common/RTIntervalArith.hxx"
#include "../Mesh/Mesh.hxx"
#include "../Triangle/Triangle.hxx"
#include "Builder/Builder.hxx"
namespace RTTL {
typedef RTBox3f box3f;
typedef RTBox3i box3i;
struct AABBPrimList
{
box3f4 getBounds4(int primID)
};
/*! a recursive grid, that is build on-demand
\warning can not have more than 1k prims per cell
\warning can not have more than 1m cells
*/
struct LazyRecursiveGrid
{
box3f primBounds; /*! bounds of all primitives inside this grid */
box3f cellBounds; /*! bounds of all *cells* of this grid. may be larger than primbounds */
bool is_built; /*! true if grid is already built, false otherwise */
// -------------------------------------------------------
// while not initialized:
//
PrimitiveList *primitive;
int *primID;
int primIDs;
vec3i res; /*! resolution of the grid. i.e., the number of cells in x, y, and z dimension */
vec3f cellWidth; /*! width of a cell, in world space coords */
/*! describes each cell in 32 bits: if cell is not built, yet, its
"is_built" flag is zeroed, and the cell can still be either a
grid or a leaf. in this case, the list of primitives can be
found in 'cellPrim', and a 'buildCell' has to be called for this
cell */
struct CommonCellInfo
{
unsigned int is_leaf : 1;
unsigned int unused : 31;
};
struct LeafCellInfo
{
unsigned int is_leaf : 1;
unsigned int begin : 21; /*!< can NOT have more than 2 million cells !!! */
unsigned int size : 10; /*!< can NOT have more than 1024 items per cell !!! */
};
struct SubgridCellInfo
{
unsigned int is_leaf : 1;
unsigned int subgridID : 31;
};
/*! cell info per cell ID. */
CommonCellInfo *cell;
vector<LazyRecursiveGrid *> subgrid; /*!< list of subgrids, referenced by SubgridCellInfo.subgridID */
int cellID(vec3i coord) const
{ return coord.x + res.x * (coord.y + res.y * (coord.z)); };
// /*! build the given cell. */
// void buildCell(int cellID)
// {
// if (cell[cellID].is_built) return;
// cout << "buliding cell " << cellID << endl;
// static const int MAKE_LEAF_THRESHOLD = 8;
// assert(MAKE_LEAF_THRESHOLD < 1024);
// // check if we'll make a leaf out of it
// if (cellPrim[cellID].end - cellPrim[cellID].begin <= MAKE_LEAF_THRESHOLD)
// {
// cell[cellID].is_built = true;
// cell[cellID].is_leaf = true;
// cell[cellID].ID = leafCell.size();
// leafCell[cell[cellID].ID] = cellPrim[cellID];
// }
// else
// {
// cell[cellID].is_built = true;
// cell[cellID].is_leaf = false;
// cell[cellID].subgridID= subgrid.size();
// subgrid[cell[cellID].ID] = new RecursiveGrid
// }
// }
LazyRecursiveGrid()
: is_built = false;
{
}
/*! single threaded build */
void build_singleThreaded(PrimitiveList &prim, const box3f &bounds, int *primBegin, int *primEnd)
{
// first of all: determine res...
#if 1
int targetNumCells;
int numPrims = primEnd - primBegin;
static const int linearNumCellsThreshold = 1000;
if (numPrims <= linearNumCellsThreshold)
/* assume that if less than linearNumCellsThreshold we'll
probably NOT have an additional recursion level, and that
then, we'll pick the num cells as what is ideal for a regular
grid */
targetNumCells = numPrims;
else
/*! otherwise, we asssume one more recursion level, in which
O(N^2/3) of the cells would actually be filled -- so let's
take that as num primitives ... */
targetNumCells = 1+ powf(numPrims,2./3.);
#else
int targetNumCells = 1 + (primEnd - primBegin) / 16; // make grid rather coarse...
#endif
res.x = (int)ceilf(diam.x * powf(targetNumCells/diam.volume(),1./3.));
res.y = (int)ceilf(diam.y * powf(targetNumCells/diam.volume(),1./3.));
res.z = (int)ceilf(diam.z * powf(targetNumCells/diam.volume(),1./3.));
assert(res.x >= 1);
assert(res.y >= 1);
assert(res.z >= 1);
numCells = res.volume();
assert(numCells < 1000000);
// other inits:
cellBounds = primBounds;
cellBounds.min -= (diam * 0.0001f);
cellBounds.max += (diam * 0.0001f);
// temporary arrays during building:
int *cell_size; /*! number of items per cell. only used temporarily during building */
int *cell_begin; /*! pointer to start of this cell's item list */
// first stage: clear all counters
cell_size = new int[numCells+4];
for (int i=0;i<=numCells;i++)
cell_size[i] = 0;
// second stage: compute all counters (incrementally)
for (int i=primBegin; i<primEnd; i++)
{
const box3f4 bounds_i = prim.getBounds4(primID[i]);
const box3i4 coords_i = worldToGrid(bounds_i);
for (int z=0;z<coords_i.z;z++)
for (int y=0;y<coords_i.y;y++)
for (int x=0;x<coords_i.x;x++)
++cell_size[cellID(vec3i(x,y,z))];
}
// third stage: prefix sum to compute cell_begin pointers
int ctr = 0;
cell_begin = new int[numCells+4];
for (int i=0;i<=numCells;i++)
{
ctr += cell_size[i];
cell_begin[i] = ctr;
}
// fourth stage: alloc item list(s), and perform actual engridding...
int totalReferences = cell_begin[numCells];
cellIDlist = new int[totalReferences];
for (int i=primBegin; i<primEnd; i++)
{
const box3f4 bounds_i = prim.getBounds4(primID[i]);
const box3i4 coords_i = worldToGrid(bounds_i);
for (int z=0;z<coords_i.z;z++)
for (int y=0;y<coords_i.y;y++)
for (int x=0;x<coords_i.x;x++)
{
int cID = cellID(vec3i(x,y,z));
--cell_size[cID];
cellIDlist[cell_begin[ID]+cell_size[ID]] = i;
}
}
delete[] cell_size;
// final stage: compute actual cell_infos, and (lazily) create recursive grids where required
for (int i=0;i<numCells;i++)
{
int numInCell = cell_begin[i+1] - cell_begin[i];
static const int makeLeafThreshold = 8;
assert(makeLeafThreshold > 0);
if (numInCell <= makeLeafThreshold)
{
cell[i].is_leaf = true;
cell[i].begin = cell_begin[i];
cell[i].size = numInCell;
assert(cell[i].size == numInCell); // to make sure nothing got lost during discretization
assert(cell[i].begin == cell_begin[i]);// to make sure nothing got lost during discretization
}
else
{
cell[i].is_leaf = false;
RecursiveGrid *grid = new RecursiveGrid(prim,cellIDlist,cell_begin[i],cell_begin[i+1]);
cell[i].subgridID = subgrid.size();
subgrid.push_back(grid);
}
}
delete[] cell_begin;
};
};
};