// Evaluates a region voxel-by-voxel, storing the output in the data // member of the tristate struct. bool Mesher::load_packed(const Region& r) { // Only load the packed matrix if we have few enough voxels. const unsigned voxels = (r.ni+1) * (r.nj+1) * (r.nk+1); if (voxels >= MIN_VOLUME) return false; // We've already run interval evaluation for this region // (at the beginning of triangulate_region), so here we'll // just disable inactive nodes. disable_nodes(tree); // Flatten a 3D region into a 1D list of points that // touches every point in the region, one by one. int q = 0; for (unsigned k=0; k <= r.nk; ++k) { for (unsigned j=0; j <= r.nj; ++j) { for (unsigned i=0; i <= r.ni; ++i) { X[q] = r.X[i]; Y[q] = r.Y[j]; Z[q] = r.Z[k]; q++; } } } // Make a dummy region that has the newly-flattened point arrays as the // X, Y, Z coordinate data arrays (so that we can run eval_r on it). packed.imin = r.imin; packed.jmin = r.jmin; packed.kmin = r.kmin; packed.ni = r.ni; packed.nj = r.nj; packed.nk = r.nk; packed.X = X; packed.Y = Y; packed.Z = Z; packed.voxels = voxels; // Run eval_r and copy the data out memcpy(data, eval_r(tree, packed), voxels * sizeof(float)); has_data = true; return true; }
void render8(MathTree* tree, Region region, uint8_t** img, volatile int* halt, void (*callback)()) { // Special interrupt system, set asynchronously by on high if (*halt) return; // Render pixel-by-pixel if we're below a certain size. if (region.voxels > 0 && region.voxels < MIN_VOLUME) { if (callback) (*callback)(); region8(tree, region, img); return; } // Pre-emptively halt evaluation if all the points in this // region are already light. uint8_t L = region.L[region.nk] >> 8; bool cull = true; for (int row = region.jmin; cull && row < region.jmin + region.nj; ++row) { for (int col = region.imin; cull && col < region.imin + region.ni; ++col) { if (L > img[row][col]) { cull = false; break; } } } if (cull) return; Interval X = {region.X[0], region.X[region.ni]}, Y = {region.Y[0], region.Y[region.nj]}, Z = {region.Z[0], region.Z[region.nk]}; Interval result = eval_i(tree, X, Y, Z); // If we're inside the object, fill with color. if (result.upper < 0) { for (int row = region.jmin; row < region.jmin + region.nj; ++row) { for (int col = region.imin; col < region.imin + region.ni; ++col) { if (L > img[row][col]) img[row][col] = L; } } } // In unambiguous cases, return immediately if (result.upper < 0 || result.lower >= 0) return; #if PRUNE disable_nodes(tree); disable_nodes_binary(tree); #endif // Subdivide and recurse if we're not at voxel size. if (region.ni*region.nj*region.nk > 1) { Region A, B; bisect(region, &A, &B); render8(tree, B, img, halt, callback); render8(tree, A, img, halt, callback); } #if PRUNE enable_nodes(tree); #endif }