mirror of https://github.com/buggins/dlangui.git
remove miner code from d3d
This commit is contained in:
parent
84dca765d9
commit
ed1e5c04aa
examples/d3d
|
@ -409,14 +409,6 @@
|
||||||
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
<filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
|
||||||
</Config>
|
</Config>
|
||||||
<Folder name="d3d">
|
<Folder name="d3d">
|
||||||
<Folder name="dminer">
|
|
||||||
<Folder name="core">
|
|
||||||
<File path="src\dminer\core\blocks.d" />
|
|
||||||
<File path="src\dminer\core\minetypes.d" />
|
|
||||||
<File path="src\dminer\core\terrain.d" />
|
|
||||||
<File path="src\dminer\core\world.d" />
|
|
||||||
</Folder>
|
|
||||||
</Folder>
|
|
||||||
<File path="src\d3d.d" />
|
<File path="src\d3d.d" />
|
||||||
</Folder>
|
</Folder>
|
||||||
</DProject>
|
</DProject>
|
||||||
|
|
|
@ -16,10 +16,6 @@ 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
|
||||||
|
@ -46,7 +42,7 @@ extern (C) int UIAppMain(string[] args) {
|
||||||
|
|
||||||
static if (ENABLE_OPENGL):
|
static if (ENABLE_OPENGL):
|
||||||
|
|
||||||
class UiWidget : VerticalLayout, CellVisitor {
|
class UiWidget : VerticalLayout {
|
||||||
this() {
|
this() {
|
||||||
super("OpenGLView");
|
super("OpenGLView");
|
||||||
layoutWidth = FILL_PARENT;
|
layoutWidth = FILL_PARENT;
|
||||||
|
@ -184,43 +180,6 @@ class UiWidget : VerticalLayout, CellVisitor {
|
||||||
brickNode.drawable = new Model(brickMaterial, brickMesh);
|
brickNode.drawable = new Model(brickMaterial, brickMesh);
|
||||||
_scene.addChild(brickNode);
|
_scene.addChild(brickNode);
|
||||||
|
|
||||||
_minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0));
|
|
||||||
_world = new World();
|
|
||||||
_world.setCell(0, 11, 10, 2);
|
|
||||||
_world.setCell(5, 11, 15, 2);
|
|
||||||
for (int x = -100; x < 100; x++)
|
|
||||||
for (int z = -100; z < 100; z++)
|
|
||||||
_world.setCell(x, 0, z, 2);
|
|
||||||
Random rnd;
|
|
||||||
rnd.setSeed(12345);
|
|
||||||
for(int i = 0; i < 1000; i++) {
|
|
||||||
int bx = rnd.next(6)-32;
|
|
||||||
int by = rnd.next(4);
|
|
||||||
int bz = rnd.next(6)-32;
|
|
||||||
//Log.fd("Setting cell %d,%d,%d", bx, by, bz);
|
|
||||||
_world.setCell(bx, by, bz, 3);
|
|
||||||
}
|
|
||||||
|
|
||||||
_world.camPosition = Position(Vector3d(0, 3, 0), Vector3d(0, 0, 1));
|
|
||||||
updateMinerMesh();
|
|
||||||
|
|
||||||
Material minerMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "blocks");
|
|
||||||
//minerMaterial.textureLinear = false;
|
|
||||||
Model minerDrawable = new Model(minerMaterial, _minerMesh);
|
|
||||||
Node3d minerNode = new Node3d("miner", minerDrawable);
|
|
||||||
_scene.addChild(minerNode);
|
|
||||||
|
|
||||||
|
|
||||||
//minerNode.visible = false;
|
|
||||||
//cubeNode.visible = false;
|
|
||||||
|
|
||||||
//CellVisitor visitor = new TestVisitor();
|
|
||||||
//Log.d("Testing cell visitor");
|
|
||||||
//long ts = currentTimeMillis;
|
|
||||||
//_world.visitVisibleCells(_world.camPosition, visitor);
|
|
||||||
//long duration = currentTimeMillis - ts;
|
|
||||||
//Log.d("DiamondVisitor finished in ", duration, " ms");
|
|
||||||
//destroy(w);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Node3d dirLightNode;
|
Node3d dirLightNode;
|
||||||
|
@ -272,23 +231,6 @@ class UiWidget : VerticalLayout, CellVisitor {
|
||||||
childById("lblRotationZ").text = to!dstring(rotationZ);
|
childById("lblRotationZ").text = to!dstring(rotationZ);
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(World world, ref Position camPosition, Vector3d pos, cell_t cell, int visibleFaces) {
|
|
||||||
BlockDef def = BLOCK_DEFS[cell];
|
|
||||||
def.createFaces(world, world.camPosition, pos, visibleFaces, _minerMesh);
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateMinerMesh() {
|
|
||||||
_minerMesh.reset();
|
|
||||||
long ts = currentTimeMillis;
|
|
||||||
_world.visitVisibleCells(_world.camPosition, this);
|
|
||||||
long duration = currentTimeMillis - ts;
|
|
||||||
Log.d("DiamondVisitor finished in ", duration, " ms ", "Vertex count: ", _minerMesh.vertexCount);
|
|
||||||
for (int i = 0; i < 20; i++)
|
|
||||||
Log.d("vertex: ", _minerMesh.vertex(i));
|
|
||||||
}
|
|
||||||
|
|
||||||
World _world;
|
|
||||||
|
|
||||||
/// 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
|
||||||
@property override bool animating() { return true; }
|
@property override bool animating() { return true; }
|
||||||
/// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
|
/// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
|
||||||
|
@ -307,17 +249,11 @@ class UiWidget : VerticalLayout, CellVisitor {
|
||||||
|
|
||||||
Scene3dRef _scene;
|
Scene3dRef _scene;
|
||||||
Camera _cam;
|
Camera _cam;
|
||||||
Mesh _minerMesh;
|
|
||||||
|
|
||||||
|
|
||||||
/// this is OpenGLDrawableDelegate implementation
|
/// this is OpenGLDrawableDelegate implementation
|
||||||
private void doDraw(Rect windowRect, Rect rc) {
|
private void doDraw(Rect windowRect, Rect rc) {
|
||||||
_cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
|
_cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
|
||||||
_cam.setIdentity();
|
_cam.setIdentity();
|
||||||
//_cam.translate(vec3(
|
|
||||||
// childById!ScrollBar("sbTranslationX").position / 10.0f,
|
|
||||||
// childById!ScrollBar("sbTranslationY").position / 10.0f,
|
|
||||||
// childById!ScrollBar("sbTranslationZ").position / 10.0f));
|
|
||||||
_cam.translateX(translationX);
|
_cam.translateX(translationX);
|
||||||
_cam.translateY(translationY);
|
_cam.translateY(translationY);
|
||||||
_cam.translateZ(translationZ);
|
_cam.translateZ(translationZ);
|
||||||
|
@ -325,73 +261,6 @@ class UiWidget : VerticalLayout, CellVisitor {
|
||||||
_cam.rotateY(rotationY);
|
_cam.rotateY(rotationY);
|
||||||
_cam.rotateZ(rotationZ);
|
_cam.rotateZ(rotationZ);
|
||||||
|
|
||||||
//Log.d("camPosition: ", _scene.cameraPosition);
|
|
||||||
//Log.d("camDirection: ", _scene.forwardVectorWorld);
|
|
||||||
//Log.d("lightPosition: ", dirLightNode.light.position);
|
|
||||||
//Log.d("lightDirection: ", dirLightNode.light.direction);
|
|
||||||
//Log.d("lightColor: ", dirLightNode.light.color);
|
|
||||||
|
|
||||||
//_cam.translate(vec3(-1, -1.5, -1)); // - angle/1000
|
|
||||||
//_cam.translate(vec3(0, 0, -1.1)); // - angle/1000
|
|
||||||
//_cam.translate(vec3(0, 3, - angle/1000)); //
|
|
||||||
//_cam.rotateZ(30.0f + angle * 0.3456778);
|
|
||||||
|
|
||||||
mat4 projectionViewMatrix = _cam.projectionViewMatrix;
|
|
||||||
|
|
||||||
// ======== Model Matrix ==================
|
|
||||||
mat4 modelMatrix;
|
|
||||||
//modelMatrix.scale(0.1f);
|
|
||||||
//modelMatrix.rotatez(30.0f + angle * 0.3456778);
|
|
||||||
//modelMatrix.rotatey(25);
|
|
||||||
//modelMatrix.rotatex(15);
|
|
||||||
//modelMatrix.rotatey(angle);
|
|
||||||
//modelMatrix.rotatex(angle * 1.98765f);
|
|
||||||
|
|
||||||
mat4 projectionViewModelMatrix = projectionViewMatrix * modelMatrix;
|
|
||||||
//Log.d("projectionViewModelMatrix: ", projectionViewModelMatrix.dump);
|
|
||||||
|
|
||||||
//{
|
|
||||||
// mat4 projection;
|
|
||||||
// projection.setPerspective(45.0f, cast(float)rc.width / rc.height, near, far);
|
|
||||||
// mat4 view;
|
|
||||||
// view.translate(translationX, translationY, translationZ);
|
|
||||||
// Log.d(" .viewMatrix.trans ", view.dump);
|
|
||||||
// view.rotateX(rotationX);
|
|
||||||
// Log.d(" .viewMatrix.rx ", view.dump);
|
|
||||||
// view.rotateY(rotationY);
|
|
||||||
// Log.d(" .viewMatrix.ry ", view.dump);
|
|
||||||
// view.rotateZ(rotationZ);
|
|
||||||
// Log.d(" .viewMatrix.rz ", view.dump);
|
|
||||||
// mat4 projectionView = projection * view;
|
|
||||||
// Log.d(" .projectionMatrix: ", projection.dump);
|
|
||||||
// Log.d(" .viewMatrix: ", view.dump);
|
|
||||||
// Log.d(" .projectionViewMatrix: ", projectionView.dump);
|
|
||||||
// Log.d(" .projectionViewMMatrix: ", (projectionView * modelMatrix).dump);
|
|
||||||
//}
|
|
||||||
|
|
||||||
//{
|
|
||||||
// import gl3n.linalg;
|
|
||||||
// static string dump(mat4 m) {
|
|
||||||
// m.transpose;
|
|
||||||
// return to!string(m[0]) ~ to!string(m[1]) ~ to!string(m[2]) ~ to!string(m[3]);
|
|
||||||
// }
|
|
||||||
// static float toRad(float angle) { return angle * 2 * PI / 360; }
|
|
||||||
// mat4 projection = mat4.perspective(rc.width, rc.height, 45.0f, near, far);
|
|
||||||
// mat4 view = mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)).rotatey(toRad(rotationY)).rotatez(toRad(rotationZ));
|
|
||||||
// Log.d("gl3n.viewMatrix: tr ", dump(mat4.identity.translate(translationX, translationY, translationZ)));
|
|
||||||
// Log.d("gl3n.viewMatrix: rx ", dump(mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX))));
|
|
||||||
// Log.d("gl3n.viewMatrix: ry ", dump(mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)).rotatey(toRad(rotationY))));
|
|
||||||
// Log.d("gl3n.viewMatrix: rz ", dump(mat4.identity.translate(translationX, translationY, translationZ).rotatex(toRad(rotationX)).rotatey(toRad(rotationY)).rotatez(toRad(rotationZ))));
|
|
||||||
// mat4 projectionView = projection * view;
|
|
||||||
// Log.d("gl3n.projectionMatrix: ", dump(projection));
|
|
||||||
// Log.d("gl3n.viewMatrix: ", dump(view));
|
|
||||||
// Log.d("gl3n.projectionViewMatrix: ", dump(projectionView));
|
|
||||||
// Log.d("gl3n.projectionViewMMatrix: ", dump(projectionView * mat4.identity));
|
|
||||||
//}
|
|
||||||
|
|
||||||
//projectionViewModelMatrix.setIdentity();
|
|
||||||
//Log.d("matrix uniform: ", projectionViewModelMatrix.m);
|
|
||||||
|
|
||||||
checkgl!glEnable(GL_CULL_FACE);
|
checkgl!glEnable(GL_CULL_FACE);
|
||||||
//checkgl!glDisable(GL_CULL_FACE);
|
//checkgl!glDisable(GL_CULL_FACE);
|
||||||
checkgl!glEnable(GL_DEPTH_TEST);
|
checkgl!glEnable(GL_DEPTH_TEST);
|
||||||
|
@ -404,19 +273,5 @@ class UiWidget : VerticalLayout, CellVisitor {
|
||||||
}
|
}
|
||||||
|
|
||||||
~this() {
|
~this() {
|
||||||
destroy(_world);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -1,287 +0,0 @@
|
||||||
module dminer.core.blocks;
|
|
||||||
|
|
||||||
import dminer.core.minetypes;
|
|
||||||
import dminer.core.world;
|
|
||||||
import dlangui.graphics.scene.mesh;
|
|
||||||
|
|
||||||
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 = 16;
|
|
||||||
immutable int BLOCK_SPRITE_OFFSET = 0;
|
|
||||||
immutable int BLOCK_TEXTURE_SPRITES_PER_LINE = 1024/16;
|
|
||||||
immutable int VERTEX_COMPONENTS = 12;
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
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) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
@property bool terrainSmoothing() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// create cube face
|
|
||||||
void createFace(World world, ref Position camPosition, Vector3d pos, Dir face, Mesh mesh) {
|
|
||||||
// default implementation
|
|
||||||
ushort startVertexIndex = cast(ushort)mesh.vertexCount;
|
|
||||||
float[VERTEX_COMPONENTS * 4] vptr;
|
|
||||||
ushort[6] iptr;
|
|
||||||
createFaceMesh(vptr.ptr, face, pos.x, pos.y, pos.z, txIndex);
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
iptr[i] = cast(ushort)(startVertexIndex + face_indexes[i]);
|
|
||||||
//if (HIGHLIGHT_GRID && ((pos.x & 7) == 0 || (pos.z & 7) == 0)) {
|
|
||||||
// for (int i = 0; i < 4; i++) {
|
|
||||||
// vptr[11 * i + 6 + 0] = 1.4f;
|
|
||||||
// vptr[11 * i + 6 + 1] = 1.4f;
|
|
||||||
// vptr[11 * i + 6 + 2] = 1.4f;
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
mesh.addVertexes(vptr);
|
|
||||||
mesh.addPart(PrimitiveType.triangles, iptr);
|
|
||||||
}
|
|
||||||
/// create faces
|
|
||||||
void createFaces(World world, ref Position camPosition, Vector3d pos, int visibleFaces, Mesh mesh) {
|
|
||||||
for (int i = 0; i < 6; i++)
|
|
||||||
if (visibleFaces & (1 << i))
|
|
||||||
createFace(world, camPosition, pos, cast(Dir)i, mesh);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pos, normal, color, tx
|
|
||||||
static const float[VERTEX_COMPONENTS * 4] face_vertices_north =
|
|
||||||
[
|
|
||||||
-0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
|
|
||||||
0.5, 0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
|
|
||||||
-0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
|
|
||||||
0.5, -0.5, -0.5, 0.0, 0.0, -1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
static const float[VERTEX_COMPONENTS * 4] face_vertices_south =
|
|
||||||
[
|
|
||||||
-0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
|
|
||||||
0.5, -0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
|
|
||||||
-0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
|
|
||||||
0.5, 0.5, 0.5, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
static const float[VERTEX_COMPONENTS * 4] face_vertices_west =
|
|
||||||
[
|
|
||||||
-0.5, -0.5, -0.5, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
|
|
||||||
-0.5, -0.5, 0.5, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
|
|
||||||
-0.5, 0.5, -0.5, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
|
|
||||||
-0.5, 0.5, 0.5, -1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0
|
|
||||||
];
|
|
||||||
|
|
||||||
static const float[VERTEX_COMPONENTS * 4] face_vertices_east =
|
|
||||||
[
|
|
||||||
0.5, -0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
|
|
||||||
0.5, -0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
|
|
||||||
0.5, 0.5, 0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
|
|
||||||
0.5, 0.5, -0.5, 1.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
static const float[VERTEX_COMPONENTS * 4] face_vertices_up =
|
|
||||||
[
|
|
||||||
-0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
|
|
||||||
0.5, 0.5, 0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
|
|
||||||
-0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
|
|
||||||
0.5, 0.5, -0.5, 0.0, 1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
static const float[VERTEX_COMPONENTS * 4] face_vertices_down =
|
|
||||||
[
|
|
||||||
-0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
|
|
||||||
0.5, -0.5, -0.5, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
|
|
||||||
-0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0,
|
|
||||||
0.5, -0.5, 0.5, 0.0, -1.0, 0.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
|
||||||
];
|
|
||||||
|
|
||||||
static const ushort[6] face_indexes =
|
|
||||||
[
|
|
||||||
0, 1, 2, 2, 1, 3
|
|
||||||
];
|
|
||||||
|
|
||||||
static const ushort[6] face_indexes_back =
|
|
||||||
[
|
|
||||||
0, 2, 1, 2, 3, 1
|
|
||||||
];
|
|
||||||
|
|
||||||
static void fillFaceMesh(float * data, const float * src, float x0, float y0, float z0, int tileX, int tileY) {
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
const float * srcvertex = src + i * VERTEX_COMPONENTS;
|
|
||||||
float * dstvertex = data + i * VERTEX_COMPONENTS;
|
|
||||||
for (int j = 0; j < VERTEX_COMPONENTS; j++) {
|
|
||||||
float v = srcvertex[j];
|
|
||||||
switch (j) {
|
|
||||||
case 0: // x
|
|
||||||
v += x0;
|
|
||||||
break;
|
|
||||||
case 1: // y
|
|
||||||
v += y0;
|
|
||||||
break;
|
|
||||||
case 2: // z
|
|
||||||
v += z0;
|
|
||||||
break;
|
|
||||||
case 10: // tx.u
|
|
||||||
v = ((tileX + v * BLOCK_SPRITE_SIZE)) / cast(float)BLOCK_TEXTURE_DX;
|
|
||||||
break;
|
|
||||||
case 11: // tx.v
|
|
||||||
//v = (BLOCK_TEXTURE_DY - (tileY + v * BLOCK_SPRITE_SIZE)) / cast(float)BLOCK_TEXTURE_DY;
|
|
||||||
v = ((tileY + v * BLOCK_SPRITE_SIZE)) / cast(float)BLOCK_TEXTURE_DY;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
dstvertex[j] = v;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void createFaceMesh(float * data, Dir face, float x0, float y0, float z0, int tileIndex) {
|
|
||||||
|
|
||||||
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) with(Dir) {
|
|
||||||
default:
|
|
||||||
case NORTH:
|
|
||||||
fillFaceMesh(data, face_vertices_north.ptr, x0, y0, z0, tileX, tileY);
|
|
||||||
break;
|
|
||||||
case SOUTH:
|
|
||||||
fillFaceMesh(data, face_vertices_south.ptr, x0, y0, z0, tileX, tileY);
|
|
||||||
break;
|
|
||||||
case WEST:
|
|
||||||
fillFaceMesh(data, face_vertices_west.ptr, x0, y0, z0, tileX, tileY);
|
|
||||||
break;
|
|
||||||
case EAST:
|
|
||||||
fillFaceMesh(data, face_vertices_east.ptr, x0, y0, z0, tileX, tileY);
|
|
||||||
break;
|
|
||||||
case UP:
|
|
||||||
fillFaceMesh(data, face_vertices_up.ptr, x0, y0, z0, tileX, tileY);
|
|
||||||
break;
|
|
||||||
case DOWN:
|
|
||||||
fillFaceMesh(data, face_vertices_down.ptr, x0, y0, z0, tileX, tileY);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// block type definitions
|
|
||||||
__gshared BlockDef[256] BLOCK_DEFS;
|
|
||||||
// faster check for block->canPass()
|
|
||||||
__gshared bool[256] BLOCK_TYPE_CAN_PASS;
|
|
||||||
// faster check for block->isOpaque()
|
|
||||||
__gshared bool[256] BLOCK_TYPE_OPAQUE;
|
|
||||||
// faster check for block->isVisible()
|
|
||||||
__gshared bool[256] BLOCK_TYPE_VISIBLE;
|
|
||||||
// faster check for block->isVisible()
|
|
||||||
__gshared bool[256] BLOCK_TERRAIN_SMOOTHING;
|
|
||||||
|
|
||||||
/// registers new block type
|
|
||||||
void registerBlockType(BlockDef def) {
|
|
||||||
if (BLOCK_DEFS[def.id]) {
|
|
||||||
if (BLOCK_DEFS[def.id] is def)
|
|
||||||
return;
|
|
||||||
destroy(BLOCK_DEFS[def.id]);
|
|
||||||
}
|
|
||||||
BLOCK_DEFS[def.id] = def;
|
|
||||||
// init property shortcuts
|
|
||||||
BLOCK_TYPE_CAN_PASS[def.id] = def.canPass;
|
|
||||||
BLOCK_TYPE_OPAQUE[def.id] = def.isOpaque;
|
|
||||||
BLOCK_TYPE_VISIBLE[def.id] = def.isVisible;
|
|
||||||
BLOCK_TERRAIN_SMOOTHING[def.id] = def.terrainSmoothing;
|
|
||||||
}
|
|
||||||
|
|
||||||
enum BlockImage : int {
|
|
||||||
stone,
|
|
||||||
grass_top,
|
|
||||||
grass_side,
|
|
||||||
grass_top_footsteps,
|
|
||||||
dirt,
|
|
||||||
bedrock,
|
|
||||||
sand,
|
|
||||||
gravel,
|
|
||||||
sandstone,
|
|
||||||
clay,
|
|
||||||
cobblestone,
|
|
||||||
cobblestone_mossy,
|
|
||||||
brick,
|
|
||||||
stonebrick,
|
|
||||||
red_sand,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// init block types array
|
|
||||||
__gshared static this() {
|
|
||||||
import std.string;
|
|
||||||
for (int i = 0; i < 256; i++) {
|
|
||||||
if (!BLOCK_DEFS[i]) {
|
|
||||||
registerBlockType(new BlockDef(cast(cell_t)i, "undef%d".format(i), BlockVisibility.INVISIBLE, 0));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BLOCK_TYPE_CAN_PASS[BOUND_SKY] = false;
|
|
||||||
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, BlockImage.stonebrick));
|
|
||||||
registerBlockType(new BlockDef(2, "brick", BlockVisibility.OPAQUE, BlockImage.brick));
|
|
||||||
registerBlockType(new BlockDef(3, "bedrock", BlockVisibility.OPAQUE, BlockImage.bedrock));
|
|
||||||
registerBlockType(new BlockDef(4, "clay", BlockVisibility.OPAQUE, BlockImage.clay));
|
|
||||||
registerBlockType(new BlockDef(5, "cobblestone", BlockVisibility.OPAQUE, BlockImage.cobblestone));
|
|
||||||
registerBlockType(new BlockDef(6, "gravel", BlockVisibility.OPAQUE, BlockImage.gravel));
|
|
||||||
registerBlockType(new BlockDef(7, "red_sand", BlockVisibility.OPAQUE, BlockImage.red_sand));
|
|
||||||
registerBlockType(new BlockDef(8, "sand", BlockVisibility.OPAQUE, BlockImage.sand));
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,731 +0,0 @@
|
||||||
module dminer.core.minetypes;
|
|
||||||
|
|
||||||
alias cell_t = ubyte;
|
|
||||||
|
|
||||||
immutable cell_t NO_CELL = 0;
|
|
||||||
immutable cell_t END_OF_WORLD = 253;
|
|
||||||
immutable cell_t VISITED_CELL = 255;
|
|
||||||
immutable cell_t VISITED_OCCUPIED = 254;
|
|
||||||
|
|
||||||
immutable cell_t BOUND_BOTTOM = 253;
|
|
||||||
immutable cell_t BOUND_SKY = 252;
|
|
||||||
|
|
||||||
enum Dir : ubyte {
|
|
||||||
NORTH = 0,
|
|
||||||
SOUTH,
|
|
||||||
EAST,
|
|
||||||
WEST,
|
|
||||||
UP,
|
|
||||||
DOWN,
|
|
||||||
}
|
|
||||||
|
|
||||||
// 26 direction masks based on Dir
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Vector2d {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
this(int xx, int yy) {
|
|
||||||
x = xx;
|
|
||||||
y = yy;
|
|
||||||
}
|
|
||||||
//bool opEqual(Vector2d v) const {
|
|
||||||
// return x == v.x && y == v.y;
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
immutable Vector2d ZERO2 = Vector2d(0, 0);
|
|
||||||
|
|
||||||
struct Vector3d {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
int z;
|
|
||||||
this(int xx, int yy, int zz) {
|
|
||||||
x = xx;
|
|
||||||
y = yy;
|
|
||||||
z = zz;
|
|
||||||
}
|
|
||||||
//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 {
|
|
||||||
return Vector3d(-x, -y, -z);
|
|
||||||
}
|
|
||||||
/// subtract vectors
|
|
||||||
Vector3d opBinary(string op : "-")(const Vector3d v) const {
|
|
||||||
return Vector3d(x - v.x, y - v.y, z - v.z);
|
|
||||||
}
|
|
||||||
/// add vectors
|
|
||||||
Vector3d opBinary(string op : "+")(const Vector3d v) const {
|
|
||||||
return Vector3d(x + v.x, y + v.y, z + v.z);
|
|
||||||
}
|
|
||||||
///
|
|
||||||
int opBinary(string op : "*")(const Vector3d v) const {
|
|
||||||
return x*v.x + y*v.y + z*v.z;
|
|
||||||
}
|
|
||||||
/// multiply vector elements by constant
|
|
||||||
Vector3d opBinary(string op : "*")(int n) const {
|
|
||||||
return Vector3d(x * n, y * n, z * n);
|
|
||||||
}
|
|
||||||
|
|
||||||
///
|
|
||||||
ref Vector3d opOpAssign(string op : "+")(const Vector3d v) {
|
|
||||||
x += v.x;
|
|
||||||
y += v.y;
|
|
||||||
z += v.z;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
///
|
|
||||||
ref Vector3d opOpAssign(string op : "-")(const Vector3d v) {
|
|
||||||
x -= v.x;
|
|
||||||
y -= v.y;
|
|
||||||
z -= v.z;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
///
|
|
||||||
ref Vector3d opOpAssign(string op : "*")(int n) {
|
|
||||||
x *= n;
|
|
||||||
y *= n;
|
|
||||||
z *= n;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
Vector3d turnLeft() {
|
|
||||||
return Vector3d(z, y, -x);
|
|
||||||
}
|
|
||||||
Vector3d turnRight() {
|
|
||||||
return Vector3d(-z, y, x);
|
|
||||||
}
|
|
||||||
Vector3d turnUp() {
|
|
||||||
return Vector3d(x, -z, y);
|
|
||||||
}
|
|
||||||
Vector3d turnDown() {
|
|
||||||
return Vector3d(x, z, -y);
|
|
||||||
}
|
|
||||||
Vector3d move(Dir dir) {
|
|
||||||
Vector3d res = this;
|
|
||||||
switch (dir) with(Dir) {
|
|
||||||
case NORTH:
|
|
||||||
res.z--;
|
|
||||||
break;
|
|
||||||
case SOUTH:
|
|
||||||
res.z++;
|
|
||||||
break;
|
|
||||||
case WEST:
|
|
||||||
res.x--;
|
|
||||||
break;
|
|
||||||
case EAST:
|
|
||||||
res.x++;
|
|
||||||
break;
|
|
||||||
case UP:
|
|
||||||
res.y++;
|
|
||||||
break;
|
|
||||||
case DOWN:
|
|
||||||
res.y--;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const Vector3d ZERO3 = Vector3d(0, 0, 0);
|
|
||||||
|
|
||||||
struct Array(T) {
|
|
||||||
private:
|
|
||||||
int _length;
|
|
||||||
T[] _data;
|
|
||||||
public:
|
|
||||||
T * ptr(int index = 0) {
|
|
||||||
return _data.ptr + index;
|
|
||||||
}
|
|
||||||
void swap(ref Array v) {
|
|
||||||
int tmp;
|
|
||||||
tmp = _length; _length = v._length; v._length = tmp;
|
|
||||||
T[] ptmp;
|
|
||||||
ptmp = _data; _data = v._data; v._data = ptmp;
|
|
||||||
}
|
|
||||||
/// ensure capacity is enough to fit sz items
|
|
||||||
void reserve(int sz) {
|
|
||||||
sz += _length;
|
|
||||||
if (_data.length < sz) {
|
|
||||||
int oldsize = cast(int)_data.length;
|
|
||||||
int newsize = 1024;
|
|
||||||
while (newsize < sz)
|
|
||||||
newsize <<= 1;
|
|
||||||
_data.length = newsize;
|
|
||||||
for (int i = oldsize; i < newsize; i++)
|
|
||||||
_data.ptr[i] = T.init;
|
|
||||||
_data.assumeSafeAppend();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@property int length() {
|
|
||||||
return _length;
|
|
||||||
}
|
|
||||||
/// append single item by ref
|
|
||||||
void append(ref const T value) {
|
|
||||||
if (_length >= _data.length)
|
|
||||||
reserve(cast(int)(_data.length == 0 ? 64 : _data.length * 2 - _length));
|
|
||||||
_data.ptr[_length++] = value;
|
|
||||||
}
|
|
||||||
/// append single item by value
|
|
||||||
void append(T value) {
|
|
||||||
if (_length >= _data.length)
|
|
||||||
reserve(cast(int)(_data.length == 0 ? 64 : _data.length * 2 - _length));
|
|
||||||
_data.ptr[_length++] = value;
|
|
||||||
}
|
|
||||||
/// append single item w/o check
|
|
||||||
void appendNoCheck(ref const T value) {
|
|
||||||
_data.ptr[_length++] = value;
|
|
||||||
}
|
|
||||||
/// append single item w/o check
|
|
||||||
void appendNoCheck(T value) {
|
|
||||||
_data.ptr[_length++] = value;
|
|
||||||
}
|
|
||||||
/// appends same value several times, return pointer to appended items
|
|
||||||
T* append(ref const T value, int count) {
|
|
||||||
reserve(count);
|
|
||||||
int startLen = _length;
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
_data.ptr[_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.ptr[_length++] = value;
|
|
||||||
return _data.ptr + startLen;
|
|
||||||
}
|
|
||||||
void clear() {
|
|
||||||
_length = 0;
|
|
||||||
}
|
|
||||||
T get(int index) {
|
|
||||||
return _data.ptr[index];
|
|
||||||
}
|
|
||||||
void set(int index, T value) {
|
|
||||||
_data.ptr[index] = value;
|
|
||||||
}
|
|
||||||
ref T opIndex(int index) {
|
|
||||||
return _data.ptr[index];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
alias FloatArray = Array!(float);
|
|
||||||
alias IntArray = Array!(int);
|
|
||||||
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 {
|
|
||||||
Vector3d pos;
|
|
||||||
Direction direction;
|
|
||||||
this(ref Position p) {
|
|
||||||
pos = p.pos;
|
|
||||||
direction = p.direction;
|
|
||||||
}
|
|
||||||
this(Vector3d position, Vector3d dir) {
|
|
||||||
pos = position;
|
|
||||||
direction = dir;
|
|
||||||
}
|
|
||||||
Vector2d calcPlaneCoords(Vector3d v) {
|
|
||||||
v = v - pos;
|
|
||||||
switch (direction.dir) with(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 shiftLeft(int step = 1) {
|
|
||||||
pos += direction.left * step;
|
|
||||||
}
|
|
||||||
void shiftRight(int step = 1) {
|
|
||||||
pos += direction.right * step;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// returns opposite direction to specified direction
|
|
||||||
Dir opposite(Dir d) {
|
|
||||||
return cast(Dir)(d ^ 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Dir turnLeft(Dir d) {
|
|
||||||
switch (d) with (Dir) {
|
|
||||||
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) with (Dir) {
|
|
||||||
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) with (Dir) {
|
|
||||||
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) with (Dir) {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
/// 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) with (Dir) {
|
|
||||||
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) ? Dir.EAST : Dir.WEST;
|
|
||||||
}
|
|
||||||
else if (y) {
|
|
||||||
dir = (y > 0) ? Dir.UP : Dir.DOWN;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
dir = (z > 0) ? Dir.SOUTH : Dir.NORTH;
|
|
||||||
}
|
|
||||||
switch (dir) with (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 = 0x5DEECE66D;
|
|
||||||
immutable ulong RANDOM_MASK = ((cast(ulong)1 << 48) - 1);
|
|
||||||
immutable ulong RANDOM_ADDEND = cast(ulong)0xB;
|
|
||||||
|
|
||||||
struct Random {
|
|
||||||
ulong seed;
|
|
||||||
//Random();
|
|
||||||
void setSeed(ulong value) {
|
|
||||||
seed = (value ^ RANDOM_MULTIPLIER) & RANDOM_MASK;
|
|
||||||
}
|
|
||||||
|
|
||||||
int next(int bits) {
|
|
||||||
seed = (seed * RANDOM_MULTIPLIER + RANDOM_ADDEND) & RANDOM_MASK;
|
|
||||||
return cast(int)(seed >> (48 - bits));
|
|
||||||
}
|
|
||||||
|
|
||||||
int nextInt() {
|
|
||||||
return next(31);
|
|
||||||
}
|
|
||||||
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 = [
|
|
||||||
Vector3d(0, 0, -1),
|
|
||||||
Vector3d(0, 0, 1),
|
|
||||||
Vector3d(-1, 0, 0),
|
|
||||||
Vector3d(1, 0, 0),
|
|
||||||
Vector3d(0, 1, 0),
|
|
||||||
Vector3d(0, -1, 0)
|
|
||||||
];
|
|
|
@ -1,153 +0,0 @@
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,501 +0,0 @@
|
||||||
module dminer.core.world;
|
|
||||||
|
|
||||||
import dminer.core.minetypes;
|
|
||||||
import dminer.core.blocks;
|
|
||||||
|
|
||||||
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
|
|
||||||
immutable int CHUNK_DX_SHIFT = 4;
|
|
||||||
immutable int CHUNK_DX = (1<<CHUNK_DX_SHIFT);
|
|
||||||
immutable int CHUNK_DX_MASK = (CHUNK_DX - 1);
|
|
||||||
|
|
||||||
// Y range: 0..CHUNK_DY-1
|
|
||||||
immutable int CHUNK_DY_SHIFT = 6;
|
|
||||||
immutable int CHUNK_DY = (1<<CHUNK_DY_SHIFT);
|
|
||||||
immutable int CHUNK_DY_MASK = (CHUNK_DY - 1);
|
|
||||||
immutable int CHUNK_DY_INV_MASK = ~CHUNK_DY_MASK;
|
|
||||||
|
|
||||||
//extern bool HIGHLIGHT_GRID;
|
|
||||||
|
|
||||||
// Layer is 256x16x16 CHUNK_DY layers = CHUNK_DY * (CHUNK_DX_SHIFT x CHUNK_DX_SHIFT) cells
|
|
||||||
struct ChunkLayer {
|
|
||||||
|
|
||||||
cell_t[CHUNK_DX * CHUNK_DX] cells;
|
|
||||||
|
|
||||||
cell_t* ptr(int x, int z) {
|
|
||||||
return &cells.ptr[(z << CHUNK_DX_SHIFT) + x];
|
|
||||||
}
|
|
||||||
cell_t get(int x, int z) {
|
|
||||||
return cells.ptr[(z << CHUNK_DX_SHIFT) + x];
|
|
||||||
}
|
|
||||||
void set(int x, int z, cell_t cell) {
|
|
||||||
cells.ptr[(z << CHUNK_DX_SHIFT) + x] = cell;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Chunk {
|
|
||||||
private:
|
|
||||||
ChunkLayer*[CHUNK_DY] layers;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// get, x, y, z are already checked for bounds
|
|
||||||
cell_t getNoCheck(int x, int y, int z) {
|
|
||||||
ChunkLayer * layer = layers.ptr[y];
|
|
||||||
if (!layer) // likely
|
|
||||||
return NO_CELL;
|
|
||||||
return layer.cells.ptr[(z << CHUNK_DX_SHIFT) + x]; // inlined return layer.get(x, z);
|
|
||||||
}
|
|
||||||
|
|
||||||
void set(int x, int y, int z, cell_t cell) {
|
|
||||||
int layerIndex = y & CHUNK_DY_MASK;
|
|
||||||
ChunkLayer * layer = layers.ptr[layerIndex];
|
|
||||||
if (!layer) {
|
|
||||||
layer = new ChunkLayer();
|
|
||||||
layers.ptr[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);
|
|
||||||
}
|
|
||||||
|
|
||||||
alias ChunkMatrix = InfiniteMatrix!(Chunk *);
|
|
||||||
|
|
||||||
/// Voxel World
|
|
||||||
class World {
|
|
||||||
private:
|
|
||||||
Position _camPosition;
|
|
||||||
int maxVisibleRange = MAX_VIEW_DISTANCE;
|
|
||||||
ChunkMatrix chunks;
|
|
||||||
DiamondVisitor visitorHelper;
|
|
||||||
public:
|
|
||||||
this() {
|
|
||||||
_camPosition = Position(Vector3d(0, 13, 0), Vector3d(0, 0, 1));
|
|
||||||
}
|
|
||||||
~this() {
|
|
||||||
}
|
|
||||||
@property final ref Position camPosition() { return _camPosition; }
|
|
||||||
|
|
||||||
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)
|
|
||||||
else
|
|
||||||
return BOUND_SKY;
|
|
||||||
}
|
|
||||||
|
|
||||||
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 = chunks.get(chunkx, chunkz);
|
|
||||||
if (!p) {
|
|
||||||
p = new Chunk();
|
|
||||||
chunks.set(chunkx, chunkz, p);
|
|
||||||
}
|
|
||||||
p.set(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
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,
|
|
||||||
visitor);
|
|
||||||
visitorHelper.visitAll(maxVisibleRange);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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 visitedId;
|
|
||||||
//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(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 = (vx + m0) + ((vz + m0) << (maxDistBits + 1));
|
|
||||||
if (vy < 0) {
|
|
||||||
// inverse index for lower half
|
|
||||||
index ^= m0mask;
|
|
||||||
}
|
|
||||||
//int index = diamondIndex(v, maxDistBits);
|
|
||||||
if (visited_ptr[index] == visitedId)// || cell == visitedEmpty)
|
|
||||||
return;
|
|
||||||
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;
|
|
||||||
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 (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.ptr[cell])
|
|
||||||
newcells.append(Vector3d(vx, vy, vz));
|
|
||||||
//cell = BLOCK_TYPE_CAN_PASS[cell] ? visitedEmpty : visitedOccupied;
|
|
||||||
}
|
|
||||||
|
|
||||||
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));
|
|
||||||
|
|
||||||
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();
|
|
||||||
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
|
|
||||||
import dlangui.core.logger;
|
|
||||||
Log.d("No more cells at distance ", dist);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
newcells.clear();
|
|
||||||
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];
|
|
||||||
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
|
|
||||||
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(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(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(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(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(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(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(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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
newcells.swap(oldcells);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
Before ![]() (image error) Size: 31 KiB |
|
@ -3,7 +3,6 @@ res/i18n/ru.ini
|
||||||
res/mdpi/cr3_logo.png
|
res/mdpi/cr3_logo.png
|
||||||
res/mdpi/tx_fabric.jpg
|
res/mdpi/tx_fabric.jpg
|
||||||
res/mdpi/crate.png
|
res/mdpi/crate.png
|
||||||
res/mdpi/blocks.png
|
|
||||||
res/mdpi/brick.png
|
res/mdpi/brick.png
|
||||||
res/mdpi/brickn.png
|
res/mdpi/brickn.png
|
||||||
res/models/suzanne.obj
|
res/models/suzanne.obj
|
||||||
|
|
Loading…
Reference in New Issue