mirror of https://github.com/buggins/dlangui.git
minecraft like renderer
This commit is contained in:
parent
3671b1f2cb
commit
01da716a70
|
@ -337,7 +337,7 @@
|
|||
<useIn>0</useIn>
|
||||
<useOut>0</useOut>
|
||||
<useArrayBounds>0</useArrayBounds>
|
||||
<noboundscheck>0</noboundscheck>
|
||||
<noboundscheck>1</noboundscheck>
|
||||
<useSwitchError>0</useSwitchError>
|
||||
<useUnitTests>0</useUnitTests>
|
||||
<useInline>1</useInline>
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -11,7 +11,8 @@ immutable int CHUNK_DX_SHIFT = 4;
|
|||
immutable int CHUNK_DX = (1<<CHUNK_DX_SHIFT);
|
||||
immutable int CHUNK_DX_MASK = (CHUNK_DX - 1);
|
||||
|
||||
immutable int CHUNK_DY_SHIFT = 7;
|
||||
// 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);
|
||||
|
||||
|
@ -109,7 +110,7 @@ public:
|
|||
/// Voxel World
|
||||
class World {
|
||||
private:
|
||||
Position camPosition;
|
||||
Position _camPosition;
|
||||
int maxVisibleRange = MAX_VIEW_DISTANCE;
|
||||
int lastChunkX = 1000000;
|
||||
int lastChunkZ = 1000000;
|
||||
|
@ -117,19 +118,21 @@ private:
|
|||
ChunkMatrix chunks;
|
||||
DiamondVisitor visitorHelper;
|
||||
public:
|
||||
this()
|
||||
{
|
||||
this() {
|
||||
_camPosition = Position(Vector3d(0, 13, 0), Vector3d(0, 0, 1));
|
||||
}
|
||||
~this() {
|
||||
|
||||
}
|
||||
ref Position getCamPosition() { return camPosition; }
|
||||
cell_t getCell(Vector3d v) {
|
||||
@property final ref Position camPosition() { return _camPosition; }
|
||||
final cell_t getCell(Vector3d v) {
|
||||
return getCell(v.x, v.y, v.z);
|
||||
}
|
||||
cell_t getCell(int x, int y, int z) {
|
||||
final cell_t getCell(int x, int y, int z) {
|
||||
if (y < 0)
|
||||
return 3;
|
||||
return BOUND_BOTTOM;
|
||||
if (y >= 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);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
Loading…
Reference in New Issue