mirror of
https://github.com/copyrighttxt/watrbx-game-engine.git
synced 2026-09-04 20:57:49 +00:00
207 lines
6.2 KiB
C++
207 lines
6.2 KiB
C++
#pragma once
|
|
|
|
#include <boost/static_assert.hpp>
|
|
#include <ostream>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Defines voxels at the cellular and sub-cellular level
|
|
|
|
namespace RBX { namespace Voxel {
|
|
|
|
enum CellMaterial
|
|
{
|
|
CELL_MATERIAL_Deprecated_Empty = 0,
|
|
CELL_MATERIAL_Grass = 1,
|
|
CELL_MATERIAL_Sand = 2,
|
|
CELL_MATERIAL_Brick = 3,
|
|
CELL_MATERIAL_Granite = 4,
|
|
CELL_MATERIAL_Asphalt = 5,
|
|
CELL_MATERIAL_Iron = 6,
|
|
CELL_MATERIAL_Aluminum = 7,
|
|
CELL_MATERIAL_Gold = 8,
|
|
CELL_MATERIAL_Wood_Plank = 9,
|
|
CELL_MATERIAL_Wood_Log = 10,
|
|
CELL_MATERIAL_Gravel = 11,
|
|
CELL_MATERIAL_Cinder_Block = 12,
|
|
CELL_MATERIAL_Stone_Block = 13,
|
|
CELL_MATERIAL_Cement = 14,
|
|
CELL_MATERIAL_Red_Plastic = 15,
|
|
CELL_MATERIAL_Blue_Plastic = 16,
|
|
CELL_MATERIAL_Water = 17,
|
|
CELL_MATERIAL_Unspecified = 255,
|
|
MAX_CELL_MATERIALS = 18,
|
|
};
|
|
|
|
enum CellBlock
|
|
{
|
|
CELL_BLOCK_Solid = 0,
|
|
CELL_BLOCK_VerticalWedge = 1,
|
|
CELL_BLOCK_CornerWedge = 2,
|
|
CELL_BLOCK_InverseCornerWedge = 3,
|
|
CELL_BLOCK_HorizontalWedge = 4,
|
|
|
|
// Enum values below this line are intentionally not reflected!
|
|
// Talk with dignatoff@ before exposing these enums!
|
|
CELL_BLOCK_Empty = 5,
|
|
|
|
//InverseVerticalWedge = 4,
|
|
//TopCornerWedge = 5,
|
|
MAX_CELL_BLOCKS = 8,
|
|
};
|
|
|
|
// Viewed from a downwards vertical perspective,
|
|
// orientation defines the corner that the block starts in in a clockwise fashion
|
|
enum CellOrientation
|
|
{
|
|
CELL_ORIENTATION_NegZ = 0, // upper left
|
|
CELL_ORIENTATION_X = 1, // upper right
|
|
CELL_ORIENTATION_Z = 2, // lower right
|
|
CELL_ORIENTATION_NegX = 3, // lower left
|
|
MAX_CELL_ORIENTATIONS = 4
|
|
};
|
|
|
|
enum WaterCellForce
|
|
{
|
|
WATER_CELL_FORCE_None = 0,
|
|
WATER_CELL_FORCE_Small = 1,
|
|
WATER_CELL_FORCE_Medium = 2,
|
|
WATER_CELL_FORCE_Strong = 3,
|
|
WATER_CELL_FORCE_MaxForce = 4,
|
|
MAX_WATER_CELL_FORCES = 5
|
|
};
|
|
|
|
enum WaterCellDirection
|
|
{
|
|
WATER_CELL_DIRECTION_NegX = 0,
|
|
WATER_CELL_DIRECTION_X = 1,
|
|
WATER_CELL_DIRECTION_NegY = 2,
|
|
WATER_CELL_DIRECTION_Y = 3,
|
|
WATER_CELL_DIRECTION_NegZ = 4,
|
|
WATER_CELL_DIRECTION_Z = 5,
|
|
MAX_WATER_CELL_DIRECTIONS = 6
|
|
};
|
|
|
|
class SolidTerrainCell {
|
|
// Material used to be stored in solid terrain voxel; it has
|
|
// subsequently been moved to a completely separate storage mechanism.
|
|
// The field is here to preserve memory layout with the earlier version.
|
|
unsigned char DEPRECATED_material : 3;
|
|
unsigned char block : 3;
|
|
unsigned char orientation : 2;
|
|
|
|
public:
|
|
CellBlock getBlock() const { return (CellBlock) block; }
|
|
CellOrientation getOrientation() const {
|
|
return (CellOrientation) orientation;
|
|
}
|
|
|
|
void setBlock(CellBlock block) { this->block = block; }
|
|
void setOrientation(CellOrientation orientation) {
|
|
this->orientation = orientation;
|
|
}
|
|
};
|
|
|
|
class WaterCell {
|
|
// Water voxels are implemented to be bit-compatible with solid voxels,
|
|
// so this bit layout matches the bit layout of SolidTerrainCell.
|
|
unsigned char dataPart2 : 3;
|
|
unsigned char blockMustBeEmpty : 3;
|
|
unsigned char dataPart1 : 2;
|
|
|
|
unsigned int getWaterData() const {
|
|
return ((dataPart1 << 3) | dataPart2) - 1;
|
|
}
|
|
public:
|
|
WaterCellForce getForce() const {
|
|
return (WaterCellForce) ((getWaterData() / MAX_WATER_CELL_DIRECTIONS) % MAX_WATER_CELL_FORCES);
|
|
}
|
|
WaterCellDirection getDirection() const {
|
|
return (WaterCellDirection) (getWaterData() % MAX_WATER_CELL_DIRECTIONS);
|
|
}
|
|
|
|
void setForceAndDirection(WaterCellForce force, WaterCellDirection direction) {
|
|
unsigned int rawData = (force * MAX_WATER_CELL_DIRECTIONS + direction) + 1;
|
|
dataPart2 = rawData & 0x7;
|
|
dataPart1 = (rawData >> 3) & 0x3;
|
|
}
|
|
};
|
|
|
|
// Data structure that represents one voxel cell. The cell can either be water or solid terrain,
|
|
// so this class is a union of WaterCell and SolidTerrainCell.
|
|
union Cell {
|
|
SolidTerrainCell solid;
|
|
WaterCell water;
|
|
|
|
Cell() {
|
|
// There isn't a simple way to make sure all of the members are
|
|
// zero by going through setter methods. SolidTerrainCell, for example,
|
|
// has no way to control the bits in DEPRECATED_material.
|
|
// Performance testing has shown this to not be a perf hit compared to
|
|
// casting this to unsigned char* and setting that to zero.
|
|
memset(this, 0, sizeof(Cell));
|
|
}
|
|
|
|
// True if the voxel is completely empty (no solid terrain and no water)
|
|
inline bool isEmpty() const;
|
|
|
|
// Indicates if this cell has been set to water explicitly by the user.
|
|
// Note that water can also exist in wedge cells. Use Region and/or
|
|
// Region::iterator methods for a way to detect all kinds of water
|
|
// simultaneously.
|
|
inline bool isExplicitWaterCell() const { return !isEmpty() && solid.getBlock() == CELL_BLOCK_Empty; }
|
|
|
|
inline bool operator==(const Cell& other) const {
|
|
return ((const unsigned char*)this)[0] == ((const unsigned char*)&other)[0];
|
|
}
|
|
inline bool operator!=(const Cell& other) const {
|
|
return !((*this) == other);
|
|
}
|
|
|
|
// Convert to/from unsigned char, for networking and saving to file
|
|
static inline unsigned char serializeAsUnsignedChar(const Cell v) {
|
|
return ((unsigned char*)&v)[0];
|
|
}
|
|
static inline Cell deserializeFromUnsignedChar(unsigned char cell) {
|
|
return ((Cell*)&cell)[0];
|
|
}
|
|
static inline unsigned char convertToUnsignedCharForFile(const Cell v) {
|
|
return ((unsigned char*)&v)[0];
|
|
}
|
|
static inline Cell readUnsignedCharFromFile(unsigned char cell) {
|
|
return ((Cell*)&cell)[0];
|
|
}
|
|
// Old style voxel access. Avoid using these methods where possible.
|
|
static inline unsigned char asUnsignedCharForDeprecatedUses(const Cell v) {
|
|
return ((unsigned char*)&v)[0];
|
|
}
|
|
static inline Cell readUnsignedCharFromDeprecatedUse(unsigned char cell) {
|
|
return ((Cell*)&cell)[0];
|
|
}
|
|
};
|
|
|
|
BOOST_STATIC_ASSERT(sizeof(Cell) == 1);
|
|
|
|
namespace Constants {
|
|
// There is exactly one way to represent an empty cell. This constant stores that representation.
|
|
extern const Cell kUniqueEmptyCellRepresentation;
|
|
// When there is water in a cell that has a solid wedge, the water state is always the same. This
|
|
// constant stores the water state for water-on-wedge cells.
|
|
extern const Cell kWaterOnWedgeCell;
|
|
}
|
|
|
|
bool Cell::isEmpty() const {
|
|
return (*this) == Constants::kUniqueEmptyCellRepresentation;
|
|
}
|
|
|
|
std::ostream& operator<<(std::ostream& os, const RBX::Voxel::Cell& v);
|
|
|
|
const int kXZ_CHUNK_SIZE = 32;
|
|
const int kY_CHUNK_SIZE = 16;
|
|
|
|
const int kCELL_SIZE = 4;
|
|
const int kHALF_CELL = kCELL_SIZE / 2;
|
|
const int kCELL_SIZE_AS_BIT_SHIFT = 2;
|
|
|
|
} }
|
|
|