This commit is contained in:
watrabi
2025-09-18 17:55:52 -04:00
commit 977f1ff4b8
15030 changed files with 17324420 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
#include "stdafx.h"
#include "Voxel/Cell.h"
namespace RBX { namespace Voxel {
static Cell constructEmptyRepresentation() {
Cell v;
v.solid.setOrientation(CELL_ORIENTATION_NegZ);
v.solid.setBlock(CELL_BLOCK_Empty);
return v;
}
static Cell constructWaterOnWedge() {
Cell v;
v.solid.setBlock(CELL_BLOCK_Empty);
v.water.setForceAndDirection(WATER_CELL_FORCE_None, WATER_CELL_DIRECTION_NegY);
return v;
}
const Cell Constants::kUniqueEmptyCellRepresentation = constructEmptyRepresentation();
const Cell Constants::kWaterOnWedgeCell = constructWaterOnWedge();
std::ostream& operator<<(std::ostream& os, const RBX::Voxel::Cell& v) {
return os << (Cell::asUnsignedCharForDeprecatedUses(v));
}
} }
+56
View File
@@ -0,0 +1,56 @@
#include "stdafx.h"
#include "Voxel/Grid.h"
#include "Voxel/Cell.h"
#include "rbx/Profiler.h"
namespace RBX { namespace Voxel {
const int Grid::Chunk::kFaceDirectionToPointerOffset[7] = {
kXOffsetMultiplier,
kZOffsetMultiplier,
-kXOffsetMultiplier,
-kZOffsetMultiplier,
kYOffsetMultiplier,
-kYOffsetMultiplier,
0
};
Grid::Chunk::Chunk() :
data(),
material(),
countOfNonEmptyCells(0),
initialized(false)
{
}
Grid::Chunk::~Chunk()
{
RBXPROFILER_COUNTER_SUB("memory/terrain/legacy", data.size() + material.size());
}
void Grid::Chunk::init(const Grid* owner) {
using namespace SpatialRegion::Constants;
if (!initialized) {
this->owner = owner;
static const int kTotalMemorySize =
kRegionXDimensionInVoxels *
kRegionYDimensionInVoxels *
kRegionZDimensionInVoxels;
std::vector<Cell> tmp1(kTotalMemorySize, Constants::kUniqueEmptyCellRepresentation);
data.swap(tmp1);
std::vector<unsigned char> tmp2(kTotalMemorySize / 2, 0xff);
material.swap(tmp2);
initialized = true;
RBXPROFILER_COUNTER_ADD("memory/terrain/legacy", data.size() + material.size());
}
}
} }
+255
View File
@@ -0,0 +1,255 @@
#include "stdafx.h"
#include "Voxel/Grid.h"
#include "rbx/Debug.h"
#include "Util/G3DCore.h"
#include "Voxel/Cell.h"
#include "Voxel/Util.h"
#include <boost/unordered_map.hpp>
namespace RBX { namespace Voxel {
Grid::Grid() : chunkMap(), countOfNonEmptyCells(0) {}
const Cell& Grid::getVoxelLikelyThisChunk(const SpatialRegion::Id& id,
const Chunk& chunk, const Vector3int16& coord) const {
const Chunk* chunkPtr;
SpatialRegion::Id coordChunkId = SpatialRegion::regionContainingVoxel(coord);
if (coordChunkId == id) {
chunkPtr = &chunk;
} else {
chunkPtr = chunkMap.find(coordChunkId);
if (chunkPtr == NULL) {
return Constants::kUniqueEmptyCellRepresentation;
}
}
return chunkPtr->getConstData()[Chunk::voxelCoordToArrayIndex(coord)];
}
void Grid::fillLocalAreaInfo(const Vector3int16& globalCoord,
const Water::RelevantNeighbors& relevantNeighbors,
Water::LocalAreaInfo* info) const {
SpatialRegion::Id mainChunkId = SpatialRegion::regionContainingVoxel(globalCoord);
const Chunk* mainChunkPtr = chunkMap.find(mainChunkId);
if (mainChunkPtr == NULL) {
RBXASSERT(false);
return;
}
const Chunk& mainChunk = *mainChunkPtr;
const Vector3int16 relativeCoord = SpatialRegion::voxelCoordinateRelativeToEnclosingRegion(globalCoord);
if (relativeCoord.isBetweenInclusive(Vector3int16::one(),
SpatialRegion::getMaxVoxelOffsetInsideRegion() - Vector3int16::one())) {
unsigned int index = Chunk::voxelCoordToArrayIndex(globalCoord);
info->aboveNeighbor =
mainChunk.getConstData()[index +
Chunk::voxelCoordOffsetToIndexOffset(relevantNeighbors.aboveNeighbor)];
info->primaryNeighbor =
mainChunk.getConstData()[index +
Chunk::voxelCoordOffsetToIndexOffset(relevantNeighbors.primaryNeighbor)];
info->secondaryNeighbor =
mainChunk.getConstData()[index +
Chunk::voxelCoordOffsetToIndexOffset(relevantNeighbors.secondaryNeighbor)];
info->diagonalNeighbor =
mainChunk.getConstData()[index +
Chunk::voxelCoordOffsetToIndexOffset(relevantNeighbors.diagonalNeighbor)];
info->diagonalUpNeighbor =
mainChunk.getConstData()[index +
Chunk::voxelCoordOffsetToIndexOffset(relevantNeighbors.diagonalUpNeighbor)];
} else {
info->aboveNeighbor = getVoxelLikelyThisChunk(mainChunkId, mainChunk,
globalCoord + relevantNeighbors.aboveNeighbor);
info->primaryNeighbor = getVoxelLikelyThisChunk(mainChunkId, mainChunk,
globalCoord + relevantNeighbors.primaryNeighbor);
info->secondaryNeighbor = getVoxelLikelyThisChunk(mainChunkId, mainChunk,
globalCoord + relevantNeighbors.secondaryNeighbor);
info->diagonalNeighbor = getVoxelLikelyThisChunk(mainChunkId, mainChunk,
globalCoord + relevantNeighbors.diagonalNeighbor);
info->diagonalUpNeighbor = getVoxelLikelyThisChunk(mainChunkId, mainChunk,
globalCoord + relevantNeighbors.diagonalUpNeighbor);
}
}
void Grid::setCell(const Vector3int16& location, Cell newCell, CellMaterial inputMaterial)
{
if (!Voxel::getTerrainExtentsInCells().contains(location))
return;
const SpatialRegion::Id chunkId = SpatialRegion::regionContainingVoxel(location);
const unsigned int arrayIndex = Chunk::voxelCoordToArrayIndex(location);
Cell prevCell = Constants::kUniqueEmptyCellRepresentation;
CellMaterial prevMaterial = CELL_MATERIAL_Water;
Chunk* existingChunk = chunkMap.find(chunkId);
if (existingChunk) {
prevCell = existingChunk->getConstData()[arrayIndex];
prevMaterial = readMaterial(&(existingChunk->getConstMaterial()[0]),
arrayIndex, prevCell);
}
CellMaterial newMaterial = inputMaterial == CELL_MATERIAL_Unspecified ?
prevMaterial : inputMaterial;
bool changed = prevCell != newCell || prevMaterial != newMaterial;
if (changed) {
// find or create Chunk
Chunk* updatingChunk = existingChunk;
if (!updatingChunk)
{
updatingChunk = &chunkMap.insert(chunkId);
updatingChunk->init(this);
}
bool hadWaterBefore = Water::cellHasWater(updatingChunk, prevCell, location);
updatingChunk->getData()[arrayIndex] = newCell;
writeMaterial(&(updatingChunk->getMaterial()[0]), arrayIndex, newMaterial);
bool hasWaterAfter = Water::cellHasWater(updatingChunk, newCell, location);
int nonEmptyDelta = prevCell.isEmpty() - newCell.isEmpty();
updatingChunk->updateCountOfNonEmptyCells(nonEmptyDelta);
countOfNonEmptyCells += nonEmptyDelta;
if (updatingChunk->hasNoUsefulData()) {
chunkMap.erase(chunkId);
}
CellChangeInfo info(location, prevCell, newCell, hadWaterBefore, hasWaterAfter, newMaterial);
for (unsigned int i = 0; i < cellChangeListeners.size(); ++i) {
cellChangeListeners[i]->terrainCellChanged(info);
}
}
}
Grid::Region Grid::getRegion(
const Vector3int16& minCoord, const Vector3int16& maxCoord) const {
SpatialRegion::Id minId = SpatialRegion::regionContainingVoxel(minCoord);
RBXASSERT(minId == SpatialRegion::regionContainingVoxel(maxCoord));
return Region(chunkMap.find(minId), minCoord, maxCoord);
}
Cell Grid::getCell(const Vector3int16& pos) const {
SpatialRegion::Id chunkId = SpatialRegion::regionContainingVoxel(pos);
if (const Chunk* chunk = chunkMap.find(chunkId)) {
return chunk->getConstData()[Chunk::voxelCoordToArrayIndex(pos)];
}
return Constants::kUniqueEmptyCellRepresentation;
}
CellMaterial Grid::getCellMaterial(const Vector3int16& pos) const {
SpatialRegion::Id chunkId = SpatialRegion::regionContainingVoxel(pos);
if (const Chunk* chunk = chunkMap.find(chunkId)) {
const unsigned int index = Chunk::voxelCoordToArrayIndex(pos);
return readMaterial(&chunk->getConstMaterial()[0], index,
chunk->getConstData()[index]);
}
return CELL_MATERIAL_Water;
}
Cell Grid::getWaterCell(const Vector3int16& pos) const {
SpatialRegion::Id chunkId(SpatialRegion::regionContainingVoxel(pos));
if (const Chunk* chunk = chunkMap.find(chunkId)) {
unsigned int arrayIndex = Chunk::voxelCoordToArrayIndex(pos);
return Water::interpretAsWaterCell(chunk, chunk->getConstData()[arrayIndex], pos);
}
return Constants::kUniqueEmptyCellRepresentation;
}
void Grid::connectListener(CellChangeListener* listener) {
if (std::find(cellChangeListeners.begin(), cellChangeListeners.end(), listener) == cellChangeListeners.end()) {
cellChangeListeners.push_back(listener);
} else {
RBXASSERT(false);
}
}
void Grid::disconnectListener(CellChangeListener* listener) {
std::vector<Voxel::CellChangeListener*>::iterator itr =
std::find(cellChangeListeners.begin(), cellChangeListeners.end(), listener);
if (itr != cellChangeListeners.end()) {
cellChangeListeners.erase(itr);
} else {
RBXASSERT(false);
}
}
std::vector<SpatialRegion::Id> Grid::getNonEmptyChunks() const
{
return chunkMap.getChunks();
}
bool Grid::isAllocated() const {
return countOfNonEmptyCells > 0;
}
std::vector<SpatialRegion::Id> Grid::getNonEmptyChunksInRegion(const Region3int16& extents) const
{
if (extents.empty())
return std::vector<SpatialRegion::Id>();
SpatialRegion::Id minRegion(SpatialRegion::regionContainingVoxel(extents.getMinPos()));
SpatialRegion::Id maxRegion(SpatialRegion::regionContainingVoxel(extents.getMaxPos()));
unsigned int totalRegionCount =
(maxRegion.value().x - minRegion.value().x + 1) *
(maxRegion.value().y - minRegion.value().y + 1) *
(maxRegion.value().z - minRegion.value().z + 1);
// chunkMap.find() is more expensive than isBetweenInclusive
if (totalRegionCount < chunkMap.size() * 2)
{
// We're querying a relatively small area, let's just iterate through all regions
std::vector<SpatialRegion::Id> result;
for (int ry = minRegion.value().y; ry <= maxRegion.value().y; ++ry)
for (int rz = minRegion.value().z; rz <= maxRegion.value().z; ++rz)
for (int rx = minRegion.value().x; rx <= maxRegion.value().x; ++rx)
{
SpatialRegion::Id id(rx, ry, rz);
if (chunkMap.find(id))
result.push_back(id);
}
return result;
}
else
{
// We're querying a relatively large area, let's scan through filled regions inside the grid
std::vector<SpatialRegion::Id> chunks = chunkMap.getChunks();
std::vector<SpatialRegion::Id> result;
for (size_t i = 0; i < chunks.size(); ++i)
{
SpatialRegion::Id id = chunks[i];
if (id.value().isBetweenInclusive(minRegion.value(), maxRegion.value()))
result.push_back(id);
}
return result;
}
}
} }
+12
View File
@@ -0,0 +1,12 @@
#include "stdafx.h"
#include "Voxel/Serializer.h"
namespace RBX { namespace Voxel {
const unsigned char SerializerConstants::kNewCellMarker = 0x01;
const unsigned char SerializerConstants::kRepeatCellMarker = 0x02;
const unsigned char SerializerConstants::kEndSequenceMarker = 0x03;
const unsigned int SerializerConstants::kRecentlyEncodedReferenceBits = 3;
} }
+140
View File
@@ -0,0 +1,140 @@
#include "stdafx.h"
#include "Voxel/Util.h"
namespace RBX { namespace Voxel {
const BlockFaceInfo UnOrientedBlockFaceInfos[6] = {
// Solid
{
{
{ BlockAxisFace::FullNoneSkipped}, // PlusX
{ BlockAxisFace::FullNoneSkipped}, // PlusZ
{ BlockAxisFace::FullNoneSkipped}, // MinusX
{ BlockAxisFace::FullNoneSkipped}, // MinusZ
{ BlockAxisFace::FullNoneSkipped}, // PlusY
{ BlockAxisFace::FullNoneSkipped}, // MinusY
}
},
// Vertical Wedge
{
{
{ BlockAxisFace::TopLeft, }, // PlusX
{ BlockAxisFace::EmptyAllSkipped}, // PlusZ
{ BlockAxisFace::TopRight, }, // MinusX
{ BlockAxisFace::FullNoneSkipped}, // MinusZ
{ BlockAxisFace::EmptyAllSkipped}, // PlusY
{ BlockAxisFace::FullNoneSkipped}, // MinusY
}
},
// Corner Wedge
{
{
{ BlockAxisFace::TopLeft, }, // PlusX
{ BlockAxisFace::EmptyAllSkipped}, // PlusZ
{ BlockAxisFace::EmptyAllSkipped}, // MinusX
{ BlockAxisFace::TopRight, }, // MinusZ
{ BlockAxisFace::EmptyAllSkipped}, // PlusY
{ BlockAxisFace::TopLeft, }, // MinusY
}
},
// Inverse corner Wedge
{
{
{ BlockAxisFace::FullNoneSkipped}, // PlusX
{ BlockAxisFace::TopLeft, }, // PlusZ
{ BlockAxisFace::TopRight, }, // MinusX
{ BlockAxisFace::FullNoneSkipped}, // MinusZ
{ BlockAxisFace::BottomLeft, }, // PlusY
{ BlockAxisFace::FullNoneSkipped}, // MinusY
}
},
// Horizontal Wedge
{
{
{ BlockAxisFace::FullNoneSkipped}, // PlusX
{ BlockAxisFace::EmptyAllSkipped}, // PlusZ
{ BlockAxisFace::EmptyAllSkipped}, // MinusX
{ BlockAxisFace::FullNoneSkipped}, // MinusZ
{ BlockAxisFace::BottomLeft, }, // PlusY
{ BlockAxisFace::TopLeft, }, // MinusY
}
},
// Empty Wedge
{
{
{ BlockAxisFace::EmptyAllSkipped }, // PlusX
{ BlockAxisFace::EmptyAllSkipped }, // PlusZ
{ BlockAxisFace::EmptyAllSkipped }, // MinusX
{ BlockAxisFace::EmptyAllSkipped }, // MinusZ
{ BlockAxisFace::EmptyAllSkipped }, // PlusY
{ BlockAxisFace::EmptyAllSkipped }, // MinusY
}
}
};
BlockAxisFace OrientedFaceMap[ 1536 ];
BlockAxisFace ComputeOrientedFace(const BlockFaceInfo& wedge, FaceDirection f,
CellOrientation orient)
{
if(f < 4)
{
unsigned char index = (f + orient) % 4;
return wedge.faces[index];
}
const BlockAxisFace& basis = wedge.faces[f];
if (basis.skippedCorner == BlockAxisFace::FullNoneSkipped ||
basis.skippedCorner == BlockAxisFace::EmptyAllSkipped) {
return basis;
}
BlockAxisFace result;
// minus Y is the same as plus y, except it is wound backwards.
// encode this by reversing the orient iteration order for minus y:
// 0 1 2 3 => 0 3 2 1
result.skippedCorner = BlockAxisFace::rotate(basis.skippedCorner,
(CellOrientation)(f == MinusY ? (4 - orient) % 4 : orient));
return result;
}
void initBlockOrientationFaceMap()
{
// max materials = 8 to represent that 3 legacy bits were used for material
static int kLEGACY_MAX_MATERIALS = 8;
static int kNUM_WEDGES = 6;
for( int i = 0; i < MAX_CELL_BLOCKS; ++i )
{
const BlockFaceInfo& wedge = i >= kNUM_WEDGES ?
UnOrientedBlockFaceInfos[0] : UnOrientedBlockFaceInfos[i];
for( int j = 0; j < kLEGACY_MAX_MATERIALS; ++j )
{
for( int k = 0; k < MAX_CELL_ORIENTATIONS; ++k )
{
for( int l = 0; l < 6; ++l ) // # of face directions
{
Cell voxel;
voxel.solid.setBlock((CellBlock)i);
voxel.solid.setOrientation((CellOrientation)k);
unsigned char mapIndex = Cell::asUnsignedCharForDeprecatedUses(voxel);
setCellMaterial_Deprecated( mapIndex, (CellMaterial)j );
OrientedFaceMap[ mapIndex*6 + l ] =
ComputeOrientedFace(wedge, (FaceDirection)l, (CellOrientation)k);
}
}
}
}
}
} }
File diff suppressed because it is too large Load Diff
+21
View File
@@ -0,0 +1,21 @@
#include "stdafx.h"
#include "Voxel/Water.h"
namespace RBX { namespace Voxel { namespace Water {
const RelevantNeighbors kRelevantNeighbors[MAX_CELL_ORIENTATIONS] = {
RelevantNeighbors(CELL_ORIENTATION_NegZ),
RelevantNeighbors(CELL_ORIENTATION_X),
RelevantNeighbors(CELL_ORIENTATION_Z),
RelevantNeighbors(CELL_ORIENTATION_NegX),
};
RelevantNeighbors::RelevantNeighbors(CellOrientation orientation) :
aboveNeighbor(kAboveNeighborCellOffset),
primaryNeighbor(kPrimaryNeighborCellOffset[orientation]),
secondaryNeighbor(kSecondaryNeighborCellOffset[orientation]),
diagonalNeighbor(primaryNeighbor + secondaryNeighbor),
diagonalUpNeighbor(primaryNeighbor + secondaryNeighbor + aboveNeighbor) {}
} } }