virtual void pageIn(const PolyVox::Region& region, PagedVolume<MaterialDensityPair44>::Chunk* pChunk) { Perlin perlin(2, 2, 1, 234); for (int x = region.getLowerX(); x <= region.getUpperX(); x++) { for (int y = region.getLowerY(); y <= region.getUpperY(); y++) { float perlinVal = perlin.Get(x / static_cast<float>(255 - 1), y / static_cast<float>(255 - 1)); perlinVal += 1.0f; perlinVal *= 0.5f; perlinVal *= 255; for (int z = region.getLowerZ(); z <= region.getUpperZ(); z++) { MaterialDensityPair44 voxel; if (z < perlinVal) { const int xpos = 50; const int zpos = 100; if ((x - xpos)*(x - xpos) + (z - zpos)*(z - zpos) < 200) { // tunnel voxel.setMaterial(0); voxel.setDensity(MaterialDensityPair44::getMinDensity()); } else { // solid voxel.setMaterial(245); voxel.setDensity(MaterialDensityPair44::getMaxDensity()); } } else { voxel.setMaterial(0); voxel.setDensity(MaterialDensityPair44::getMinDensity()); } // Voxel position within a chunk always start from zero. So if a chunk represents region (4, 8, 12) to (11, 19, 15) // then the valid chunk voxels are from (0, 0, 0) to (7, 11, 3). Hence we subtract the lower corner position of the // region from the volume space position in order to get the chunk space position. pChunk->setVoxel(x - region.getLowerX(), y - region.getLowerY(), z - region.getLowerZ(), voxel); } } } }
// This function encodes a Region as a 64-bit integer so that it can be used as a key to access chunk data in the SQLite database. // A region actually contains more than 64-bits of data so some has to be lost here. Specifically we assume that we already know // the size of the region (so we only have to encode it's lower corner and not its upper corner or extents), and we also restrict // the range of valid coordinates. A Region's coordinates are represented by 3-bits of data, but we only support converting to a key // if every coordinate can be represented by 21 bits of data. This way we can fit three coordinates only 63 bits of data. This limits // the range of values to +/- 2^20, which is enough for our purposes. uint64_t regionToKey(const PolyVox::Region& region) { // Cast to unsigned values so that bit shifting works predictably. uint32_t x = static_cast<uint32_t>(region.getLowerX()); uint32_t y = static_cast<uint32_t>(region.getLowerY()); uint32_t z = static_cast<uint32_t>(region.getLowerZ()); // The magnitude of our input values is fairly restricted, but the values could stil be negative. This means the sign bit could // be set and this needs to be encoded as well. We therefore perform a left rotate on the bits to bring the sign bit into the LSB. x = rotateLeft(x); y = rotateLeft(y); z = rotateLeft(z); // Now convert to 64-bits uint64_t x64 = x; uint64_t y64 = y; uint64_t z64 = z; // Morten-encode the components to give our final key uint64_t result = EncodeMorton3(x64, y64, z64); // Return the combined value return result; }