From 73f63090f5cdfa785deb175337fa1be40fba727b Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 22 Mar 2016 09:47:22 +0300 Subject: [PATCH] porting minecraft-like voxel engine implementation for d3d example --- examples/d3d/src/d3d.d | 21 +- examples/d3d/src/dminer/core/blocks.d | 117 +++-- examples/d3d/src/dminer/core/minetypes.d | 622 ++++++++++------------- examples/d3d/src/dminer/core/world.d | 362 +++++++++---- 4 files changed, 628 insertions(+), 494 deletions(-) diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d index ca7934ef..dad1b47e 100644 --- a/examples/d3d/src/d3d.d +++ b/examples/d3d/src/d3d.d @@ -10,6 +10,10 @@ import dlangui.graphics.gldrawbuf; import derelict.opengl3.gl3; import derelict.opengl3.gl; +import dminer.core.world; +import dminer.core.minetypes; +import dminer.core.blocks; + mixin APP_ENTRY_POINT; /// 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)); } - import dminer.core.world; World w = new World(); for (int x = -100; x < 100; x++) for (int z = -100; z < 100; z++) 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 @@ -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 class MyGLProgram : GLProgram { diff --git a/examples/d3d/src/dminer/core/blocks.d b/examples/d3d/src/dminer/core/blocks.d index 7a438ba3..7531b897 100644 --- a/examples/d3d/src/dminer/core/blocks.d +++ b/examples/d3d/src/dminer/core/blocks.d @@ -2,67 +2,65 @@ module dminer.core.blocks; import dminer.core.minetypes; -/* -#define BLOCK_TEXTURE_FILENAME "res/png/blocks.png" -#define BLOCK_TEXTURE_DX 1024 -#define BLOCK_TEXTURE_DY 1024 -#define BLOCK_SPRITE_SIZE 16 -#define BLOCK_SPRITE_STEP 20 -#define BLOCK_SPRITE_OFFSET 21 -#define BLOCK_TEXTURE_SPRITES_PER_LINE 50 +immutable string BLOCK_TEXTURE_FILENAME = "blocks"; +immutable int BLOCK_TEXTURE_DX = 1024; +immutable int BLOCK_TEXTURE_DY = 1024; +immutable int BLOCK_SPRITE_SIZE = 16; +immutable int BLOCK_SPRITE_STEP = 20; +immutable int BLOCK_SPRITE_OFFSET = 21; +immutable int BLOCK_TEXTURE_SPRITES_PER_LINE = 50; -*/ enum BlockVisibility { - INVISIBLE, - OPAQUE, // completely opaque (cells covered by this block are invisible) - OPAQUE_SEPARATE_TX, - HALF_OPAQUE, // partially paque, cells covered by this block can be visible, render as normal block - HALF_OPAQUE_SEPARATE_TX, - HALF_TRANSPARENT, // should be rendered last (semi transparent texture) -}; + INVISIBLE, + OPAQUE, // completely opaque (cells covered by this block are invisible) + OPAQUE_SEPARATE_TX, + HALF_OPAQUE, // partially paque, cells covered by this block can be visible, render as normal block + HALF_OPAQUE_SEPARATE_TX, + HALF_TRANSPARENT, // should be rendered last (semi transparent texture) +} class BlockDef { public: - cell_t id; - string name; - BlockVisibility visibility = BlockVisibility.INVISIBLE; - int txIndex; - this() { - } - this(cell_t blockId, string blockName, BlockVisibility v, int tx) { + cell_t id; + string name; + BlockVisibility visibility = BlockVisibility.INVISIBLE; + int txIndex; + this() { + } + this(cell_t blockId, string blockName, BlockVisibility v, int tx) { id = blockId; name = blockName; visibility = v; txIndex = tx; - } - ~this() { } - // blocks behind this block can be visible - @property bool canPass() { - return visibility == BlockVisibility.INVISIBLE - || visibility == BlockVisibility.HALF_OPAQUE - || visibility == BlockVisibility.HALF_OPAQUE_SEPARATE_TX - || visibility == BlockVisibility.HALF_TRANSPARENT; - } - // block is fully opaque (all blocks behind are invisible) - @property bool isOpaque() { - return visibility == BlockVisibility.OPAQUE - || visibility == BlockVisibility.OPAQUE_SEPARATE_TX; - } - // block is visible - @property bool isVisible() { - return visibility != BlockVisibility.INVISIBLE; - } + ~this() { + } + // blocks behind this block can be visible + @property bool canPass() { + return visibility == BlockVisibility.INVISIBLE + || visibility == BlockVisibility.HALF_OPAQUE + || visibility == BlockVisibility.HALF_OPAQUE_SEPARATE_TX + || visibility == BlockVisibility.HALF_TRANSPARENT; + } + // block is fully opaque (all blocks behind are invisible) + @property bool isOpaque() { + return visibility == BlockVisibility.OPAQUE + || visibility == BlockVisibility.OPAQUE_SEPARATE_TX; + } + // block is visible + @property bool isVisible() { + return visibility != BlockVisibility.INVISIBLE; + } - @property bool terrainSmoothing() { - return false; - } + @property bool terrainSmoothing() { + return false; + } - /// create cube face - //void createFace(World * world, Position & camPosition, Vector3d pos, Dir face, FloatArray & vertices, IntArray & indexes) { + /// create cube face + //void createFace(World * world, Position & camPosition, Vector3d pos, Dir face, FloatArray & vertices, IntArray & indexes) { //} - /// create faces - //void createFaces(World * world, Position & camPosition, Vector3d pos, int visibleFaces, FloatArray & vertices, IntArray & indexes) { + /// create faces + //void createFaces(World * world, Position & camPosition, Vector3d pos, int visibleFaces, FloatArray & vertices, IntArray & indexes) { //} } @@ -105,5 +103,26 @@ __gshared static this() { BLOCK_TYPE_VISIBLE[BOUND_SKY] = false; BLOCK_TYPE_CAN_PASS[BOUND_BOTTOM] = false; 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)); + +} diff --git a/examples/d3d/src/dminer/core/minetypes.d b/examples/d3d/src/dminer/core/minetypes.d index f0df0975..dc2970c0 100644 --- a/examples/d3d/src/dminer/core/minetypes.d +++ b/examples/d3d/src/dminer/core/minetypes.d @@ -173,8 +173,8 @@ struct Vector3d { int opBinary(string op : "*")(const Vector3d v) const { return x*v.x + y*v.y + z*v.z; } - /// - int opBinary(string op : "*")(int n) const { + /// multiply vector elements by constant + Vector3d opBinary(string op : "*")(int n) const { return Vector3d(x * n, y * n, z * n); } @@ -183,21 +183,21 @@ struct Vector3d { x += v.x; y += v.y; z += v.z; - return *this; + return this; } /// ref Vector3d opOpAssign(string op : "-")(const Vector3d v) { x -= v.x; y -= v.y; z -= v.z; - return *this; + return this; } /// ref Vector3d opOpAssign(string op : "*")(int n) { x *= n; y *= n; z *= n; - return *this; + return this; } Vector3d turnLeft() { return Vector3d(z, y, -x); @@ -237,7 +237,8 @@ struct Vector3d { } return res; } -}; +} + const Vector3d ZERO3 = Vector3d(0, 0, 0); struct Array(T) { @@ -271,14 +272,26 @@ public: @property int length() { return _length; } + /// append single item by ref void append(ref const T value) { if (_length >= _data.length) reserve(_data.length == 0 ? 64 : _data.length * 2 - _length); _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) { _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 T* append(ref const T value, int count) { reserve(count); @@ -287,6 +300,14 @@ public: _data[_length++] = value; 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() { _length = 0; } @@ -443,221 +464,33 @@ public: } } -/+ -template struct InfiniteArray { -private: - T * data; - int size; - int minIdx; - int maxIdx; - void resize(int sz) { - if (sz < 128) - sz = 128; - else - sz = sz * 2; - if (size < sz) { - data = (T*)realloc(data, sizeof(T) * sz); - for (int i = size; i < sz; i++) - data[i] = initValue; - size = sz; - } - } -public: - int minIndex() { - return minIdx; - } - int maxIndex() { - return maxIdx; - } - void set(int index, T value) { - int idx = index < 0 ? (-index) * 2 - 1 : index * 2; - 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) { - if (index < minIdx || index >= maxIdx) - return initValue; - int idx = index < 0 ? (-index) * 2 - 1 : index * 2; - return data[idx]; - } - InfiniteArray() : data(NULL), size(0), minIdx(0), maxIdx(0) { - } - ~InfiniteArray() { - if (data) { - 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 -Dir opposite(Dir d) { - return (Dir)(d ^ 1); -} - -Dir turnLeft(Dir d) { - switch (d) { - case WEST: - return SOUTH; - case EAST: - return NORTH; - default: - case NORTH: - return WEST; - case SOUTH: - return EAST; - case UP: - return SOUTH; - case DOWN: - return NORTH; - } -} - -Dir turnRight(Dir d) { - switch (d) { - case WEST: - return NORTH; - case EAST: - return SOUTH; - default: - case NORTH: - return EAST; - case SOUTH: - return WEST; - case UP: - return NORTH; - case DOWN: - return SOUTH; - } -} - -Dir turnUp(Dir d) { - switch (d) { - case WEST: - return UP; - case EAST: - return UP; - default: - case NORTH: - return UP; - case SOUTH: - return UP; - case UP: - return SOUTH; - case DOWN: - return NORTH; - } -} - -Dir turnDown(Dir d) { - switch (d) { - case WEST: - return DOWN; - case EAST: - return DOWN; - default: - case NORTH: - return DOWN; - case SOUTH: - return DOWN; - case UP: - return NORTH; - case DOWN: - return SOUTH; - } -} - - -class Direction { - this(int x, int y, int z) { - set(x, y, z); - } - this(Vector3d v) { - set(v); - } - this(Dir d) { - set(d); - } - this() { - set(0, 0, -1); - } - /// set by direction code - void set(Dir d); - /// set by vector - void set(int x, int y, int z); - /// set by vector - void set(Vector3d v) { set(v.x, v.y, v.z); } - - void turnLeft() { - set(::turnLeft(dir)); - } - void turnRight() { - set(::turnRight(dir)); - } - void turnUp() { - set(::turnUp(dir)); - } - void turnDown() { - set(::turnDown(dir)); - } - - Dir dir; - Vector3d forward; - Vector3d up; - Vector3d right; - Vector3d left; - Vector3d down; - Vector3d forwardUp; - Vector3d forwardDown; - Vector3d forwardLeft; - Vector3d forwardLeftUp; - Vector3d forwardLeftDown; - Vector3d forwardRight; - Vector3d forwardRightUp; - Vector3d forwardRightDown; -}; - struct Position { Vector3d pos; Direction direction; - Position() { - + this(ref Position p) { + pos = p.pos; + direction = p.direction; } - Position(Position & p) : pos(p.pos), direction(p.direction) { - - } - Position(Vector3d position, Vector3d dir) : pos(position), direction(dir) { - + this(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); + 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() { @@ -678,154 +511,220 @@ struct Position { 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; } - - /// put cell w/o bounds checking, (0,0,0) is center of array - inline void put(Vector3d v, cell_t cell) { - _data[((v.y + MAX_DIST) << (ROW_BITS * 2)) | ((v.z + MAX_DIST) << ROW_BITS) | (v.x + MAX_DIST)] = cell; - } - - /// v is zero based destination coordinates - void putLayer(Vector3d v, cell_t * layer, int dx, int dz, int stripe); - - /// put cell w/o bounds checking - inline void put(int index, cell_t cell) { - _data[index] = cell; - } - - /// 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(); +/// returns opposite direction to specified direction +Dir opposite(Dir d) { + return cast(Dir)(d ^ 1); +} + +Dir turnLeft(Dir d) { + switch (d) { + case WEST: + return SOUTH; + case EAST: + return NORTH; + default: + case NORTH: + return WEST; + case SOUTH: + return EAST; + case UP: + return SOUTH; + case DOWN: + return NORTH; + } +} + +Dir turnRight(Dir d) { + switch (d) { + case WEST: + return NORTH; + case EAST: + return SOUTH; + default: + case NORTH: + return EAST; + case SOUTH: + return WEST; + case UP: + return NORTH; + case DOWN: + return SOUTH; + } +} + +Dir turnUp(Dir d) { + switch (d) { + case WEST: + return UP; + case EAST: + return UP; + default: + case NORTH: + return UP; + case SOUTH: + return UP; + case UP: + return SOUTH; + case DOWN: + return NORTH; + } +} + +Dir turnDown(Dir d) { + switch (d) { + case WEST: + return DOWN; + case EAST: + return DOWN; + default: + case NORTH: + return DOWN; + case SOUTH: + return DOWN; + case UP: + return NORTH; + case DOWN: + return SOUTH; + } +} + + +struct Direction { + this(int x, int y, int z) { + set(x, y, z); + } + this(Vector3d v) { + set(v); + } + this(Dir d) { + set(d); + } + /// set by direction code + void set(Dir d) { + switch (d) { + 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 + 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() { + set(.turnLeft(dir)); + } + void turnRight() { + set(.turnRight(dir)); + } + void turnUp() { + set(.turnUp(dir)); + } + void turnDown() { + set(.turnDown(dir)); + } + + Dir dir; + Vector3d forward; + Vector3d up; + Vector3d right; + Vector3d left; + Vector3d down; + Vector3d forwardUp; + Vector3d forwardDown; + Vector3d forwardLeft; + Vector3d forwardLeftUp; + Vector3d forwardLeftDown; + Vector3d forwardRight; + Vector3d forwardRightUp; + Vector3d forwardRightDown; +} + +/// returns number of bits to store integer +int bitsFor(int n) { + int res; + for (res = 0; n > 0; res++) + n >>= 1; + return res; +} + +/// returns 0 for 0, 1 for negatives, 2 for positives +int mySign(int n) { + if (n > 0) + return 1; + else if (n < 0) + return -1; + else + return 0; } -+/ immutable ulong RANDOM_MULTIPLIER = ((cast(ulong)1 << 48) - 1); immutable ulong RANDOM_MASK = ((cast(ulong)1 << 48) - 1); @@ -849,4 +748,11 @@ struct Random { 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) +]; diff --git a/examples/d3d/src/dminer/core/world.d b/examples/d3d/src/dminer/core/world.d index f6ad3cb9..b6c4a1d3 100644 --- a/examples/d3d/src/dminer/core/world.d +++ b/examples/d3d/src/dminer/core/world.d @@ -20,115 +20,114 @@ immutable int CHUNK_DY_MASK = (CHUNK_DY - 1); // Layer is 256x16x16 CHUNK_DY layers = CHUNK_DY * (CHUNK_DX_SHIFT x CHUNK_DX_SHIFT) cells struct ChunkLayer { private: - cell_t cells[CHUNK_DX * CHUNK_DX]; + cell_t cells[CHUNK_DX * CHUNK_DX]; public: - cell_t* ptr(int x, int z) { - return &cells[(z << CHUNK_DX_SHIFT) + x]; - } - cell_t get(int x, int z) { - return cells[(z << CHUNK_DX_SHIFT) + x]; - } - void set(int x, int z, cell_t cell) { - cells[(z << CHUNK_DX_SHIFT) + x] = cell; - } + cell_t* ptr(int x, int z) { + return &cells[(z << CHUNK_DX_SHIFT) + x]; + } + cell_t get(int x, int z) { + return cells[(z << CHUNK_DX_SHIFT) + x]; + } + void set(int x, int z, cell_t cell) { + cells[(z << CHUNK_DX_SHIFT) + x] = cell; + } } struct Chunk { private: - ChunkLayer * layers[CHUNK_DY]; - int bottomLayer = - 1; - int topLayer = -1; + ChunkLayer * layers[CHUNK_DY]; + int bottomLayer = - 1; + int topLayer = -1; public: - ~this() { - for (int i = 0; i < CHUNK_DY; i++) - if (layers[i]) - destroy(layers[i]); - } - int getMinLayer() { return bottomLayer; } - int getMaxLayer() { return topLayer; } - void updateMinMaxLayer(ref int minLayer, ref int maxLayer) { - if (minLayer == -1 || minLayer > bottomLayer) - minLayer = bottomLayer; - if (maxLayer == -1 || maxLayer < topLayer) - maxLayer = topLayer; - } - cell_t get(int x, int y, int z) { - //if (!this) - // return NO_CELL; - ChunkLayer * layer = layers[y & CHUNK_DY_MASK]; - if (!layer) - return NO_CELL; - return layer.get(x & CHUNK_DX_MASK, z & CHUNK_DY_MASK); - } - void set(int x, int y, int z, cell_t cell) { - int layerIndex = y & CHUNK_DY_MASK; - ChunkLayer * layer = layers[layerIndex]; - if (!layer) { - layer = new ChunkLayer(); - layers[layerIndex] = layer; - if (topLayer == -1 || topLayer < layerIndex) - topLayer = layerIndex; - if (bottomLayer == -1 || bottomLayer > layerIndex) - bottomLayer = layerIndex; - } - layer.set(x & CHUNK_DX_MASK, z & CHUNK_DY_MASK, cell); - } + ~this() { + for (int i = 0; i < CHUNK_DY; i++) + if (layers[i]) + destroy(layers[i]); + } + int getMinLayer() { return bottomLayer; } + int getMaxLayer() { return topLayer; } + void updateMinMaxLayer(ref int minLayer, ref int maxLayer) { + if (minLayer == -1 || minLayer > bottomLayer) + minLayer = bottomLayer; + if (maxLayer == -1 || maxLayer < topLayer) + maxLayer = topLayer; + } + cell_t get(int x, int y, int z) { + //if (!this) + // return NO_CELL; + ChunkLayer * layer = layers[y & CHUNK_DY_MASK]; + if (!layer) + return NO_CELL; + return layer.get(x & CHUNK_DX_MASK, z & CHUNK_DY_MASK); + } + void set(int x, int y, int z, cell_t cell) { + int layerIndex = y & CHUNK_DY_MASK; + ChunkLayer * layer = layers[layerIndex]; + if (!layer) { + layer = new ChunkLayer(); + layers[layerIndex] = layer; + if (topLayer == -1 || topLayer < layerIndex) + topLayer = layerIndex; + if (bottomLayer == -1 || bottomLayer > layerIndex) + bottomLayer = layerIndex; + } + layer.set(x & CHUNK_DX_MASK, z & CHUNK_DY_MASK, cell); + } - /// srcpos coords x, z are in chunk bounds - //void getCells(Vector3d srcpos, Vector3d dstpos, Vector3d size, VolumeData & buf); + /// srcpos coords x, z are in chunk bounds + //void getCells(Vector3d srcpos, Vector3d dstpos, Vector3d size, VolumeData & buf); } struct ChunkMatrix { private: - int minx; - int maxx; - int minz; - int maxz; - InfiniteMatrix!(Chunk *) matrix; + int minx; + int maxx; + int minz; + int maxz; + InfiniteMatrix!(Chunk *) matrix; public: - @property int minX() { return minx; } - @property int maxX() { return maxx; } - @property int minZ() { return minz; } - @property int maxZ() { return maxz; } - Chunk * get(int x, int z) { + @property int minX() { return minx; } + @property int maxX() { return maxx; } + @property int minZ() { return minz; } + @property int maxZ() { return maxz; } + Chunk * get(int x, int z) { return matrix.get(x, z); - } - void set(int x, int z, Chunk * chunk) { - matrix.set(x, z, chunk); + } + void set(int x, int z, Chunk * chunk) { + matrix.set(x, z, chunk); if (minz > z) minz = z; if (maxz < z + 1) maxz = z + 1; - if (minx > x) - minx = x; - if (maxx < x + 1) - maxx = x + 1; - } + if (minx > x) + minx = x; + if (maxx < x + 1) + maxx = x + 1; + } } /// Voxel World class World { private: - //Position camPosition; - int maxVisibleRange = MAX_VIEW_DISTANCE; - int lastChunkX = 1000000; - int lastChunkZ = 1000000; - Chunk * lastChunk; - ChunkMatrix chunks; - //DiamondVisitor visitorHelper; + Position camPosition; + int maxVisibleRange = MAX_VIEW_DISTANCE; + int lastChunkX = 1000000; + int lastChunkZ = 1000000; + Chunk * lastChunk; + ChunkMatrix chunks; + DiamondVisitor visitorHelper; public: - this() + this() { } - ~this() { + ~this() { - } - //void visitVisibleCellsAllDirectionsFast(Position & position, CellVisitor * visitor); - //Position & getCamPosition() { return camPosition; } - cell_t getCell(Vector3d v) { - return getCell(v.x, v.y, v.z); - } - cell_t getCell(int x, int y, int z) { + } + ref Position getCamPosition() { return camPosition; } + cell_t getCell(Vector3d v) { + return getCell(v.x, v.y, v.z); + } + cell_t getCell(int x, int y, int z) { if (y < 0) return 3; int chunkx = x >> CHUNK_DX_SHIFT; @@ -146,11 +145,11 @@ public: return NO_CELL; return p.get(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK); } - bool isOpaque(Vector3d v) { + bool isOpaque(Vector3d v) { cell_t cell = getCell(v); return BLOCK_TYPE_OPAQUE[cell] && cell != BOUND_SKY; } - void setCell(int x, int y, int z, cell_t value) { + void setCell(int x, int y, int z, cell_t value) { int chunkx = x >> CHUNK_DX_SHIFT; int chunkz = z >> CHUNK_DX_SHIFT; Chunk * p; @@ -172,6 +171,197 @@ public: } p.set(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK, value); } - //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); + } + } }