mirror of https://github.com/buggins/dlangui.git
431 lines
18 KiB
D
431 lines
18 KiB
D
module d3d;
|
|
|
|
import dlangui;
|
|
import dlangui.graphics.scene.scene3d;
|
|
import dlangui.graphics.scene.camera;
|
|
import dlangui.graphics.scene.mesh;
|
|
import dlangui.graphics.scene.material;
|
|
import dlangui.graphics.glsupport;
|
|
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
|
|
extern (C) int UIAppMain(string[] args) {
|
|
// embed resources listed in views/resources.list into executable
|
|
embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
|
|
|
|
// create window
|
|
Window window = Platform.instance.createWindow("DlangUI example - 3D Application", null, WindowFlag.Resizable, 600, 500);
|
|
window.mainWidget = new UiWidget();
|
|
|
|
//MeshPart part = new MeshPart();
|
|
|
|
// show window
|
|
window.show();
|
|
|
|
// run message loop
|
|
return Platform.instance.enterMessageLoop();
|
|
}
|
|
|
|
class UiWidget : VerticalLayout, CellVisitor {
|
|
this() {
|
|
super("OpenGLView");
|
|
layoutWidth = FILL_PARENT;
|
|
layoutHeight = FILL_PARENT;
|
|
alignment = Align.Center;
|
|
try {
|
|
parseML(q{
|
|
{
|
|
margins: 10
|
|
padding: 10
|
|
backgroundImageId: "tx_fabric.tiled"
|
|
layoutWidth: fill
|
|
layoutHeight: fill
|
|
|
|
VerticalLayout {
|
|
id: glView
|
|
margins: 10
|
|
padding: 10
|
|
layoutWidth: fill
|
|
layoutHeight: fill
|
|
TextWidget { text: "There should be OpenGL animation on background"; textColor: "red"; fontSize: 150%; fontWeight: 800; fontFace: "Arial" }
|
|
TextWidget { text: "Do you see it? If no, there is some bug in Mesh rendering code..."; fontSize: 120% }
|
|
// arrange controls as form - table with two columns
|
|
TableLayout {
|
|
colCount: 6
|
|
TextWidget { text: "Translation X" }
|
|
TextWidget { id: lblTranslationX; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbTranslationX; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 200; alpha: 0.6 }
|
|
TextWidget { text: "Rotation X" }
|
|
TextWidget { id: lblRotationX; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbRotationX; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 200; alpha: 0.6 }
|
|
TextWidget { text: "Translation Y" }
|
|
TextWidget { id: lblTranslationY; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbTranslationY; orientation: horizontal; minValue: -100; maxValue: 100; position: 15; minWidth: 200; alpha: 0.6 }
|
|
TextWidget { text: "Rotation Y" }
|
|
TextWidget { id: lblRotationY; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbRotationY; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 150; alpha: 0.6 }
|
|
TextWidget { text: "Translation Z" }
|
|
TextWidget { id: lblTranslationZ; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbTranslationZ; orientation: horizontal; minValue: -100; maxValue: 100; position: 45; minWidth: 150; alpha: 0.6 }
|
|
TextWidget { text: "Rotation Z" }
|
|
TextWidget { id: lblRotationZ; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbRotationZ; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 150; alpha: 0.6 }
|
|
TextWidget { text: "Near" }
|
|
TextWidget { id: lblNear; text: "0.1"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbNear; orientation: horizontal; minValue: 1; maxValue: 100; position: 1; minWidth: 150; alpha: 0.6 }
|
|
TextWidget { text: "Far" }
|
|
TextWidget { id: lblFar; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
|
|
ScrollBar { id: sbFar; orientation: horizontal; minValue: 20; maxValue: 1000; position: 1000; minWidth: 150; alpha: 0.6 }
|
|
}
|
|
VSpacer { layoutWeight: 30 }
|
|
HorizontalLayout {
|
|
TextWidget { text: "Some buttons:" }
|
|
Button { id: btnOk; text: "Ok"; fontSize: 27px }
|
|
Button { id: btnCancel; text: "Cancel"; fontSize: 27px }
|
|
}
|
|
}
|
|
}
|
|
}, "", this);
|
|
} catch (Exception e) {
|
|
Log.e("Failed to parse dml", e);
|
|
}
|
|
// assign OpenGL drawable to child widget background
|
|
childById("glView").backgroundDrawable = DrawableRef(new OpenGLDrawable(&doDraw));
|
|
controlsToVars();
|
|
assignHandlers();
|
|
|
|
_scene = new Scene3d();
|
|
|
|
_cam = new Camera();
|
|
_cam.translate(vec3(0, 14, -7));
|
|
|
|
_scene.activeCamera = _cam;
|
|
|
|
int x0 = 0;
|
|
int y0 = 0;
|
|
int z0 = 0;
|
|
|
|
_mesh = Mesh.createCubeMesh(vec3(x0+ 0, y0 + 0, z0 + 0), 0.3f);
|
|
for (int i = 0; i < 10; i++) {
|
|
_mesh.addCubeMesh(vec3(x0+ 0, y0+0, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1, 1, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+0, z0+ 0), 0.2f, vec4(1, i / 12, 1, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ -i * 2 - 1.0f, y0+0, z0+ 0), 0.2f, vec4(1, i / 12, 1, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ 0, y0+i * 2 + 1.0f, z0+ 0), 0.2f, vec4(1, 1, i / 12 + 0.1, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ 0, y0+-i * 2 - 1.0f, z0+ 0), 0.2f, vec4(1, 1, i / 12 + 0.1, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+i * 2 + 1.0f, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, i / 12, i / 12, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ -i * 2 + 1.0f, y0+i * 2 + 1.0f, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, i / 12, 1 - i / 12, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+-i * 2 + 1.0f, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1 - i / 12, i / 12, 1));
|
|
_mesh.addCubeMesh(vec3(x0+ -i * 2 - 1.0f, y0+-i * 2 - 1.0f, z0+ -i * 2 - 1.0f), 0.2f, vec4(1 - i / 12, i / 12, i / 12, 1));
|
|
}
|
|
|
|
_minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0));
|
|
_world = new World();
|
|
for (int x = -100; x < 100; x++)
|
|
for (int z = -100; z < 100; z++)
|
|
_world.setCell(x, 0, z, 1);
|
|
_world.setCell(0, 11, 10, 2);
|
|
_world.setCell(5, 11, 15, 2);
|
|
Random rnd;
|
|
rnd.setSeed(12345);
|
|
for(int i = 0; i < 1000; i++)
|
|
_world.setCell(rnd.next(6)-32, rnd.next(4), rnd.next(6)-32, 3);
|
|
|
|
_world.camPosition = Position(Vector3d(0, 3, 0), Vector3d(0, 0, 1));
|
|
updateMinerMesh();
|
|
//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);
|
|
}
|
|
|
|
float rotationX;
|
|
float rotationY;
|
|
float rotationZ;
|
|
float translationX;
|
|
float translationY;
|
|
float translationZ;
|
|
float near;
|
|
float far;
|
|
|
|
/// handle scroll event
|
|
bool onScrollEvent(AbstractSlider source, ScrollEvent event) {
|
|
controlsToVars();
|
|
return true;
|
|
}
|
|
|
|
void assignHandlers() {
|
|
childById!ScrollBar("sbNear").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbFar").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbRotationX").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbRotationY").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbRotationZ").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbTranslationX").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbTranslationY").scrollEvent = &onScrollEvent;
|
|
childById!ScrollBar("sbTranslationZ").scrollEvent = &onScrollEvent;
|
|
}
|
|
|
|
void controlsToVars() {
|
|
near = childById!ScrollBar("sbNear").position / 10.0f;
|
|
far = childById!ScrollBar("sbFar").position / 10.0f;
|
|
translationX = childById!ScrollBar("sbTranslationX").position / 10.0f;
|
|
translationY = childById!ScrollBar("sbTranslationY").position / 10.0f;
|
|
translationZ = childById!ScrollBar("sbTranslationZ").position / 10.0f;
|
|
rotationX = childById!ScrollBar("sbRotationX").position;
|
|
rotationY = childById!ScrollBar("sbRotationY").position;
|
|
rotationZ = childById!ScrollBar("sbRotationZ").position;
|
|
childById("lblNear").text = to!dstring(near);
|
|
childById("lblFar").text = to!dstring(far);
|
|
childById("lblTranslationX").text = to!dstring(translationX);
|
|
childById("lblTranslationY").text = to!dstring(translationY);
|
|
childById("lblTranslationZ").text = to!dstring(translationZ);
|
|
childById("lblRotationX").text = to!dstring(rotationX);
|
|
childById("lblRotationY").text = to!dstring(rotationY);
|
|
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);
|
|
}
|
|
|
|
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)
|
|
override void animate(long interval) {
|
|
//Log.d("animating");
|
|
_cam.rotateX(0.01);
|
|
_cam.rotateY(0.02);
|
|
angle += interval * 0.000002f;
|
|
invalidate();
|
|
}
|
|
float angle = 0;
|
|
|
|
MyGLProgram _program;
|
|
Scene3d _scene;
|
|
Camera _cam;
|
|
Mesh _mesh;
|
|
Mesh _minerMesh;
|
|
GLTexture _tx;
|
|
GLTexture _blockstx;
|
|
|
|
|
|
/// this is OpenGLDrawableDelegate implementation
|
|
private void doDraw(Rect windowRect, Rect rc) {
|
|
if (!_program) {
|
|
_program = new MyGLProgram();
|
|
}
|
|
if (!_program.check())
|
|
return;
|
|
if (!_tx)
|
|
_tx = new GLTexture("crate");
|
|
if (!_blockstx)
|
|
_blockstx = new GLTexture("blocks");
|
|
if (!_tx.isValid || !_blockstx.isValid) {
|
|
Log.e("Invalid texture");
|
|
return;
|
|
}
|
|
_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);
|
|
_cam.rotateX(rotationX);
|
|
_cam.rotateY(rotationY);
|
|
_cam.rotateZ(rotationZ);
|
|
//_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);
|
|
checkgl!glCullFace(GL_BACK);
|
|
|
|
_program.bind();
|
|
_program.setUniform("matrix", projectionViewModelMatrix);
|
|
_tx.texture.setup();
|
|
_tx.texture.setSamplerParams(true);
|
|
|
|
_program.draw(_mesh);
|
|
|
|
_tx.texture.unbind();
|
|
|
|
_blockstx.texture.setup();
|
|
_blockstx.texture.setSamplerParams(false);
|
|
|
|
_program.draw(_minerMesh);
|
|
|
|
_blockstx.texture.unbind();
|
|
|
|
_program.unbind();
|
|
checkgl!glDisable(GL_DEPTH_TEST);
|
|
checkgl!glDisable(GL_CULL_FACE);
|
|
}
|
|
|
|
~this() {
|
|
destroy(_scene);
|
|
if (_program)
|
|
destroy(_program);
|
|
if (_tx)
|
|
destroy(_tx);
|
|
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);
|
|
}
|
|
}
|
|
|
|
// Simple texture + color shader
|
|
class MyGLProgram : GLProgram {
|
|
@property override string vertexSource() {
|
|
return q{
|
|
in vec4 vertex;
|
|
in vec4 colAttr;
|
|
in vec4 texCoord;
|
|
out vec4 col;
|
|
out vec4 texc;
|
|
uniform mat4 matrix;
|
|
void main(void)
|
|
{
|
|
gl_Position = matrix * vertex;
|
|
col = colAttr;
|
|
texc = texCoord;
|
|
}
|
|
};
|
|
|
|
}
|
|
@property override string fragmentSource() {
|
|
return q{
|
|
uniform sampler2D tex;
|
|
in vec4 col;
|
|
in vec4 texc;
|
|
out vec4 outColor;
|
|
void main(void)
|
|
{
|
|
outColor = texture(tex, texc.st) * col;
|
|
}
|
|
};
|
|
}
|
|
|
|
// attribute locations
|
|
protected int matrixLocation;
|
|
protected int vertexLocation;
|
|
protected int colAttrLocation;
|
|
protected int texCoordLocation;
|
|
|
|
override bool initLocations() {
|
|
matrixLocation = getUniformLocation("matrix");
|
|
vertexLocation = getAttribLocation("vertex");
|
|
colAttrLocation = getAttribLocation("colAttr");
|
|
texCoordLocation = getAttribLocation("texCoord");
|
|
return matrixLocation >= 0 && vertexLocation >= 0 && colAttrLocation >= 0 && texCoordLocation >= 0;
|
|
}
|
|
|
|
/// get location for vertex attribute
|
|
override int getVertexElementLocation(VertexElementType type) {
|
|
switch(type) with(VertexElementType) {
|
|
case POSITION:
|
|
return vertexLocation;
|
|
case COLOR:
|
|
return colAttrLocation;
|
|
case TEXCOORD0:
|
|
return texCoordLocation;
|
|
default:
|
|
return super.getVertexElementLocation(type);
|
|
}
|
|
}
|
|
|
|
}
|
|
|