diff --git a/dlangui-monod-linux.dproj b/dlangui-monod-linux.dproj
index 1376d1e7..a7a4b57a 100644
--- a/dlangui-monod-linux.dproj
+++ b/dlangui-monod-linux.dproj
@@ -256,6 +256,7 @@
+
@@ -270,6 +271,7 @@
+
@@ -286,6 +288,7 @@
+
diff --git a/dlangui-monod-osx.dproj b/dlangui-monod-osx.dproj
index 665ca7b0..dfd82c8a 100644
--- a/dlangui-monod-osx.dproj
+++ b/dlangui-monod-osx.dproj
@@ -115,6 +115,7 @@
+
@@ -129,6 +130,7 @@
+
@@ -145,6 +147,7 @@
+
diff --git a/dlangui-msvc.visualdproj b/dlangui-msvc.visualdproj
index cec418cb..fef32695 100644
--- a/dlangui-msvc.visualdproj
+++ b/dlangui-msvc.visualdproj
@@ -748,6 +748,7 @@
+
@@ -767,6 +768,7 @@
+
@@ -777,6 +779,7 @@
+
diff --git a/examples/d3d/d3d-msvc.visualdproj b/examples/d3d/d3d-msvc.visualdproj
index 369a7246..20d53180 100644
--- a/examples/d3d/d3d-msvc.visualdproj
+++ b/examples/d3d/d3d-msvc.visualdproj
@@ -54,7 +54,7 @@
1
$(DMDInstallDir)windows\bin\dmd.exe
$(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source
- views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders
+ views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders views/res/models
$(ConfigurationName)
$(OutDir)
@@ -146,7 +146,7 @@
0
0
0
- 2.043
+ 2
0
0
0
@@ -156,7 +156,7 @@
1
$(DMDInstallDir)windows\bin\dmd.exe
$(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source
- views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders
+ views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders views/res/models
$(ConfigurationName)
$(OutDir)
@@ -258,7 +258,7 @@
1
$(DMDInstallDir)windows\bin\dmd.exe
$(SolutionDir)/../dlangui/src $(SolutionDir)/../dlangui/3rdparty $(SolutionDir)/../dlangui/deps/DerelictGL3/source $(SolutionDir)/../dlangui/deps/DerelictUtil/source $(SolutionDir)/../dlangui/deps/DerelictFT/source $(SolutionDir)/../dlangui/deps/DerelictSDL2/source
- views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders
+ views views/res views/res/i18n views/res/mdpi views/res/hdpi views/res/shaders views/res/models
$(ConfigurationName)
$(OutDir)
diff --git a/examples/d3d/dub.json b/examples/d3d/dub.json
index b41e6cca..94b57412 100644
--- a/examples/d3d/dub.json
+++ b/examples/d3d/dub.json
@@ -5,7 +5,7 @@
"license": "Boost",
"authors": ["Vadim Lopatin"],
- "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/shaders"],
+ "stringImportPaths": ["views", "views/res", "views/res/i18n", "views/res/mdpi", "views/res/shaders", "views/res/models"],
"targetPath": "bin",
"targetName": "d3d",
diff --git a/examples/d3d/src/d3d.d b/examples/d3d/src/d3d.d
index 3f7d392f..eaa31298 100644
--- a/examples/d3d/src/d3d.d
+++ b/examples/d3d/src/d3d.d
@@ -8,6 +8,7 @@ import dlangui.graphics.scene.material;
import dlangui.graphics.scene.effect;
import dlangui.graphics.scene.model;
import dlangui.graphics.scene.node;
+import dlangui.graphics.scene.objimport;
import dlangui.graphics.glsupport;
import dlangui.graphics.gldrawbuf;
import derelict.opengl3.gl3;
@@ -133,6 +134,10 @@ class UiWidget : VerticalLayout, CellVisitor {
Node3d cubeNode = new Node3d("cubes", cubeDrawable);
_scene.addChild(cubeNode);
+ ObjModelImport importer;
+ string src = loadTextResource("suzanne.obj");
+ importer.parse(src);
+
_minerMesh = new Mesh(VertexFormat(VertexElementType.POSITION, VertexElementType.NORMAL, VertexElementType.COLOR, VertexElementType.TEXCOORD0));
_world = new World();
diff --git a/examples/d3d/views/res/models/suzanne.obj b/examples/d3d/views/res/models/suzanne.obj
new file mode 100644
index 00000000..5d51b99a
--- /dev/null
+++ b/examples/d3d/views/res/models/suzanne.obj
@@ -0,0 +1,1013 @@
+# Blender v2.62 (sub 0) OBJ File: ''
+# www.blender.org
+mtllib suzanne.mtl
+o Monkey
+v 1.557551 1.541131 0.480829
+v 0.331108 1.541131 1.596098
+v 1.536168 1.436254 0.329004
+v 0.181992 1.436254 1.560428
+v 1.478211 1.373008 0.181574
+v 0.040715 1.373008 1.488764
+v 1.299164 1.255507 0.438430
+v 0.313379 1.255507 1.334856
+v 1.391609 1.338692 0.539742
+v 0.405477 1.338692 1.436484
+v 1.463655 1.481125 0.616616
+v 0.475179 1.481125 1.515489
+v 1.364483 1.546302 0.736294
+v 0.603715 1.546302 1.428101
+v 1.229196 1.444066 0.728841
+v 0.609112 1.444066 1.292716
+v 1.099516 1.382490 0.672423
+v 0.565234 1.382490 1.158274
+v 0.999523 1.680306 0.748103
+v 0.650045 1.680306 1.065901
+v 1.143843 1.689665 0.787413
+v 0.675507 1.689665 1.213296
+v 1.311700 1.699877 0.771950
+v 0.644211 1.699876 1.378933
+v 1.346024 1.859916 0.715994
+v 0.585255 1.859916 1.407802
+v 1.200208 1.936552 0.696964
+v 0.580124 1.936552 1.260838
+v 1.064277 1.981164 0.633672
+v 0.529995 1.981164 1.119523
+v 1.249393 2.101073 0.383699
+v 0.263608 2.101073 1.280125
+v 1.350597 2.035456 0.494642
+v 0.364465 2.035455 1.391384
+v 1.437718 1.921785 0.588093
+v 0.449242 1.921785 1.486966
+v 1.539091 1.854744 0.460530
+v 0.312649 1.854744 1.575799
+v 1.507180 1.928740 0.297126
+v 0.153003 1.928740 1.528550
+v 1.442972 1.971683 0.142823
+v 0.005477 1.971683 1.450013
+v 1.536074 1.667319 0.059548
+v -0.086243 1.667319 1.534807
+v 1.582090 1.679180 0.226901
+v 0.075998 1.679179 1.596471
+v 1.585635 1.693070 0.417696
+v 0.265598 1.693070 1.618075
+v 1.591538 1.698184 0.488689
+v 0.335712 1.698184 1.630677
+v 1.555366 1.831457 0.522179
+v 0.372478 1.831457 1.597841
+v 1.475218 1.888964 0.629304
+v 0.486715 1.888964 1.528202
+v 1.400874 1.836088 0.734210
+v 0.598192 1.836088 1.464130
+v 1.371363 1.704175 0.781462
+v 0.648027 1.704175 1.439229
+v 1.416026 1.578656 0.750873
+v 0.613345 1.578656 1.480793
+v 1.500561 1.704465 0.657092
+v 0.511977 1.704464 1.556063
+v 1.496745 1.523239 0.652977
+v 0.508242 1.523239 1.551874
+v 1.570519 1.574025 0.538842
+v 0.387631 1.574025 1.614504
+v 0.884647 2.056404 0.972832
+v 0.978271 1.910794 1.075789
+v 1.007056 -0.010544 1.107443
+v 1.023780 0.665525 1.125833
+v 1.023886 0.911022 1.125950
+v 0.991120 -0.217316 1.089918
+v 0.731860 2.063051 0.804815
+v 0.608941 2.262743 0.669642
+v -0.702664 2.617960 -0.772708
+v -1.013210 1.943970 -1.114210
+v -0.970250 1.169563 -1.066968
+v -0.339555 0.413568 -0.373404
+v 1.080089 0.879063 0.535973
+v 0.431237 0.879063 1.126008
+v 1.162680 0.361279 0.480163
+v 0.367854 0.361279 1.202940
+v 1.224984 -0.044071 0.455140
+v 0.337042 -0.044072 1.262593
+v 1.233364 -0.380861 0.426531
+v 0.307767 -0.380861 1.268224
+v 1.187077 -0.550258 0.474563
+v 0.359969 -0.550258 1.226697
+v 1.037141 -0.603638 0.668392
+v 0.567130 -0.603638 1.095798
+v 0.822848 -0.627828 0.904871
+v 1.301277 0.986458 0.231784
+v 0.107462 0.986458 1.317383
+v 1.536013 1.183073 -0.063415
+v -0.208648 1.183072 1.523096
+v 1.691008 1.511699 -0.338022
+v -0.496704 1.511699 1.651379
+v 1.809938 1.935251 -0.277375
+v -0.447597 1.935251 1.775520
+v 1.699542 2.114131 -0.067254
+v -0.227962 2.114130 1.685526
+v 1.482161 2.332810 0.255507
+v 0.113942 2.332810 1.499701
+v 1.296200 2.551259 0.513268
+v 0.388161 2.551259 1.338996
+v 1.123635 2.491603 0.732056
+v 0.622313 2.491603 1.187935
+v 0.999250 2.181512 0.870335
+v 0.771754 2.181512 1.077210
+v 1.181442 2.004993 0.825873
+v 0.710232 2.004993 1.254370
+v 1.118734 1.826579 0.888449
+v 0.778467 1.826579 1.197872
+v 1.243571 1.359620 0.762021
+v 0.640781 1.359620 1.310170
+v 1.413467 1.283638 0.507156
+v 0.370966 1.283638 1.455156
+v 1.554596 1.368817 0.284158
+v 0.135601 1.368817 1.574524
+v 1.667730 1.575157 0.099474
+v -0.058970 1.575156 1.669653
+v 1.694565 1.785974 0.068322
+v -0.092524 1.785974 1.693416
+v 1.647587 1.933794 0.157522
+v 0.000725 1.933794 1.655100
+v 1.496208 2.068395 0.405105
+v 0.261536 2.068394 1.527857
+v 1.272432 2.132214 0.705662
+v 0.581941 2.132214 1.333562
+v 1.010509 -0.174395 1.111239
+v 1.157375 -0.174807 0.954419
+v 0.840480 -0.174807 1.242588
+v 1.151300 -0.350989 0.924204
+v 0.810977 -0.350989 1.233679
+v 1.069282 -0.440411 0.973784
+v 0.868104 -0.440411 1.156726
+v 0.964561 -0.463026 1.060711
+v 0.985469 0.904933 1.083704
+v 0.968272 0.991639 1.064793
+v 1.109568 0.953310 0.948632
+v 0.839248 0.953310 1.194449
+v 1.147907 0.806256 0.918546
+v 0.805665 0.806256 1.229764
+v 1.105752 0.656782 0.959886
+v 0.850813 0.656782 1.191716
+v 1.401087 1.141674 0.436000
+v 0.301304 1.141673 1.436091
+v 1.606451 1.311528 0.112870
+v -0.039829 1.311528 1.609918
+v 1.731937 1.580541 -0.089250
+v -0.252928 1.580541 1.715692
+v 1.802342 1.882002 -0.068724
+v -0.239164 1.882001 1.787725
+v 1.759268 2.034402 0.098814
+v -0.068300 2.034402 1.760717
+v 1.555273 2.243515 0.417633
+v 0.268411 2.243514 1.587844
+v 1.399993 2.399956 0.639232
+v 0.503725 2.399956 1.454256
+v 1.265033 2.351730 0.810953
+v 0.687459 2.351729 1.336171
+v 1.136191 2.091978 0.950311
+v 0.838396 2.091978 1.221111
+v 1.180835 1.062361 0.862932
+v 0.747182 1.062361 1.257276
+v 1.218603 0.353955 0.759067
+v 0.640205 0.353955 1.285033
+v 1.267841 -0.057563 0.720826
+v 0.597472 -0.057563 1.330428
+v 1.268471 -0.308299 0.693952
+v 0.570659 -0.308300 1.328509
+v 1.212580 -0.476107 0.708830
+v 0.590765 -0.476107 1.274279
+v 1.099028 -0.534266 0.815843
+v 0.708054 -0.534266 1.171375
+v 0.910663 -0.555989 1.001440
+v 0.943180 1.300730 1.037200
+v 0.950303 1.628774 1.045033
+v 1.369922 2.150492 0.573698
+v 0.441335 2.150492 1.418112
+v 1.145915 1.481920 0.847275
+v 0.734903 1.481920 1.221030
+v 1.115217 1.641806 0.882467
+v 0.772845 1.641806 1.193804
+v 1.157501 -0.015738 0.952884
+v 0.838939 -0.015738 1.242568
+v 1.119044 0.367634 0.972940
+v 0.862548 0.367634 1.206184
+v 0.998981 0.362086 1.098563
+v 0.987565 0.602611 1.086009
+v 1.137300 0.724992 1.018816
+v 0.906488 0.724992 1.228704
+v 1.192659 0.823835 0.980435
+v 0.863035 0.823835 1.280179
+v 1.148682 0.955153 0.985944
+v 0.872686 0.955153 1.236922
+v 1.062688 0.975967 1.060763
+v 0.955315 0.975967 1.158402
+v 1.062707 0.863441 1.168641
+v 1.107904 0.946747 1.091309
+v 0.981441 0.946747 1.206309
+v 1.169164 0.932992 1.036933
+v 0.921505 0.932992 1.262142
+v 1.188745 0.834247 1.053575
+v 0.936218 0.834247 1.283211
+v 1.147209 0.762518 1.064424
+v 0.950953 0.762518 1.242890
+v 1.051170 0.731220 1.155954
+v 1.087167 0.602707 0.504372
+v 0.399108 0.602707 1.130060
+v 1.152946 0.790166 0.800188
+v 0.687361 0.790166 1.223568
+v 1.166985 0.621767 0.778931
+v 0.664870 0.621767 1.235530
+v 1.061312 0.743784 0.535731
+v 0.432775 0.743784 1.107293
+v 0.960657 -0.422809 1.056419
+v 1.033371 -0.401393 0.996301
+v 0.893921 -0.401393 1.123110
+v 1.105542 -0.317474 0.962951
+v 0.853884 -0.317474 1.191797
+v 1.106624 -0.201489 0.985600
+v 0.876329 -0.201489 1.195020
+v 0.930534 -0.260704 1.023293
+v 1.035395 -0.242586 0.930010
+v 0.827737 -0.242586 1.118844
+v 1.041032 -0.311107 0.908482
+v 0.805772 -0.311107 1.122417
+v 0.986559 -0.361714 0.940082
+v 0.842390 -0.361714 1.071183
+v 0.913247 -0.382032 1.004283
+v 1.198416 1.655756 0.833149
+v 0.715867 1.655756 1.271957
+v 1.223934 1.534917 0.811856
+v 0.692252 1.534917 1.295342
+v 1.390455 2.043658 0.574672
+v 0.440359 2.043658 1.438644
+v 1.311339 2.029925 0.677864
+v 0.550582 2.029925 1.369661
+v 1.511618 1.990023 0.452471
+v 0.307229 1.990023 1.547685
+v 1.614724 1.887367 0.235843
+v 0.081807 1.887367 1.629805
+v 1.650974 1.760813 0.173539
+v 0.016349 1.760813 1.659989
+v 1.636168 1.592645 0.203798
+v 0.047875 1.592644 1.648116
+v 1.555524 1.430897 0.368259
+v 0.219236 1.430897 1.583416
+v 1.443544 1.368865 0.548299
+v 0.409075 1.368865 1.488996
+v 1.299790 1.440982 0.749171
+v 0.622662 1.440982 1.364918
+v 1.201537 1.801527 0.820673
+v 0.703152 1.801526 1.273881
+v 1.241358 1.942831 0.768528
+v 0.647468 1.942831 1.308583
+v 1.254534 1.911219 0.726075
+v 0.603958 1.911219 1.317679
+v 1.212705 1.793844 0.773491
+v 0.655124 1.793844 1.280529
+v 1.304707 1.469300 0.711148
+v 0.584345 1.469300 1.366212
+v 1.431898 1.411445 0.539336
+v 0.401256 1.411445 1.476554
+v 1.528865 1.464708 0.379283
+v 0.232736 1.464707 1.557921
+v 1.593959 1.608745 0.238406
+v 0.086326 1.608744 1.609376
+v 1.604108 1.748941 0.207146
+v 0.054245 1.748941 1.616518
+v 1.571505 1.862729 0.265004
+v 0.114931 1.862729 1.589543
+v 1.490815 1.960163 0.449563
+v 0.306305 1.960163 1.526700
+v 1.319638 1.985078 0.659029
+v 0.531045 1.985078 1.376137
+v 1.389737 1.999994 0.567665
+v 0.433452 1.999993 1.437266
+v 1.230905 1.557108 0.770216
+v 0.650139 1.557108 1.298337
+v 1.206948 1.665424 0.783007
+v 0.665142 1.665424 1.275699
+v 0.905195 2.160242 0.631140
+v 0.542545 2.160242 0.960917
+v 1.021863 2.422813 0.556044
+v 0.456734 2.422813 1.069946
+v 1.175368 2.467711 0.357759
+v 0.244798 2.467711 1.203975
+v 1.273369 2.246875 0.145016
+v 0.023728 2.246875 1.281380
+v 1.494610 2.068221 -0.220211
+v -0.360817 2.068221 1.467026
+v 1.611447 1.906675 -0.407303
+v -0.558136 1.906675 1.565613
+v 1.513929 1.511406 -0.490959
+v -0.632176 1.511405 1.460608
+v 1.353052 1.174716 -0.252732
+v -0.379781 1.174715 1.323023
+v 1.141863 0.959670 0.109124
+v 0.000456 0.959670 1.147065
+v 0.230544 2.745087 0.253526
+v -0.217983 2.860323 -0.239712
+v -0.751438 0.698307 -0.826344
+v 0.204333 0.323680 0.224702
+v 0.683270 -0.590867 0.751380
+v 0.548793 -0.305803 0.603498
+v 0.480488 0.066628 0.528384
+v 0.391822 0.258160 0.430880
+v 1.255002 1.550009 -0.888187
+v -1.003088 1.550008 1.165212
+v 1.057206 1.653400 -1.160972
+v -1.255907 1.653399 0.942463
+v 0.510876 1.589572 -1.572621
+v -1.613947 1.589572 0.359592
+v -0.319041 1.832516 -1.472797
+v -1.435948 1.832516 -0.457135
+v 1.057196 1.072262 -0.761879
+v -0.858609 1.072262 0.980262
+v 0.676626 0.896405 -1.027135
+v -1.086617 0.896404 0.576274
+v 0.413484 1.064152 -1.385578
+v -1.418518 1.064151 0.280358
+v -0.381602 1.153586 -1.326173
+v -1.284056 1.153586 -0.505524
+v 0.893291 0.448559 0.317635
+v 0.231579 0.448559 0.919365
+v 0.628560 0.346935 0.237874
+v 0.177256 0.346935 0.648269
+v 0.985057 -0.214397 0.308618
+v 0.213908 -0.214397 1.009864
+v 0.930297 0.154679 0.324968
+v 0.235372 0.154679 0.956900
+v 1.045723 -0.495595 0.338245
+v 0.237655 -0.495596 1.073064
+v 0.761846 -0.249747 0.436806
+v 0.362666 -0.249747 0.799801
+v 0.692574 0.120917 0.386553
+v 0.319201 0.120917 0.726080
+v 0.889282 -0.550767 0.527306
+v 0.440686 -0.550767 0.935237
+v 0.866849 0.633415 0.265023
+v 0.181708 0.633415 0.888058
+v 0.971819 0.785468 0.376266
+v 0.282507 0.785467 1.003094
+v 1.002157 0.871088 0.401905
+v 0.305155 0.871088 1.035725
+v 0.537224 0.462841 -0.013933
+v -0.064765 0.462841 0.533488
+v 0.096352 0.528093 -0.649756
+v -0.655961 0.528093 0.034363
+v -0.229716 0.791713 -1.115710
+v -1.088929 0.791713 -0.334382
+v -0.025686 2.533815 -1.187650
+v -1.179875 2.533815 -0.138085
+v 0.363411 2.760881 -0.761910
+v -0.792912 2.760881 0.289595
+v 0.745792 2.653251 -0.343772
+v -0.412881 2.653250 0.709870
+v 1.053638 2.248427 -0.022378
+v -0.122096 2.248426 1.046779
+v 1.355605 1.928091 -0.602985
+v -0.728700 1.928090 1.292382
+v 1.209707 2.088272 -0.435627
+v -0.548272 2.088271 1.162996
+v 0.915656 2.395282 -0.769655
+v -0.852941 2.395281 0.838623
+v 1.132045 2.123478 -0.930592
+v -1.033654 2.123477 1.038792
+v 0.846456 2.175955 -1.253081
+v -1.327637 2.175955 0.723935
+v 0.592378 2.463061 -1.127310
+v -1.178360 2.463060 0.482915
+v 0.289811 2.256173 -1.447439
+v -1.468385 2.256172 0.151381
+v 0.574317 2.044939 -1.512020
+v -1.559628 2.044938 0.428489
+v 0.102084 1.661294 -1.567933
+v -1.570552 1.661294 -0.046917
+v 0.017868 1.062824 -1.321718
+v -1.317466 1.062823 -0.107429
+v 0.851869 1.741247 -1.384874
+v -1.459349 1.741246 0.716838
+v 0.794671 0.787800 -0.263381
+v -0.337481 0.787799 0.766145
+v 0.372789 0.759805 -0.823582
+v -0.855194 0.759805 0.293088
+v 0.887300 1.805215 -1.560567
+v -1.637609 1.805214 0.735465
+v 0.891097 0.867476 -1.269492
+v -1.348203 0.867476 0.766821
+v 1.032408 0.929593 -1.777943
+v -1.867754 0.929592 0.859326
+v 1.199819 1.188194 -2.192019
+v -2.295827 1.188193 0.986756
+v 1.256881 1.604292 -2.309551
+v -2.418238 1.604291 1.032427
+v 1.119334 1.898593 -2.190074
+v -2.286267 1.898592 0.906818
+v 0.971133 1.901480 -1.843758
+v -1.927468 1.901479 0.792092
+v 1.005618 1.824832 -1.792481
+v -1.879689 1.824831 0.831280
+v 1.109664 1.817010 -2.096161
+v -2.191860 1.817009 0.906088
+v 1.199953 1.565677 -2.203251
+v -2.307022 1.565676 0.985826
+v 1.159299 1.216397 -2.096514
+v -2.196913 1.216396 0.955467
+v 1.054898 1.008124 -1.740850
+v -1.832959 1.008124 0.885229
+v 0.965013 0.965728 -1.313626
+v -1.399141 0.965728 0.836223
+v 0.949716 1.740221 -1.560909
+v -1.643862 1.740220 0.797568
+v 0.919668 1.640003 -1.657580
+v -1.737251 1.640002 0.758497
+v 0.944636 1.027873 -1.465680
+v -1.548580 1.027872 0.801533
+v 1.002205 1.064740 -1.819136
+v -1.905900 1.064740 0.825357
+v 1.088955 1.230499 -2.114828
+v -2.208481 1.230498 0.883704
+v 1.124225 1.502054 -2.206796
+v -2.303376 1.502054 0.910102
+v 1.049719 1.696317 -2.119388
+v -2.209303 1.696317 0.844212
+v 0.957388 1.704767 -1.862547
+v -1.944871 1.704766 0.776629
+v 0.883818 1.617079 -1.427106
+v -1.504418 1.617079 0.744643
+v 0.802852 1.395699 -1.455047
+v -1.524563 1.395699 0.661393
+v 0.735013 1.248339 -1.374532
+v -1.437983 1.248339 0.601487
+v 0.777492 1.204265 -1.438980
+v -1.506165 1.204265 0.637670
+v 0.810284 1.112657 -1.425561
+v -1.495913 1.112656 0.671585
+v 0.815743 1.043388 -1.397158
+v -1.468155 1.043387 0.679711
+v 0.934364 1.169691 -1.057214
+v -1.140979 1.169691 0.830003
+v 0.813120 1.035102 -1.169837
+v -1.241608 1.035102 0.698636
+v 0.796321 1.175481 -1.228149
+v -1.298067 1.175480 0.676388
+v 0.859151 1.461221 -1.325128
+v -1.400562 1.461220 0.729748
+v 0.870465 1.529796 -1.536327
+v -1.611883 1.529796 0.721002
+v 0.833001 1.482436 -1.625002
+v -1.696610 1.482436 0.675306
+v 0.785163 1.045334 -1.485415
+v -1.553119 1.045333 0.640907
+v 0.793887 1.109109 -1.528569
+v -1.596905 1.109108 0.645503
+v 0.757396 1.205590 -1.509305
+v -1.574270 1.205590 0.611002
+v 0.702964 1.255423 -1.454944
+v -1.514998 1.255422 0.561965
+v 0.769856 1.364408 -1.538364
+v -1.604379 1.364408 0.620653
+v 0.926996 1.644125 -1.941652
+v -2.020740 1.644124 0.738880
+v 1.011446 1.637343 -2.152561
+v -2.238701 1.637342 0.802969
+v 1.083534 1.471622 -2.230516
+v -2.323135 1.471621 0.867347
+v 1.048134 1.243852 -2.138737
+v -2.228415 1.243851 0.840801
+v 0.951427 1.098139 -1.877573
+v -1.959264 1.098138 0.769271
+v 0.892197 1.057657 -1.561390
+v -1.638892 1.057657 0.740262
+v 0.882213 1.582588 -1.748385
+v -1.824100 1.582587 0.712608
+v 0.818061 1.272776 -1.608669
+v -1.678935 1.272776 0.661980
+v 0.867717 1.172179 -1.643435
+v -1.718249 1.172179 0.708120
+v 0.919564 1.267513 -1.802554
+v -1.881564 1.267512 0.744659
+v 0.876376 1.378890 -1.727318
+v -1.802575 1.378889 0.708793
+v 0.925619 1.485198 -1.843698
+v -1.923097 1.485197 0.746789
+v 0.978380 1.378467 -1.933059
+v -2.017054 1.378466 0.790847
+v 1.027766 1.461404 -2.023433
+v -2.111700 1.461404 0.831448
+v 0.981870 1.562784 -1.981166
+v -2.065275 1.562783 0.789764
+v 0.833511 1.722392 -1.996331
+v -2.066317 1.722392 0.640635
+v 1.041956 1.758106 -2.334999
+v -2.423209 1.758106 0.816058
+v 1.197357 1.568206 -2.417396
+v -2.519958 1.568205 0.962954
+v 1.119228 1.261748 -2.334125
+v -2.429660 1.261747 0.893065
+v 0.884160 1.041271 -1.954334
+v -2.029307 1.041270 0.695035
+v 0.708126 0.986850 -1.510021
+v -1.570315 0.986849 0.561885
+v 0.702928 1.636983 -1.667190
+v -1.726285 1.636982 0.541821
+usemtl Material
+s 1
+f 47 1 3 45
+f 4 2 48 46
+f 45 3 5 43
+f 6 4 46 44
+f 3 9 7 5
+f 8 10 4 6
+f 1 11 9 3
+f 10 12 2 4
+f 11 13 15 9
+f 16 14 12 10
+f 9 15 17 7
+f 18 16 10 8
+f 15 21 19 17
+f 20 22 16 18
+f 13 23 21 15
+f 22 24 14 16
+f 23 25 27 21
+f 28 26 24 22
+f 21 27 29 19
+f 30 28 22 20
+f 27 33 31 29
+f 32 34 28 30
+f 25 35 33 27
+f 34 36 26 28
+f 35 37 39 33
+f 40 38 36 34
+f 33 39 41 31
+f 42 40 34 32
+f 39 45 43 41
+f 44 46 40 42
+f 37 47 45 39
+f 46 48 38 40
+f 47 37 51 49
+f 52 38 48 50
+f 37 35 53 51
+f 54 36 38 52
+f 35 25 55 53
+f 56 26 36 54
+f 25 23 57 55
+f 58 24 26 56
+f 23 13 59 57
+f 60 14 24 58
+f 13 11 63 59
+f 64 12 14 60
+f 11 1 65 63
+f 66 2 12 64
+f 1 47 49 65
+f 50 48 2 66
+f 61 65 49
+f 50 66 62
+f 63 65 61
+f 62 66 64
+f 61 59 63
+f 64 60 62
+f 61 57 59
+f 60 58 62
+f 61 55 57
+f 58 56 62
+f 61 53 55
+f 56 54 62
+f 61 51 53
+f 54 52 62
+f 61 49 51
+f 52 50 62
+f 89 174 176 91
+f 176 175 90 91
+f 87 172 174 89
+f 175 173 88 90
+f 85 170 172 87
+f 173 171 86 88
+f 83 168 170 85
+f 171 169 84 86
+f 81 166 168 83
+f 169 167 82 84
+f 79 92 146 164
+f 147 93 80 165
+f 92 94 148 146
+f 149 95 93 147
+f 94 96 150 148
+f 151 97 95 149
+f 96 98 152 150
+f 153 99 97 151
+f 98 100 154 152
+f 155 101 99 153
+f 100 102 156 154
+f 157 103 101 155
+f 102 104 158 156
+f 159 105 103 157
+f 104 106 160 158
+f 161 107 105 159
+f 106 108 162 160
+f 163 109 107 161
+f 108 67 68 162
+f 68 67 109 163
+f 110 128 160 162
+f 161 129 111 163
+f 128 179 158 160
+f 159 180 129 161
+f 126 156 158 179
+f 159 157 127 180
+f 124 154 156 126
+f 157 155 125 127
+f 122 152 154 124
+f 155 153 123 125
+f 120 150 152 122
+f 153 151 121 123
+f 118 148 150 120
+f 151 149 119 121
+f 116 146 148 118
+f 149 147 117 119
+f 114 164 146 116
+f 147 165 115 117
+f 114 181 177 164
+f 177 182 115 165
+f 110 162 68 112
+f 68 163 111 113
+f 112 68 178 183
+f 178 68 113 184
+f 177 181 183 178
+f 184 182 177 178
+f 135 137 176 174
+f 176 137 136 175
+f 133 135 174 172
+f 175 136 134 173
+f 131 133 172 170
+f 173 134 132 171
+f 166 187 185 168
+f 186 188 167 169
+f 131 170 168 185
+f 169 171 132 186
+f 144 190 189 187
+f 189 190 145 188
+f 185 187 189 69
+f 189 188 186 69
+f 130 131 185 69
+f 186 132 130 69
+f 142 193 191 144
+f 192 194 143 145
+f 140 195 193 142
+f 194 196 141 143
+f 139 197 195 140
+f 196 198 139 141
+f 138 71 197 139
+f 198 71 138 139
+f 190 144 191 70
+f 192 145 190 70
+f 70 191 206 208
+f 207 192 70 208
+f 71 199 200 197
+f 201 199 71 198
+f 197 200 202 195
+f 203 201 198 196
+f 195 202 204 193
+f 205 203 196 194
+f 193 204 206 191
+f 207 205 194 192
+f 199 204 202 200
+f 203 205 199 201
+f 199 208 206 204
+f 207 208 199 205
+f 139 140 164 177
+f 165 141 139 177
+f 140 142 211 164
+f 212 143 141 165
+f 142 144 213 211
+f 214 145 143 212
+f 144 187 166 213
+f 167 188 145 214
+f 81 209 213 166
+f 214 210 82 167
+f 209 215 211 213
+f 212 216 210 214
+f 79 164 211 215
+f 212 165 80 216
+f 131 130 72 222
+f 72 130 132 223
+f 133 131 222 220
+f 223 132 134 221
+f 135 133 220 218
+f 221 134 136 219
+f 137 135 218 217
+f 219 136 137 217
+f 217 218 229 231
+f 230 219 217 231
+f 218 220 227 229
+f 228 221 219 230
+f 220 222 225 227
+f 226 223 221 228
+f 222 72 224 225
+f 224 72 223 226
+f 224 231 229 225
+f 230 231 224 226
+f 225 229 227
+f 228 230 226
+f 183 181 234 232
+f 235 182 184 233
+f 112 183 232 254
+f 233 184 113 255
+f 110 112 254 256
+f 255 113 111 257
+f 181 114 252 234
+f 253 115 182 235
+f 114 116 250 252
+f 251 117 115 253
+f 116 118 248 250
+f 249 119 117 251
+f 118 120 246 248
+f 247 121 119 249
+f 120 122 244 246
+f 245 123 121 247
+f 122 124 242 244
+f 243 125 123 245
+f 124 126 240 242
+f 241 127 125 243
+f 126 179 236 240
+f 237 180 127 241
+f 179 128 238 236
+f 239 129 180 237
+f 128 110 256 238
+f 257 111 129 239
+f 238 256 258 276
+f 259 257 239 277
+f 236 238 276 278
+f 277 239 237 279
+f 240 236 278 274
+f 279 237 241 275
+f 242 240 274 272
+f 275 241 243 273
+f 244 242 272 270
+f 273 243 245 271
+f 246 244 270 268
+f 271 245 247 269
+f 248 246 268 266
+f 269 247 249 267
+f 250 248 266 264
+f 267 249 251 265
+f 252 250 264 262
+f 265 251 253 263
+f 234 252 262 280
+f 263 253 235 281
+f 256 254 260 258
+f 261 255 257 259
+f 254 232 282 260
+f 283 233 255 261
+f 232 234 280 282
+f 281 235 233 283
+f 67 108 284 73
+f 285 109 67 73
+f 108 106 286 284
+f 287 107 109 285
+f 106 104 288 286
+f 289 105 107 287
+f 104 102 290 288
+f 291 103 105 289
+f 102 100 292 290
+f 293 101 103 291
+f 100 98 294 292
+f 295 99 101 293
+f 98 96 296 294
+f 297 97 99 295
+f 96 94 298 296
+f 299 95 97 297
+f 94 92 300 298
+f 301 93 95 299
+f 308 309 328 338
+f 329 309 308 339
+f 307 308 338 336
+f 339 308 307 337
+f 306 307 336 340
+f 337 307 306 341
+f 89 91 306 340
+f 306 91 90 341
+f 87 89 340 334
+f 341 90 88 335
+f 85 87 334 330
+f 335 88 86 331
+f 83 85 330 332
+f 331 86 84 333
+f 330 336 338 332
+f 339 337 331 333
+f 330 334 340 336
+f 341 335 331 337
+f 326 332 338 328
+f 339 333 327 329
+f 81 83 332 326
+f 333 84 82 327
+f 209 342 344 215
+f 345 343 210 216
+f 81 326 342 209
+f 343 327 82 210
+f 79 215 344 346
+f 345 216 80 347
+f 79 346 300 92
+f 301 347 80 93
+f 77 324 352 304
+f 353 325 77 304
+f 304 352 350 78
+f 351 353 304 78
+f 78 350 348 305
+f 349 351 78 305
+f 305 348 328 309
+f 329 349 305 309
+f 326 328 348 342
+f 349 329 327 343
+f 296 298 318 310
+f 319 299 297 311
+f 76 316 324 77
+f 325 317 76 77
+f 302 358 356 303
+f 357 359 302 303
+f 303 356 354 75
+f 355 357 303 75
+f 75 354 316 76
+f 317 355 75 76
+f 292 294 362 364
+f 363 295 293 365
+f 364 362 368 366
+f 369 363 365 367
+f 366 368 370 372
+f 371 369 367 373
+f 372 370 376 374
+f 377 371 373 375
+f 314 378 374 376
+f 375 379 315 377
+f 316 354 374 378
+f 375 355 317 379
+f 354 356 372 374
+f 373 357 355 375
+f 356 358 366 372
+f 367 359 357 373
+f 358 360 364 366
+f 365 361 359 367
+f 290 292 364 360
+f 365 293 291 361
+f 74 360 358 302
+f 359 361 74 302
+f 284 286 288 290
+f 289 287 285 291
+f 284 290 360 74
+f 361 291 285 74
+f 73 284 74
+f 74 285 73
+f 294 296 310 362
+f 311 297 295 363
+f 310 312 368 362
+f 369 313 311 363
+f 312 382 370 368
+f 371 383 313 369
+f 314 376 370 382
+f 371 377 315 383
+f 348 350 386 384
+f 387 351 349 385
+f 318 384 386 320
+f 387 385 319 321
+f 298 300 384 318
+f 385 301 299 319
+f 300 344 342 384
+f 343 345 301 385
+f 342 348 384
+f 385 349 343
+f 300 346 344
+f 345 347 301
+f 314 322 380 378
+f 381 323 315 379
+f 316 378 380 324
+f 381 379 317 325
+f 320 386 380 322
+f 381 387 321 323
+f 350 352 380 386
+f 381 353 351 387
+f 324 380 352
+f 353 381 325
+f 400 388 414 402
+f 415 389 401 403
+f 400 402 404 398
+f 405 403 401 399
+f 398 404 406 396
+f 407 405 399 397
+f 396 406 408 394
+f 409 407 397 395
+f 394 408 410 392
+f 411 409 395 393
+f 392 410 412 390
+f 413 411 393 391
+f 410 420 418 412
+f 419 421 411 413
+f 408 422 420 410
+f 421 423 409 411
+f 406 424 422 408
+f 423 425 407 409
+f 404 426 424 406
+f 425 427 405 407
+f 402 428 426 404
+f 427 429 403 405
+f 402 414 416 428
+f 417 415 403 429
+f 318 320 444 442
+f 445 321 319 443
+f 320 390 412 444
+f 413 391 321 445
+f 310 318 442 312
+f 443 319 311 313
+f 382 430 414 388
+f 415 431 383 389
+f 412 418 440 444
+f 441 419 413 445
+f 438 446 444 440
+f 445 447 439 441
+f 434 446 438 436
+f 439 447 435 437
+f 432 448 446 434
+f 447 449 433 435
+f 430 448 432 450
+f 433 449 431 451
+f 414 430 450 416
+f 451 431 415 417
+f 312 448 430 382
+f 431 449 313 383
+f 312 442 446 448
+f 447 443 313 449
+f 442 444 446
+f 447 445 443
+f 416 450 452 476
+f 453 451 417 477
+f 450 432 462 452
+f 463 433 451 453
+f 432 434 460 462
+f 461 435 433 463
+f 434 436 458 460
+f 459 437 435 461
+f 436 438 456 458
+f 457 439 437 459
+f 438 440 454 456
+f 455 441 439 457
+f 440 418 474 454
+f 475 419 441 455
+f 428 416 476 464
+f 477 417 429 465
+f 426 428 464 466
+f 465 429 427 467
+f 424 426 466 468
+f 467 427 425 469
+f 422 424 468 470
+f 469 425 423 471
+f 420 422 470 472
+f 471 423 421 473
+f 418 420 472 474
+f 473 421 419 475
+f 458 456 480 478
+f 481 457 459 479
+f 478 480 482 484
+f 483 481 479 485
+f 484 482 488 486
+f 489 483 485 487
+f 486 488 490 492
+f 491 489 487 493
+f 464 476 486 492
+f 487 477 465 493
+f 452 484 486 476
+f 487 485 453 477
+f 452 462 478 484
+f 479 463 453 485
+f 458 478 462 460
+f 463 479 459 461
+f 454 474 480 456
+f 481 475 455 457
+f 472 482 480 474
+f 481 483 473 475
+f 470 488 482 472
+f 483 489 471 473
+f 468 490 488 470
+f 489 491 469 471
+f 466 492 490 468
+f 491 493 467 469
+f 464 492 466
+f 467 493 465
+f 392 390 504 502
+f 505 391 393 503
+f 394 392 502 500
+f 503 393 395 501
+f 396 394 500 498
+f 501 395 397 499
+f 398 396 498 496
+f 499 397 399 497
+f 400 398 496 494
+f 497 399 401 495
+f 388 400 494 506
+f 495 401 389 507
+f 494 502 504 506
+f 505 503 495 507
+f 494 496 500 502
+f 501 497 495 503
+f 496 498 500
+f 501 499 497
+f 314 382 388 506
+f 389 383 315 507
+f 314 506 504 322
+f 505 507 315 323
+f 320 322 504 390
+f 505 323 321 391
diff --git a/examples/d3d/views/resources.list b/examples/d3d/views/resources.list
index 28d55c35..61d7ce47 100644
--- a/examples/d3d/views/resources.list
+++ b/examples/d3d/views/resources.list
@@ -6,3 +6,4 @@ res/mdpi/crate.png
res/mdpi/blocks.png
res/shaders/textured.vert
res/shaders/textured.frag
+res/models/suzanne.obj
diff --git a/src/dlangui/core/parseutils.d b/src/dlangui/core/parseutils.d
new file mode 100644
index 00000000..b5f6bc7c
--- /dev/null
+++ b/src/dlangui/core/parseutils.d
@@ -0,0 +1,42 @@
+module dlangui.core.parseutils;
+
+long parseLong(inout string v, long defValue = 0) {
+ int len = cast(int)v.length;
+ if (len == 0)
+ return defValue;
+ int sign = 1;
+ long value = 0;
+ int digits = 0;
+ foreach(i; 0 .. len) {
+ char ch = v[i];
+ if (ch == '-') {
+ if (i != 0)
+ return defValue;
+ sign = -1;
+ } else if (ch >= '0' && ch <= '9') {
+ digits++;
+ value = value * 10 + (ch - '0');
+ } else {
+ return defValue;
+ }
+ }
+ return digits > 0 ? (sign > 0 ? value : -value) : defValue;
+}
+
+ulong parseULong(inout string v, ulong defValue = 0) {
+ int len = cast(int)v.length;
+ if (len == 0)
+ return defValue;
+ ulong value = 0;
+ int digits = 0;
+ foreach(i; 0 .. len) {
+ char ch = v[i];
+ if (ch >= '0' && ch <= '9') {
+ digits++;
+ value = value * 10 + (ch - '0');
+ } else {
+ return defValue;
+ }
+ }
+ return digits > 0 ? value : defValue;
+}
diff --git a/src/dlangui/core/settings.d b/src/dlangui/core/settings.d
index 59f4c0be..6f64318f 100644
--- a/src/dlangui/core/settings.d
+++ b/src/dlangui/core/settings.d
@@ -28,6 +28,7 @@ module dlangui.core.settings;
import dlangui.core.logger;
import dlangui.core.types : parseHexDigit;
+public import dlangui.core.parseutils;
import std.range;
//import std.algorithm : clamp, equal;
import std.algorithm : equal;
@@ -1906,44 +1907,4 @@ final class Setting {
}
}
-long parseLong(inout string v, long defValue = 0) {
- int len = cast(int)v.length;
- if (len == 0)
- return defValue;
- int sign = 1;
- long value = 0;
- int digits = 0;
- foreach(i; 0 .. len) {
- char ch = v[i];
- if (ch == '-') {
- if (i != 0)
- return defValue;
- sign = -1;
- } else if (ch >= '0' && ch <= '9') {
- digits++;
- value = value * 10 + (ch - '0');
- } else {
- return defValue;
- }
- }
- return digits > 0 ? (sign > 0 ? value : -value) : defValue;
-}
-
-ulong parseULong(inout string v, ulong defValue = 0) {
- int len = cast(int)v.length;
- if (len == 0)
- return defValue;
- ulong value = 0;
- int digits = 0;
- foreach(i; 0 .. len) {
- char ch = v[i];
- if (ch >= '0' && ch <= '9') {
- digits++;
- value = value * 10 + (ch - '0');
- } else {
- return defValue;
- }
- }
- return digits > 0 ? value : defValue;
-}
diff --git a/src/dlangui/dml/parser.d b/src/dlangui/dml/parser.d
index eb34b6fe..37d6097f 100644
--- a/src/dlangui/dml/parser.d
+++ b/src/dlangui/dml/parser.d
@@ -34,26 +34,7 @@ import std.algorithm : equal, min, max;
import std.utf : toUTF32, toUTF8;
import std.array : join;
public import dlangui.dml.annotations;
-
-class ParserException : Exception {
- protected string _msg;
- protected string _file;
- protected int _line;
- protected int _pos;
-
- @property string file() { return _file; }
- @property string msg() { return _msg; }
- @property int line() { return _line; }
- @property int pos() { return _pos; }
-
- this(string msg, string file, int line, int pos) {
- super(msg ~ " at " ~ file ~ " line " ~ to!string(line) ~ " column " ~ to!string(pos));
- _msg = msg;
- _file = file;
- _line = line;
- _pos = pos;
- }
-}
+public import dlangui.dml.tokenizer;
/// parser exception - unknown (unregistered) widget name
class UnknownWidgetException : ParserException {
@@ -78,447 +59,6 @@ class UnknownPropertyException : UnknownWidgetException {
}
}
-enum TokenType : ushort {
- /// end of file
- eof,
- /// end of line
- eol,
- /// whitespace
- whitespace,
- /// string literal
- str,
- /// integer literal
- integer,
- /// floating point literal
- floating,
- /// comment
- comment,
- /// ident
- ident,
- /// error
- error,
- // operators
- /// : operator
- colon,
- /// . operator
- dot,
- /// ; operator
- semicolon,
- /// , operator
- comma,
- /// - operator
- minus,
- /// + operator
- plus,
- /// [
- curlyOpen,
- /// ]
- curlyClose,
- /// (
- open,
- /// )
- close,
- /// [
- squareOpen,
- /// ]
- squareClose,
-}
-
-struct Token {
- TokenType type;
- ushort line;
- ushort pos;
- bool multiline;
- string text;
- union {
- int intvalue;
- double floatvalue;
- }
- public @property string toString() const {
- if (type == TokenType.integer)
- return "" ~ to!string(line) ~ ":" ~ to!string(pos) ~ " " ~ to!string(type) ~ " " ~ to!string(intvalue);
- else if (type == TokenType.floating)
- return "" ~ to!string(line) ~ ":" ~ to!string(pos) ~ " " ~ to!string(type) ~ " " ~ to!string(floatvalue);
- else
- return "" ~ to!string(line) ~ ":" ~ to!string(pos) ~ " " ~ to!string(type) ~ " \"" ~ text ~ "\"";
- }
- @property bool isMultilineComment() {
- return type == TokenType.comment && multiline;
- }
-}
-
-/// simple tokenizer for DlangUI ML
-class Tokenizer {
- protected LineStream _lines;
-
- dchar[] _lineText;
- ushort _line;
- ushort _pos;
- int _len;
- dchar _prevChar;
- string _filename;
-
- Token _token;
-
- enum : int {
- EOF_CHAR = 0x001A,
- EOL_CHAR = 0x000A
- }
-
- this(string source, string filename = "") {
- _filename = filename;
- _lines = LineStream.create(source, filename);
- _lineText = _lines.readLine();
- _len = cast(int)_lineText.length;
- _line = 0;
- _pos = 0;
- _prevChar = 0;
- }
-
- ~this() {
- destroy(_lines);
- _lines = null;
- }
-
- protected dchar peekChar() {
- if (_pos < _len)
- return _lineText[_pos];
- else if (_lineText is null)
- return EOF_CHAR;
- return EOL_CHAR;
- }
-
- protected dchar peekNextChar() {
- if (_pos < _len - 1)
- return _lineText[_pos + 1];
- else if (_lineText is null)
- return EOF_CHAR;
- return EOL_CHAR;
- }
-
- protected dchar nextChar() {
- if (_pos < _len)
- _prevChar = _lineText[_pos++];
- else if (_lineText is null)
- _prevChar = EOF_CHAR;
- else {
- _lineText = _lines.readLine();
- _len = cast(int)_lineText.length;
- _line++;
- _pos = 0;
- _prevChar = EOL_CHAR;
- }
- return _prevChar;
- }
-
- protected dchar skipChar() {
- nextChar();
- return peekChar();
- }
-
- protected void setTokenStart() {
- _token.pos = _pos;
- _token.line = _line;
- _token.text = null;
- _token.intvalue = 0;
- }
-
- protected ref const(Token) parseEof() {
- _token.type = TokenType.eof;
- return _token;
- }
-
- protected ref const(Token) parseEol() {
- _token.type = TokenType.eol;
- nextChar();
- return _token;
- }
-
- protected ref const(Token) parseWhiteSpace() {
- _token.type = TokenType.whitespace;
- for(;;) {
- dchar ch = skipChar();
- if (ch != ' ' && ch != '\t')
- break;
- }
- return _token;
- }
-
- static bool isAlpha(dchar ch) {
- return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
- }
-
- static bool isNum(dchar ch) {
- return (ch >= '0' && ch <= '9');
- }
-
- static bool isAlphaNum(dchar ch) {
- return isNum(ch) || isAlpha(ch);
- }
-
- private char[] _stringbuf;
- protected ref const(Token) parseString() {
- _token.type = TokenType.str;
- //skipChar(); // skip "
- bool lastBackslash = false;
- _stringbuf.length = 0;
- for(;;) {
- dchar ch = skipChar();
- if (ch == '\"') {
- if (lastBackslash) {
- _stringbuf ~= ch;
- lastBackslash = false;
- } else {
- skipChar();
- break;
- }
- } else if (ch == '\\') {
- if (lastBackslash) {
- _stringbuf ~= ch;
- lastBackslash = false;
- } else {
- lastBackslash = true;
- }
- } else if (ch == EOL_CHAR) {
- skipChar();
- break;
- } else if (lastBackslash) {
- if (ch == 'n')
- ch = '\n';
- else if (ch == 't')
- ch = '\t';
- _stringbuf ~= ch;
- lastBackslash = false;
- } else {
- _stringbuf ~= ch;
- lastBackslash = false;
- }
- }
- _token.text = _stringbuf.dup;
- return _token;
- }
-
- protected ref const(Token) parseIdent() {
- _token.type = TokenType.ident;
- _stringbuf.length = 0;
- _stringbuf ~= peekChar();
- for(;;) {
- dchar ch = skipChar();
- if (!isAlphaNum(ch))
- break;
- _stringbuf ~= ch;
- }
- _token.text = _stringbuf.dup;
- return _token;
- }
-
- protected ref const(Token) parseFloating(int n) {
- _token.type = TokenType.floating;
- dchar ch = peekChar();
- // floating point
- int div = 1;
- int n2 = 0;
- for (;;) {
- ch = skipChar();
- if (!isNum(ch))
- break;
- n2 = n2 * 10 + (ch - '0');
- div *= 10;
- }
- _token.floatvalue = cast(double)n + (div > 0 ? cast(double)n2 / div : 0.0);
- string suffix;
- if (ch == '%') {
- suffix ~= ch;
- ch = skipChar();
- } else {
- while (ch >= 'a' && ch <= 'z') {
- suffix ~= ch;
- ch = skipChar();
- }
- }
- if (isAlphaNum(ch) || ch == '.')
- return parseError();
- _token.text = suffix;
- return _token;
- }
-
- protected ref const(Token) parseHex(int prefixLen) {
- dchar ch = 0;
- foreach(i; 0 .. prefixLen)
- ch = skipChar();
-
- uint n = parseHexDigit(ch);
- if (n == uint.max)
- return parseError();
-
- for(;;) {
- ch = skipChar();
- uint digit = parseHexDigit(ch);
- if (digit == uint.max)
- break;
- n = (n << 4) + digit;
- }
- string suffix;
- if (ch == '%') {
- suffix ~= ch;
- ch = skipChar();
- } else {
- while (ch >= 'a' && ch <= 'z') {
- suffix ~= ch;
- ch = skipChar();
- }
- }
- if (isAlphaNum(ch) || ch == '.')
- return parseError();
- _token.type = TokenType.integer;
- _token.intvalue = n;
- _token.text = suffix;
- return _token;
- }
-
- protected ref const(Token) parseNumber() {
- dchar ch = peekChar();
- uint n = ch - '0';
- for(;;) {
- ch = skipChar();
- if (!isNum(ch))
- break;
- n = n * 10 + (ch - '0');
- }
- if (ch == '.')
- return parseFloating(n);
- string suffix;
- if (ch == '%') {
- suffix ~= ch;
- ch = skipChar();
- } else {
- while (ch >= 'a' && ch <= 'z') {
- suffix ~= ch;
- ch = skipChar();
- }
- }
- if (isAlphaNum(ch) || ch == '.')
- return parseError();
- _token.type = TokenType.integer;
- _token.intvalue = n;
- _token.text = suffix;
- return _token;
- }
-
- protected ref const(Token) parseSingleLineComment() {
- for(;;) {
- dchar ch = skipChar();
- if (ch == EOL_CHAR || ch == EOF_CHAR)
- break;
- }
- _token.type = TokenType.comment;
- _token.multiline = false;
- return _token;
- }
-
- protected ref const(Token) parseMultiLineComment() {
- skipChar();
- for(;;) {
- dchar ch = skipChar();
- if (ch == '*' && peekNextChar() == '/') {
- skipChar();
- skipChar();
- break;
- }
- if (ch == EOF_CHAR)
- break;
- }
- _token.type = TokenType.comment;
- _token.multiline = true;
- return _token;
- }
-
- protected ref const(Token) parseError() {
- _token.type = TokenType.error;
- for(;;) {
- dchar ch = skipChar();
- if (ch == ' ' || ch == '\t' || ch == EOL_CHAR || ch == EOF_CHAR)
- break;
- }
- return _token;
- }
-
- protected ref const(Token) parseOp(TokenType op) {
- _token.type = op;
- skipChar();
- return _token;
- }
-
- /// get next token
- ref const(Token) nextToken() {
- setTokenStart();
- dchar ch = peekChar();
- if (ch == EOF_CHAR)
- return parseEof();
- if (ch == EOL_CHAR)
- return parseEol();
- if (ch == ' ' || ch == '\t')
- return parseWhiteSpace();
- if (ch == '\"')
- return parseString();
- if (isAlpha(ch))
- return parseIdent();
- if (ch == '0' && peekNextChar == 'x')
- return parseHex(2);
- if (ch == '#')
- return parseHex(1);
- if (isNum(ch))
- return parseNumber();
- if (ch == '.' && isNum(peekNextChar()))
- return parseFloating(0);
- if (ch == '/' && peekNextChar() == '/')
- return parseSingleLineComment();
- if (ch == '/' && peekNextChar() == '*')
- return parseMultiLineComment();
- switch (ch) {
- case '.': return parseOp(TokenType.dot);
- case ':': return parseOp(TokenType.colon);
- case ';': return parseOp(TokenType.semicolon);
- case ',': return parseOp(TokenType.comma);
- case '-': return parseOp(TokenType.minus);
- case '+': return parseOp(TokenType.plus);
- case '{': return parseOp(TokenType.curlyOpen);
- case '}': return parseOp(TokenType.curlyClose);
- case '(': return parseOp(TokenType.open);
- case ')': return parseOp(TokenType.close);
- case '[': return parseOp(TokenType.squareOpen);
- case ']': return parseOp(TokenType.squareClose);
- default:
- return parseError();
- }
- }
-
- string getContextSource() {
- string s = toUTF8(_lineText);
- if (_pos == 0)
- return " near `^^^" ~ s[0..min($,30)] ~ "`";
- if (_pos >= _len)
- return " near `" ~ s[max(_len - 30, 0) .. $] ~ "^^^`";
- return " near `" ~ s[max(_pos - 15, 0) .. _pos] ~ "^^^" ~ s[_pos .. min(_pos + 15, $)] ~ "`";
- }
-
- void emitError(string msg) {
- throw new ParserException(msg ~ getContextSource(), _filename, _token.line, _token.pos);
- }
-
- void emitUnknownPropertyError(string objectName, string propName) {
- throw new UnknownPropertyException("Unknown property " ~ objectName ~ "." ~ propName ~ getContextSource(), objectName, propName, _filename, _token.line, _token.pos);
- }
-
- void emitUnknownObjectError(string objectName) {
- throw new UnknownWidgetException("Unknown widget type " ~ objectName ~ getContextSource(), objectName, _filename, _token.line, _token.pos);
- }
-
- void emitError(string msg, ref const Token token) {
- throw new ParserException(msg, _filename, token.line, token.pos);
- }
-}
-
class MLParser {
protected string _code;
protected string _filename;
@@ -590,11 +130,11 @@ class MLParser {
}
protected void unknownObjectError(string objectName) {
- _tokenizer.emitUnknownObjectError(objectName);
+ throw new UnknownWidgetException("Unknown widget type " ~ objectName ~ _tokenizer.getContextSource(), objectName, _tokenizer.filename, _tokenizer.line, _tokenizer.pos);
}
protected void unknownPropertyError(string objectName, string propName) {
- _tokenizer.emitUnknownPropertyError(objectName, propName);
+ throw new UnknownPropertyException("Unknown property " ~ objectName ~ "." ~ propName ~ _tokenizer.getContextSource(), objectName, propName, _tokenizer.filename, _tokenizer.line, _tokenizer.pos);
}
Widget createWidget(string name) {
diff --git a/src/dlangui/dml/tokenizer.d b/src/dlangui/dml/tokenizer.d
new file mode 100644
index 00000000..2b6e04f2
--- /dev/null
+++ b/src/dlangui/dml/tokenizer.d
@@ -0,0 +1,501 @@
+module dlangui.dml.tokenizer;
+
+import dlangui.core.types;
+import dlangui.core.linestream;
+
+import std.conv : to;
+import std.utf : toUTF32, toUTF8;
+import std.algorithm : equal, min, max;
+
+enum TokenType : ushort {
+ /// end of file
+ eof,
+ /// end of line
+ eol,
+ /// whitespace
+ whitespace,
+ /// string literal
+ str,
+ /// integer literal
+ integer,
+ /// floating point literal
+ floating,
+ /// comment
+ comment,
+ /// ident
+ ident,
+ /// error
+ error,
+ // operators
+ /// : operator
+ colon,
+ /// . operator
+ dot,
+ /// ; operator
+ semicolon,
+ /// / operator
+ divide,
+ /// , operator
+ comma,
+ /// - operator
+ minus,
+ /// + operator
+ plus,
+ /// [
+ curlyOpen,
+ /// ]
+ curlyClose,
+ /// (
+ open,
+ /// )
+ close,
+ /// [
+ squareOpen,
+ /// ]
+ squareClose,
+}
+
+struct Token {
+ TokenType type;
+ ushort line;
+ ushort pos;
+ bool multiline;
+ string text;
+ union {
+ int intvalue;
+ double floatvalue;
+ }
+ public @property string toString() const {
+ if (type == TokenType.integer)
+ return "" ~ to!string(line) ~ ":" ~ to!string(pos) ~ " " ~ to!string(type) ~ " " ~ to!string(intvalue);
+ else if (type == TokenType.floating)
+ return "" ~ to!string(line) ~ ":" ~ to!string(pos) ~ " " ~ to!string(type) ~ " " ~ to!string(floatvalue);
+ else
+ return "" ~ to!string(line) ~ ":" ~ to!string(pos) ~ " " ~ to!string(type) ~ " \"" ~ text ~ "\"";
+ }
+ @property bool isMultilineComment() {
+ return type == TokenType.comment && multiline;
+ }
+}
+
+class ParserException : Exception {
+ protected string _msg;
+ protected string _file;
+ protected int _line;
+ protected int _pos;
+
+ @property string file() { return _file; }
+ @property string msg() { return _msg; }
+ @property int line() { return _line; }
+ @property int pos() { return _pos; }
+
+ this(string msg, string file, int line, int pos) {
+ super(msg ~ " at " ~ file ~ " line " ~ to!string(line) ~ " column " ~ to!string(pos));
+ _msg = msg;
+ _file = file;
+ _line = line;
+ _pos = pos;
+ }
+}
+
+/// simple tokenizer for DlangUI ML
+class Tokenizer {
+
+ protected string[] _singleLineCommentPrefixes = ["//"];
+ protected LineStream _lines;
+ protected dchar[] _lineText;
+ protected ushort _line;
+ protected ushort _pos;
+ protected int _len;
+ protected dchar _prevChar;
+ protected string _filename;
+ protected Token _token;
+
+ enum : int {
+ EOF_CHAR = 0x001A,
+ EOL_CHAR = 0x000A
+ }
+
+ this(string source, string filename = "", string[] singleLineCommentPrefixes = ["//"]) {
+ _singleLineCommentPrefixes = singleLineCommentPrefixes;
+ _filename = filename;
+ _lines = LineStream.create(source, filename);
+ _lineText = _lines.readLine();
+ _len = cast(int)_lineText.length;
+ _line = 0;
+ _pos = 0;
+ _prevChar = 0;
+ }
+
+ ~this() {
+ destroy(_lines);
+ _lines = null;
+ }
+
+ protected dchar peekChar() {
+ if (_pos < _len)
+ return _lineText[_pos];
+ else if (_lineText is null)
+ return EOF_CHAR;
+ return EOL_CHAR;
+ }
+
+ protected dchar peekNextChar() {
+ if (_pos < _len - 1)
+ return _lineText[_pos + 1];
+ else if (_lineText is null)
+ return EOF_CHAR;
+ return EOL_CHAR;
+ }
+
+ protected dchar nextChar() {
+ if (_pos < _len)
+ _prevChar = _lineText[_pos++];
+ else if (_lineText is null)
+ _prevChar = EOF_CHAR;
+ else {
+ _lineText = _lines.readLine();
+ _len = cast(int)_lineText.length;
+ _line++;
+ _pos = 0;
+ _prevChar = EOL_CHAR;
+ }
+ return _prevChar;
+ }
+
+ protected dchar skipChar() {
+ nextChar();
+ return peekChar();
+ }
+
+ protected void setTokenStart() {
+ _token.pos = _pos;
+ _token.line = _line;
+ _token.text = null;
+ _token.intvalue = 0;
+ }
+
+ protected ref const(Token) parseEof() {
+ _token.type = TokenType.eof;
+ return _token;
+ }
+
+ protected ref const(Token) parseEol() {
+ _token.type = TokenType.eol;
+ nextChar();
+ return _token;
+ }
+
+ protected ref const(Token) parseWhiteSpace() {
+ _token.type = TokenType.whitespace;
+ for(;;) {
+ dchar ch = skipChar();
+ if (ch != ' ' && ch != '\t')
+ break;
+ }
+ return _token;
+ }
+
+ static bool isAlpha(dchar ch) {
+ return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
+ }
+
+ static bool isNum(dchar ch) {
+ return (ch >= '0' && ch <= '9');
+ }
+
+ static bool isAlphaNum(dchar ch) {
+ return isNum(ch) || isAlpha(ch);
+ }
+
+ private char[] _stringbuf;
+ protected ref const(Token) parseString() {
+ _token.type = TokenType.str;
+ //skipChar(); // skip "
+ bool lastBackslash = false;
+ _stringbuf.length = 0;
+ for(;;) {
+ dchar ch = skipChar();
+ if (ch == '\"') {
+ if (lastBackslash) {
+ _stringbuf ~= ch;
+ lastBackslash = false;
+ } else {
+ skipChar();
+ break;
+ }
+ } else if (ch == '\\') {
+ if (lastBackslash) {
+ _stringbuf ~= ch;
+ lastBackslash = false;
+ } else {
+ lastBackslash = true;
+ }
+ } else if (ch == EOL_CHAR) {
+ skipChar();
+ break;
+ } else if (lastBackslash) {
+ if (ch == 'n')
+ ch = '\n';
+ else if (ch == 't')
+ ch = '\t';
+ _stringbuf ~= ch;
+ lastBackslash = false;
+ } else {
+ _stringbuf ~= ch;
+ lastBackslash = false;
+ }
+ }
+ _token.text = _stringbuf.dup;
+ return _token;
+ }
+
+ protected ref const(Token) parseIdent() {
+ _token.type = TokenType.ident;
+ _stringbuf.length = 0;
+ _stringbuf ~= peekChar();
+ for(;;) {
+ dchar ch = skipChar();
+ if (!isAlphaNum(ch))
+ break;
+ _stringbuf ~= ch;
+ }
+ _token.text = _stringbuf.dup;
+ return _token;
+ }
+
+ protected ref const(Token) parseFloating(int n) {
+ _token.type = TokenType.floating;
+ dchar ch = peekChar();
+ // floating point
+ int div = 1;
+ int n2 = 0;
+ for (;;) {
+ ch = skipChar();
+ if (!isNum(ch))
+ break;
+ n2 = n2 * 10 + (ch - '0');
+ div *= 10;
+ }
+ _token.floatvalue = cast(double)n + (div > 0 ? cast(double)n2 / div : 0.0);
+ string suffix;
+ if (ch == '%') {
+ suffix ~= ch;
+ ch = skipChar();
+ } else {
+ while (ch >= 'a' && ch <= 'z') {
+ suffix ~= ch;
+ ch = skipChar();
+ }
+ }
+ if (isAlphaNum(ch) || ch == '.')
+ return parseError();
+ _token.text = suffix;
+ return _token;
+ }
+
+ protected ref const(Token) parseHex(int prefixLen) {
+ dchar ch = 0;
+ foreach(i; 0 .. prefixLen)
+ ch = skipChar();
+
+ uint n = parseHexDigit(ch);
+ if (n == uint.max)
+ return parseError();
+
+ for(;;) {
+ ch = skipChar();
+ uint digit = parseHexDigit(ch);
+ if (digit == uint.max)
+ break;
+ n = (n << 4) + digit;
+ }
+ string suffix;
+ if (ch == '%') {
+ suffix ~= ch;
+ ch = skipChar();
+ } else {
+ while (ch >= 'a' && ch <= 'z') {
+ suffix ~= ch;
+ ch = skipChar();
+ }
+ }
+ if (isAlphaNum(ch) || ch == '.')
+ return parseError();
+ _token.type = TokenType.integer;
+ _token.intvalue = n;
+ _token.text = suffix;
+ return _token;
+ }
+
+ protected ref const(Token) parseNumber() {
+ dchar ch = peekChar();
+ uint n = ch - '0';
+ for(;;) {
+ ch = skipChar();
+ if (!isNum(ch))
+ break;
+ n = n * 10 + (ch - '0');
+ }
+ if (ch == '.')
+ return parseFloating(n);
+ string suffix;
+ if (ch == '%') {
+ suffix ~= ch;
+ ch = skipChar();
+ } else {
+ while (ch >= 'a' && ch <= 'z') {
+ suffix ~= ch;
+ ch = skipChar();
+ }
+ }
+ if (isAlphaNum(ch) || ch == '.')
+ return parseError();
+ _token.type = TokenType.integer;
+ _token.intvalue = n;
+ _token.text = suffix;
+ return _token;
+ }
+
+ protected ref const(Token) parseSingleLineComment() {
+ for(;;) {
+ dchar ch = skipChar();
+ if (ch == EOL_CHAR || ch == EOF_CHAR)
+ break;
+ }
+ _token.type = TokenType.comment;
+ _token.multiline = false;
+ return _token;
+ }
+
+ protected ref const(Token) parseMultiLineComment() {
+ skipChar();
+ for(;;) {
+ dchar ch = skipChar();
+ if (ch == '*' && peekNextChar() == '/') {
+ skipChar();
+ skipChar();
+ break;
+ }
+ if (ch == EOF_CHAR)
+ break;
+ }
+ _token.type = TokenType.comment;
+ _token.multiline = true;
+ return _token;
+ }
+
+ protected ref const(Token) parseError() {
+ _token.type = TokenType.error;
+ for(;;) {
+ dchar ch = skipChar();
+ if (ch == ' ' || ch == '\t' || ch == EOL_CHAR || ch == EOF_CHAR)
+ break;
+ }
+ return _token;
+ }
+
+ protected ref const(Token) parseOp(TokenType op) {
+ _token.type = op;
+ skipChar();
+ return _token;
+ }
+
+ /// get next token
+ ref const(Token) nextToken() {
+ setTokenStart();
+ dchar ch = peekChar();
+ if (ch == EOF_CHAR)
+ return parseEof();
+ if (ch == EOL_CHAR)
+ return parseEol();
+ if (ch == ' ' || ch == '\t')
+ return parseWhiteSpace();
+ if (ch == '\"')
+ return parseString();
+ if (isAlpha(ch))
+ return parseIdent();
+ if (ch == '0' && peekNextChar == 'x')
+ return parseHex(2);
+ if (ch == '#')
+ return parseHex(1);
+ if (isNum(ch))
+ return parseNumber();
+ if (ch == '.' && isNum(peekNextChar()))
+ return parseFloating(0);
+ foreach(prefix; _singleLineCommentPrefixes) {
+ if (ch == prefix[0] && (prefix.length == 1 || peekNextChar() == prefix[1]))
+ return parseSingleLineComment();
+ }
+ if (ch == '/' && peekNextChar() == '*')
+ return parseMultiLineComment();
+ switch (ch) {
+ case '.': return parseOp(TokenType.dot);
+ case ':': return parseOp(TokenType.colon);
+ case ';': return parseOp(TokenType.semicolon);
+ case ',': return parseOp(TokenType.comma);
+ case '-': return parseOp(TokenType.minus);
+ case '+': return parseOp(TokenType.plus);
+ case '{': return parseOp(TokenType.curlyOpen);
+ case '}': return parseOp(TokenType.curlyClose);
+ case '(': return parseOp(TokenType.open);
+ case ')': return parseOp(TokenType.close);
+ case '[': return parseOp(TokenType.squareOpen);
+ case ']': return parseOp(TokenType.squareClose);
+ case '/': return parseOp(TokenType.divide);
+ default:
+ return parseError();
+ }
+ }
+
+ string getContextSource() {
+ string s = toUTF8(_lineText);
+ if (_pos == 0)
+ return " near `^^^" ~ s[0..min($,30)] ~ "`";
+ if (_pos >= _len)
+ return " near `" ~ s[max(_len - 30, 0) .. $] ~ "^^^`";
+ return " near `" ~ s[max(_pos - 15, 0) .. _pos] ~ "^^^" ~ s[_pos .. min(_pos + 15, $)] ~ "`";
+ }
+
+ @property string filename() {
+ return filename;
+ }
+ @property int line() {
+ return _token.line;
+ }
+ @property int pos() {
+ return _token.pos;
+ }
+
+ void emitError(string msg) {
+ throw new ParserException(msg ~ getContextSource(), _filename, _token.line, _token.pos);
+ }
+
+ void emitError(string msg, ref const Token token) {
+ throw new ParserException(msg, _filename, token.line, token.pos);
+ }
+}
+
+/// tokenize source into array of tokens (excluding EOF)
+public Token[] tokenize(string code, string[] _singleLineCommentPrefixes = ["//"]) {
+ Token[] res;
+ auto tokenizer = new Tokenizer(code, "");
+ for (;;) {
+ auto token = tokenizer.nextToken();
+ if (token.type == TokenType.eof)
+ break;
+ res ~= token;
+ }
+ return res;
+}
+
+/// exclude whitespace tokens at beginning and end of token sequence
+Token[] trimSpaceTokens(Token[] tokens, bool trimBeginning = true, bool trimEnd = true) {
+ if (trimBeginning)
+ while(tokens.length > 0 && tokens[0].type == TokenType.whitespace)
+ tokens = tokens[1 .. $];
+ if (trimEnd)
+ while(tokens.length > 0 && tokens[$ - 1].type == TokenType.whitespace)
+ tokens = tokens[0 .. $ - 1];
+ return tokens;
+}
diff --git a/src/dlangui/graphics/scene/objimport.d b/src/dlangui/graphics/scene/objimport.d
new file mode 100644
index 00000000..b2ccf256
--- /dev/null
+++ b/src/dlangui/graphics/scene/objimport.d
@@ -0,0 +1,194 @@
+module dlangui.graphics.scene.objimport;
+
+import dlangui.core.logger;
+import dlangui.dml.tokenizer;
+
+struct ObjModelImport {
+ alias FaceIndex = int[3];
+
+ private float[] _vertexData;
+ private float[] _normalData;
+ private float[] _txData;
+ private int _vertexCount;
+ private int _normalCount;
+ private int _triangleCount;
+ private int _txCount;
+ private float[8] _buf;
+ protected float[] parseFloatList(Token[] tokens, int maxItems = 3, float padding = 0) {
+ int i = 0;
+ foreach(t; tokens) {
+ if (i >= maxItems)
+ break;
+ if (t.type == TokenType.floating)
+ _buf[i++] = cast(float)t.floatvalue;
+ else if (t.type == TokenType.integer)
+ _buf[i++] = cast(float)t.intvalue;
+ }
+ while(i < maxItems)
+ _buf[i++] = padding;
+ if (i > 0)
+ return _buf[0 .. i];
+ return null;
+ }
+ //# List of geometric vertices, with (x,y,z[,w]) coordinates, w is optional and defaults to 1.0.
+ //v 0.123 0.234 0.345 1.0
+ protected bool parseVertexLine(Token[] tokens) {
+ float[] data = parseFloatList(tokens, 3, 0);
+ if (data.length == 3) {
+ _vertexData ~= data;
+ _vertexCount++;
+ return true;
+ }
+ return false;
+ }
+ //# List of texture coordinates, in (u, v [,w]) coordinates, these will vary between 0 and 1, w is optional and defaults to 0.
+ //vt 0.500 1 [0]
+ protected bool parseVertexTextureLine(Token[] tokens) {
+ float[] data = parseFloatList(tokens, 2, 0);
+ if (data.length == 2) {
+ _txData ~= data;
+ _txCount++;
+ return true;
+ }
+ return false;
+ }
+ //# List of vertex normals in (x,y,z) form; normals might not be unit vectors.
+ //vn 0.707 0.000 0.707
+ protected bool parseVertexNormalsLine(Token[] tokens) {
+ float[] data = parseFloatList(tokens, 3, 0);
+ if (data.length == 3) {
+ _normalData ~= data;
+ _normalCount++;
+ return true;
+ }
+ return false;
+ }
+
+ static protected bool skipToken(ref Token[] tokens) {
+ tokens = tokens.length > 1 ? tokens[1 .. $] : null;
+ return tokens.length > 0;
+ }
+ static protected bool parseIndex(ref Token[] tokens, ref int data) {
+ int sign = 1;
+ if (tokens[0].type == TokenType.minus) {
+ sign = -1;
+ skipToken(tokens);
+ }
+ if (tokens[0].type == TokenType.integer) {
+ data = tokens[0].intvalue * sign;
+ skipToken(tokens);
+ return true;
+ }
+ return false;
+ }
+ static protected bool skip(ref Token[] tokens, TokenType type) {
+ if (tokens.length > 0 && tokens[0].type == type) {
+ skipToken(tokens);
+ return true;
+ }
+ return false;
+ }
+ static protected bool parseFaceIndex(ref Token[] tokens, ref FaceIndex data) {
+ int i = 0;
+ if (tokens.length == 0)
+ return false;
+ if (!parseIndex(tokens, data[0]))
+ return false;
+ if (skip(tokens, TokenType.divide)) {
+ parseIndex(tokens, data[1]);
+ if (skip(tokens, TokenType.divide)) {
+ if (!parseIndex(tokens, data[2]))
+ return false;
+ }
+ }
+ return tokens.length == 0 || skip(tokens, TokenType.whitespace);
+ }
+ //# Parameter space vertices in ( u [,v] [,w] ) form; free form geometry statement ( see below )
+ //vp 0.310000 3.210000 2.100000
+ protected bool parseParameterSpaceLine(Token[] tokens) {
+ // not supported
+
+ return true;
+ }
+
+ //f 1 2 3
+ //f 3/1 4/2 5/3
+ //f 6/4/1 3/5/3 7/6/5
+ protected bool parseFaceLine(Token[] tokens) {
+ FaceIndex[10] indexes;
+ int i = 0;
+ while(parseFaceIndex(tokens, indexes[i])) {
+ if (++i >= 10)
+ break;
+ }
+ for (int j = 1; j + 1 < i; j++)
+ addTriangle(indexes[0], indexes[j], indexes[j + 1]);
+ return true;
+ }
+
+ protected bool addTriangle(FaceIndex v1, FaceIndex v2, FaceIndex v3) {
+ _triangleCount++;
+ return true;
+ }
+
+ protected bool parseLine(Token[] tokens) {
+ tokens = trimSpaceTokens(tokens);
+ if (tokens.length) {
+ if (tokens[0].type == TokenType.comment)
+ return true; // ignore comment
+ if (tokens[0].type == TokenType.ident) {
+ string ident = tokens[0].text;
+ tokens = trimSpaceTokens(tokens[1 .. $], true, false);
+ if (ident == "v") // vertex
+ return parseVertexLine(tokens);
+ if (ident == "vt") // texture coords
+ return parseVertexTextureLine(tokens);
+ if (ident == "vn") // normals
+ return parseVertexNormalsLine(tokens);
+ if (ident == "vp") // parameter space
+ return parseParameterSpaceLine(tokens);
+ if (ident == "f") // face
+ return parseFaceLine(tokens);
+ }
+ }
+ return true;
+ }
+ bool parse(string source) {
+ import dlangui.dml.tokenizer;
+ try {
+ Token[] tokens = tokenize(source, ["#"]);
+ int start = 0;
+ int i = 0;
+ for ( ; i <= tokens.length; i++) {
+ if (i == tokens.length || tokens[i].type == TokenType.eol) {
+ if (i > start && !parseLine(tokens[start .. i]))
+ return false;
+ start = i + 1;
+ }
+ }
+ } catch (ParserException e) {
+ Log.d("failed to tokenize OBJ source", e);
+ return false;
+ }
+ return true;
+ }
+
+}
+
+// load text resource
+string loadTextResource(string resourceId) {
+ import dlangui.graphics.resources;
+ import std.string : endsWith;
+ string filename;
+ filename = drawableCache.findResource(resourceId);
+ if (!filename) {
+ Log.e("Object resource file not found for resourceId ", resourceId);
+ assert(false);
+ }
+ string s = cast(string)loadResourceBytes(filename);
+ if (!s) {
+ Log.e("Cannot read shader source resource ", resourceId, " from file ", filename);
+ assert(false);
+ }
+ return s;
+}