From 01da716a70d477913d4d1880709d8ef0389552d3 Mon Sep 17 00:00:00 2001 From: Vadim Lopatin Date: Tue, 22 Mar 2016 11:55:05 +0300 Subject: [PATCH] minecraft like renderer --- examples/d3d/d3d-msvc.visualdproj | 2 +- examples/d3d/src/d3d.d | 34 ++++-- examples/d3d/src/dminer/core/blocks.d | 147 +++++++++++++++++++++++++- examples/d3d/src/dminer/core/world.d | 41 +++---- src/dlangui/graphics/scene/mesh.d | 11 ++ 5 files changed, 203 insertions(+), 32 deletions(-) diff --git a/examples/d3d/d3d-msvc.visualdproj b/examples/d3d/d3d-msvc.visualdproj index 7a816e91..72b19e55 100644 --- a/examples/d3d/d3d-msvc.visualdproj +++ b/examples/d3d/d3d-msvc.visualdproj @@ -337,7 +337,7 @@ 0 0 0 - 0 + 1 0 0 1 diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d index f4e8f429..51e51c14 100644 --- a/examples/d3d/src/d3d.d +++ b/examples/d3d/src/d3d.d @@ -34,7 +34,7 @@ extern (C) int UIAppMain(string[] args) { return Platform.instance.enterMessageLoop(); } -class UiWidget : VerticalLayout { +class UiWidget : VerticalLayout, CellVisitor { this() { super("OpenGLView"); layoutWidth = FILL_PARENT; @@ -121,22 +121,38 @@ class UiWidget : VerticalLayout { _mesh.addCubeMesh(vec3(-i * 2 - 1.0f, -i * 2 - 1.0f, -i * 2 - 1.0f), 0.2f, vec4(1 - i / 12, i / 12, i / 12, 1)); } - World w = new World(); + _minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0)); + World _world = new World(); for (int x = -1000; x < 1000; x++) for (int z = -1000; z < 1000; z++) - w.setCell(x, 10, z, 1); - w.setCell(0, 11, 10, 2); - w.setCell(5, 11, 15, 2); - Position position = Position(Vector3d(0, 13, 0), Vector3d(0, 0, 1)); + _world.setCell(x, 10, z, 1); + _world.setCell(0, 11, 10, 2); + _world.setCell(5, 11, 15, 2); + _world.camPosition = Position(Vector3d(0, 13, 0), Vector3d(0, 0, 1)); CellVisitor visitor = new TestVisitor(); Log.d("Testing cell visitor"); long ts = currentTimeMillis; - w.visitVisibleCells(position, visitor); + _world.visitVisibleCells(_world.camPosition, visitor); long duration = currentTimeMillis - ts; Log.d("DiamondVisitor finished in ", duration, " ms"); - destroy(w); + //destroy(w); } + 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"); + } + + 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) @@ -153,6 +169,7 @@ class UiWidget : VerticalLayout { Scene3d _scene; Camera _cam; Mesh _mesh; + Mesh _minerMesh; GLTexture _tx; @@ -212,6 +229,7 @@ class UiWidget : VerticalLayout { destroy(_program); if (_tx) destroy(_tx); + destroy(_world); } } diff --git a/examples/d3d/src/dminer/core/blocks.d b/examples/d3d/src/dminer/core/blocks.d index 4e51add2..052ef691 100644 --- a/examples/d3d/src/dminer/core/blocks.d +++ b/examples/d3d/src/dminer/core/blocks.d @@ -1,6 +1,8 @@ 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; @@ -9,6 +11,7 @@ immutable int BLOCK_SPRITE_SIZE = 16; immutable int BLOCK_SPRITE_STEP = 20; immutable int BLOCK_SPRITE_OFFSET = 21; immutable int BLOCK_TEXTURE_SPRITES_PER_LINE = 50; +immutable int VERTEX_COMPONENTS = 12; enum BlockVisibility { INVISIBLE, @@ -57,13 +60,149 @@ public: } /// create cube face - //void createFace(World * world, Position & camPosition, Vector3d pos, Dir face, FloatArray & vertices, IntArray & indexes) { - //} + 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 + 0.5f, pos.y + 0.5f, pos.z + 0.5f, 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, Position & camPosition, Vector3d pos, int visibleFaces, FloatArray & vertices, IntArray & indexes) { - //} + 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 < 11; j++) { + float v = srcvertex[j]; + switch (j) { + default: + case 0: // x + v += x0; + break; + case 1: // y + v += y0; + break; + case 2: // z + v += z0; + break; + case 9: // tx.u + v = ((tileX + v * BLOCK_SPRITE_SIZE)) / cast(float)BLOCK_TEXTURE_DX; + break; + case 10: // tx.v + v = (BLOCK_TEXTURE_DY - (tileY + v * BLOCK_SPRITE_SIZE)) / cast(float)BLOCK_TEXTURE_DY; + 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) { + 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; diff --git a/examples/d3d/src/dminer/core/world.d b/examples/d3d/src/dminer/core/world.d index fcb94c1d..41d7e6f2 100644 --- a/examples/d3d/src/dminer/core/world.d +++ b/examples/d3d/src/dminer/core/world.d @@ -11,7 +11,8 @@ immutable int CHUNK_DX_SHIFT = 4; immutable int CHUNK_DX = (1<= CHUNK_DY) + return BOUND_SKY; int chunkx = x >> CHUNK_DX_SHIFT; int chunkz = z >> CHUNK_DX_SHIFT; Chunk * p; @@ -145,11 +148,11 @@ public: return NO_CELL; return p.get(x & CHUNK_DX_MASK, y, z & CHUNK_DX_MASK); } - bool isOpaque(Vector3d v) { + final bool isOpaque(Vector3d v) { cell_t cell = getCell(v); - return BLOCK_TYPE_OPAQUE[cell] && cell != BOUND_SKY; + return BLOCK_TYPE_OPAQUE.ptr[cell] && cell != BOUND_SKY; } - void setCell(int x, int y, int z, cell_t value) { + 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; @@ -172,7 +175,7 @@ public: } //bool canPass(Vector3d pos, Vector3d size) { //} - void visitVisibleCells(ref Position position, CellVisitor visitor) { + final void visitVisibleCells(ref Position position, CellVisitor visitor) { visitorHelper.init(this, &position, visitor); visitorHelper.visitAll(MAX_VIEW_DISTANCE); @@ -228,24 +231,24 @@ struct DiamondVisitor { cell_t cell = world.getCell(pos); // read cell from world - if (BLOCK_TYPE_VISIBLE[cell]) { + if (BLOCK_TYPE_VISIBLE.ptr[cell]) { int visibleFaces = 0; - if (v.y <= 0 && v * DIRECTION_VECTORS[DIR_UP] <= 0 && + if (v.y <= 0 && v * DIRECTION_VECTORS.ptr[DIR_UP] <= 0 && !world.isOpaque(pos.move(DIR_UP))) visibleFaces |= MASK_UP; - if (v.y >= 0 && v * DIRECTION_VECTORS[DIR_DOWN] <= 0 && + if (v.y >= 0 && v * DIRECTION_VECTORS.ptr[DIR_DOWN] <= 0 && !world.isOpaque(pos.move(DIR_DOWN))) visibleFaces |= MASK_DOWN; - if (v.x <= 0 && v * DIRECTION_VECTORS[DIR_EAST] <= 0 && + if (v.x <= 0 && v * DIRECTION_VECTORS.ptr[DIR_EAST] <= 0 && !world.isOpaque(pos.move(DIR_EAST))) visibleFaces |= MASK_EAST; - if (v.x >= 0 && v * DIRECTION_VECTORS[DIR_WEST] <= 0 && + if (v.x >= 0 && v * DIRECTION_VECTORS.ptr[DIR_WEST] <= 0 && !world.isOpaque(pos.move(DIR_WEST))) visibleFaces |= MASK_WEST; - if (v.z <= 0 && v * DIRECTION_VECTORS[DIR_SOUTH] <= 0 && + if (v.z <= 0 && v * DIRECTION_VECTORS.ptr[DIR_SOUTH] <= 0 && !world.isOpaque(pos.move(DIR_SOUTH))) visibleFaces |= MASK_SOUTH; - if (v.z >= 0 && v * DIRECTION_VECTORS[DIR_NORTH] <= 0 && + if (v.z >= 0 && v * DIRECTION_VECTORS.ptr[DIR_NORTH] <= 0 && !world.isOpaque(pos.move(DIR_NORTH))) visibleFaces |= MASK_NORTH; visitor.visit(world, *position, pos, cell, visibleFaces); diff --git a/src/dlangui/graphics/scene/mesh.d b/src/dlangui/graphics/scene/mesh.d index 952fc072..a4a56bd3 100644 --- a/src/dlangui/graphics/scene/mesh.d +++ b/src/dlangui/graphics/scene/mesh.d @@ -174,6 +174,17 @@ class Mesh { _dirtyVertexBuffer = true; } + void reset() { + _vertexCount = 0; + _vertexData.length = 0; + _dirtyVertexBuffer = true; + if (_parts.length) { + foreach(p; _parts) + destroy(p); + _parts.length = 0; + } + } + /// returns vertex count @property int vertexCount() const { return _vertexCount; }