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