diff --git a/dlangui-msvc.visualdproj b/dlangui-msvc.visualdproj
index 36161889..2fa39adf 100644
--- a/dlangui-msvc.visualdproj
+++ b/dlangui-msvc.visualdproj
@@ -31,10 +31,10 @@
0
0
0
- 0
+ 1
0
- 0
- 0
+ 1
+ 1
0
0
0
@@ -235,9 +235,9 @@
0
0
0
- 0
+ 1
0
- 0
+ 1
1
0
0
@@ -248,7 +248,7 @@
0
0
0
- 2.043
+ 2
0
0
0
@@ -337,10 +337,10 @@
0
0
0
- 0
+ 1
0
- 0
- 0
+ 1
+ 1
0
0
1
@@ -541,9 +541,9 @@
0
0
0
- 0
+ 1
0
- 0
+ 1
1
1
0
diff --git a/examples/d3d/d3d-msvc.visualdproj b/examples/d3d/d3d-msvc.visualdproj
index 6d39644a..2cf675dd 100644
--- a/examples/d3d/d3d-msvc.visualdproj
+++ b/examples/d3d/d3d-msvc.visualdproj
@@ -413,6 +413,7 @@
+
diff --git a/examples/d3d/src/dminer/core/blocks.d b/examples/d3d/src/dminer/core/blocks.d
index e89ab10c..3ce10bf4 100644
--- a/examples/d3d/src/dminer/core/blocks.d
+++ b/examples/d3d/src/dminer/core/blocks.d
@@ -1,8 +1,5 @@
module dminer.core.blocks;
-public import dlangui.core.config;
-static if (ENABLE_OPENGL):
-
import dminer.core.minetypes;
import dminer.core.world;
import dlangui.graphics.scene.mesh;
@@ -184,7 +181,7 @@ static void createFaceMesh(float * data, Dir face, float x0, float y0, float z0,
int tileX = (tileIndex % BLOCK_TEXTURE_SPRITES_PER_LINE) * BLOCK_SPRITE_STEP + BLOCK_SPRITE_OFFSET;
int tileY = (tileIndex / BLOCK_TEXTURE_SPRITES_PER_LINE) * BLOCK_SPRITE_STEP + BLOCK_SPRITE_OFFSET;
// data is 11 comp * 4 vert floats
- switch (face) {
+ switch (face) with(Dir) {
default:
case NORTH:
fillFaceMesh(data, face_vertices_north.ptr, x0, y0, z0, tileX, tileY);
diff --git a/examples/d3d/src/dminer/core/minetypes.d b/examples/d3d/src/dminer/core/minetypes.d
index 88fef484..6f326f40 100644
--- a/examples/d3d/src/dminer/core/minetypes.d
+++ b/examples/d3d/src/dminer/core/minetypes.d
@@ -1,8 +1,5 @@
module dminer.core.minetypes;
-public import dlangui.core.config;
-static if (ENABLE_OPENGL):
-
alias cell_t = ubyte;
immutable cell_t NO_CELL = 0;
@@ -13,126 +10,46 @@ immutable cell_t VISITED_OCCUPIED = 254;
immutable cell_t BOUND_BOTTOM = 253;
immutable cell_t BOUND_SKY = 252;
-enum : ubyte {
+enum Dir : ubyte {
NORTH = 0,
SOUTH,
- WEST,
EAST,
+ WEST,
UP,
DOWN,
}
-alias Dir = ubyte;
-
-/// Extended Dir simple Dir directions can be combined; first 6 items of DirEx match items of Dir - 26 directions (3*3*3-1)
-enum : ubyte {
- // main directions
- DIR_NORTH = 0,
- DIR_SOUTH,
- DIR_WEST,
- DIR_EAST,
- DIR_UP,
- DIR_DOWN,
- // combined directions
- DIR_WEST_UP,
- DIR_EAST_UP,
- DIR_WEST_DOWN,
- DIR_EAST_DOWN,
- DIR_NORTH_WEST,
- DIR_NORTH_EAST,
- DIR_NORTH_UP,
- DIR_NORTH_DOWN,
- DIR_NORTH_WEST_UP,
- DIR_NORTH_EAST_UP,
- DIR_NORTH_WEST_DOWN,
- DIR_NORTH_EAST_DOWN,
- DIR_SOUTH_WEST,
- DIR_SOUTH_EAST,
- DIR_SOUTH_UP,
- DIR_SOUTH_DOWN,
- DIR_SOUTH_WEST_UP,
- DIR_SOUTH_EAST_UP,
- DIR_SOUTH_WEST_DOWN,
- DIR_SOUTH_EAST_DOWN,
- DIR_MAX,
- DIR_MIN = DIR_NORTH,
-}
-alias DirEx = ubyte;
-
// 26 direction masks based on Dir
-enum : uint {
- MASK_NORTH = (1 << NORTH),
- MASK_SOUTH = (1 << SOUTH),
- MASK_WEST = (1 << WEST),
- MASK_EAST = (1 << EAST),
- MASK_UP = (1 << UP),
- MASK_DOWN = (1 << DOWN),
- MASK_WEST_UP = (1 << WEST) | MASK_UP,
- MASK_EAST_UP = (1 << EAST) | MASK_UP,
- MASK_WEST_DOWN = (1 << WEST) | MASK_DOWN,
- MASK_EAST_DOWN = (1 << EAST) | MASK_DOWN,
- MASK_NORTH_WEST = MASK_NORTH | MASK_WEST,
- MASK_NORTH_EAST = MASK_NORTH | MASK_EAST,
- MASK_NORTH_UP = MASK_NORTH | MASK_UP,
- MASK_NORTH_DOWN = MASK_NORTH | MASK_DOWN,
- MASK_NORTH_WEST_UP = MASK_NORTH | MASK_WEST | MASK_UP,
- MASK_NORTH_EAST_UP = MASK_NORTH | MASK_EAST | MASK_UP,
- MASK_NORTH_WEST_DOWN = MASK_NORTH | MASK_WEST | MASK_DOWN,
- MASK_NORTH_EAST_DOWN = MASK_NORTH | MASK_EAST | MASK_DOWN,
- MASK_SOUTH_WEST = MASK_SOUTH | MASK_WEST,
- MASK_SOUTH_EAST = MASK_SOUTH | MASK_EAST,
- MASK_SOUTH_UP = MASK_SOUTH | MASK_UP,
- MASK_SOUTH_DOWN = MASK_SOUTH | MASK_DOWN,
- MASK_SOUTH_WEST_UP = MASK_SOUTH | MASK_WEST | MASK_UP,
- MASK_SOUTH_EAST_UP = MASK_SOUTH | MASK_EAST | MASK_UP,
- MASK_SOUTH_WEST_DOWN = MASK_SOUTH | MASK_WEST | MASK_DOWN,
- MASK_SOUTH_EAST_DOWN = MASK_SOUTH | MASK_EAST | MASK_DOWN,
+enum DirMask : ubyte {
+ MASK_NORTH = (1 << Dir.NORTH),
+ MASK_SOUTH = (1 << Dir.SOUTH),
+ MASK_EAST = (1 << Dir.EAST),
+ MASK_WEST = (1 << Dir.WEST),
+ MASK_UP = (1 << Dir.UP),
+ MASK_DOWN = (1 << Dir.DOWN),
+ MASK_ALL = 0x3F,
+ //MASK_WEST_UP = (1 << Dir.WEST) | MASK_UP,
+ //MASK_EAST_UP = (1 << Dir.EAST) | MASK_UP,
+ //MASK_WEST_DOWN = (1 << Dir.WEST) | MASK_DOWN,
+ //MASK_EAST_DOWN = (1 << Dir.EAST) | MASK_DOWN,
+ //MASK_NORTH_WEST = MASK_NORTH | MASK_WEST,
+ //MASK_NORTH_EAST = MASK_NORTH | MASK_EAST,
+ //MASK_NORTH_UP = MASK_NORTH | MASK_UP,
+ //MASK_NORTH_DOWN = MASK_NORTH | MASK_DOWN,
+ //MASK_NORTH_WEST_UP = MASK_NORTH | MASK_WEST | MASK_UP,
+ //MASK_NORTH_EAST_UP = MASK_NORTH | MASK_EAST | MASK_UP,
+ //MASK_NORTH_WEST_DOWN = MASK_NORTH | MASK_WEST | MASK_DOWN,
+ //MASK_NORTH_EAST_DOWN = MASK_NORTH | MASK_EAST | MASK_DOWN,
+ //MASK_SOUTH_WEST = MASK_SOUTH | MASK_WEST,
+ //MASK_SOUTH_EAST = MASK_SOUTH | MASK_EAST,
+ //MASK_SOUTH_UP = MASK_SOUTH | MASK_UP,
+ //MASK_SOUTH_DOWN = MASK_SOUTH | MASK_DOWN,
+ //MASK_SOUTH_WEST_UP = MASK_SOUTH | MASK_WEST | MASK_UP,
+ //MASK_SOUTH_EAST_UP = MASK_SOUTH | MASK_EAST | MASK_UP,
+ //MASK_SOUTH_WEST_DOWN = MASK_SOUTH | MASK_WEST | MASK_DOWN,
+ //MASK_SOUTH_EAST_DOWN = MASK_SOUTH | MASK_EAST | MASK_DOWN,
}
-alias DirMask = uint;
-
-/+
-struct SymmetricMatrix (T, T initValue) {
-private:
- int _size;
- int dx;
- int dx2;
- T * data;
-public:
- this(int sz = 1) {
- _size = sz;
- reset(sz);
- }
- ~this() {
- if (data)
- delete[] data;
- }
- T get(int x, int y) {
- return data[(x + dx2) * dx + (y + dx2)];
- }
- void set(int x, int y, T value) {
- data[(x + dx2) * dx + (y + dx2)] = value;
- }
- int size() {
- return _size;
- }
- void reset(int sz) {
- if (_size != sz || !data) {
- _size = sz;
- dx = _size + _size - 1;
- dx2 = dx / 2;
- if (data)
- delete[] data;
- data = new T[dx * dx];
- }
- for (int i = dx * dx - 1; i >= 0; i--)
- data[i] = initValue;
- }
-}
-
-alias BoolSymmetricMatrix = SymmetricMatrix!(bool, false);
-+/
-
struct Vector2d {
int x;
int y;
@@ -140,9 +57,9 @@ struct Vector2d {
x = xx;
y = yy;
}
- bool opEqual(Vector2d v) const {
- return x == v.x && y == v.y;
- }
+ //bool opEqual(Vector2d v) const {
+ // return x == v.x && y == v.y;
+ //}
}
immutable Vector2d ZERO2 = Vector2d(0, 0);
@@ -156,9 +73,9 @@ struct Vector3d {
y = yy;
z = zz;
}
- bool opEqual(const Vector3d v) const {
- return x == v.x && y == v.y && z == v.z;
- }
+ //bool opEqual(const Vector3d v) const {
+ // return x == v.x && y == v.y && z == v.z;
+ //}
/// returns vector with all components which are negative of components for this vector
Vector3d opUnary(string op : "-")() const {
@@ -214,25 +131,25 @@ struct Vector3d {
Vector3d turnDown() {
return Vector3d(x, z, -y);
}
- Vector3d move(DirEx dir) {
+ Vector3d move(Dir dir) {
Vector3d res = this;
- switch (dir) {
- case DIR_NORTH:
+ switch (dir) with(Dir) {
+ case NORTH:
res.z--;
break;
- case DIR_SOUTH:
+ case SOUTH:
res.z++;
break;
- case DIR_WEST:
+ case WEST:
res.x--;
break;
- case DIR_EAST:
+ case EAST:
res.x++;
break;
- case DIR_UP:
+ case UP:
res.y++;
break;
- case DIR_DOWN:
+ case DOWN:
res.y--;
break;
default:
@@ -406,12 +323,11 @@ public:
struct InfiniteMatrix(T) {
private:
- int _minx = 0;
- int _maxx = 0;
- int _miny = 0;
- int _maxy = 0;
int _size = 0;
int _sizeShift = 0;
+ int _sizeShiftMul2 = 0;
+ int _sizeMask = 0;
+ int _invSizeMask = 0;
T[] _data;
void resize(int newSizeShift) {
int newSize = (1<= _size || y < -_size || y >= _size)
+ if (!_data)
return null;
- return _data.ptr[calcIndex(x, y)];
+ 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) {
@@ -455,6 +379,8 @@ public:
}
resize(newSizeShift);
}
+ x += _size;
+ y += _size;
int index = calcIndex(x, y);
if (_data.ptr[index])
destroy(_data.ptr[index]);
@@ -480,7 +406,7 @@ struct Position {
}
Vector2d calcPlaneCoords(Vector3d v) {
v = v - pos;
- switch (direction.dir) {
+ switch (direction.dir) with(Dir) {
default:
case NORTH:
return Vector2d(v.x, v.y);
@@ -502,6 +428,12 @@ struct Position {
void turnRight() {
direction.turnRight();
}
+ void shiftLeft(int step = 1) {
+ pos += direction.left * step;
+ }
+ void shiftRight(int step = 1) {
+ pos += direction.right * step;
+ }
void turnUp() {
direction.turnUp();
}
@@ -514,6 +446,18 @@ struct Position {
void backward(int step = 1) {
pos -= direction.forward * step;
}
+ void moveUp(int step = 1) {
+ pos += direction.up * step;
+ }
+ void moveDown(int step = 1) {
+ pos += direction.down * step;
+ }
+ void moveLeft(int step = 1) {
+ pos += direction.left * step;
+ }
+ void moveRight(int step = 1) {
+ pos += direction.right * step;
+ }
}
@@ -523,7 +467,7 @@ Dir opposite(Dir d) {
}
Dir turnLeft(Dir d) {
- switch (d) {
+ switch (d) with (Dir) {
case WEST:
return SOUTH;
case EAST:
@@ -541,7 +485,7 @@ Dir turnLeft(Dir d) {
}
Dir turnRight(Dir d) {
- switch (d) {
+ switch (d) with (Dir) {
case WEST:
return NORTH;
case EAST:
@@ -559,7 +503,7 @@ Dir turnRight(Dir d) {
}
Dir turnUp(Dir d) {
- switch (d) {
+ switch (d) with (Dir) {
case WEST:
return UP;
case EAST:
@@ -577,7 +521,7 @@ Dir turnUp(Dir d) {
}
Dir turnDown(Dir d) {
- switch (d) {
+ switch (d) with (Dir) {
case WEST:
return DOWN;
case EAST:
@@ -605,9 +549,26 @@ struct Direction {
this(Dir d) {
set(d);
}
+ /// returns Y axis rotation angle in degrees (0, 90, 180, 270)
+ @property float angle() {
+ switch (dir) with (Dir) {
+ default:
+ case NORTH:
+ return 0;
+ case SOUTH:
+ return 180;
+ case WEST:
+ return 90;
+ case EAST:
+ return 270;
+ case UP:
+ case DOWN:
+ return 0;
+ }
+ }
/// set by direction code
void set(Dir d) {
- switch (d) {
+ switch (d) with (Dir) {
default:
case NORTH:
set(0, 0, -1);
@@ -635,15 +596,15 @@ struct Direction {
void set(int x, int y, int z) {
forward = Vector3d(x, y, z);
if (x) {
- dir = (x > 0) ? EAST : WEST;
+ dir = (x > 0) ? Dir.EAST : Dir.WEST;
}
else if (y) {
- dir = (y > 0) ? UP : DOWN;
+ dir = (y > 0) ? Dir.UP : Dir.DOWN;
}
else {
- dir = (z > 0) ? SOUTH : NORTH;
+ dir = (z > 0) ? Dir.SOUTH : Dir.NORTH;
}
- switch (dir) {
+ switch (dir) with (Dir) {
case UP:
up = Vector3d(1, 0, 0);
left = Vector3d(0, 0, 1);
@@ -748,7 +709,16 @@ struct Random {
int nextInt() {
return next(31);
}
- int nextInt(int n);
+ int nextInt(int n) {
+ if ((n & -n) == n) // i.e., n is a power of 2
+ return cast(int)((n * cast(long)next(31)) >> 31);
+ int bits, val;
+ do {
+ bits = next(31);
+ val = bits % n;
+ } while (bits - val + (n - 1) < 0);
+ return val;
+ }
}
const Vector3d[6] DIRECTION_VECTORS = [
diff --git a/examples/d3d/src/dminer/core/terrain.d b/examples/d3d/src/dminer/core/terrain.d
new file mode 100644
index 00000000..2310200d
--- /dev/null
+++ b/examples/d3d/src/dminer/core/terrain.d
@@ -0,0 +1,153 @@
+module dminer.core.terrain;
+
+import dminer.core.minetypes;
+
+
+struct TerrainGen {
+ private int dx;
+ private int dy;
+ private int xpow;
+ private int ypow;
+ private short[] data;
+ private Random rnd;
+ private void diamond(int x, int y, int size, int offset) {
+ int avg = (get(x, y - size) + get(x + size, y) + get(x, y + size) + get(x - size, y)) >> 2;
+ set(x, y, avg + offset);
+ }
+ private void square(int x, int y, int size, int offset) {
+ int avg = (get(x - size, y - size) + get(x + size, y - size) + get(x - size, y + size) + get(x - size, y - size)) >> 2;
+ set(x, y, avg + offset);
+ }
+
+ this(int xbits, int zbits) {
+ xpow = xbits;
+ ypow = zbits;
+ dx = (1 << xpow) + 1;
+ dy = (1 << ypow) + 1;
+ data = new short[dx * dy];
+ }
+ ~this() {
+ }
+ void filter(int range) {
+ short[] tmp = new short[dx * dy];
+ int div = (range * 2 + 1) * (range * 2 + 1);
+ for (int y = 0; y < dy; y++) {
+ for (int x = 0; x < dx; x++) {
+ int s = 0;
+ for (int yy = -range; yy <= range; yy++) {
+ for (int xx = -range; xx <= range; xx++) {
+ s += get(x + xx, y + yy);
+ }
+ }
+ s /= div;
+ tmp[(y << ypow) + y + x] = cast(short)s;
+ }
+ }
+ int sz = dx * dy;
+ data[0 .. sz] = tmp[0 .. sz];
+ }
+
+ void generate(int seed, short[] initData, int stepBits) {
+ rnd.setSeed(seed);
+ int step = 1 << stepBits;
+ int index = 0;
+ for (int y = 0; y <= dy; y += step) {
+ for (int x = 0; x <= dx; x += step) {
+ set(x, y, initData[index++]);
+ }
+ }
+ int half = step >> 1;
+ while (half > 0) {
+ int scale = step;
+ for (int y = half; y < dy; y += step) {
+ for (int x = half; x < dx; x++) {
+ square(x, y, half, rnd.nextInt(scale * 2) - scale);
+ }
+ }
+ for (int y = 0; y <= dy; y += half) {
+ for (int x = (y + half) % step; x <= dx; x += step) {
+ diamond(x, y, half, rnd.nextInt(scale * 2) - scale);
+ }
+ }
+ step >>= 1;
+ half >>= 1;
+ }
+ }
+ void generateWithScale(int seed, short[] initData, int stepBits, TerrainGen scaleMap) {
+ rnd.setSeed(seed);
+ int step = 1 << stepBits;
+ int index = 0;
+ for (int y = 0; y <= dy; y += step) {
+ for (int x = 0; x <= dx; x += step) {
+ set(x, y, initData[index++]);
+ }
+ }
+ int half = step >> 1;
+ while (half > 0) {
+ for (int y = half; y < dy; y += step) {
+ for (int x = half; x < dx; x++) {
+ int scale = (scaleMap.get(x, y) * step) >> 8;
+ scale = rnd.nextInt(scale * 2) - scale;
+ if (step < 4)
+ scale = 0;
+ square(x, y, half, scale);
+ }
+ }
+ for (int y = 0; y <= dy; y += half) {
+ for (int x = (y + half) % step; x <= dx; x += step) {
+ int scale = (scaleMap.get(x, y) * step) >> 8;
+ scale = rnd.nextInt(scale * 2) - scale;
+ if (step < 4)
+ scale = 0;
+ diamond(x, y, half, scale);
+ }
+ }
+ step >>= 1;
+ half >>= 1;
+ }
+ }
+ @property int width() {
+ return dx - 1;
+ }
+ @property int height() {
+ return dy - 1;
+ }
+ int get(int x, int y) {
+ if (x < 0 || y < 0 || x >= dx || y >= dy)
+ return 0;
+ return data[(y << ypow) + y + x];
+ }
+ void set(int x, int y, int value) {
+ if (x < 0 || y < 0 || x >= dx || y >= dy)
+ return;
+ if (value < -32767)
+ value = -32767;
+ if (value > 32767)
+ value = 32767;
+ data[(y << ypow) + y + x] = cast(short)value;
+ }
+ /// ensure that data is in range [minvalue, maxvalue]
+ void limit(int minvalue, int maxvalue) {
+ // find actual min/max
+ int minv, maxv;
+ minv = maxv = get(0, 0);
+ for (int y = 0; y <= dy; y++) {
+ for (int x = 0; x <= dx; x++) {
+ int v = get(x, y);
+ if (minv > v)
+ minv = v;
+ if (maxv < v)
+ maxv = v;
+ }
+ }
+ int mul = (maxvalue - minvalue);
+ int div = (maxv - minv);
+ if (div > 0) {
+ for (int y = 0; y <= dy; y++) {
+ for (int x = 0; x <= dx; x++) {
+ set(x, y, minvalue + (get(x, y) - minv) * mul / div);
+ }
+ }
+ }
+ }
+}
diff --git a/examples/d3d/src/dminer/core/world.d b/examples/d3d/src/dminer/core/world.d
index b5da0387..024c46a6 100644
--- a/examples/d3d/src/dminer/core/world.d
+++ b/examples/d3d/src/dminer/core/world.d
@@ -1,12 +1,9 @@
module dminer.core.world;
-public import dlangui.core.config;
-static if (ENABLE_OPENGL):
-
import dminer.core.minetypes;
import dminer.core.blocks;
-const int MAX_VIEW_DISTANCE_BITS = 7;
+const int MAX_VIEW_DISTANCE_BITS = 8;
const int MAX_VIEW_DISTANCE = (1 << MAX_VIEW_DISTANCE_BITS);
// Layer is 16x16 (CHUNK_DX_SHIFT x CHUNK_DX_SHIFT) cells
@@ -18,14 +15,15 @@ immutable int CHUNK_DX_MASK = (CHUNK_DX - 1);
immutable int CHUNK_DY_SHIFT = 6;
immutable int CHUNK_DY = (1< z)
- minz = z;
- if (maxz < z + 1)
- maxz = z + 1;
- if (minx > x)
- minx = x;
- if (maxx < x + 1)
- maxx = x + 1;
- }
-}
+alias ChunkMatrix = InfiniteMatrix!(Chunk *);
/// Voxel World
class World {
private:
Position _camPosition;
int maxVisibleRange = MAX_VIEW_DISTANCE;
- int lastChunkX = 1000000;
- int lastChunkZ = 1000000;
- Chunk * lastChunk;
ChunkMatrix chunks;
DiamondVisitor visitorHelper;
public:
@@ -125,63 +103,64 @@ public:
_camPosition = Position(Vector3d(0, 13, 0), Vector3d(0, 0, 1));
}
~this() {
-
}
@property final ref Position camPosition() { return _camPosition; }
- final cell_t getCell(Vector3d v) {
- return getCell(v.x, v.y, v.z);
- }
+
final cell_t getCell(int x, int y, int z) {
+ if (!(y & CHUNK_DY_INV_MASK)) {
+ if (Chunk * p = chunks.get(x >> CHUNK_DX_SHIFT, z >> CHUNK_DX_SHIFT))
+ return p.getNoCheck(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK);
+ return NO_CELL;
+ }
+ // y out of bounds
if (y < 0)
return BOUND_BOTTOM;
- if (y >= CHUNK_DY)
+ //if (y >= CHUNK_DY)
+ else
return BOUND_SKY;
- int chunkx = x >> CHUNK_DX_SHIFT;
- int chunkz = z >> CHUNK_DX_SHIFT;
- Chunk * p;
- if (lastChunkX == chunkx && lastChunkZ == chunkz) {
- p = lastChunk;
- } else {
- p = chunks.get(chunkx, chunkz);
- lastChunkX = chunkx;
- lastChunkZ = chunkz;
- lastChunk = p;
- }
- if (!p)
- return NO_CELL;
- return p.get(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK);
}
- final bool isOpaque(Vector3d v) {
- cell_t cell = getCell(v);
+
+ final bool isOpaque(int x, int y, int z) {
+ cell_t cell = getCell(x, y, z);
return BLOCK_TYPE_OPAQUE.ptr[cell] && cell != BOUND_SKY;
}
+
final 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;
- if (lastChunkX == chunkx && lastChunkZ == chunkz) {
- p = lastChunk;
- } else {
- p = chunks.get(chunkx, chunkz);
- lastChunkX = chunkx;
- lastChunkZ = chunkz;
- lastChunk = p;
- }
+ Chunk * p = chunks.get(chunkx, chunkz);
if (!p) {
p = new Chunk();
chunks.set(chunkx, chunkz, p);
- lastChunkX = chunkx;
- lastChunkZ = chunkz;
- lastChunk = p;
}
p.set(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK, value);
}
- //bool canPass(Vector3d pos, Vector3d size) {
- //}
+
+ void setCellRange(Vector3d pos, Vector3d sz, cell_t value) {
+ for (int x = 0; x < sz.x; x++)
+ for (int y = 0; y < sz.y; y++)
+ for (int z = 0; z < sz.z; z++)
+ setCell(pos.x + x, pos.y + y, pos.z + z, value);
+ }
+
+ bool canPass(Vector3d pos) {
+ return canPass(Vector3d(pos.x - 2, pos.y - 3, pos.z - 2), Vector3d(4, 5, 4));
+ }
+
+ bool canPass(Vector3d pos, Vector3d size) {
+ for (int x = 0; x <= size.x; x++)
+ for (int z = 0; z <= size.z; z++)
+ for (int y = 0; y < size.y; y++) {
+ if (isOpaque(pos.x + x, pos.y + y, pos.z + z))
+ return false;
+ }
+ return true;
+ }
final void visitVisibleCells(ref Position position, CellVisitor visitor) {
- visitorHelper.init(this, &position,
+ visitorHelper.init(this,
+ &position,
visitor);
- visitorHelper.visitAll(MAX_VIEW_DISTANCE);
+ visitorHelper.visitAll(maxVisibleRange);
}
}
@@ -203,8 +182,8 @@ struct DiamondVisitor {
cell_t * visited_ptr;
Vector3dArray oldcells;
Vector3dArray newcells;
- ubyte visitedOccupied;
- ubyte visitedEmpty;
+ ubyte visitedId;
+ //ubyte visitedEmpty;
int m0;
int m0mask;
void init(World w, Position * pos, CellVisitor v) {
@@ -213,59 +192,72 @@ struct DiamondVisitor {
visitor = v;
pos0 = position.pos;
}
- void visitCell(Vector3d v) {
+ void visitCell(int vx, int vy, int vz) {
//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) {
+ int index = (vx + m0) + ((vz + m0) << (maxDistBits + 1));
+ if (vy < 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)
+ if (visited_ptr[index] == visitedId)// || cell == visitedEmpty)
return;
- //if (v * position.direction.forward < dist / 3)
+ visitCellNoCheck(vx, vy, vz);
+ visited_ptr[index] = visitedId; // cell;
+ }
+
+ void visitCellNoCheck(int vx, int vy, int vz) {
+ //if (v * position.direction.forward < dist / 3) // limit by visible from cam
// return;
- Vector3d pos = pos0 + v;
- cell_t cell = world.getCell(pos);
+ //Vector3d pos = pos0 + v;
+ int posx = pos0.x + vx;
+ int posy = pos0.y + vy;
+ int posz = pos0.z + vz;
+ cell_t cell = world.getCell(posx, posy, posz);
// read cell from world
if (BLOCK_TYPE_VISIBLE.ptr[cell]) {
int visibleFaces = 0;
- if (v.y <= 0 && v * DIRECTION_VECTORS.ptr[DIR_UP] <= 0 &&
- !world.isOpaque(pos.move(DIR_UP)))
- visibleFaces |= MASK_UP;
- if (v.y >= 0 && v * DIRECTION_VECTORS.ptr[DIR_DOWN] <= 0 &&
- !world.isOpaque(pos.move(DIR_DOWN)))
- visibleFaces |= MASK_DOWN;
- if (v.x <= 0 && v * DIRECTION_VECTORS.ptr[DIR_EAST] <= 0 &&
- !world.isOpaque(pos.move(DIR_EAST)))
- visibleFaces |= MASK_EAST;
- if (v.x >= 0 && v * DIRECTION_VECTORS.ptr[DIR_WEST] <= 0 &&
- !world.isOpaque(pos.move(DIR_WEST)))
- visibleFaces |= MASK_WEST;
- if (v.z <= 0 && v * DIRECTION_VECTORS.ptr[DIR_SOUTH] <= 0 &&
- !world.isOpaque(pos.move(DIR_SOUTH)))
- visibleFaces |= MASK_SOUTH;
- if (v.z >= 0 && v * DIRECTION_VECTORS.ptr[DIR_NORTH] <= 0 &&
- !world.isOpaque(pos.move(DIR_NORTH)))
- visibleFaces |= MASK_NORTH;
- visitor.visit(world, *position, pos, cell, visibleFaces);
+ if (vy <= 0 && !world.isOpaque(posx, posy + 1, posz))
+ visibleFaces |= DirMask.MASK_UP;
+ if (vy >= 0 && !world.isOpaque(posx, posy - 1, posz))
+ visibleFaces |= DirMask.MASK_DOWN;
+ if (vx <= 0 && !world.isOpaque(posx + 1, posy, posz))
+ visibleFaces |= DirMask.MASK_EAST;
+ if (vx >= 0 && !world.isOpaque(posx - 1, posy, posz))
+ visibleFaces |= DirMask.MASK_WEST;
+ if (vz <= 0 && !world.isOpaque(posx, posy, posz + 1))
+ visibleFaces |= DirMask.MASK_SOUTH;
+ if (vz >= 0 && !world.isOpaque(posx, posy, posz - 1))
+ visibleFaces |= DirMask.MASK_NORTH;
+ visitor.visit(world, *position, Vector3d(posx, posy, posz), cell, visibleFaces);
}
// mark as visited
- if (BLOCK_TYPE_CAN_PASS[cell])
- newcells.append(v);
+ if (BLOCK_TYPE_CAN_PASS.ptr[cell])
+ newcells.append(Vector3d(vx, vy, vz));
//cell = BLOCK_TYPE_CAN_PASS[cell] ? visitedEmpty : visitedOccupied;
- visited_ptr[index] = visitedOccupied; // cell;
+ }
+
+ bool needVisit(int index) {
+ if (visited_ptr[index] != visitedId) {
+ visited_ptr[index] = visitedId;
+ return true;
+ }
+ return false;
+ }
+
+ static int myAbs(int n) {
+ return n < 0 ? -n : n;
}
void visitAll(int maxDistance) {
maxDist = maxDistance;
+ maxDistance *= 2;
maxDistBits = bitsFor(maxDist);
+ int maxDistMask = ~((1 << maxDistBits) - 1);
+ maxDistBits++;
m0 = 1 << maxDistBits;
m0mask = (m0 - 1) + ((m0 - 1) << (maxDistBits + 1));
@@ -281,87 +273,144 @@ struct DiamondVisitor {
visited.clear();
visited.append(cast(ubyte)0, vsize);
visited_ptr = visited.ptr();
- visitedOccupied = 2;
- visitedEmpty = 3;
+ visitedId = 2;
oldcells.clear();
oldcells.append(Vector3d(0, 0, 0));
+ Dir dir = position.direction.dir;
+ int zstep = 1 << (maxDistBits + 1);
for (; dist < maxDistance; dist++) {
// for each distance
- if (oldcells.length() == 0) // no cells to pass through
+ if (oldcells.length() == 0) { // no cells to pass through
+ import dlangui.core.logger;
+ Log.d("No more cells at distance ", dist);
break;
+ }
newcells.clear();
- visitedOccupied += 2;
- visitedEmpty += 2;
- //CRLog::trace("dist: %d cells: %d", dist, oldcells.length());
+ visitedId++;
+ int maxUp = (((dist + 1) * 7) / 8) + 1;
+ int maxDown = - (dist < 3 ? 3 : (((dist + 1) * 7) / 8)) - 1;
+ //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);
+ assert(myAbs(pt.x) + myAbs(pt.y) + myAbs(pt.z) == dist - 1);
+ if (((pt.x + maxDist) | (pt.y + maxDist) | (pt.z + maxDist)) & maxDistMask)
+ continue;
+ if (dist > 2) {
+ // skip some directions
+ if (pt.y > maxUp || pt.y < maxDown)
+ continue;
+ if (dir == Dir.SOUTH) {
+ if (pt.z < -1)
+ continue;
+ } else if (dir == Dir.NORTH) {
+ if (pt.z > 1)
+ continue;
+ } else if (dir == Dir.EAST) {
+ if (pt.x < -1)
+ continue;
+ } else { // WEST
+ if (pt.x > 1)
+ continue;
+ }
+ }
+ int mx = pt.x;
+ int my = pt.y;
+ int mz = pt.z;
+ int sx = mx > 0 ? 1 : 0;
+ int sy = my > 0 ? 1 : 0;
+ int sz = mz > 0 ? 1 : 0;
+ if (mx < 0) {
+ mx = -mx;
+ sx = -1;
+ }
+ if (my < 0) {
+ my = -my;
+ sy = -1;
+ }
+ if (mz < 0) {
+ mz = -mz;
+ sz = -1;
+ }
+ int ymask = sy < 0 ? m0mask : 0;
+ int index = ((pt.x + m0) + ((pt.z + m0) << (maxDistBits + 1))) ^ ymask;
if (sx && sy && sz) {
+ //bool noStepZ = (mx > mz) || (my > mz);
// 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));
+ int xindex = index + (sy < 0 ? -sx : sx);
+ if (visited_ptr[xindex] != visitedId) {
+ visitCellNoCheck(pt.x + sx, pt.y, pt.z);
+ visited_ptr[xindex] = visitedId;
+ }
+ int zindex = index + (sz * sy > 0 ? zstep : -zstep);
+ if (visited_ptr[zindex] != visitedId) {
+ visitCellNoCheck(pt.x, pt.y, pt.z + sz);
+ visited_ptr[zindex] = visitedId;
+ }
+ if (!ymask && sy < 0)
+ index ^= m0mask;
+ if (visited_ptr[index] != visitedId) {
+ visitCellNoCheck(pt.x, pt.y + sy, pt.z);
+ visited_ptr[index] = visitedId;
+ }
} 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));
+ visitCell(pt.x + 1, pt.y, pt.z);
+ visitCell(pt.x - 1, pt.y, pt.z);
+ visitCell(pt.x, pt.y + 1, pt.z);
+ visitCell(pt.x, pt.y - 1, pt.z);
+ visitCell(pt.x, pt.y, pt.z + 1);
+ visitCell(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));
+ visitCell(pt.x, pt.y, pt.z + sz);
+ visitCell(pt.x + 1, pt.y, pt.z);
+ visitCell(pt.x - 1, pt.y, pt.z);
+ visitCell(pt.x, pt.y + 1, pt.z);
+ visitCell(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));
+ visitCell(pt.x, pt.y + sy, pt.z);
+ visitCell(pt.x + 1, pt.y, pt.z);
+ visitCell(pt.x - 1, pt.y, pt.z);
+ visitCell(pt.x, pt.y, pt.z + 1);
+ visitCell(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));
+ visitCell(pt.x, pt.y + sy, pt.z);
+ visitCell(pt.x, pt.y, pt.z + sz);
+ visitCell(pt.x + 1, pt.y, pt.z);
+ visitCell(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));
+ visitCell(pt.x + sx, pt.y, pt.z);
+ visitCell(pt.x, pt.y + 1, pt.z);
+ visitCell(pt.x, pt.y - 1, pt.z);
+ visitCell(pt.x, pt.y, pt.z + 1);
+ visitCell(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));
+ visitCell(pt.x + sx, pt.y, pt.z);
+ visitCell(pt.x, pt.y, pt.z + sz);
+ visitCell(pt.x, pt.y + 1, pt.z);
+ visitCell(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));
+ visitCell(pt.x + sx, pt.y, pt.z);
+ visitCell(pt.x, pt.y + sy, pt.z);
+ visitCell(pt.x, pt.y, pt.z + 1);
+ visitCell(pt.x, pt.y, pt.z - 1);
}
}
}
@@ -370,3 +419,83 @@ struct DiamondVisitor {
}
}
}
+
+static short[] TERRAIN_INIT_DATA = [
+ // V
+ 10, 10, 10, 10, 30, 30, 30, 30, 30, 30, 30, 30, 10, 10, 10, 10, 10,
+ 10, 10, 20, 50, 50, 50, 50, 50, 50, 50, 50, 50, 20, 20, 20, 20, 10,
+ 10, 20, 20, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 20, 20, 10,
+ 10, 20, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 20, 10,
+ 10, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 20, 30,
+ 30, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 30,
+ 30, 50, 50, 50, 50, 50, 50, 50, 120, 50, 50, 50, 50, 50, 50, 50, 30,
+ 30, 50, 50, 50, 50, 50, 50, 110, 140, 130, 50, 50, 50, 50, 50, 50, 30,
+ 30, 50, 50, 50, 50, 50, 50, 140, 150, 140, 50, 50, 50, 50, 50, 50, 30, // <==
+ 30, 50, 50, 50, 50, 50, 50, 110, 140, 120, 50, 50, 50, 50, 50, 50, 30,
+ 30, 50, 50, 50, 50, 50, 50, 50, 110, 50, 50, 50, 50, 50, 50, 50, 30,
+ 30, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 10,
+ 30, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 10,
+ 30, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 40, 50, 10,
+ 30, 20, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 40, 20, 20, 10,
+ 30, 20, 20, 50, 50, 50, 50, 50, 50, 50, 40, 20, 20, 20, 20, 20, 10,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 10, 10, 10, 10, 10,
+ // ^
+];
+
+static short[] TERRAIN_SCALE_DATA = [
+ // V
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 30, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 45, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 80, 20, 20, 20, 40, 50, 40, 20, 20,
+ 20, 20, 20, 20, 20, 20, 90, 20, 80, 20, 30, 20, 20, 30, 20, 20, 20,
+ 20, 20, 20, 20, 20, 90, 20, 80, 30, 20, 40, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 90, 30, 40, 30, 50, 20, 20, 20, 20, 20, 20, // <==
+ 20, 20, 20, 20, 20, 20, 50, 20, 30, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 40, 70, 40, 90, 20, 40, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 80, 20, 50, 70, 50, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 60, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ // ^
+];
+
+void initWorldTerrain(World world, int terrSizeBits = 10, int x0 = 0, int z0 = 0) {
+ import dminer.core.terrain;
+ int terrSize = 1 << terrSizeBits;
+ TerrainGen scaleterr = TerrainGen(terrSizeBits, terrSizeBits); // 512x512
+ scaleterr.generate(4321, TERRAIN_SCALE_DATA, terrSizeBits - 4); // init grid is 16x16 (1 << (9-7))
+ scaleterr.filter(1);
+ //scaleterr.filter(2);
+ scaleterr.limit(0, 90);
+ TerrainGen terr = TerrainGen(terrSizeBits, terrSizeBits); // 512x512
+ terr.generateWithScale(123456, TERRAIN_INIT_DATA, terrSizeBits - 4, scaleterr); // init grid is 16x16 (1 << (9-7))
+ terr.filter(1);
+ terr.limit(5, CHUNK_DY * 3 / 4);
+ terr.filter(1);
+ for (int x = 0; x < terrSize; x++) {
+ for (int z = 0; z < terrSize; z++) {
+ int h = terr.get(x, z);
+ cell_t cell = 1;
+ //if (h < CHUNK_DY / 10)
+ // cell = 100;
+ //else if (h < CHUNK_DY / 5)
+ // cell = 101;
+ //else if (h < CHUNK_DY / 4)
+ // cell = 102;
+ //else if (h < CHUNK_DY / 3)
+ // cell = 103;
+ //else if (h < CHUNK_DY / 2)
+ // cell = 104;
+ //else
+ // cell = 105;
+ for (int y = 0; y < h; y++) {
+ world.setCell(x0 + x - terrSize / 2, y, z0 + z - terrSize / 2, cell);
+ }
+ }
+ }
+}
diff --git a/src/dlangui/graphics/scene/transform.d b/src/dlangui/graphics/scene/transform.d
index 4e367f5e..040f9a47 100644
--- a/src/dlangui/graphics/scene/transform.d
+++ b/src/dlangui/graphics/scene/transform.d
@@ -102,7 +102,7 @@ class Transform : RefCountedObject {
_hasTranslation = _hasRotation = _hasScale = _dirtyTransform = false;
_scale = vec3(1.0f, 1.0f, 1.0f);
_translation = vec3(0.0f, 0.0f, 0.0f);
- _rotation = mat4.identity;
+ _rotation.setIdentity();
_matrix.setIdentity();
}