porting minecraft-like voxel engine implementation for d3d example

This commit is contained in:
Vadim Lopatin 2016-03-22 09:47:22 +03:00
parent e525e13e73
commit 73f63090f5
4 changed files with 628 additions and 494 deletions

View File

@ -10,6 +10,10 @@ import dlangui.graphics.gldrawbuf;
import derelict.opengl3.gl3; import derelict.opengl3.gl3;
import derelict.opengl3.gl; import derelict.opengl3.gl;
import dminer.core.world;
import dminer.core.minetypes;
import dminer.core.blocks;
mixin APP_ENTRY_POINT; mixin APP_ENTRY_POINT;
/// entry point for dlangui based application /// entry point for dlangui based application
@ -117,11 +121,15 @@ class UiWidget : VerticalLayout {
_mesh.addCubeMesh(vec3(-i * 2 - 1.0f, -i * 2 - 1.0f, -i * 2 - 1.0f), 0.2f, vec4(1 - i / 12, i / 12, i / 12, 1)); _mesh.addCubeMesh(vec3(-i * 2 - 1.0f, -i * 2 - 1.0f, -i * 2 - 1.0f), 0.2f, vec4(1 - i / 12, i / 12, i / 12, 1));
} }
import dminer.core.world;
World w = new World(); World w = new World();
for (int x = -100; x < 100; x++) for (int x = -100; x < 100; x++)
for (int z = -100; z < 100; z++) for (int z = -100; z < 100; z++)
w.setCell(x, 10, z, 1); w.setCell(x, 10, z, 1);
Position position = Position(Vector3d(0, 13, 0), Vector3d(0, 1, 0));
CellVisitor visitor = new TestVisitor();
Log.d("Testing cell visitor");
w.visitVisibleCells(position, visitor);
destroy(w);
} }
/// returns true is widget is being animated - need to call animate() and redraw /// returns true is widget is being animated - need to call animate() and redraw
@ -202,6 +210,17 @@ class UiWidget : VerticalLayout {
} }
} }
class TestVisitor : CellVisitor {
void newDirection(ref Position camPosition) {
Log.d("TestVisitor.newDirection");
}
void visitFace(World world, ref Position camPosition, Vector3d pos, cell_t cell, Dir face) {
Log.d("TestVisitor.visitFace ", pos, " cell=", cell, " face=", face);
}
void visit(World world, ref Position camPosition, Vector3d pos, cell_t cell, int visibleFaces) {
Log.d("TestVisitor.visit ", pos, " cell=", cell);
}
}
// Simple texture + color shader // Simple texture + color shader
class MyGLProgram : GLProgram { class MyGLProgram : GLProgram {

View File

@ -2,16 +2,14 @@ module dminer.core.blocks;
import dminer.core.minetypes; import dminer.core.minetypes;
/* immutable string BLOCK_TEXTURE_FILENAME = "blocks";
#define BLOCK_TEXTURE_FILENAME "res/png/blocks.png" immutable int BLOCK_TEXTURE_DX = 1024;
#define BLOCK_TEXTURE_DX 1024 immutable int BLOCK_TEXTURE_DY = 1024;
#define BLOCK_TEXTURE_DY 1024 immutable int BLOCK_SPRITE_SIZE = 16;
#define BLOCK_SPRITE_SIZE 16 immutable int BLOCK_SPRITE_STEP = 20;
#define BLOCK_SPRITE_STEP 20 immutable int BLOCK_SPRITE_OFFSET = 21;
#define BLOCK_SPRITE_OFFSET 21 immutable int BLOCK_TEXTURE_SPRITES_PER_LINE = 50;
#define BLOCK_TEXTURE_SPRITES_PER_LINE 50
*/
enum BlockVisibility { enum BlockVisibility {
INVISIBLE, INVISIBLE,
OPAQUE, // completely opaque (cells covered by this block are invisible) OPAQUE, // completely opaque (cells covered by this block are invisible)
@ -19,7 +17,7 @@ enum BlockVisibility {
HALF_OPAQUE, // partially paque, cells covered by this block can be visible, render as normal block HALF_OPAQUE, // partially paque, cells covered by this block can be visible, render as normal block
HALF_OPAQUE_SEPARATE_TX, HALF_OPAQUE_SEPARATE_TX,
HALF_TRANSPARENT, // should be rendered last (semi transparent texture) HALF_TRANSPARENT, // should be rendered last (semi transparent texture)
}; }
class BlockDef { class BlockDef {
public: public:
@ -105,5 +103,26 @@ __gshared static this() {
BLOCK_TYPE_VISIBLE[BOUND_SKY] = false; BLOCK_TYPE_VISIBLE[BOUND_SKY] = false;
BLOCK_TYPE_CAN_PASS[BOUND_BOTTOM] = false; BLOCK_TYPE_CAN_PASS[BOUND_BOTTOM] = false;
BLOCK_TYPE_VISIBLE[BOUND_BOTTOM] = true; BLOCK_TYPE_VISIBLE[BOUND_BOTTOM] = true;
}
// empty cell
registerBlockType(new BlockDef(0, "empty", BlockVisibility.INVISIBLE, 0));
// standard block types
registerBlockType(new BlockDef(1, "gray_brick", BlockVisibility.OPAQUE, 0));
registerBlockType(new BlockDef(2, "brick", BlockVisibility.OPAQUE, 1));
registerBlockType(new BlockDef(3, "bedrock", BlockVisibility.OPAQUE, 2));
registerBlockType(new BlockDef(4, "clay", BlockVisibility.OPAQUE, 3));
registerBlockType(new BlockDef(5, "cobblestone", BlockVisibility.OPAQUE, 4));
registerBlockType(new BlockDef(6, "gravel", BlockVisibility.OPAQUE, 5));
registerBlockType(new BlockDef(7, "red_sand", BlockVisibility.OPAQUE, 6));
registerBlockType(new BlockDef(8, "sand", BlockVisibility.OPAQUE, 7));
registerBlockType(new BlockDef(50, "box", BlockVisibility.HALF_OPAQUE, 50));
//registerBlockType(new TerrainBlock(100, "terrain_bedrock", 2));
//registerBlockType(new TerrainBlock(101, "terrain_clay", 3));
//registerBlockType(new TerrainBlock(102, "terrain_cobblestone", 4));
//registerBlockType(new TerrainBlock(103, "terrain_gravel", 5));
//registerBlockType(new TerrainBlock(104, "terrain_red_sand", 6));
//registerBlockType(new TerrainBlock(105, "terrain_sand", 7));
}

View File

@ -173,8 +173,8 @@ struct Vector3d {
int opBinary(string op : "*")(const Vector3d v) const { int opBinary(string op : "*")(const Vector3d v) const {
return x*v.x + y*v.y + z*v.z; return x*v.x + y*v.y + z*v.z;
} }
/// /// multiply vector elements by constant
int opBinary(string op : "*")(int n) const { Vector3d opBinary(string op : "*")(int n) const {
return Vector3d(x * n, y * n, z * n); return Vector3d(x * n, y * n, z * n);
} }
@ -183,21 +183,21 @@ struct Vector3d {
x += v.x; x += v.x;
y += v.y; y += v.y;
z += v.z; z += v.z;
return *this; return this;
} }
/// ///
ref Vector3d opOpAssign(string op : "-")(const Vector3d v) { ref Vector3d opOpAssign(string op : "-")(const Vector3d v) {
x -= v.x; x -= v.x;
y -= v.y; y -= v.y;
z -= v.z; z -= v.z;
return *this; return this;
} }
/// ///
ref Vector3d opOpAssign(string op : "*")(int n) { ref Vector3d opOpAssign(string op : "*")(int n) {
x *= n; x *= n;
y *= n; y *= n;
z *= n; z *= n;
return *this; return this;
} }
Vector3d turnLeft() { Vector3d turnLeft() {
return Vector3d(z, y, -x); return Vector3d(z, y, -x);
@ -237,7 +237,8 @@ struct Vector3d {
} }
return res; return res;
} }
}; }
const Vector3d ZERO3 = Vector3d(0, 0, 0); const Vector3d ZERO3 = Vector3d(0, 0, 0);
struct Array(T) { struct Array(T) {
@ -271,14 +272,26 @@ public:
@property int length() { @property int length() {
return _length; return _length;
} }
/// append single item by ref
void append(ref const T value) { void append(ref const T value) {
if (_length >= _data.length) if (_length >= _data.length)
reserve(_data.length == 0 ? 64 : _data.length * 2 - _length); reserve(_data.length == 0 ? 64 : _data.length * 2 - _length);
_data[_length++] = value; _data[_length++] = value;
} }
/// append single item by value
void append(T value) {
if (_length >= _data.length)
reserve(_data.length == 0 ? 64 : _data.length * 2 - _length);
_data[_length++] = value;
}
/// append single item w/o check
void appendNoCheck(ref const T value) { void appendNoCheck(ref const T value) {
_data[_length++] = value; _data[_length++] = value;
} }
/// append single item w/o check
void appendNoCheck(T value) {
_data[_length++] = value;
}
/// appends same value several times, return pointer to appended items /// appends same value several times, return pointer to appended items
T* append(ref const T value, int count) { T* append(ref const T value, int count) {
reserve(count); reserve(count);
@ -287,6 +300,14 @@ public:
_data[_length++] = value; _data[_length++] = value;
return _data.ptr + startLen; return _data.ptr + startLen;
} }
/// appends same value several times, return pointer to appended items
T* append(T value, int count) {
reserve(count);
int startLen = _length;
for (int i = 0; i < count; i++)
_data[_length++] = value;
return _data.ptr + startLen;
}
void clear() { void clear() {
_length = 0; _length = 0;
} }
@ -443,69 +464,59 @@ public:
} }
} }
/+ struct Position {
template<typename T, T initValue, void(*disposeFunction)(T value) > struct InfiniteArray { Vector3d pos;
private: Direction direction;
T * data; this(ref Position p) {
int size; pos = p.pos;
int minIdx; direction = p.direction;
int maxIdx; }
void resize(int sz) { this(Vector3d position, Vector3d dir) {
if (sz < 128) pos = position;
sz = 128; direction = dir;
else }
sz = sz * 2; Vector2d calcPlaneCoords(Vector3d v) {
if (size < sz) { v = v - pos;
data = (T*)realloc(data, sizeof(T) * sz); switch (direction.dir) {
for (int i = size; i < sz; i++) default:
data[i] = initValue; case NORTH:
size = sz; return Vector2d(v.x, v.y);
case SOUTH:
return Vector2d(-v.x, v.y);
case EAST:
return Vector2d(v.z, v.y);
case WEST:
return Vector2d(-v.z, v.y);
case UP:
return Vector2d(-v.z, v.x);
case DOWN:
return Vector2d(v.z, v.x);
} }
} }
public: void turnLeft() {
int minIndex() { direction.turnLeft();
return minIdx;
} }
int maxIndex() { void turnRight() {
return maxIdx; direction.turnRight();
} }
void set(int index, T value) { void turnUp() {
int idx = index < 0 ? (-index) * 2 - 1 : index * 2; direction.turnUp();
resize(idx + 1);
T oldData = data[idx];
if (oldData != initValue)
disposeFunction(oldData);
data[idx] = value;
if (minIdx > index)
minIdx = index;
if (maxIdx < index + 1)
maxIdx = index + 1;
} }
T get(int index) { void turnDown() {
if (index < minIdx || index >= maxIdx) direction.turnDown();
return initValue;
int idx = index < 0 ? (-index) * 2 - 1 : index * 2;
return data[idx];
} }
InfiniteArray() : data(NULL), size(0), minIdx(0), maxIdx(0) { void forward(int step = 1) {
pos += direction.forward * step;
} }
~InfiniteArray() { void backward(int step = 1) {
if (data) { pos -= direction.forward * step;
for (int i = 0; i < size; i++) {
if (data[i] != initValue)
disposeFunction(data[i]);
} }
free(data);
}
data = NULL;
size = 0;
} }
};
/// returns opposite direction to specified direction /// returns opposite direction to specified direction
Dir opposite(Dir d) { Dir opposite(Dir d) {
return (Dir)(d ^ 1); return cast(Dir)(d ^ 1);
} }
Dir turnLeft(Dir d) { Dir turnLeft(Dir d) {
@ -581,7 +592,7 @@ Dir turnDown(Dir d) {
} }
class Direction { struct Direction {
this(int x, int y, int z) { this(int x, int y, int z) {
set(x, y, z); set(x, y, z);
} }
@ -591,27 +602,94 @@ class Direction {
this(Dir d) { this(Dir d) {
set(d); set(d);
} }
this() {
set(0, 0, -1);
}
/// set by direction code /// set by direction code
void set(Dir d); void set(Dir d) {
/// set by vector switch (d) {
void set(int x, int y, int z); default:
case NORTH:
set(0, 0, -1);
break;
case SOUTH:
set(0, 0, 1);
break;
case WEST:
set(-1, 0, 0);
break;
case EAST:
set(1, 0, 0);
break;
case UP:
set(0, 1, 0);
break;
case DOWN:
set(0, -1, 0);
break;
}
}
/// set by vector /// set by vector
void set(Vector3d v) { set(v.x, v.y, v.z); } void set(Vector3d v) { set(v.x, v.y, v.z); }
/// set by vector
void set(int x, int y, int z) {
forward = Vector3d(x, y, z);
if (x) {
dir = (x > 0) ? EAST : WEST;
}
else if (y) {
dir = (y > 0) ? UP : DOWN;
}
else {
dir = (z > 0) ? SOUTH : NORTH;
}
switch (dir) {
case UP:
up = Vector3d(1, 0, 0);
left = Vector3d(0, 0, 1);
break;
case DOWN:
up = Vector3d(1, 0, 0);
left = Vector3d(0, 0, -1);
break;
default:
case NORTH:
up = Vector3d(0, 1, 0);
left = Vector3d(-1, 0, 0);
break;
case SOUTH:
up = Vector3d(0, 1, 0);
left = Vector3d(1, 0, 0);
break;
case EAST:
up = Vector3d(0, 1, 0);
left = Vector3d(0, 0, -1);
break;
case WEST:
up = Vector3d(0, 1, 0);
left = Vector3d(0, 0, 1);
break;
}
down = -up;
right = -left;
forwardUp = forward + up;
forwardDown = forward + down;
forwardLeft = forward + left;
forwardLeftUp = forward + left + up;
forwardLeftDown = forward + left + down;
forwardRight = forward + right;
forwardRightUp = forward + right + up;
forwardRightDown = forward + right + down;
}
void turnLeft() { void turnLeft() {
set(::turnLeft(dir)); set(.turnLeft(dir));
} }
void turnRight() { void turnRight() {
set(::turnRight(dir)); set(.turnRight(dir));
} }
void turnUp() { void turnUp() {
set(::turnUp(dir)); set(.turnUp(dir));
} }
void turnDown() { void turnDown() {
set(::turnDown(dir)); set(.turnDown(dir));
} }
Dir dir; Dir dir;
@ -628,205 +706,26 @@ class Direction {
Vector3d forwardRight; Vector3d forwardRight;
Vector3d forwardRightUp; Vector3d forwardRightUp;
Vector3d forwardRightDown; Vector3d forwardRightDown;
};
struct Position {
Vector3d pos;
Direction direction;
Position() {
}
Position(Position & p) : pos(p.pos), direction(p.direction) {
}
Position(Vector3d position, Vector3d dir) : pos(position), direction(dir) {
}
Vector2d calcPlaneCoords(Vector3d v) {
v = v - pos;
switch (direction.dir) {
default:
case NORTH:
return Vector2d(v.x, v.y);
case SOUTH:
return Vector2d(-v.x, v.y);
case EAST:
return Vector2d(v.z, v.y);
case WEST:
return Vector2d(-v.z, v.y);
case UP:
return Vector2d(-v.z, v.x);
case DOWN:
return Vector2d(v.z, v.x);
}
}
void turnLeft() {
direction.turnLeft();
}
void turnRight() {
direction.turnRight();
}
void turnUp() {
direction.turnUp();
}
void turnDown() {
direction.turnDown();
}
void forward(int step = 1) {
pos += direction.forward * step;
}
void backward(int step = 1) {
pos -= direction.forward * step;
}
};
struct CellToVisit {
union {
struct {
int index;
cell_t cell;
ubyte dir;
};
ulong data;
};
CellToVisit() : data(0) {}
CellToVisit(int idx, cell_t cellValue, DirEx direction) : index(idx), cell(cellValue), dir(direction) {}
CellToVisit(const CellToVisit & v) : data(v.data) {}
CellToVisit(lUInt64 v) : data(v) {}
inline CellToVisit& operator = (CellToVisit v) {
data = v.data;
return *this;
}
inline CellToVisit& operator = (lUInt64 v) {
data = v;
return *this;
}
};
struct VolumeData {
int MAX_DIST_BITS;
int ROW_BITS;
int MAX_DIST;
int ROW_SIZE;
int DATA_SIZE;
int ROW_MASK;
cell_t * _data;
int directionDelta[64];
int directionExDelta[26];
int mainDirectionDeltas[6][9];
int mainDirectionDeltasNoForward[6][9];
VolumeData(int distBits);
~VolumeData() {
delete[] _data;
}
int size() { return MAX_DIST; }
void clear() {
memset(_data, 0, sizeof(cell_t) * DATA_SIZE);
} }
cell_t * ptr() { return _data; } /// returns number of bits to store integer
int bitsFor(int n) {
/// put cell w/o bounds checking, (0,0,0) is center of array int res;
inline void put(Vector3d v, cell_t cell) { for (res = 0; n > 0; res++)
_data[((v.y + MAX_DIST) << (ROW_BITS * 2)) | ((v.z + MAX_DIST) << ROW_BITS) | (v.x + MAX_DIST)] = cell; n >>= 1;
return res;
} }
/// v is zero based destination coordinates /// returns 0 for 0, 1 for negatives, 2 for positives
void putLayer(Vector3d v, cell_t * layer, int dx, int dz, int stripe); int mySign(int n) {
if (n > 0)
/// put cell w/o bounds checking return 1;
inline void put(int index, cell_t cell) { else if (n < 0)
_data[index] = cell; return -1;
else
return 0;
} }
/// read w/o bounds checking, (0,0,0) is center of array
inline cell_t get(Vector3d v) {
return _data[((v.y + MAX_DIST) << (ROW_BITS * 2)) | ((v.z + MAX_DIST) << ROW_BITS) | (v.x + MAX_DIST)];
}
inline cell_t get(int index) {
return _data[index];
}
/// get array index for point - (0,0,0) is center
inline int getIndex(Vector3d v) {
return ((v.y + MAX_DIST) << (ROW_BITS * 2)) | ((v.z + MAX_DIST) << ROW_BITS) | (v.x + MAX_DIST);
}
inline Vector3d indexToPoint(int index) {
return Vector3d((index & ROW_MASK) - MAX_DIST,
((index >> (ROW_BITS * 2)) & ROW_MASK) - MAX_DIST,
((index >> (ROW_BITS)) & ROW_MASK) - MAX_DIST);
}
inline int moveIndex(int oldIndex, DirMask direction) {
return oldIndex + directionDelta[direction];
}
inline int moveIndex(int oldIndex, DirEx direction) {
return oldIndex + directionExDelta[direction];
}
inline CellToVisit getNext(int index, DirEx direction, DirEx baseDir) {
int nextIndex = index + directionExDelta[direction];
return CellToVisit(nextIndex, _data[nextIndex], baseDir);
}
void getNearCellsForDirection(int index, DirEx direction, CellToVisit cells[9]);
void getNearCellsForDirectionNoForward(int index, DirEx direction, CellToVisit cells[9]);
void getNearCellsForDirection(int index, DirEx direction, cell_t cells[9]);
void getNearCellsForDirectionNoForward(int index, DirEx direction, cell_t cells[9]);
void fillLayer(int y, cell_t cell);
int * thisPlaneDirections(DirEx dir) { return mainDirectionDeltasNoForward[dir]; }
int * nextPlaneDirections(DirEx dir) { return mainDirectionDeltas[dir]; }
};
struct DirectionHelper {
DirEx dir;
IntArray oldcells;
IntArray newcells;
IntArray spreadcells;
int forwardCellCount;
void start(int index, DirEx direction);
void nextDistance();
void prepareSpreading();
};
class World;
class CellVisitor {
public:
virtual ~CellVisitor() {}
virtual void newDirection(Position & camPosition) { }
virtual void visitFace(World * world, Position & camPosition, Vector3d pos, cell_t cell, Dir face) { }
virtual void visit(World * world, Position & camPosition, Vector3d pos, cell_t cell, int visibleFaces) { }
}
struct VolumeVisitor {
World * world;
VolumeData * volume;
CellVisitor * visitor;
Position * position;
DirectionHelper helpers[6];
DirEx direction; // camera forward direction
DirEx oppdirection; // opposite direction
Vector3d dirvector;
int distance;
VolumeVisitor();
void init(World * w, Position * pos, VolumeData * data, CellVisitor * v);
~VolumeVisitor();
bool visitCell(int index, cell_t cell);
void appendNewCell(int index, int distance);
void visitPlaneForward(int startIndex, DirEx direction);
// move in forward direction
void visitPlaneSpread(int startIndex, DirEx direction);
void visitAll();
}
+/
immutable ulong RANDOM_MULTIPLIER = ((cast(ulong)1 << 48) - 1); immutable ulong RANDOM_MULTIPLIER = ((cast(ulong)1 << 48) - 1);
immutable ulong RANDOM_MASK = ((cast(ulong)1 << 48) - 1); immutable ulong RANDOM_MASK = ((cast(ulong)1 << 48) - 1);
immutable ulong RANDOM_ADDEND = cast(ulong)0xB; immutable ulong RANDOM_ADDEND = cast(ulong)0xB;
@ -849,4 +748,11 @@ struct Random {
int nextInt(int n); int nextInt(int n);
} }
extern const Vector3d DIRECTION_VECTORS[6]; const Vector3d DIRECTION_VECTORS[6] = [
Vector3d(0, 0, -1),
Vector3d(0, 0, 1),
Vector3d(-1, 0, 0),
Vector3d(1, 0, 0),
Vector3d(0, 1, 0),
Vector3d(0, -1, 0)
];

View File

@ -109,13 +109,13 @@ public:
/// Voxel World /// Voxel World
class World { class World {
private: private:
//Position camPosition; Position camPosition;
int maxVisibleRange = MAX_VIEW_DISTANCE; int maxVisibleRange = MAX_VIEW_DISTANCE;
int lastChunkX = 1000000; int lastChunkX = 1000000;
int lastChunkZ = 1000000; int lastChunkZ = 1000000;
Chunk * lastChunk; Chunk * lastChunk;
ChunkMatrix chunks; ChunkMatrix chunks;
//DiamondVisitor visitorHelper; DiamondVisitor visitorHelper;
public: public:
this() this()
{ {
@ -123,8 +123,7 @@ public:
~this() { ~this() {
} }
//void visitVisibleCellsAllDirectionsFast(Position & position, CellVisitor * visitor); ref Position getCamPosition() { return camPosition; }
//Position & getCamPosition() { return camPosition; }
cell_t getCell(Vector3d v) { cell_t getCell(Vector3d v) {
return getCell(v.x, v.y, v.z); return getCell(v.x, v.y, v.z);
} }
@ -174,4 +173,195 @@ public:
} }
//bool canPass(Vector3d pos, Vector3d size) { //bool canPass(Vector3d pos, Vector3d size) {
//} //}
void visitVisibleCells(ref Position position, CellVisitor visitor) {
visitorHelper.init(this, &position,
visitor);
visitorHelper.visitAll(MAX_VIEW_DISTANCE);
}
}
interface CellVisitor {
void newDirection(ref Position camPosition);
void visitFace(World world, ref Position camPosition, Vector3d pos, cell_t cell, Dir face);
void visit(World world, ref Position camPosition, Vector3d pos, cell_t cell, int visibleFaces);
}
struct DiamondVisitor {
int maxDist;
int maxDistBits;
int dist;
World world;
Position * position;
Vector3d pos0;
CellVisitor visitor;
CellArray visited;
cell_t * visited_ptr;
Vector3dArray oldcells;
Vector3dArray newcells;
ubyte visitedOccupied;
ubyte visitedEmpty;
int m0;
int m0mask;
void init(World w, Position * pos, CellVisitor v) {
world = w;
position = pos;
visitor = v;
pos0 = position.pos;
}
void visitCell(Vector3d v) {
//CRLog::trace("visitCell(%d %d %d) dist=%d", v.x, v.y, v.z, myAbs(v.x) + myAbs(v.y) + myAbs(v.z));
//int occupied = visitedOccupied;
int index = (v.x + m0) + ((v.z + m0) << (maxDistBits + 1));
if (v.y < 0) {
// inverse index for lower half
index ^= m0mask;
//m0--;
//x ^= m0;
//y ^= m0;
}
//int index = diamondIndex(v, maxDistBits);
if (visited_ptr[index] == visitedOccupied)// || cell == visitedEmpty)
return;
if (v * position.direction.forward < dist / 3)
return;
Vector3d pos = pos0 + v;
cell_t cell = world.getCell(pos);
// read cell from world
if (BLOCK_TYPE_VISIBLE[cell]) {
int visibleFaces = 0;
if (v.y <= 0 && v * DIRECTION_VECTORS[DIR_UP] <= 0 &&
!world.isOpaque(pos.move(DIR_UP)))
visibleFaces |= MASK_UP;
if (v.y >= 0 && v * DIRECTION_VECTORS[DIR_DOWN] <= 0 &&
!world.isOpaque(pos.move(DIR_DOWN)))
visibleFaces |= MASK_DOWN;
if (v.x <= 0 && v * DIRECTION_VECTORS[DIR_EAST] <= 0 &&
!world.isOpaque(pos.move(DIR_EAST)))
visibleFaces |= MASK_EAST;
if (v.x >= 0 && v * DIRECTION_VECTORS[DIR_WEST] <= 0 &&
!world.isOpaque(pos.move(DIR_WEST)))
visibleFaces |= MASK_WEST;
if (v.z <= 0 && v * DIRECTION_VECTORS[DIR_SOUTH] <= 0 &&
!world.isOpaque(pos.move(DIR_SOUTH)))
visibleFaces |= MASK_SOUTH;
if (v.z >= 0 && v * DIRECTION_VECTORS[DIR_NORTH] <= 0 &&
!world.isOpaque(pos.move(DIR_NORTH)))
visibleFaces |= MASK_NORTH;
visitor.visit(world, *position, pos, cell, visibleFaces);
}
// mark as visited
if (BLOCK_TYPE_CAN_PASS[cell])
newcells.append(v);
//cell = BLOCK_TYPE_CAN_PASS[cell] ? visitedEmpty : visitedOccupied;
visited_ptr[index] = visitedOccupied; // cell;
}
void visitAll(int maxDistance) {
maxDist = maxDistance;
maxDistBits = bitsFor(maxDist);
m0 = 1 << maxDistBits;
m0mask = (m0 - 1) + ((m0 - 1) << (maxDistBits + 1));
oldcells.clear();
newcells.clear();
oldcells.reserve(maxDist * 4 * 4);
newcells.reserve(maxDist * 4 * 4);
dist = 1;
int vsize = ((1 << maxDistBits) * (1 << maxDistBits)) << 2;
visited.clear();
visited.append(cast(ubyte)0, vsize);
visited_ptr = visited.ptr();
visitedOccupied = 2;
visitedEmpty = 3;
oldcells.clear();
oldcells.append(Vector3d(0, 0, 0));
for (; dist < maxDistance; dist++) {
// for each distance
if (oldcells.length() == 0) // no cells to pass through
break;
newcells.clear();
visitedOccupied += 2;
visitedEmpty += 2;
//CRLog::trace("dist: %d cells: %d", dist, oldcells.length());
for (int i = 0; i < oldcells.length(); i++) {
Vector3d pt = oldcells[i];
int sx = mySign(pt.x);
int sy = mySign(pt.y);
int sz = mySign(pt.z);
if (sx && sy && sz) {
// 1, 1, 1
visitCell(Vector3d(pt.x + sx, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y + sy, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + sz));
} else {
// has 0 in one of coords
if (!sx) {
if (!sy) {
if (!sz) {
// 0, 0, 0
visitCell(Vector3d(pt.x + 1, pt.y, pt.z));
visitCell(Vector3d(pt.x - 1, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y + 1, pt.z));
visitCell(Vector3d(pt.x, pt.y - 1, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + 1));
visitCell(Vector3d(pt.x, pt.y, pt.z - 1));
} else {
// 0, 0, 1
visitCell(Vector3d(pt.x, pt.y, pt.z + sz));
visitCell(Vector3d(pt.x + 1, pt.y, pt.z));
visitCell(Vector3d(pt.x - 1, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y + 1, pt.z));
visitCell(Vector3d(pt.x, pt.y - 1, pt.z));
}
} else {
if (!sz) {
// 0, 1, 0
visitCell(Vector3d(pt.x, pt.y + sy, pt.z));
visitCell(Vector3d(pt.x + 1, pt.y, pt.z));
visitCell(Vector3d(pt.x - 1, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + 1));
visitCell(Vector3d(pt.x, pt.y, pt.z - 1));
} else {
// 0, 1, 1
visitCell(Vector3d(pt.x, pt.y + sy, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + sz));
visitCell(Vector3d(pt.x + 1, pt.y, pt.z));
visitCell(Vector3d(pt.x - 1, pt.y, pt.z));
}
}
} else {
if (!sy) {
if (!sz) {
// 1, 0, 0
visitCell(Vector3d(pt.x + sx, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y + 1, pt.z));
visitCell(Vector3d(pt.x, pt.y - 1, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + 1));
visitCell(Vector3d(pt.x, pt.y, pt.z - 1));
} else {
// 1, 0, 1
visitCell(Vector3d(pt.x + sx, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + sz));
visitCell(Vector3d(pt.x, pt.y + 1, pt.z));
visitCell(Vector3d(pt.x, pt.y - 1, pt.z));
}
} else {
// 1, 1, 0
visitCell(Vector3d(pt.x + sx, pt.y, pt.z));
visitCell(Vector3d(pt.x, pt.y + sy, pt.z));
visitCell(Vector3d(pt.x, pt.y, pt.z + 1));
visitCell(Vector3d(pt.x, pt.y, pt.z - 1));
}
}
}
}
newcells.swap(oldcells);
}
}
} }