mirror of https://github.com/buggins/dlangui.git
dminer - chunk
This commit is contained in:
parent
e31fd88107
commit
23fc79142f
|
@ -0,0 +1,451 @@
|
|||
module dminer.core.chunk;
|
||||
|
||||
import dminer.core.minetypes;
|
||||
import dminer.core.blocks;
|
||||
|
||||
enum USE_NEW_WORLD_IMPL = true;
|
||||
|
||||
|
||||
// Y range: 0..CHUNK_DY-1
|
||||
immutable int CHUNK_DY_SHIFT = 7;
|
||||
immutable int CHUNK_DY = (1<<CHUNK_DY_SHIFT);
|
||||
immutable int CHUNK_DY_MASK = (CHUNK_DY - 1);
|
||||
immutable int CHUNK_DY_INV_MASK = ~CHUNK_DY_MASK;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
immutable int CHUNKS_Y = 128 / 8;
|
||||
immutable int CHUNKS_BITS_X = 9;
|
||||
immutable int CHUNKS_BITS_Z = 9;
|
||||
immutable int CHUNKS_X = (1 << CHUNKS_BITS_X); // X range: -CHUNKS_X*8 .. CHUNKS_X*8
|
||||
immutable int CHUNKS_Z = (1 << CHUNKS_BITS_Z); // Z range: -CHUNKS_Z*8 .. CHUNKS_Z*8
|
||||
immutable int CHUNKS_X_MASK = (CHUNKS_X << 1) - 1;
|
||||
immutable int CHUNKS_Z_MASK = (CHUNKS_Z << 1) - 1;
|
||||
|
||||
// vertical stack of chunks with same X, Z, and different Y
|
||||
struct ChunkStack {
|
||||
protected int _minChunkY;
|
||||
protected int _chunkCount;
|
||||
SmallChunk ** _chunks;
|
||||
/// get chunk from stack by chunk Y index
|
||||
SmallChunk * get(int chunkY) {
|
||||
int idx = chunkY - _minChunkY;
|
||||
if (idx < 0 || idx >= _chunkCount)
|
||||
return null;
|
||||
return _chunks[idx];
|
||||
}
|
||||
@property int topNonEmptyY() {
|
||||
return ((_minChunkY + _chunkCount) << 3) - 1;
|
||||
}
|
||||
void set(int chunkY, SmallChunk * item) {
|
||||
int idx = chunkY - _minChunkY;
|
||||
if (idx >= 0 && idx < _chunkCount) {
|
||||
if (_chunks[idx]) {
|
||||
if (_chunks[idx] is item)
|
||||
return;
|
||||
SmallChunk.free(_chunks[idx]);
|
||||
}
|
||||
_chunks[idx] = item;
|
||||
return;
|
||||
} else if (!_chunkCount) {
|
||||
// need to reallocate
|
||||
// initial allocation
|
||||
_minChunkY = chunkY;
|
||||
_chunkCount = 1;
|
||||
_chunks = allocChunks(1);
|
||||
_chunks[0] = item;
|
||||
} else {
|
||||
// need to reallocate
|
||||
// realloc
|
||||
int newMinY;
|
||||
int newChunkCount;
|
||||
if (chunkY < _minChunkY) {
|
||||
newMinY = chunkY;
|
||||
newChunkCount = _minChunkY + _chunkCount - newMinY;
|
||||
} else {
|
||||
newMinY = _minChunkY;
|
||||
newChunkCount = chunkY - _minChunkY + 1;
|
||||
}
|
||||
SmallChunk ** newChunks = allocChunks(newChunkCount);
|
||||
// copy old data
|
||||
for(int i = 0; i < _chunkCount; i++)
|
||||
newChunks[i + _minChunkY - newMinY] = _chunks[i];
|
||||
newChunks[chunkY - newMinY] = item;
|
||||
freeChunks(_chunks);
|
||||
_chunkCount = newChunkCount;
|
||||
_minChunkY = newMinY;
|
||||
_chunks = newChunks;
|
||||
}
|
||||
}
|
||||
private SmallChunk ** allocChunks(int len) {
|
||||
if (len <= 0)
|
||||
return null;
|
||||
import core.stdc.stdlib : malloc;
|
||||
SmallChunk ** res = cast(SmallChunk **) malloc(len * (SmallChunk *).sizeof);
|
||||
for(int i = 0; i < len; i++)
|
||||
res[i] = null;
|
||||
return res;
|
||||
}
|
||||
private void freeChunks(ref SmallChunk ** chunks) {
|
||||
if (chunks) {
|
||||
import core.stdc.stdlib : free;
|
||||
free(chunks);
|
||||
chunks = null;
|
||||
}
|
||||
}
|
||||
void clear() {
|
||||
if (_chunkCount) {
|
||||
for(int i = 0; i < _chunkCount; i++) {
|
||||
SmallChunk.free(_chunks[i]);
|
||||
}
|
||||
freeChunks(_chunks);
|
||||
}
|
||||
_chunks = null;
|
||||
_chunkCount = 0;
|
||||
_minChunkY = -1;
|
||||
}
|
||||
~this() {
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// 8x8x8 chunk
|
||||
struct SmallChunk {
|
||||
cell_t[8*8*8] cells; // 512 bytes
|
||||
ubyte[8*8*8] sunlight; // 512 bytes
|
||||
ulong[8] opaquePlanesX; // 64 bytes
|
||||
ulong[8] opaquePlanesY; // 64 bytes
|
||||
ulong[8] opaquePlanesZ; // 64 bytes
|
||||
ulong[8] canPassPlanesX; // 64 bytes
|
||||
ulong[8] canPassPlanesY; // 64 bytes
|
||||
ulong[8] canPassPlanesZ; // 64 bytes
|
||||
ulong[6][6] canPassFromTo; // 288 bytes
|
||||
SmallChunk * [6] nearChunks;
|
||||
bool dirty;
|
||||
|
||||
static SmallChunk * alloc() nothrow @nogc {
|
||||
import core.stdc.stdlib : malloc;
|
||||
SmallChunk * res = cast(SmallChunk *)malloc(SmallChunk.sizeof);
|
||||
*res = SmallChunk.init;
|
||||
return res;
|
||||
}
|
||||
|
||||
static void free(SmallChunk * obj) {
|
||||
if (!obj)
|
||||
return;
|
||||
import core.stdc.stdlib : free;
|
||||
free(obj);
|
||||
}
|
||||
|
||||
cell_t getCell(int x, int y, int z) const {
|
||||
return cells[((((y&7) << 3) | (z&7)) << 3) | (x&7)];
|
||||
}
|
||||
void setCell(int x, int y, int z, cell_t value) {
|
||||
dirty = true;
|
||||
cells[((((y&7) << 3) | (z&7)) << 3) | (x&7)] = value;
|
||||
}
|
||||
cell_t getCellNoCheck(int x, int y, int z) const {
|
||||
return cells[(((y << 3) | z) << 3) | x];
|
||||
}
|
||||
void generateMasks() {
|
||||
// x planes: z,y
|
||||
for(int x = 0; x < 8; x++) {
|
||||
ulong opaqueFlags = 0;
|
||||
ulong canPassFlags = 0;
|
||||
ulong mask = 1;
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int z = 0; z < 8; z++) {
|
||||
cell_t cell = cells[(((y << 3) | z) << 3) | x];
|
||||
if (BLOCK_TYPE_OPAQUE.ptr[cell])
|
||||
opaqueFlags |= mask;
|
||||
if (BLOCK_TYPE_CAN_PASS.ptr[cell])
|
||||
canPassFlags |= mask;
|
||||
mask = mask << 1;
|
||||
}
|
||||
}
|
||||
opaquePlanesX[x] = opaqueFlags;
|
||||
canPassPlanesX[x] = canPassFlags;
|
||||
}
|
||||
// y planes : x,z
|
||||
for(int y = 0; y < 8; y++) {
|
||||
ulong opaqueFlags = 0;
|
||||
ulong canPassFlags = 0;
|
||||
ulong mask = 1;
|
||||
for (int z = 0; z < 8; z++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
cell_t cell = cells[(((y << 3) | z) << 3) | x];
|
||||
if (BLOCK_TYPE_OPAQUE.ptr[cell])
|
||||
opaqueFlags |= mask;
|
||||
if (BLOCK_TYPE_CAN_PASS.ptr[cell])
|
||||
canPassFlags |= mask;
|
||||
mask = mask << 1;
|
||||
}
|
||||
}
|
||||
opaquePlanesY[y] = opaqueFlags;
|
||||
canPassPlanesY[y] = canPassFlags;
|
||||
}
|
||||
// z planes: x,y
|
||||
for(int z = 0; z < 8; z++) {
|
||||
ulong opaqueFlags = 0;
|
||||
ulong canPassFlags = 0;
|
||||
ulong mask = 1;
|
||||
for (int y = 0; y < 8; y++) {
|
||||
for (int x = 0; x < 8; x++) {
|
||||
cell_t cell = cells[(((y << 3) | z) << 3) | x];
|
||||
if (BLOCK_TYPE_OPAQUE.ptr[cell])
|
||||
opaqueFlags |= mask;
|
||||
if (BLOCK_TYPE_CAN_PASS.ptr[cell])
|
||||
canPassFlags |= mask;
|
||||
mask = mask << 1;
|
||||
}
|
||||
}
|
||||
opaquePlanesZ[z] = opaqueFlags;
|
||||
canPassPlanesZ[z] = canPassFlags;
|
||||
}
|
||||
// can pass from to
|
||||
for (Dir from = Dir.min; from <= Dir.max; ++from) {
|
||||
for (Dir to = Dir.min; to <= Dir.max; ++to) {
|
||||
}
|
||||
}
|
||||
dirty = false;
|
||||
}
|
||||
static void spreadFlags(ulong src, ref ulong[8] planes, ref ulong[8] dst, int start, int end, ubyte spreadMask) {
|
||||
if (start < end) {
|
||||
for (int i = start; i <= end; ++i) {
|
||||
ulong mask = src;
|
||||
if (spreadMask & SpreadMask.SpreadLeft)
|
||||
mask |= ((src << 1) & 0xFEFEFEFEFEFEFEFE);
|
||||
if (spreadMask & SpreadMask.SpreadRight)
|
||||
mask |= ((src >> 1) & 0x7F7F7F7F7F7F7F7F);
|
||||
if (spreadMask & SpreadMask.SpreadUp)
|
||||
mask |= ((src << 8) & 0xFFFFFFFFFFFFFF00);
|
||||
if (spreadMask & SpreadMask.SpreadDown)
|
||||
mask |= ((src >> 8) & 0x00FFFFFFFFFFFFFF);
|
||||
src = planes[i] & mask;
|
||||
dst[i] = src;
|
||||
}
|
||||
} else {
|
||||
for (int i = end; i >= start; --i) {
|
||||
ulong mask = src;
|
||||
if (spreadMask & SpreadMask.SpreadLeft)
|
||||
mask |= ((src << 1) & 0xFEFEFEFEFEFEFEFE);
|
||||
if (spreadMask & SpreadMask.SpreadRight)
|
||||
mask |= ((src >> 1) & 0x7F7F7F7F7F7F7F7F);
|
||||
if (spreadMask & SpreadMask.SpreadUp)
|
||||
mask |= ((src << 8) & 0xFFFFFFFFFFFFFF00);
|
||||
if (spreadMask & SpreadMask.SpreadDown)
|
||||
mask |= ((src >> 8) & 0x00FFFFFFFFFFFFFF);
|
||||
src = planes[i] & mask;
|
||||
dst[i] = src;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ulong canPass(ulong mask, Dir dir, Dir to, ubyte dirMask = DirMask.MASK_ALL) {
|
||||
ulong[8] planes;
|
||||
ubyte spreadMask = DIR_AND_MASK_TO_SPREAD_FLAGS[dirMask][dir];
|
||||
final switch(dir) with (Dir) {
|
||||
case NORTH:
|
||||
spreadFlags(mask, canPassPlanesZ, planes, 0, 7, spreadMask);
|
||||
final switch (to) {
|
||||
case NORTH:
|
||||
return planes[7];
|
||||
case SOUTH:
|
||||
return planes[0];
|
||||
case EAST:
|
||||
return slicePlane7(planes);
|
||||
case WEST:
|
||||
return slicePlane0(planes);
|
||||
case UP:
|
||||
return slicePlane7(planes);
|
||||
case DOWN:
|
||||
return slicePlane0(planes);
|
||||
}
|
||||
case SOUTH:
|
||||
spreadFlags(mask, canPassPlanesZ, planes, 7, 0, spreadMask);
|
||||
final switch (to) {
|
||||
case NORTH:
|
||||
return planes[7];
|
||||
case SOUTH:
|
||||
return planes[0];
|
||||
case EAST:
|
||||
return slicePlane7(planes);
|
||||
case WEST:
|
||||
return slicePlane0(planes);
|
||||
case UP:
|
||||
return slicePlane7(planes);
|
||||
case DOWN:
|
||||
return slicePlane0(planes);
|
||||
}
|
||||
case WEST:
|
||||
spreadFlags(mask, canPassPlanesX, planes, 7, 0, spreadMask);
|
||||
final switch (to) {
|
||||
case NORTH:
|
||||
return slicePlane7(planes);
|
||||
case SOUTH:
|
||||
return slicePlane0(planes);
|
||||
case EAST:
|
||||
return planes[7];
|
||||
case WEST:
|
||||
return planes[0];
|
||||
case UP:
|
||||
return slicePlane7(planes);
|
||||
case DOWN:
|
||||
return slicePlane0(planes);
|
||||
}
|
||||
case EAST:
|
||||
spreadFlags(mask, canPassPlanesX, planes, 0, 7, spreadMask);
|
||||
final switch (to) {
|
||||
case NORTH:
|
||||
return slicePlane7(planes);
|
||||
case SOUTH:
|
||||
return slicePlane0(planes);
|
||||
case EAST:
|
||||
return planes[7];
|
||||
case WEST:
|
||||
return planes[0];
|
||||
case UP:
|
||||
return slicePlane7(planes);
|
||||
case DOWN:
|
||||
return slicePlane0(planes);
|
||||
}
|
||||
case UP:
|
||||
spreadFlags(mask, canPassPlanesY, planes, 0, 7, spreadMask);
|
||||
final switch (to) {
|
||||
case NORTH:
|
||||
return slicePlane7(planes);
|
||||
case SOUTH:
|
||||
return slicePlane0(planes);
|
||||
case EAST:
|
||||
return slicePlane7(planes);
|
||||
case WEST:
|
||||
return slicePlane0(planes);
|
||||
case UP:
|
||||
return planes[7];
|
||||
case DOWN:
|
||||
return planes[0];
|
||||
}
|
||||
case DOWN:
|
||||
spreadFlags(mask, canPassPlanesY, planes, 7, 0, spreadMask);
|
||||
final switch (to) {
|
||||
case NORTH:
|
||||
return slicePlane7(planes);
|
||||
case SOUTH:
|
||||
return slicePlane0(planes);
|
||||
case EAST:
|
||||
return slicePlane7(planes);
|
||||
case WEST:
|
||||
return slicePlane0(planes);
|
||||
case UP:
|
||||
return planes[7];
|
||||
case DOWN:
|
||||
return planes[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static ulong slicePlane0(ref ulong[8] planes) {
|
||||
ulong res = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
res |= (planes[i] & 0x0101010101010101) << i;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
static ulong slicePlane7(ref ulong[8] planes) {
|
||||
ulong res = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
res |= (planes[i] & 0x8080808080808080) >> (7 - i);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
enum SpreadMask : ubyte {
|
||||
SpreadLeft = 1,
|
||||
SpreadRight = 2,
|
||||
SpreadUp = 4,
|
||||
SpreadDown = 8,
|
||||
}
|
||||
|
||||
ubyte dirMaskToSpreadMask(Dir dir, ubyte dirMask) {
|
||||
ubyte res = 0;
|
||||
final switch (dir) with (Dir) {
|
||||
case NORTH: // from north
|
||||
case SOUTH:
|
||||
res |= (dirMask & DirMask.MASK_UP) ? SpreadMask.SpreadUp : 0;
|
||||
res |= (dirMask & DirMask.MASK_DOWN) ? SpreadMask.SpreadDown : 0;
|
||||
res |= (dirMask & DirMask.MASK_EAST) ? SpreadMask.SpreadLeft : 0;
|
||||
res |= (dirMask & DirMask.MASK_WEST) ? SpreadMask.SpreadRight : 0;
|
||||
break;
|
||||
case WEST:
|
||||
case EAST:
|
||||
res |= (dirMask & DirMask.MASK_UP) ? SpreadMask.SpreadUp : 0;
|
||||
res |= (dirMask & DirMask.MASK_DOWN) ? SpreadMask.SpreadDown : 0;
|
||||
res |= (dirMask & DirMask.MASK_NORTH) ? SpreadMask.SpreadLeft : 0;
|
||||
res |= (dirMask & DirMask.MASK_SOUTH) ? SpreadMask.SpreadRight : 0;
|
||||
break;
|
||||
case UP:
|
||||
case DOWN:
|
||||
res |= (dirMask & DirMask.MASK_EAST) ? SpreadMask.SpreadLeft : 0;
|
||||
res |= (dirMask & DirMask.MASK_WEST) ? SpreadMask.SpreadRight : 0;
|
||||
res |= (dirMask & DirMask.MASK_NORTH) ? SpreadMask.SpreadUp : 0;
|
||||
res |= (dirMask & DirMask.MASK_SOUTH) ? SpreadMask.SpreadDown : 0;
|
||||
break;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// immutable SpreadMask[DirMask][Dir] DIR_AND_MASK_TO_SPREAD_FLAGS
|
||||
mixin(generateDirMaskSource());
|
||||
|
||||
string generateDirMaskSource() {
|
||||
import std.conv : to;
|
||||
char[] src;
|
||||
src ~= "immutable ubyte[64][6] DIR_AND_MASK_TO_SPREAD_FLAGS = [\n";
|
||||
for (Dir from = Dir.min; from <= Dir.max; from++) {
|
||||
if (from)
|
||||
src ~= ",\n";
|
||||
src ~= " // ";
|
||||
src ~= to!string(from);
|
||||
src ~= "\n [";
|
||||
for (ubyte mask = 0; mask < 64; mask++) {
|
||||
ubyte res = dirMaskToSpreadMask(from, mask);
|
||||
if (mask)
|
||||
src ~= ", ";
|
||||
if (mask == 32)
|
||||
src ~= "\n ";
|
||||
src ~= to!string(res);
|
||||
}
|
||||
src ~= "]";
|
||||
}
|
||||
src ~= "\n];\n";
|
||||
return src.dup;
|
||||
}
|
||||
|
||||
void testDirMaskToSpreadMask() {
|
||||
import dlangui.core.logger;
|
||||
for (Dir from = Dir.min; from <= Dir.max; from++) {
|
||||
for (ubyte mask = 0; mask < 64; mask++) {
|
||||
ubyte res = dirMaskToSpreadMask(from, mask);
|
||||
char[]buf;
|
||||
buf ~= "[";
|
||||
if (mask & DirMask.MASK_NORTH) buf ~= " NORTH";
|
||||
if (mask & DirMask.MASK_SOUTH) buf ~= " SOUTH";
|
||||
if (mask & DirMask.MASK_WEST) buf ~= " WEST";
|
||||
if (mask & DirMask.MASK_EAST) buf ~= " EAST";
|
||||
if (mask & DirMask.MASK_UP) buf ~= " UP";
|
||||
if (mask & DirMask.MASK_DOWN) buf ~= " DOWN";
|
||||
buf ~= " ] => (";
|
||||
if (res & SpreadMask.SpreadLeft) buf ~= " SpreadLeft";
|
||||
if (res & SpreadMask.SpreadRight) buf ~= " SpreadRight";
|
||||
if (res & SpreadMask.SpreadUp) buf ~= " SpreadUp";
|
||||
if (res & SpreadMask.SpreadDown) buf ~= " SpreadDown";
|
||||
buf ~= " )";
|
||||
Log.d("dirMaskToSpreadMask ", from, " ", buf);
|
||||
}
|
||||
}
|
||||
Log.d("Source: \n", generateDirMaskSource());
|
||||
}
|
Loading…
Reference in New Issue