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