From ed1e5c04aae9c6f631f9a10014edeca8853e8e23 Mon Sep 17 00:00:00 2001
From: Vadim Lopatin <coolreader.org@gmail.com>
Date: Mon, 25 Apr 2016 14:07:18 +0300
Subject: [PATCH] remove miner code from d3d

---
 examples/d3d/d3d-msvc.visualdproj        |   8 -
 examples/d3d/src/d3d.d                   | 147 +----
 examples/d3d/src/dminer/core/blocks.d    | 287 ---------
 examples/d3d/src/dminer/core/minetypes.d | 731 -----------------------
 examples/d3d/src/dminer/core/terrain.d   | 153 -----
 examples/d3d/src/dminer/core/world.d     | 501 ----------------
 examples/d3d/views/res/mdpi/blocks.png   | Bin 31980 -> 0 bytes
 examples/d3d/views/resources.list        |   1 -
 8 files changed, 1 insertion(+), 1827 deletions(-)
 delete mode 100644 examples/d3d/src/dminer/core/blocks.d
 delete mode 100644 examples/d3d/src/dminer/core/minetypes.d
 delete mode 100644 examples/d3d/src/dminer/core/terrain.d
 delete mode 100644 examples/d3d/src/dminer/core/world.d
 delete mode 100644 examples/d3d/views/res/mdpi/blocks.png

diff --git a/examples/d3d/d3d-msvc.visualdproj b/examples/d3d/d3d-msvc.visualdproj
index 2cf675dd..8152b0a7 100644
--- a/examples/d3d/d3d-msvc.visualdproj
+++ b/examples/d3d/d3d-msvc.visualdproj
@@ -409,14 +409,6 @@
   <filesToClean>*.obj;*.cmd;*.build;*.json;*.dep</filesToClean>
  </Config>
  <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" />
  </Folder>
 </DProject>
diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d
index ad78d6ca..d7ee9aa3 100644
--- a/examples/d3d/src/d3d.d
+++ b/examples/d3d/src/d3d.d
@@ -16,10 +16,6 @@ import dlangui.graphics.gldrawbuf;
 import derelict.opengl3.gl3;
 import derelict.opengl3.gl;
 
-import dminer.core.world;
-import dminer.core.minetypes;
-import dminer.core.blocks;
-
 mixin APP_ENTRY_POINT;
 
 /// entry point for dlangui based application
@@ -46,7 +42,7 @@ extern (C) int UIAppMain(string[] args) {
 
 static if (ENABLE_OPENGL):
 
-class UiWidget : VerticalLayout, CellVisitor {
+class UiWidget : VerticalLayout {
     this() {
         super("OpenGLView");
         layoutWidth = FILL_PARENT;
@@ -184,43 +180,6 @@ class UiWidget : VerticalLayout, CellVisitor {
         brickNode.drawable = new Model(brickMaterial, brickMesh);
         _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;
@@ -272,23 +231,6 @@ class UiWidget : VerticalLayout, CellVisitor {
         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
     @property override bool animating() { return true; }
     /// 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;
     Camera _cam;
-    Mesh _minerMesh;
-
 
     /// this is OpenGLDrawableDelegate implementation
     private void doDraw(Rect windowRect, Rect rc) {
         _cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
         _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.translateY(translationY);
         _cam.translateZ(translationZ);
@@ -325,73 +261,6 @@ class UiWidget : VerticalLayout, CellVisitor {
         _cam.rotateY(rotationY);
         _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!glDisable(GL_CULL_FACE);
         checkgl!glEnable(GL_DEPTH_TEST);
@@ -404,19 +273,5 @@ class UiWidget : VerticalLayout, CellVisitor {
     }
 
     ~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);
-    }
-}
-
diff --git a/examples/d3d/src/dminer/core/blocks.d b/examples/d3d/src/dminer/core/blocks.d
deleted file mode 100644
index 3ce10bf4..00000000
--- a/examples/d3d/src/dminer/core/blocks.d
+++ /dev/null
@@ -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));
-
-}
diff --git a/examples/d3d/src/dminer/core/minetypes.d b/examples/d3d/src/dminer/core/minetypes.d
deleted file mode 100644
index 6f326f40..00000000
--- a/examples/d3d/src/dminer/core/minetypes.d
+++ /dev/null
@@ -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)
-];
diff --git a/examples/d3d/src/dminer/core/terrain.d b/examples/d3d/src/dminer/core/terrain.d
deleted file mode 100644
index 2310200d..00000000
--- a/examples/d3d/src/dminer/core/terrain.d
+++ /dev/null
@@ -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);
-                }
-            }
-        }
-    }
-}
diff --git a/examples/d3d/src/dminer/core/world.d b/examples/d3d/src/dminer/core/world.d
deleted file mode 100644
index 024c46a6..00000000
--- a/examples/d3d/src/dminer/core/world.d
+++ /dev/null
@@ -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);
-            }
-        }
-    }
-}
diff --git a/examples/d3d/views/res/mdpi/blocks.png b/examples/d3d/views/res/mdpi/blocks.png
deleted file mode 100644
index 0440ab4bfce11772ed34fd0f01bb48077f628b10..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 31980
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
I1JmID2O=^wWB>pF

diff --git a/examples/d3d/views/resources.list b/examples/d3d/views/resources.list
index 49e2f24f..f40f5911 100644
--- a/examples/d3d/views/resources.list
+++ b/examples/d3d/views/resources.list
@@ -3,7 +3,6 @@ res/i18n/ru.ini
 res/mdpi/cr3_logo.png
 res/mdpi/tx_fabric.jpg
 res/mdpi/crate.png
-res/mdpi/blocks.png
 res/mdpi/brick.png
 res/mdpi/brickn.png
 res/models/suzanne.obj