minecraft like renderer

This commit is contained in:
Vadim Lopatin 2016-03-22 11:55:05 +03:00
parent 3671b1f2cb
commit 01da716a70
5 changed files with 203 additions and 32 deletions

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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);

View File

@ -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; }