optimize dminer example; fix win32 opengl support; enable wireframe mode for drawing of meshes

This commit is contained in:
Vadim Lopatin 2017-06-23 15:47:02 +03:00
parent 388bc94cf7
commit 4c1e97c952
10 changed files with 108 additions and 46 deletions

View File

@ -96,7 +96,7 @@ X<-----x-----
private immutable float CCC = 0.5; // cell cube coordinates
private immutable float TC0 = 0.0;
private immutable float TC1 = 1.0;
private immutable float TC1 = 0.99;
__gshared static const float[VERTEX_COMPONENTS * 4] face_vertices_north =
[
@ -184,7 +184,7 @@ __gshared static const float[VERTEX_COMPONENTS * 4] face_vertices_down =
__gshared static const ushort[6] face_indexes =
[
2, 1, 0, 0, 3, 2 // CCW
2, 1, 0, 0, 3, 2 // CCW
];
__gshared static const ushort[6] face_indexes_back =

View File

@ -6,7 +6,7 @@ import dminer.core.world;
import dlangui.graphics.scene.mesh;
version = FAST_VISIBILITY_PATH;
//version = FAST_VISIBILITY_PATH;
// Y range: 0..CHUNK_DY-1
immutable int CHUNK_DY = 128;
@ -29,7 +29,7 @@ interface CellVisitor {
}
interface ChunkVisitor {
void visit(World world, SmallChunk * chunk);
bool visit(World world, SmallChunk * chunk);
}
// vertical stack of chunks with same X, Z, and different Y
@ -1550,13 +1550,18 @@ struct VisibilityCheckIterator {
if (!mask)
return;
// distance test
Vector3d diff = p - camPos;
Vector3d diff = (p + Vector3d(4,4,4)) - camPos;
if (diff.squaredLength() > maxDistanceSquared)
return;
// direction test (TODO)
int dot = diff.dot(cameraDirection);
if (dot < 8000)
return;
int distance = diff.squaredLength;
if (distance > 10*10) {
diff = (diff * 256 + cameraDirection * 16) / 256;
//diff += cameraDirection;
// direction test (TODO)
int dot = diff.dot(cameraDirection);
if (dot < 12000)
return;
}
//....
// plan visiting
VisibilityCheckChunk * plan = getOrAddPlannedChunk(p);
@ -1571,7 +1576,8 @@ struct VisibilityCheckIterator {
swap(visitedChunks, plannedChunks);
plannedChunks.length = 0;
foreach (ref p; visitedChunks) {
visitor.visit(world, p.chunk);
if (!visitor.visit(world, p.chunk))
continue;
/// set mask of spread directions
p.spreadToDirMask = calcSpreadMask(p.pos, startPos);
p.tracePaths();

View File

@ -120,6 +120,10 @@ struct Vector3d {
Vector3d opBinary(string op : "*")(int n) const {
return Vector3d(x * n, y * n, z * n);
}
/// divide 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) {

View File

@ -7,7 +7,7 @@ import dminer.core.chunk;
version (Android) {
const int MAX_VIEW_DISTANCE = 60;
} else {
const int MAX_VIEW_DISTANCE = 120;
const int MAX_VIEW_DISTANCE = 180;
}

View File

@ -15,6 +15,8 @@ import dlangui.graphics.scene.effect;
import dlangui.graphics.glsupport;
import dlangui.graphics.gldrawbuf;
//version = TEST_VISITOR_PERFORMANCE;
/*
version (Android) {
//enum SUPPORT_LEGACY_OPENGL = false;
@ -62,8 +64,9 @@ extern (C) int UIAppMain(string[] args) {
class ChunkVisitCounter : ChunkVisitor {
int count;
void visit(World world, SmallChunk * chunk) {
bool visit(World world, SmallChunk * chunk) {
count++;
return true;
}
}
@ -78,6 +81,10 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor {
private Camera _cam;
private vec3 _camPosition;
private vec3 _camForwardVector;
private bool _wireframe;
@property bool wireframe() { return _wireframe; }
@property void wireframe(bool flgWireframe) { _wireframe = flgWireframe; }
this(World world, Material material, Camera cam) {
super(material);
@ -94,7 +101,7 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor {
_pos = _world.camPosition.pos;
_camPosition = _cam.translation;
_camForwardVector = _cam.forwardVectorWorld;
_camPosition -= _camForwardVector * 8;
//_camPosition -= _camForwardVector * 8;
_skippedCount = _drawnCount = 0;
long ts = currentTimeMillis();
//_chunkVisitor.visitChunks(_pos);
@ -102,34 +109,48 @@ class MinerDrawable : MaterialDrawableObject, ChunkVisitor {
camVector.x = cast(int)(_camForwardVector.x * 256);
camVector.y = cast(int)(_camForwardVector.y * 256);
camVector.z = cast(int)(_camForwardVector.z * 256);
ChunkVisitCounter countVisitor = new ChunkVisitCounter();
_chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE);
_chunkIterator.visitVisibleChunks(countVisitor, camVector);
long durationNoDraw = currentTimeMillis() - ts;
_chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE);
_chunkIterator.visitVisibleChunks(this, camVector);
long duration = currentTimeMillis() - ts;
Log.d("drawing of Miner scene finished in ", duration, " ms skipped:", _skippedCount, " drawn:", _drawnCount, " duration(noDraw)=", durationNoDraw);
version (TEST_VISITOR_PERFORMANCE) {
ChunkVisitCounter countVisitor = new ChunkVisitCounter();
_chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE);
_chunkIterator.visitVisibleChunks(countVisitor, camVector);
long durationNoDraw = currentTimeMillis() - ts;
_chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE);
_chunkIterator.visitVisibleChunks(this, camVector);
long duration = currentTimeMillis() - ts;
Log.d("drawing of Miner scene finished in ", duration, " ms skipped:", _skippedCount, " drawn:", _drawnCount, " duration(noDraw)=", durationNoDraw);
} else {
_chunkIterator.start(_world, _world.camPosition.pos, MAX_VIEW_DISTANCE);
_chunkIterator.visitVisibleChunks(this, camVector);
long duration = currentTimeMillis() - ts;
Log.d("drawing of Miner scene finished in ", duration, " ms skipped:", _skippedCount, " drawn:", _drawnCount);
}
}
void visit(World world, SmallChunk * chunk) {
bool visit(World world, SmallChunk * chunk) {
if (chunk) {
Vector3d p = chunk.position;
vec3 chunkPos = vec3(p.x + 4, p.y + 4, p.z + 4);
vec3 chunkDirection = (chunkPos - _camPosition).normalized;
float camDist = (_camPosition - chunkPos).length;
vec3 chunkDirection = (chunkPos - (_camPosition - (_camForwardVector * 12))).normalized;
float dot = _camForwardVector.dot(chunkDirection);
//Log.d("visit() chunkPos ", chunkPos, " chunkDir ", chunkDirection, " camDir ");
if (dot < 0.7) { // cos(45)
float threshold = 0.87;
if (camDist < 12)
threshold = 0.5;
//Log.d("visit() chunkPos ", chunkPos, " chunkDir ", chunkDirection, " camDir ", " dot ", dot, " threshold ", threshold);
if (dot < threshold) { // cos(45)
_skippedCount++;
return;
return false;
}
Mesh mesh = chunk.getMesh(world);
if (mesh) {
_material.bind(_node, mesh, lights(_node));
_material.drawMesh(mesh);
_material.drawMesh(mesh, _wireframe);
_material.unbind();
_drawnCount++;
}
return true;
}
return true;
}
}
@ -232,7 +253,8 @@ class UiWidget : VerticalLayout { //, CellVisitor
//updateMinerMesh();
Material minerMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "blocks");
minerMaterial.ambientColor = vec3(0.05,0.05,0.05);
//Material minerMaterial = new Material(EffectId("colored.vert", "colored.frag", null), "blocks");
minerMaterial.ambientColor = vec3(0.25,0.25,0.25);
minerMaterial.textureLinear = false;
minerMaterial.fogParams = new FogParams(vec4(0.01, 0.01, 0.01, 1), 12, 80);
//minerMaterial.specular = 10;
@ -240,6 +262,7 @@ class UiWidget : VerticalLayout { //, CellVisitor
//_minerDrawable.autobindLights = false;
//Model minerDrawable = new Model(minerMaterial, _minerMesh);
Node3d minerNode = new Node3d("miner", _minerDrawable);
//_minerDrawable.wireframe = true;
_scene.addChild(minerNode);
@ -342,6 +365,9 @@ class UiWidget : VerticalLayout { //, CellVisitor
override bool onKeyEvent(KeyEvent event) {
if (event.action == KeyAction.KeyDown) {
switch(event.keyCode) with(KeyCode) {
case F1:
_minerDrawable.wireframe = !_minerDrawable.wireframe;
return true;
case KEY_W:
case UP:
_world.camPosition.forward(1);
@ -455,11 +481,13 @@ class UiWidget : VerticalLayout { //, CellVisitor
import std.string : format;
Widget w = childById("lblPosition");
string dir = _world.camPosition.direction.dir.to!string;
dstring s = format("pos(%d,%d) h=%d fps:%d %s [F]lying: %s [U]pdateMesh: %s", _world.camPosition.pos.x, _world.camPosition.pos.z, _world.camPosition.pos.y,
dstring s = format("pos(%d,%d) h=%d fps:%d %s [F]lying: %s [U]pdateMesh: %s [F1] wireframe: %s", _world.camPosition.pos.x, _world.camPosition.pos.z, _world.camPosition.pos.y,
_fps,
dir,
flying,
enableMeshUpdate).toUTF32;
enableMeshUpdate,
_minerDrawable ? _minerDrawable.wireframe : false
).toUTF32;
w.text = s;
}

View File

@ -435,13 +435,13 @@ class GLProgram : dlangui.graphics.scene.mesh.GraphicsEffect {
}
/// draw mesh using this program (program should be bound by this time and all uniforms should be set)
override void draw(Mesh mesh) {
override void draw(Mesh mesh, bool wireframe) {
VertexBuffer vb = mesh.vertexBuffer;
if (!vb) {
vb = new GLVertexBuffer();
mesh.vertexBuffer = vb;
}
vb.draw(this);
vb.draw(this, wireframe);
}
}
@ -1310,16 +1310,39 @@ class GLVertexBuffer : VertexBuffer {
}
/// draw mesh using specified effect
override void draw(GraphicsEffect effect) {
override void draw(GraphicsEffect effect, bool wireframe) {
//bind();
enableAttributes(effect);
foreach (fragment; _indexFragments) {
checkgl!glDrawRangeElements(primitiveTypeToGL(fragment.type),
0, _vertexCount - 1, // The first to last vertex
fragment.end - fragment.start, // count of indexes used to draw elements
GL_UNSIGNED_SHORT,
cast(char*)(fragment.start * short.sizeof) // offset from index buffer beginning to fragment start
);
if (wireframe && fragment.type == PrimitiveType.triangles) {
// TODO: support wireframe not only for triangles
int triangleCount = fragment.end - fragment.start;
//triangleCount /= 3;
//checkgl!glDisable(GL_CULL_FACE);
for (int i = 0; i < triangleCount; i += 3) {
// GL line loop works strange; use GL_LINES instead
checkgl!glDrawRangeElements(GL_LINE_LOOP, //GL_TRIANGLES,
0, _vertexCount - 1, // The first to last vertex start, end
3, // count of indexes used to draw elements
GL_UNSIGNED_SHORT,
cast(char*)((fragment.start + i) * short.sizeof) // offset from index buffer beginning to fragment start
);
//checkgl!glDrawRangeElements(GL_LINES, //GL_TRIANGLES,
// 0, _vertexCount - 1, // The first to last vertex start, end
// 2, // count of indexes used to draw elements
// GL_UNSIGNED_SHORT,
// cast(char*)((fragment.start + i + 1) * short.sizeof) // offset from index buffer beginning to fragment start
// );
}
//checkgl!glEnable(GL_CULL_FACE);
} else {
checkgl!glDrawRangeElements(primitiveTypeToGL(fragment.type),
0, _vertexCount - 1, // The first to last vertex
fragment.end - fragment.start, // count of indexes used to draw elements
GL_UNSIGNED_SHORT,
cast(char*)(fragment.start * short.sizeof) // offset from index buffer beginning to fragment start
);
}
}
disableAttributes(effect);
//unbind();
@ -1381,10 +1404,11 @@ class DummyVertexBuffer : VertexBuffer {
}
/// draw mesh using specified effect
override void draw(GraphicsEffect effect) {
override void draw(GraphicsEffect effect, bool wireframe) {
//bind();
enableAttributes(effect);
foreach (fragment; _indexFragments) {
// TODO: support wireframe
checkgl!glDrawRangeElements(primitiveTypeToGL(fragment.type),
0, _vertexCount,
fragment.end - fragment.start,

View File

@ -230,8 +230,8 @@ class Material : RefCountedObject {
}
}
void drawMesh(Mesh mesh) {
effect.draw(mesh);
void drawMesh(Mesh mesh, bool wireframe) {
effect.draw(mesh, wireframe);
}
void unbind() {

View File

@ -63,7 +63,7 @@ abstract class GraphicsEffect : RefCountedObject {
/// returns true if effect has uniform
bool hasUniform(string uniformName);
void draw(Mesh mesh);
void draw(Mesh mesh, bool wireframe);
}
enum DefaultUniform : int {
@ -162,7 +162,7 @@ class VertexBuffer {
/// set or change data
void setData(Mesh mesh) { }
/// draw mesh using specified effect
void draw(GraphicsEffect effect) { }
void draw(GraphicsEffect effect, bool wireframe) { }
}
/// location for element is not found

View File

@ -29,7 +29,7 @@ class Model : MaterialDrawableObject {
override void draw(Node3d node, bool wireframe) {
/// override it
_material.bind(node, _mesh, lights(node));
_material.drawMesh(_mesh);
_material.drawMesh(_mesh, wireframe);
_material.unbind();
}
}

View File

@ -1574,7 +1574,7 @@ class Platform {
}
static if (ENABLE_OPENGL) {
private __gshared bool _OPENGL_ENABLED = false;
private __gshared bool _OPENGL_ENABLED = true;
/// check if hardware acceleration is enabled
@property bool openglEnabled() { return _OPENGL_ENABLED; }
/// call on app initialization if OpenGL support is detected