1 module d3d;
2
3 import dlangui;
4 import dlangui.graphics.scene.scene3d;
5 import dlangui.graphics.scene.camera;
6 import dlangui.graphics.scene.mesh;
7 import dlangui.graphics.scene.material;
8 import dlangui.graphics.scene.effect;
9 import dlangui.graphics.scene.model;
10 import dlangui.graphics.scene.node;
11 import dlangui.graphics.scene.light;
12 import dlangui.graphics.scene.objimport;
13 import dlangui.graphics.scene.fbximport;
14 import dlangui.graphics.glsupport;
15 import dlangui.graphics.gldrawbuf;
16 import derelict.opengl.gl;
17
18 mixin APP_ENTRY_POINT;
19
20 /// entry point for dlangui based application
21 extern (C) int UIAppMain(string[] args) {
22 // embed resources listed in views/resources.list into executable
23 embeddedResourceList.addResources(embedResourcesFromList!("resources.list")());
24
25 // create window
26 Window window = Platform.instance.createWindow("DlangUI example - 3D Application", null, WindowFlag.Resizable, 600, 500);
27 static if (ENABLE_OPENGL) {
28 window.mainWidget = new UiWidget();
29 } else {
30 window.mainWidget = new TextWidget("error", "Please build with OpenGL enabled"d);
31 }
32
33 //MeshPart part = new MeshPart();
34
35 // show window
36 window.show();
37
38 // run message loop
39 return Platform.instance.enterMessageLoop();
40 }
41
42 static if (ENABLE_OPENGL):
43
44 class UiWidget : VerticalLayout {
45 this() {
46 super("OpenGLView");
47 layoutWidth = FILL_PARENT;
48 layoutHeight = FILL_PARENT;
49 alignment = Align.Center;
50 try {
51 parseML(q{
52 {
53 margins: 10
54 padding: 10
55 backgroundImageId: "tx_fabric.tiled"
56 layoutWidth: fill
57 layoutHeight: fill
58
59 VerticalLayout {
60 id: glView
61 margins: 10
62 padding: 10
63 layoutWidth: fill
64 layoutHeight: fill
65 TextWidget { text: "There should be OpenGL animation on background"; textColor: "red"; fontSize: 150%; fontWeight: 800; fontFace: "Arial" }
66 TextWidget { text: "Do you see it? If no, there is some bug in Mesh rendering code..."; fontSize: 120% }
67 // arrange controls as form - table with two columns
68 TableLayout {
69 colCount: 6
70 TextWidget { text: "Translation X" }
71 TextWidget { id: lblTranslationX; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
72 ScrollBar { id: sbTranslationX; orientation: horizontal; minValue: -100; maxValue: 100; position: 0; minWidth: 200; alpha: 0.6 }
73 TextWidget { text: "Rotation X" }
74 TextWidget { id: lblRotationX; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
75 ScrollBar { id: sbRotationX; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 200; alpha: 0.6 }
76 TextWidget { text: "Translation Y" }
77 TextWidget { id: lblTranslationY; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
78 ScrollBar { id: sbTranslationY; orientation: horizontal; minValue: -100; maxValue: 100; position: 15; minWidth: 200; alpha: 0.6 }
79 TextWidget { text: "Rotation Y" }
80 TextWidget { id: lblRotationY; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
81 ScrollBar { id: sbRotationY; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 150; alpha: 0.6 }
82 TextWidget { text: "Translation Z" }
83 TextWidget { id: lblTranslationZ; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
84 ScrollBar { id: sbTranslationZ; orientation: horizontal; minValue: -100; maxValue: 100; position: 45; minWidth: 150; alpha: 0.6 }
85 TextWidget { text: "Rotation Z" }
86 TextWidget { id: lblRotationZ; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
87 ScrollBar { id: sbRotationZ; orientation: horizontal; minValue: -180; maxValue: 180; position: 0; minWidth: 150; alpha: 0.6 }
88 TextWidget { text: "Near" }
89 TextWidget { id: lblNear; text: "0.1"; minWidth: 80; backgroundColor: 0x80FFFFFF }
90 ScrollBar { id: sbNear; orientation: horizontal; minValue: 1; maxValue: 100; position: 1; minWidth: 150; alpha: 0.6 }
91 TextWidget { text: "Far" }
92 TextWidget { id: lblFar; text: "0.0"; minWidth: 80; backgroundColor: 0x80FFFFFF }
93 ScrollBar { id: sbFar; orientation: horizontal; minValue: 20; maxValue: 1000; position: 1000; minWidth: 150; alpha: 0.6 }
94 }
95 VSpacer { layoutWeight: 30 }
96 HorizontalLayout {
97 TextWidget { text: "Some buttons:" }
98 Button { id: btnOk; text: "Ok"; fontSize: 27px }
99 Button { id: btnCancel; text: "Cancel"; fontSize: 27px }
100 }
101 }
102 }
103 }, "", this);
104 } catch (Exception e) {
105 Log.e("Failed to parse dml", e);
106 }
107 // assign OpenGL drawable to child widget background
108 childById("glView").backgroundDrawable = DrawableRef(new OpenGLDrawable(&doDraw));
109 controlsToVars();
110 assignHandlers();
111
112 _scene = new Scene3d();
113
114 _cam = new Camera();
115 _cam.translate(vec3(0, 14, -7));
116
117 _scene.activeCamera = _cam;
118
119 dirLightNode = new Node3d();
120 //dirLightNode.lookAt(vec3(-5, -5, -5), vec3(0, 0, 0), vec3(0, 1, 0));
121 dirLightNode.rotateY(-15);
122 //dirLightNode.rotateX(20);
123 dirLightNode.translateX(2);
124 dirLightNode.translateY(3);
125 dirLightNode.translateZ(0);
126 dirLightNode.light = Light.createPoint(vec3(2, 2, 2), 15); //Light.createDirectional(vec3(1, 0.5, 0.5));
127 //dirLightNode.light = Light.createDirectional(vec3(1, 0.5, 0.8));
128 dirLightNode.light.enabled = true;
129 _scene.addChild(dirLightNode);
130
131 int x0 = 0;
132 int y0 = 0;
133 int z0 = 0;
134
135 Mesh _mesh = Mesh.createCubeMesh(vec3(x0+ 0, y0 + 0, z0 + 0), 0.3f);
136 for (int i = 0; i < 10; i++) {
137 _mesh.addCubeMesh(vec3(x0+ 0, y0+0, z0+ i * 2 + 1.0f), 0.2f, vec4(i / 12, 1, 1, 1));
138 _mesh.addCubeMesh(vec3(x0+ i * 2 + 1.0f, y0+0, z0+ 0), 0.2f, vec4(1, i / 12, 1, 1));
139 _mesh.addCubeMesh(vec3(x0+ -i * 2 - 1.0f, y0+0, z0+ 0), 0.2f, vec4(1, i / 12, 1, 1));
140 _mesh.addCubeMesh(vec3(x0+ 0, y0+i * 2 + 1.0f, z0+ 0), 0.2f, vec4(1, 1, i / 12 + 0.1, 1));
141 _mesh.addCubeMesh(vec3(x0+ 0, y0+-i * 2 - 1.0f, z0+ 0), 0.2f, vec4(1, 1, i / 12 + 0.1, 1));
142 _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));
143 _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));
144 _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));
145 _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));
146 }
147 Material cubeMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "crate");
148 Model cubeDrawable = new Model(cubeMaterial, _mesh);
149 Node3d cubeNode = new Node3d("cubes", cubeDrawable);
150 _scene.addChild(cubeNode);
151
152 debug(fbximport) {
153 // test FBX import
154 FbxModelImport importer;
155 string src = loadTextResource("suzanne.fbx");
156 importer.filename = "suzanne.fbx";
157 importer.parse(src);
158 }
159
160 ObjModelImport importer;
161 string src = loadTextResource("suzanne.obj");
162 importer.parse(src);
163 Log.d("suzanne mesh:", importer.mesh.dumpVertexes(20));
164 Material suzanneMaterial = new Material(EffectId("colored.vert", "colored.frag", null), null); //"SPECULAR"
165 //suzanneMaterial.ambientColor = vec3(0.5, 0.5, 0.5);
166 suzanneMaterial.diffuseColor = vec4(0.7, 0.7, 0.5, 1.0);
167 //suzanneMaterial.specular = true;
168 Model suzanneDrawable = new Model(suzanneMaterial, importer.mesh);
169 suzanneNode = new Node3d("suzanne", suzanneDrawable);
170 suzanneNode.translate(vec3(2, 2, -5));
171 _scene.addChild(suzanneNode);
172
173
174 brickNode = new Node3d("brick");
175 brickNode.translate(vec3(-2, 2, -3));
176 Mesh brickMesh = Mesh.createCubeMesh(vec3(0, 0, 0), 0.8, vec4(0.8, 0.8, 0.8, 1));
177 Material brickMaterial = new Material(EffectId("textured.vert", "textured.frag", null), "brick", "brickn"); // with bump mapping
178 //brickMaterial.specular = true;
179 brickNode.drawable = new Model(brickMaterial, brickMesh);
180 _scene.addChild(brickNode);
181
182 }
183
184 Node3d dirLightNode;
185 Node3d suzanneNode;
186 Node3d brickNode;
187
188 float rotationX;
189 float rotationY;
190 float rotationZ;
191 float translationX;
192 float translationY;
193 float translationZ;
194 float near;
195 float far;
196
197 /// handle scroll event
198 bool onScrollEvent(AbstractSlider source, ScrollEvent event) {
199 controlsToVars();
200 return true;
201 }
202
203 void assignHandlers() {
204 childById!ScrollBar("sbNear").scrollEvent = &onScrollEvent;
205 childById!ScrollBar("sbFar").scrollEvent = &onScrollEvent;
206 childById!ScrollBar("sbRotationX").scrollEvent = &onScrollEvent;
207 childById!ScrollBar("sbRotationY").scrollEvent = &onScrollEvent;
208 childById!ScrollBar("sbRotationZ").scrollEvent = &onScrollEvent;
209 childById!ScrollBar("sbTranslationX").scrollEvent = &onScrollEvent;
210 childById!ScrollBar("sbTranslationY").scrollEvent = &onScrollEvent;
211 childById!ScrollBar("sbTranslationZ").scrollEvent = &onScrollEvent;
212 }
213
214 void controlsToVars() {
215 near = childById!ScrollBar("sbNear").position / 10.0f;
216 far = childById!ScrollBar("sbFar").position / 10.0f;
217 translationX = childById!ScrollBar("sbTranslationX").position / 10.0f;
218 translationY = childById!ScrollBar("sbTranslationY").position / 10.0f;
219 translationZ = childById!ScrollBar("sbTranslationZ").position / 10.0f;
220 rotationX = childById!ScrollBar("sbRotationX").position;
221 rotationY = childById!ScrollBar("sbRotationY").position;
222 rotationZ = childById!ScrollBar("sbRotationZ").position;
223 childById("lblNear").text = to!dstring(near);
224 childById("lblFar").text = to!dstring(far);
225 childById("lblTranslationX").text = to!dstring(translationX);
226 childById("lblTranslationY").text = to!dstring(translationY);
227 childById("lblTranslationZ").text = to!dstring(translationZ);
228 childById("lblRotationX").text = to!dstring(rotationX);
229 childById("lblRotationY").text = to!dstring(rotationY);
230 childById("lblRotationZ").text = to!dstring(rotationZ);
231 }
232
233 /// returns true is widget is being animated - need to call animate() and redraw
234 @property override bool animating() { return true; }
235 /// animates window; interval is time left from previous draw, in hnsecs (1/10000000 of second)
236 override void animate(long interval) {
237 //Log.d("animating");
238 _cam.rotateX(0.01);
239 _cam.rotateY(0.02);
240 angle += interval * 0.000002f;
241 invalidate();
242 suzanneNode.rotateY(interval * 0.000002f);
243 brickNode.rotateY(interval * 0.00000123f);
244 brickNode.rotateZ(interval * 0.0000004123f);
245 brickNode.rotateX(interval * 0.0000007543f);
246 }
247 float angle = 0;
248
249 Scene3dRef _scene;
250 Camera _cam;
251
252 /// this is OpenGLDrawableDelegate implementation
253 private void doDraw(Rect windowRect, Rect rc) {
254 _cam.setPerspective(rc.width, rc.height, 45.0f, near, far);
255 _cam.setIdentity();
256 _cam.translateX(translationX);
257 _cam.translateY(translationY);
258 _cam.translateZ(translationZ);
259 _cam.rotateX(rotationX);
260 _cam.rotateY(rotationY);
261 _cam.rotateZ(rotationZ);
262
263 checkgl!glEnable(GL_CULL_FACE);
264 //checkgl!glDisable(GL_CULL_FACE);
265 checkgl!glEnable(GL_DEPTH_TEST);
266 checkgl!glCullFace(GL_BACK);
267
268 _scene.drawScene(false);
269
270 checkgl!glDisable(GL_DEPTH_TEST);
271 checkgl!glDisable(GL_CULL_FACE);
272 }
273
274 ~this() {
275 }
276 }