miner example improvements

This commit is contained in:
Vadim Lopatin 2017-05-12 15:31:27 +03:00
parent 83072c5254
commit c8a9d34534
4 changed files with 410 additions and 165 deletions

View File

@ -5,6 +5,8 @@ import dminer.core.blocks;
import dminer.core.world;
import dlangui.graphics.scene.mesh;
// Y range: 0..CHUNK_DY-1
immutable int CHUNK_DY = 128;
@ -25,6 +27,10 @@ interface CellVisitor {
void visit(World world, ref Position camPosition, Vector3d pos, cell_t cell, int visibleFaces);
}
interface ChunkVisitor {
void visit(World world, SmallChunk * chunk);
}
// vertical stack of chunks with same X, Z, and different Y
struct ChunkStack {
protected int _minChunkY;
@ -135,15 +141,15 @@ struct ChunkStack {
struct SmallChunk {
protected cell_t[8*8*8] cells; // 512 bytes
protected ubyte[8*8*8] sunlight; // 512 bytes
protected ulong[8] opaquePlanesX; // 64 bytes
protected ulong[8] opaquePlanesY; // 64 bytes
protected ulong[8] opaquePlanesZ; // 64 bytes
protected ulong[8] visiblePlanesX; // 64 bytes
protected ulong[8] visiblePlanesY; // 64 bytes
protected ulong[8] visiblePlanesZ; // 64 bytes
protected ulong[8] canPassPlanesX; // 64 bytes
protected ulong[8] canPassPlanesY; // 64 bytes
protected ulong[8] canPassPlanesZ; // 64 bytes
protected ulong[8] opaquePlanesX; // 64 bytes WEST to EAST
protected ulong[8] opaquePlanesY; // 64 bytes DOWN to UP
protected ulong[8] opaquePlanesZ; // 64 bytes NORTH to SOUTH
protected ulong[8] visiblePlanesX; // 64 bytes WEST to EAST
protected ulong[8] visiblePlanesY; // 64 bytes DOWN to UP
protected ulong[8] visiblePlanesZ; // 64 bytes NORTH to SOUTH
protected ulong[8] canPassPlanesX; // 64 bytes WEST to EAST
protected ulong[8] canPassPlanesY; // 64 bytes DOWN to UP
protected ulong[8] canPassPlanesZ; // 64 bytes NORTH to SOUTH
//ulong[6][6] canPassFromTo; // 288 bytes
SmallChunk * [6] nearChunks;
protected Vector3d _pos;
@ -389,6 +395,40 @@ struct SmallChunk {
}
return count;
}
/*
X planes (WEST EAST): z, y
z=0 z=1 z=2 z=3 z=4 z=5 z=6 z=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
Y planes (DOWN UP): x, z
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
z=0 0 1 2 3 4 5 6 7
z=1 8 9 10 11 12 13 14 15
z=2 16 17 18 19 29 21 22 23
z=3 24 25 26 27 28 29 30 31
z=4 32 33 34 35 36 37 38 39
z=5 40 41 42 43 44 45 46 47
z=6 48 49 50 51 52 53 54 55
z=7 56 57 58 59 60 61 62 63
Z planes (NORTH SOUTH): x, y
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
*/
private void generateMasks() {
// x planes: z,y
for(int x = 0; x < 8; x++) {
@ -707,3 +747,334 @@ void testDirMaskToSpreadMask() {
Log.d("Source: \n", generateDirMaskSource());
}
/// mask for available spread direction for chunk dest visited from camera chunk position origin
ubyte calcSpreadMask(Vector3d dest, Vector3d origin) {
ubyte res = 0;
if (dest.x < origin.x) {
res |= DirMask.MASK_WEST;
} else if (dest.x > origin.x) {
res |= DirMask.MASK_EAST;
} else {
res |= DirMask.MASK_WEST | DirMask.MASK_EAST;
}
if (dest.y < origin.y) {
res |= DirMask.MASK_DOWN;
} else if (dest.y > origin.y) {
res |= DirMask.MASK_UP;
} else {
res |= DirMask.MASK_DOWN | DirMask.MASK_UP;
}
if (dest.z < origin.z) {
res |= DirMask.MASK_NORTH;
} else if (dest.z > origin.z) {
res |= DirMask.MASK_SOUTH;
} else {
res |= DirMask.MASK_NORTH | DirMask.MASK_SOUTH;
}
return res;
}
/*
Z planes (NORTH SOUTH): x, y
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
*/
ulong spreadZPlane(ulong mask, ulong canPassMask, ubyte spreadToDirMask) {
ulong res = mask & canPassMask;
if (!res)
return 0;
if (spreadToDirMask & DirMask.MASK_WEST) { // x--
res |= ((mask & 0xFEFEFEFEFEFEFEFEL) >> 1) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_EAST) { // x++
res |= ((mask & 0x7f7f7f7f7f7f7f7fL) << 1) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_UP) { // y++
res |= ((mask & 0x00ffffffffffffffL) << 8) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_DOWN) { // y--
res |= ((mask & 0xffffffffffffff00L) >> 8) & canPassMask;
}
return res;
}
/*
X planes (WEST EAST): z, y
z=0 z=1 z=2 z=3 z=4 z=5 z=6 z=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
*/
ulong spreadXPlane(ulong mask, ulong canPassMask, ubyte spreadToDirMask) {
ulong res = mask & canPassMask;
if (!res)
return 0;
if (spreadToDirMask & DirMask.MASK_NORTH) { // z--
res |= ((mask & 0xFEFEFEFEFEFEFEFEL) >> 1) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_SOUTH) { // z++
res |= ((mask & 0x7f7f7f7f7f7f7f7fL) << 1) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_UP) { // y++
res |= ((mask & 0x00ffffffffffffffL) << 8) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_DOWN) { // y--
res |= ((mask & 0xffffffffffffff00L) >> 8) & canPassMask;
}
return res;
}
/*
Y planes (DOWN UP): x, z
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
z=0 0 1 2 3 4 5 6 7
z=1 8 9 10 11 12 13 14 15
z=2 16 17 18 19 29 21 22 23
z=3 24 25 26 27 28 29 30 31
z=4 32 33 34 35 36 37 38 39
z=5 40 41 42 43 44 45 46 47
z=6 48 49 50 51 52 53 54 55
z=7 56 57 58 59 60 61 62 63
*/
ulong spreadYPlane(ulong mask, ulong canPassMask, ubyte spreadToDirMask) {
ulong res = mask & canPassMask;
if (!res)
return 0;
if (spreadToDirMask & DirMask.MASK_WEST) { // x--
res |= ((mask & 0xFEFEFEFEFEFEFEFEL) >> 1) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_EAST) { // x++
res |= ((mask & 0x7f7f7f7f7f7f7f7fL) << 1) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_SOUTH) { // z++
res |= ((mask & 0x00ffffffffffffffL) << 8) & canPassMask;
}
if (spreadToDirMask & DirMask.MASK_NORTH) { // z--
res |= ((mask & 0xffffffffffffff00L) >> 8) & canPassMask;
}
return res;
}
/*
Z planes (NORTH SOUTH): x, y
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
X planes (WEST EAST): z, y
z=0 z=1 z=2 z=3 z=4 z=5 z=6 z=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
*/
ulong xPlaneFromZplanes(ref ulong[8] planes, int x) {
ulong res = 0;
for (int z = 0; z < 8; z++) {
ulong n = planes[z]; // one plane == z
n = n >> x; // move to low bit
n &= 0x0101010101010101L;
n = n << z; // move to Z bit
res |= n;
}
return res;
}
/*
Z planes (NORTH SOUTH): x, y
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
Y planes (DOWN UP): x, z
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
z=0 0 1 2 3 4 5 6 7
z=1 8 9 10 11 12 13 14 15
z=2 16 17 18 19 29 21 22 23
z=3 24 25 26 27 28 29 30 31
z=4 32 33 34 35 36 37 38 39
z=5 40 41 42 43 44 45 46 47
z=6 48 49 50 51 52 53 54 55
z=7 56 57 58 59 60 61 62 63
*/
ulong yPlaneFromZplanes(ref ulong[8] planes, int y) {
ulong res = 0;
for (int z = 0; z < 8; z++) {
ulong n = planes[z]; // one plane == z
n = n >> (y * 3); // move to low byte
n &= 0xFF;
n = n << (z * 3); // move to Z position
res |= n;
}
return res;
}
struct VisibilityCheckChunk {
SmallChunk * chunk;
ulong[6] maskFrom;
ulong[6] maskTo;
ubyte visitedFromDirMask;
ubyte spreadToDirMask;
void setMask(ulong mask, Dir fromDir) {
maskFrom[fromDir] |= mask;
visitedFromDirMask |= (1 << fromDir);
}
/*
Z planes (NORTH SOUTH): x, y
x=0 x=1 x=2 x=3 x=4 x=5 x=6 x=7
y=0 0 1 2 3 4 5 6 7
y=1 8 9 10 11 12 13 14 15
y=2 16 17 18 19 29 21 22 23
y=3 24 25 26 27 28 29 30 31
y=4 32 33 34 35 36 37 38 39
y=5 40 41 42 43 44 45 46 47
y=6 48 49 50 51 52 53 54 55
y=7 56 57 58 59 60 61 62 63
*/
void applyZPlanesTrace(ref ulong[8] planes) {
if (spreadToDirMask & DirMask.MASK_WEST) { // x--
// X planes (WEST EAST): z, y
maskTo[Dir.WEST] |= xPlaneFromZplanes(planes, 0);
}
if (spreadToDirMask & DirMask.MASK_EAST) { // x++
// X planes (WEST EAST): z, y
maskTo[Dir.EAST] |= xPlaneFromZplanes(planes, 7);
}
if (spreadToDirMask & DirMask.MASK_DOWN) { // y--
// Y planes (DOWN UP): x, z
maskTo[Dir.DOWN] |= yPlaneFromZplanes(planes, 0);
}
if (spreadToDirMask & DirMask.MASK_UP) { // y++
// Y planes (DOWN UP): x, z
maskTo[Dir.UP] |= yPlaneFromZplanes(planes, 7);
}
}
void tracePaths() {
if (auto mask = maskFrom[Dir.NORTH]) {
ulong[8] planes;
for (int i = 7; i >= 0; i--) {
mask = spreadZPlane(mask, chunk.canPassPlanesZ[i], spreadToDirMask);
if (!mask)
break;
planes[i] = mask;
}
maskTo[Dir.NORTH] |= planes[0];
applyZPlanesTrace(planes);
} else if (auto mask = maskFrom[Dir.SOUTH]) {
ulong[8] planes;
for (int i = 0; i <= 7; i++) {
mask = spreadZPlane(mask, chunk.canPassPlanesZ[i], spreadToDirMask);
if (!mask)
break;
planes[i] = mask;
}
maskTo[Dir.SOUTH] |= planes[7];
applyZPlanesTrace(planes);
}
if (auto mask = maskFrom[Dir.DOWN]) {
} else if (auto mask = maskFrom[Dir.UP]) {
}
if (auto mask = maskFrom[Dir.WEST]) {
} else if (auto mask = maskFrom[Dir.EAST]) {
}
}
}
/// Diamond iterator for visibility check
struct VisibilityCheckIterator {
World world;
Vector3d startPos;
SmallChunk * startChunk;
ChunkVisitor visitor;
VisibilityCheckChunk[] plannedChunks;
VisibilityCheckChunk[] visitedChunks;
VisibilityCheckChunk * getOrAddPlannedChunk(SmallChunk * newChunk) {
foreach(ref p; plannedChunks) {
if (p.chunk is newChunk)
return &p;
}
VisibilityCheckChunk plan;
plan.chunk = newChunk;
plannedChunks ~= plan;
return &plannedChunks[$ - 1];
}
// step 1: plan visiting chunk
void planVisitChunk(int x, int y, int z, Dir fromDir, ulong mask) {
if (!mask)
return;
SmallChunk * newChunk = world.getCellChunk(x, y, z);
if (!newChunk)
return;
VisibilityCheckChunk * plan = getOrAddPlannedChunk(newChunk);
plan.setMask(mask, fromDir);
}
// step 2: visit all planned chunks: move planned to visited; trace paths; plan new visits
void visitPlannedChunks() {
import std.algorithm : swap;
swap(visitedChunks, plannedChunks);
plannedChunks.length = 0;
foreach (ref p; visitedChunks) {
visitor.visit(world, p.chunk);
/// set mask of spread directions
p.spreadToDirMask = calcSpreadMask(p.chunk.position, startPos);
p.tracePaths;
}
}
void start(World world, Vector3d startPos) {
this.world = world;
this.startChunk = world.getCellChunk(startPos.x, startPos.y, startPos.z);
this.startPos = this.startChunk.position; // position aligned by 8 cells
plannedChunks.assumeSafeAppend;
plannedChunks.length = 0;
visitedChunks.assumeSafeAppend;
visitedChunks.length = 0;
}
void visitVisibleChunks(ChunkVisitor visitor) {
this.visitor = visitor;
visitor.visit(world, startChunk);
if (auto mask = startChunk.getSideCanPassToMask(Dir.NORTH))
planVisitChunk(startPos.x, startPos.y, startPos.z, Dir.NORTH, mask);
if (auto mask = startChunk.getSideCanPassToMask(Dir.SOUTH))
planVisitChunk(startPos.x, startPos.y, startPos.z, Dir.SOUTH, mask);
if (auto mask = startChunk.getSideCanPassToMask(Dir.WEST))
planVisitChunk(startPos.x, startPos.y, startPos.z, Dir.WEST, mask);
if (auto mask = startChunk.getSideCanPassToMask(Dir.EAST))
planVisitChunk(startPos.x, startPos.y, startPos.z, Dir.EAST, mask);
if (auto mask = startChunk.getSideCanPassToMask(Dir.UP))
planVisitChunk(startPos.x, startPos.y, startPos.z, Dir.UP, mask);
if (auto mask = startChunk.getSideCanPassToMask(Dir.DOWN))
planVisitChunk(startPos.x, startPos.y, startPos.z, Dir.DOWN, mask);
}
}

View File

@ -10,13 +10,31 @@ immutable cell_t VISITED_OCCUPIED = 254;
immutable cell_t BOUND_BOTTOM = 253;
immutable cell_t BOUND_SKY = 252;
/*
World coordinates
A UP
|
| / NORTH
| /
WEST |/
-----------|-----------> EAST
/|
/ |
SOUTH/ |
L |
| DOWN
*/
/// World direction
enum Dir : ubyte {
NORTH = 0,
SOUTH,
EAST,
WEST,
UP,
DOWN,
NORTH = 0, /// z--
SOUTH, /// z++
EAST, /// x++
WEST, /// x--
UP, /// y++
DOWN, /// y--
}
// 26 direction masks based on Dir
@ -64,10 +82,15 @@ struct Vector2d {
immutable Vector2d ZERO2 = Vector2d(0, 0);
/// Integer 3d vector: x,y,z
struct Vector3d {
/// WEST-EAST
int x;
/// DOWN-UP
int y;
/// NORTH-SOUTH
int z;
this(int xx, int yy, int zz) {
x = xx;
y = yy;
@ -249,152 +272,6 @@ alias CellArray = Array!(cell_t);
alias Vector2dArray = Array!(Vector2d);
alias Vector3dArray = Array!(Vector3d);
/*
/// array with support of both positive and negative indexes
struct InfiniteArray(T) {
private:
T[] dataPlus;
T[] dataMinus;
int minIdx;
int maxIdx;
public:
@property int minIndex() { return minIdx; }
@property int maxIndex() { return maxIdx; }
void disposeFunction(T p) {
destroy(p);
}
~this() {
foreach(p; dataPlus)
if (p !is T.init)
disposeFunction(p);
foreach(p; dataMinus)
if (p !is T.init)
disposeFunction(p);
}
T get(int index) {
if (index >= 0) {
if (index >= maxIdx)
return T.init;
return dataPlus[index];
} else {
if (index <= minIdx)
return T.init;
return dataMinus[-index];
}
}
void set(int index, T value) {
if (index >= 0) {
if (index >= maxIdx) {
// extend array
if (index <= dataPlus.length) {
int oldsize = dataPlus.length;
int newsize = 1024;
while (newsize <= index)
newsize <<= 1;
dataPlus.length = newsize;
dataPlus.assumeSafeAppend;
for(int i = oldsize; i < newsize; i++)
dataPlus[i] = T.init;
}
maxIdx = index + 1;
}
if (dataPlus[index] !is T.init && dataPlus[index] !is value)
disposeFunction(dataPlus[index]);
dataPlus[index] = value;
} else {
if (index <= minIdx) {
// extend array
if (-index <= dataMinus.length) {
int oldsize = dataMinus.length;
int newsize = 1024;
while (newsize <= -index)
newsize <<= 1;
dataMinus.length = newsize;
dataMinus.assumeSafeAppend;
for(int i = oldsize; i < newsize; i++)
dataMinus[i] = T.init;
}
maxIdx = index - 1;
}
if (dataMinus[-index] !is T.init && dataMinus[-index] !is value)
disposeFunction(dataMinus[-index]);
dataMinus[-index] = value;
}
}
}
struct InfiniteMatrix(T) {
private:
int _size = 0;
int _sizeShift = 0;
int _sizeShiftMul2 = 0;
int _sizeMask = 0;
int _invSizeMask = 0;
T[] _data;
void resize(int newSizeShift) {
int newSize = (1<<newSizeShift);
T[] newdata;
newdata.length = newSize * 2 * newSize * 2;
newdata[0 .. $] = null;
for (int y = -_size; y < _size; y++) {
for (int x = -_size; x < _size; x++) {
T v = get(x, y);
if (x < -newSize || x >= newSize || y < -newSize || y >= newSize) {
// destory: // outside new size
destroy(v);
} else {
// move
newdata[((y + newSize) << (newSizeShift + 1)) | (x + newSize)] = v;
}
}
}
_data = newdata;
_size = newSize;
_sizeShift = newSizeShift;
_sizeShiftMul2 = _sizeShift + 1;
_sizeMask = (1 << _sizeShiftMul2) - 1;
_invSizeMask = ~_sizeMask;
}
int calcIndex(int x, int y) {
return (y << _sizeShiftMul2) + x;
}
public:
@property int size() { return _size; }
T get(int x, int y) {
if (!_data)
return null;
x += _size;
y += _size;
if (!((x | y) & ~_sizeMask)) {
return _data.ptr[(y << _sizeShiftMul2) + x]; //calcIndex(x, y)
}
return null;
}
void set(int x, int y, T v) {
if (x < -_size || x >= _size || y < -_size || y >= _size) {
int newSizeShift = _sizeShift < 6 ? 6 : _sizeShift + 1;
for (; ;newSizeShift++) {
int sz = 1 << newSizeShift;
if (x < -sz || x >= sz || y < -sz || y >= sz)
continue;
break;
}
resize(newSizeShift);
}
x += _size;
y += _size;
int index = calcIndex(x, y);
if (_data.ptr[index])
destroy(_data.ptr[index]);
_data.ptr[index] = v;
}
~this() {
foreach(ref v; _data)
if (v)
destroy(v);
}
}
*/
struct Position {

View File

@ -219,10 +219,6 @@ private:
int maxVisibleRange = MAX_VIEW_DISTANCE;
}
interface ChunkVisitor {
void visit(World world, SmallChunk * chunk);
}
struct VisitorCell {
SmallChunk * chunk;
ulong[6] accessible;

View File

@ -430,6 +430,7 @@ class UiWidget : VerticalLayout { //, CellVisitor
}
void updatePositionMessage() {
import std.string : format;
Widget w = childById("lblPosition");
string dir = _world.camPosition.direction.dir.to!string;
dstring s = format("pos(%d,%d) h=%d fps:%d %s [F]lying: %s [U]pdateMesh: %s", _world.camPosition.pos.x, _world.camPosition.pos.z, _world.camPosition.pos.y,