mirror of https://github.com/buggins/dlangui.git
277 lines
12 KiB
D
277 lines
12 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.scene.effect;
|
|
import dlangui.graphics.scene.model;
|
|
import dlangui.graphics.scene.node;
|
|
import dlangui.graphics.scene.light;
|
|
import dlangui.graphics.scene.objimport;
|
|
import dlangui.graphics.scene.fbximport;
|
|
import dlangui.graphics.glsupport;
|
|
import dlangui.graphics.gldrawbuf;
|
|
import bindbc.opengl;
|
|
|
|
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);
|
|
static if (ENABLE_OPENGL) {
|
|
window.mainWidget = new UiWidget();
|
|
} else {
|
|
window.mainWidget = new TextWidget("error", "Please build with OpenGL enabled"d);
|
|
}
|
|
|
|
//MeshPart part = new MeshPart();
|
|
|
|
// show window
|
|
window.show();
|
|
|
|
// run message loop
|
|
return Platform.instance.enterMessageLoop();
|
|
}
|
|
|
|
static if (ENABLE_OPENGL):
|
|
|
|
class UiWidget : VerticalLayout {
|
|
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;
|
|
|
|
dirLightNode = new Node3d();
|
|
//dirLightNode.lookAt(vec3(-5, -5, -5), vec3(0, 0, 0), vec3(0, 1, 0));
|
|
dirLightNode.rotateY(-15);
|
|
//dirLightNode.rotateX(20);
|
|
dirLightNode.translateX(2);
|
|
dirLightNode.translateY(3);
|
|
dirLightNode.translateZ(0);
|
|
dirLightNode.light = Light.createPoint(vec3(2, 2, 2), 15); //Light.createDirectional(vec3(1, 0.5, 0.5));
|
|
//dirLightNode.light = Light.createDirectional(vec3(1, 0.5, 0.8));
|
|
dirLightNode.light.enabled = true;
|
|
_scene.addChild(dirLightNode);
|
|
|
|
int x0 = 0;
|
|
int y0 = 0;
|
|
int z0 = 0;
|
|
|
|
Mesh _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));
|
|
}
|
|
Material cubeMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "crate");
|
|
Model cubeDrawable = new Model(cubeMaterial, _mesh);
|
|
Node3d cubeNode = new Node3d("cubes", cubeDrawable);
|
|
_scene.addChild(cubeNode);
|
|
|
|
debug(fbximport) {
|
|
// test FBX import
|
|
FbxModelImport importer;
|
|
string src = loadTextResource("suzanne.fbx");
|
|
importer.filename = "suzanne.fbx";
|
|
importer.parse(src);
|
|
}
|
|
|
|
ObjModelImport importer;
|
|
string src = loadTextResource("suzanne.obj");
|
|
importer.parse(src);
|
|
Log.d("suzanne mesh:", importer.mesh.dumpVertexes(20));
|
|
Material suzanneMaterial = new Material(EffectId("colored.vert", "colored.frag", null), null); //"SPECULAR"
|
|
//suzanneMaterial.ambientColor = vec3(0.5, 0.5, 0.5);
|
|
suzanneMaterial.diffuseColor = vec4(0.7, 0.7, 0.5, 1.0);
|
|
//suzanneMaterial.specular = true;
|
|
Model suzanneDrawable = new Model(suzanneMaterial, importer.mesh);
|
|
suzanneNode = new Node3d("suzanne", suzanneDrawable);
|
|
suzanneNode.translate(vec3(2, 2, -5));
|
|
_scene.addChild(suzanneNode);
|
|
|
|
|
|
brickNode = new Node3d("brick");
|
|
brickNode.translate(vec3(-2, 2, -3));
|
|
Mesh brickMesh = Mesh.createCubeMesh(vec3(0, 0, 0), 0.8, vec4(0.8, 0.8, 0.8, 1));
|
|
Material brickMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "brick", "brickn"); // with bump mapping
|
|
//brickMaterial.specular = true;
|
|
brickNode.drawable = new Model(brickMaterial, brickMesh);
|
|
_scene.addChild(brickNode);
|
|
|
|
}
|
|
|
|
Node3d dirLightNode;
|
|
Node3d suzanneNode;
|
|
Node3d brickNode;
|
|
|
|
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);
|
|
}
|
|
|
|
/// 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();
|
|
suzanneNode.rotateY(interval * 0.000002f);
|
|
brickNode.rotateY(interval * 0.00000123f);
|
|
brickNode.rotateZ(interval * 0.0000004123f);
|
|
brickNode.rotateX(interval * 0.0000007543f);
|
|
}
|
|
float angle = 0;
|
|
|
|
Scene3dRef _scene;
|
|
Camera _cam;
|
|
|
|
/// this is OpenGLDrawableDelegate implementation
|
|
private void doDraw(Rect windowRect, Rect rc) {
|
|
_cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
|
|
_cam.setIdentity();
|
|
_cam.translateX(translationX);
|
|
_cam.translateY(translationY);
|
|
_cam.translateZ(translationZ);
|
|
_cam.rotateX(rotationX);
|
|
_cam.rotateY(rotationY);
|
|
_cam.rotateZ(rotationZ);
|
|
|
|
checkgl!glEnable(GL_CULL_FACE);
|
|
//checkgl!glDisable(GL_CULL_FACE);
|
|
checkgl!glEnable(GL_DEPTH_TEST);
|
|
checkgl!glCullFace(GL_BACK);
|
|
|
|
_scene.drawScene(false);
|
|
|
|
checkgl!glDisable(GL_DEPTH_TEST);
|
|
checkgl!glDisable(GL_CULL_FACE);
|
|
}
|
|
|
|
~this() {
|
|
}
|
|
}
|