diff --git a/data/levels/cemetery/cemetery.scene b/data/levels/cemetery/cemetery.scene
index c422fe4..f96acfd 100644
--- a/data/levels/cemetery/cemetery.scene
+++ b/data/levels/cemetery/cemetery.scene
@@ -1,16 +1,4 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
+
\ No newline at end of file
diff --git a/data/levels/cemetery/cemetery.xml b/data/levels/cemetery/cemetery.xml
index 34dc925..d9813be 100644
--- a/data/levels/cemetery/cemetery.xml
+++ b/data/levels/cemetery/cemetery.xml
@@ -5,7 +5,8 @@
-
+
+
diff --git a/data/levels/cemetery/graveyard_fence.wmb b/data/levels/cemetery/graveyard_fence.wmb
new file mode 100644
index 0000000..7ddf4ff
Binary files /dev/null and b/data/levels/cemetery/graveyard_fence.wmb differ
diff --git a/data/levels/cemetery/graveyard_terrain.mtl b/data/levels/cemetery/graveyard_terrain.mtl
new file mode 100644
index 0000000..ca9478d
--- /dev/null
+++ b/data/levels/cemetery/graveyard_terrain.mtl
@@ -0,0 +1,13 @@
+# Blender MTL File: 'None'
+# Material Count: 1
+
+newmtl graveyard_terrain
+Ns 225.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.450000
+d 1.000000
+illum 2
+map_Kd data\\textures\\scenes\\cemetery\\grass_01.png
diff --git a/data/levels/cemetery/graveyard_terrain.obj b/data/levels/cemetery/graveyard_terrain.obj
new file mode 100644
index 0000000..9780a2e
--- /dev/null
+++ b/data/levels/cemetery/graveyard_terrain.obj
@@ -0,0 +1,1237 @@
+# Blender v2.93.9 OBJ File: ''
+# www.blender.org
+mtllib graveyard_terrain.mtl
+o Plane
+v -13.994647 0.198030 14.007830
+v 14.005352 0.198030 14.007830
+v -13.994647 0.198030 -13.992170
+v 14.005352 0.198030 -13.992170
+v -13.994647 0.198030 0.007829
+v 0.005352 0.198030 14.007830
+v 14.005352 0.198030 0.007829
+v 0.005352 0.198030 -13.992170
+v 0.005352 0.193592 0.007829
+v -13.994647 0.198030 7.007829
+v 7.005352 0.198030 14.007830
+v 14.005352 0.198030 -6.992170
+v -6.994648 0.198030 -13.992170
+v -13.994647 0.198030 -6.992170
+v -6.994648 0.198030 14.007830
+v 14.005352 0.198030 7.007829
+v 7.005352 0.198030 -13.992170
+v -0.093537 -2.520149 -6.680429
+v 0.005352 0.198030 7.007829
+v -6.994648 0.198030 0.007829
+v 7.005352 0.198030 0.007829
+v 7.005352 0.198030 7.007829
+v -6.994648 0.198030 7.007829
+v -7.009819 -0.205784 -6.982327
+v 7.139185 -1.330649 -7.023788
+v -13.994647 0.198030 10.507830
+v 10.505352 0.198030 14.007830
+v 14.005352 0.198030 -10.492170
+v -10.494647 0.198030 -13.992170
+v -13.994647 0.198030 -3.492171
+v -3.494648 0.198030 14.007830
+v 14.005352 0.198030 3.507829
+v 3.505352 0.198030 -13.992170
+v -0.077773 -2.228935 -11.052467
+v 0.005352 0.198030 3.507829
+v -10.494647 0.198030 0.007829
+v 3.505352 0.131490 0.007829
+v -13.994647 0.198030 3.507829
+v 3.505352 0.198030 14.007830
+v 14.005352 0.198030 -3.492171
+v -3.494648 0.198030 -13.992170
+v -13.994647 0.198030 -10.492170
+v -10.494647 0.198030 14.007830
+v 14.005352 0.198030 10.507830
+v 10.505352 0.198030 -13.992170
+v 0.004458 -0.483784 -3.487910
+v 0.005352 0.198030 10.507830
+v -3.494648 0.198030 0.007829
+v 10.505352 0.198030 0.007829
+v 7.005352 0.198030 3.507829
+v 7.005352 0.198030 10.507830
+v 3.505352 0.198030 7.007829
+v 10.505352 0.198030 7.007829
+v -6.994648 0.198030 3.507829
+v -6.994648 0.198030 10.507830
+v -10.494647 0.198030 7.007829
+v -3.494648 0.198030 7.007829
+v -7.126102 -1.092774 -10.575894
+v -6.994648 0.198030 -3.492171
+v -10.494647 0.139471 -6.992170
+v -3.827258 -1.858437 -6.889590
+v 7.086862 -0.594465 -10.609703
+v 7.005352 -0.106106 -3.492171
+v 3.515711 -2.735657 -6.892769
+v 10.632570 -0.765775 -6.949374
+v 10.505352 0.198030 -3.492171
+v 3.471525 -0.642571 -3.453192
+v 3.605784 -2.025665 -10.987428
+v -3.494648 0.169566 -3.492171
+v -10.494647 0.198030 -3.492171
+v -10.494714 0.143291 -10.492186
+v -3.494648 0.198030 10.507830
+v -10.494647 0.198030 10.507830
+v -10.494647 0.198030 3.507829
+v 10.505352 0.198030 10.507830
+v 3.505352 0.198030 10.507830
+v 3.505352 0.198030 3.507829
+v 10.505352 0.198030 3.507829
+v -3.494648 0.198030 3.507829
+v -3.825607 -2.353528 -10.928943
+v 10.508364 0.140748 -10.498987
+v -13.994647 0.198030 12.257830
+v 12.255352 0.198030 14.007830
+v 14.005352 0.198030 -12.242170
+v -12.244647 0.198030 -13.992170
+v -13.994647 0.198030 -1.742170
+v -1.744648 0.198030 14.007830
+v 14.005352 0.198030 1.757829
+v 1.755352 0.198030 -13.992170
+v -0.003075 -0.615490 -12.356902
+v 0.005352 0.198030 1.757829
+v -12.244647 0.198030 0.007829
+v 1.755352 0.123430 0.007829
+v -13.994647 0.198030 5.257829
+v 5.255352 0.198030 14.007830
+v 14.005352 0.198030 -5.242170
+v -5.244648 0.198030 -13.992170
+v -13.994647 0.198030 -8.742170
+v -8.744647 0.198030 14.007830
+v 14.005352 0.198030 8.757830
+v 8.755352 0.198030 -13.992170
+v -0.002846 -0.794923 -5.176853
+v 0.005352 0.198030 8.757830
+v -5.244648 0.198030 0.007829
+v 8.755352 0.198030 0.007829
+v 7.005352 0.198030 1.757829
+v 7.005352 0.198030 8.757830
+v 1.755352 0.198030 7.007829
+v 8.755352 0.198030 7.007829
+v -6.994648 0.198030 1.757829
+v -6.994648 0.198030 8.757830
+v -12.244647 0.198030 7.007829
+v -5.244648 0.198030 7.007829
+v -6.998144 0.144437 -12.250756
+v -6.994648 0.198030 -5.242170
+v -12.244647 0.198030 -6.992170
+v -5.395401 -0.709339 -6.914695
+v 7.018450 0.094787 -12.266043
+v 7.028772 -0.906719 -5.238959
+v 1.652928 -2.611688 -6.711912
+v 8.910598 -1.379015 -6.974581
+v -13.994647 0.198030 8.757830
+v 8.755352 0.198030 14.007830
+v 14.005352 0.198030 -8.742170
+v -8.744647 0.198030 -13.992170
+v -13.994647 0.198030 -5.242170
+v -5.244648 0.198030 14.007830
+v 14.005352 0.198030 5.257829
+v 5.255352 0.198030 -13.992170
+v -0.241114 -4.011624 -8.845256
+v 0.005352 0.198030 5.257829
+v -8.744647 0.198030 0.007829
+v 5.255352 0.198030 0.007829
+v -13.994647 0.198030 1.757829
+v 1.755352 0.198030 14.007830
+v 14.005352 0.198030 -1.742170
+v -1.744648 0.198030 -13.992170
+v -13.994647 0.198030 -12.242170
+v -12.244647 0.198030 14.007830
+v 14.005352 0.198030 12.257830
+v 12.255352 0.198030 -13.992170
+v 0.005352 -0.248975 -1.742170
+v 0.005352 0.198030 12.257830
+v -1.744648 0.198030 0.007829
+v 12.255352 0.198030 0.007829
+v 7.005352 0.198030 5.257829
+v 7.005352 0.198030 12.257830
+v 5.255352 0.198030 7.007829
+v 12.255352 0.198030 7.007829
+v -6.994648 0.198030 5.257829
+v -6.994648 0.198030 12.257830
+v -8.744647 0.198030 7.007829
+v -1.744648 0.198030 7.007829
+v -7.139831 -1.274453 -8.692099
+v -6.994648 0.198030 -1.742170
+v -8.744661 -0.056984 -6.992162
+v -1.896161 -2.362718 -6.847846
+v 7.205418 -1.602244 -8.911171
+v 7.005352 0.196140 -1.742170
+v 5.338655 -1.765204 -7.044480
+v 12.273880 -0.141726 -6.985443
+v 10.507221 0.181511 -5.241514
+v 10.505352 0.198030 -1.742170
+v 8.755352 0.198030 -3.492171
+v 12.255352 0.198030 -3.492171
+v 3.463326 -1.172850 -5.143327
+v 3.505299 -0.484244 -1.742147
+v 1.742567 -0.435603 -3.455432
+v 5.252357 -0.884825 -3.488338
+v 3.505432 -0.048902 -12.243008
+v 3.565034 -3.213815 -8.935175
+v 1.684000 -2.251085 -11.171163
+v 5.408823 -1.381215 -10.784749
+v -3.505133 -0.169595 -5.238741
+v -3.494648 0.198030 -1.742170
+v -5.244648 0.198030 -3.492171
+v -1.744648 -0.426294 -3.492171
+v -10.494647 0.198030 -5.242170
+v -10.494647 0.198030 -1.742170
+v -12.244647 0.198030 -3.492171
+v -8.744647 0.198030 -3.492171
+v -10.494647 0.198030 -12.242170
+v -10.494725 -0.102015 -8.742188
+v -12.244647 0.198030 -10.492170
+v -8.763747 -0.191373 -10.495032
+v -3.494648 0.198030 8.757830
+v -3.494648 0.198030 12.257830
+v -5.244648 0.198030 10.507830
+v -1.744648 0.198030 10.507830
+v -10.494647 0.198030 8.757830
+v -10.494647 0.198030 12.257830
+v -12.244647 0.198030 10.507830
+v -8.744647 0.198030 10.507830
+v -10.494647 0.198030 1.757829
+v -10.494647 0.198030 5.257829
+v -12.244647 0.198030 3.507829
+v -8.744647 0.198030 3.507829
+v 10.505352 0.198030 8.757830
+v 10.505352 0.198030 12.257830
+v 8.755352 0.198030 10.507830
+v 12.255352 0.198030 10.507830
+v 3.505352 0.198030 8.757830
+v 3.505352 0.198030 12.257830
+v 1.755352 0.198030 10.507830
+v 5.255352 0.198030 10.507830
+v 3.505352 0.198030 1.757829
+v 3.505352 0.198030 5.257829
+v 1.755352 0.198030 3.507829
+v 5.255352 0.198030 3.507829
+v 10.505352 0.198030 1.757829
+v 10.505352 0.198030 5.257829
+v 8.755352 0.198030 3.507829
+v 12.255352 0.198030 3.507829
+v -3.494648 0.198030 1.757829
+v -3.494648 0.198030 5.257829
+v -5.244648 0.198030 3.507829
+v -1.744648 0.198030 3.507829
+v -3.542220 -0.374271 -12.358070
+v -4.112876 -3.311711 -8.676560
+v -5.501352 -2.028401 -10.782839
+v -1.900922 -2.596831 -11.031785
+v 10.505352 0.198030 -12.242170
+v 10.561519 -0.226619 -8.771412
+v 8.792251 -0.340791 -10.557952
+v 12.255352 0.198030 -10.492170
+v 12.255352 0.198030 -8.742170
+v 8.948801 -1.579888 -8.890796
+v 8.757542 0.145079 -12.248607
+v -2.139508 -3.766012 -8.780711
+v -5.596035 -2.389454 -8.657863
+v -5.266485 -0.071257 -12.305037
+v -1.744648 0.198030 5.257829
+v -5.244648 0.198030 5.257829
+v -5.244648 0.198030 1.757829
+v 12.255352 0.198030 5.257829
+v 8.755352 0.198030 5.257829
+v 8.755352 0.198030 1.757829
+v 5.255352 0.198030 5.257829
+v 1.755352 0.198030 5.257829
+v 1.755352 0.198030 1.757829
+v 5.255352 0.198030 12.257830
+v 1.755352 0.198030 12.257830
+v 1.755352 0.198030 8.757830
+v 12.255352 0.198030 12.257830
+v 8.755352 0.198030 12.257830
+v 8.755352 0.198030 8.757830
+v -8.744647 0.198030 5.257829
+v -12.244647 0.198030 5.257829
+v -12.244647 0.198030 1.757829
+v -8.744647 0.198030 12.257830
+v -12.244647 0.198030 12.257830
+v -12.244647 0.198030 8.757830
+v -1.744648 0.198030 12.257830
+v -5.244648 0.198030 12.257830
+v -5.244648 0.198030 8.757830
+v -8.766276 -0.706617 -8.738627
+v -12.244647 0.197937 -8.742170
+v -12.244647 0.198030 -12.242170
+v -8.744647 0.198030 -1.742170
+v -12.244647 0.198030 -1.742170
+v -12.244647 0.198030 -5.242170
+v -1.744648 0.166440 -1.742170
+v -5.244648 0.198030 -1.742170
+v -5.245092 0.195319 -5.241882
+v 5.489839 -2.119642 -8.949414
+v 1.562953 -3.970965 -8.882751
+v 1.742962 -0.355982 -12.314992
+v 5.255352 -0.274671 -1.742170
+v 1.755352 -0.416680 -1.742170
+v 1.741244 -0.982065 -5.153770
+v 12.255352 0.198030 -1.742170
+v 8.755352 0.198030 -1.742170
+v 8.774186 -0.019219 -5.237497
+v 12.255424 0.149553 -5.242145
+v 5.244075 -1.283640 -5.210855
+v 5.261870 0.143939 -12.253246
+v -1.744648 -0.699109 -5.242170
+v -8.744647 0.198030 -5.242170
+v -8.744647 0.198030 -12.242170
+v -1.744648 0.198030 8.757830
+v -8.744647 0.198030 8.757830
+v -8.744647 0.198030 1.757829
+v 12.255352 0.198030 8.757830
+v 5.255352 0.198030 8.757830
+v 5.255352 0.198030 1.757829
+v 12.255352 0.198030 1.757829
+v -1.744648 0.198030 1.757829
+v -1.763049 -0.534874 -12.336933
+v 12.255352 0.198030 -12.242170
+vt 2.276192 2.051382
+vt 2.054317 2.273257
+vt 2.054317 2.051382
+vt 0.500123 2.065928
+vt 0.279317 2.273257
+vt 0.276984 2.063396
+vt 0.501192 0.276382
+vt 0.279317 0.498257
+vt 0.279317 0.276382
+vt 2.276192 0.276382
+vt 2.054317 0.498257
+vt 2.054317 0.276382
+vt 1.388692 0.276382
+vt 1.166817 0.498257
+vt 1.166817 0.276382
+vt 1.388692 -0.611118
+vt 1.166817 -0.389243
+vt 1.166817 -0.611118
+vt 2.276192 -0.611118
+vt 2.054317 -0.389243
+vt 2.054317 -0.611118
+vt -0.386308 0.276382
+vt -0.608183 0.498257
+vt -0.608183 0.276382
+vt -0.386308 -0.611118
+vt -0.608183 -0.389243
+vt -0.608183 -0.611118
+vt 0.501192 -0.611118
+vt 0.279317 -0.389243
+vt 0.279317 -0.611118
+vt -0.386752 2.052470
+vt -0.608183 2.273257
+vt -0.608183 2.051382
+vt -0.386308 1.163882
+vt -0.608185 1.385756
+vt -0.608183 1.163882
+vt 0.279317 0.430346
+vt 0.488654 0.199464
+vt 0.260107 0.219424
+vt 1.167643 2.052786
+vt 1.388692 2.273257
+vt 1.166817 2.273257
+vt 1.391661 1.163475
+vt 1.177378 1.392389
+vt 1.165387 1.159911
+vt 2.054326 1.163878
+vt 2.276192 1.385757
+vt 2.056666 1.384904
+vt 1.612954 1.163289
+vt 1.848571 1.380331
+vt 1.630250 1.383527
+vt 1.832442 0.720132
+vt 1.610567 0.942007
+vt 1.610567 0.720132
+vt 2.276192 0.720132
+vt 2.054317 0.942007
+vt 2.054317 0.720132
+vt 0.939613 1.151350
+vt 0.710081 1.350224
+vt 0.721278 1.152674
+vt 0.723067 0.720132
+vt 0.940653 0.937065
+vt 0.721446 0.937349
+vt 1.166817 0.720132
+vt 1.388692 0.942007
+vt 1.166437 0.941521
+vt 0.944952 2.051488
+vt 0.723067 2.273257
+vt 0.721496 2.060615
+vt 0.952508 1.632102
+vt 0.714020 1.915593
+vt 0.698673 1.625455
+vt 1.414057 1.629059
+vt 1.186275 1.866602
+vt 1.196546 1.633907
+vt 0.056112 1.163447
+vt -0.183547 1.375934
+vt -0.164490 1.163845
+vt 0.057442 0.720132
+vt -0.164433 0.942007
+vt -0.164433 0.720132
+vt 0.501192 0.720132
+vt 0.279317 0.942007
+vt 0.279317 0.720132
+vt -0.830058 1.163882
+vt -1.051933 1.385757
+vt -1.051933 1.163882
+vt -0.830058 0.720132
+vt -1.051933 0.942007
+vt -1.051933 0.720132
+vt -0.386308 0.720132
+vt -0.608183 0.942007
+vt -0.608183 0.720132
+vt -0.830058 2.051382
+vt -1.051933 2.273257
+vt -1.051933 2.051382
+vt -1.051933 1.607632
+vt -0.830067 1.829509
+vt -1.051933 1.829507
+vt -0.610926 1.607183
+vt -0.402975 1.840122
+vt -0.610605 1.829870
+vt 0.057442 -0.611118
+vt -0.164433 -0.389243
+vt -0.164433 -0.611118
+vt 0.057442 -1.054868
+vt -0.164433 -0.832993
+vt -0.164433 -1.054868
+vt 0.501192 -1.054868
+vt 0.279317 -0.832993
+vt 0.279317 -1.054868
+vt -0.830058 -0.611118
+vt -1.051933 -0.389243
+vt -1.051933 -0.611118
+vt -0.830058 -1.054868
+vt -1.051933 -0.832993
+vt -1.051933 -1.054868
+vt -0.386308 -1.054868
+vt -0.608183 -0.832993
+vt -0.608183 -1.054868
+vt -0.830058 0.276382
+vt -1.051933 0.498257
+vt -1.051933 0.276382
+vt -0.830058 -0.167368
+vt -1.051933 0.054507
+vt -1.051933 -0.167368
+vt -0.386308 -0.167368
+vt -0.608183 0.054507
+vt -0.608183 -0.167368
+vt 1.832442 -0.611118
+vt 1.610567 -0.389243
+vt 1.610567 -0.611118
+vt 1.832442 -1.054868
+vt 1.610567 -0.832993
+vt 1.610567 -1.054868
+vt 2.276192 -1.054868
+vt 2.054317 -0.832993
+vt 2.054317 -1.054868
+vt 0.944942 -0.611118
+vt 0.723067 -0.389243
+vt 0.723067 -0.611118
+vt 0.944942 -1.054868
+vt 0.723067 -0.832993
+vt 0.723067 -1.054868
+vt 1.388692 -1.054868
+vt 1.166817 -0.832993
+vt 1.166817 -1.054868
+vt 0.723067 0.276382
+vt 0.944942 0.498257
+vt 0.723067 0.498257
+vt 0.944942 -0.167368
+vt 0.723067 0.054507
+vt 0.723067 -0.167368
+vt 1.388692 -0.167368
+vt 1.166817 0.054507
+vt 1.166817 -0.167368
+vt 1.832442 0.276382
+vt 1.610567 0.498257
+vt 1.610567 0.276382
+vt 1.832442 -0.167368
+vt 1.610567 0.054507
+vt 1.610567 -0.167368
+vt 2.276192 -0.167368
+vt 2.054317 0.054507
+vt 2.054317 -0.167368
+vt 0.057442 0.276382
+vt -0.164433 0.498257
+vt -0.164433 0.276382
+vt 0.057442 -0.167368
+vt -0.164433 0.054507
+vt -0.164433 -0.167368
+vt 0.501192 -0.167368
+vt 0.279317 0.054507
+vt 0.279317 -0.167368
+vt 0.051410 2.066076
+vt -0.164433 2.273257
+vt -0.167202 2.059352
+vt -0.020941 1.599313
+vt -0.196980 1.866359
+vt -0.208984 1.596943
+vt 0.469943 1.620701
+vt 0.259503 1.897922
+vt 0.229254 1.612518
+vt 1.610844 2.052198
+vt 1.832442 2.273257
+vt 1.610567 2.273257
+vt 1.839563 1.611339
+vt 1.615245 1.837847
+vt 1.635093 1.626475
+vt 2.276192 1.607632
+vt 2.054317 1.829507
+vt 2.054317 1.607632
+vt 1.832823 1.830371
+vt 1.399026 1.844408
+vt 1.405660 1.389766
+vt 1.390352 2.054409
+vt 1.832442 2.051382
+vt 0.015481 1.884883
+vt 0.260107 1.367458
+vt 0.015272 1.372751
+vt -0.404715 1.601283
+vt -0.388232 1.384509
+vt -0.386308 2.273257
+vt -0.402975 0.380435
+vt -0.167202 0.509949
+vt -0.386752 0.537296
+vt -0.196980 0.261811
+vt 0.051410 0.471531
+vt 0.057442 0.054507
+vt 0.057442 -0.389243
+vt 0.501192 -0.389243
+vt -0.386308 0.054507
+vt -0.386308 -0.389243
+vt -0.386308 0.498257
+vt 1.832442 0.054507
+vt 1.832442 -0.389243
+vt 2.276192 -0.389243
+vt 1.388692 0.054507
+vt 1.388692 -0.389243
+vt 1.388692 0.498257
+vt 0.944942 0.054507
+vt 0.944942 -0.389243
+vt 0.501192 0.054507
+vt 0.501192 0.498257
+vt 0.944942 -0.832993
+vt 1.166817 -1.276743
+vt 0.944942 -1.276743
+vt 1.388692 -1.276743
+vt 0.501192 -0.832993
+vt 0.723067 -1.276743
+vt 0.501192 -1.276743
+vt 1.832442 -0.832993
+vt 2.054317 -1.276743
+vt 1.832442 -1.276743
+vt 2.276192 -1.276743
+vt 1.388692 -0.832993
+vt 1.610567 -1.276743
+vt -0.830058 0.054507
+vt -0.830058 -0.389243
+vt -1.273808 0.054507
+vt -1.273808 -0.167368
+vt -1.273808 -0.389243
+vt -1.273808 0.498257
+vt -1.273808 0.276382
+vt -0.830058 -0.832993
+vt -0.608183 -1.276743
+vt -0.830058 -1.276743
+vt -0.386308 -1.276743
+vt -1.273808 -0.832993
+vt -1.273808 -1.054868
+vt -1.051933 -1.276743
+vt -1.273808 -1.276743
+vt -1.273808 -0.611118
+vt 0.057442 -0.832993
+vt 0.279317 -1.276743
+vt 0.057442 -1.276743
+vt -0.386308 -0.832993
+vt -0.164433 -1.276743
+vt -0.830068 1.607634
+vt -0.830058 1.385757
+vt -1.273808 1.829507
+vt -1.273808 1.607632
+vt -1.273808 1.385757
+vt -1.273808 2.273257
+vt -1.273808 2.051382
+vt -0.830058 0.942007
+vt -0.830058 0.498257
+vt -1.273808 0.942007
+vt -1.273808 0.720132
+vt -1.273808 1.163882
+vt 0.057442 0.942007
+vt 0.057442 0.498257
+vt -0.386308 0.942007
+vt 0.957675 1.892298
+vt 0.946255 1.373154
+vt 0.490653 1.900544
+vt 0.488654 1.346232
+vt 0.501192 2.273257
+vt 0.714020 0.233578
+vt 0.500123 0.440948
+vt 0.490653 0.236386
+vt 0.957675 0.262158
+vt 0.721496 0.473850
+vt 0.944935 0.720129
+vt 1.388692 0.720132
+vt 0.501078 0.941467
+vt 0.721278 0.394471
+vt 0.500152 0.418198
+vt 0.500152 1.155600
+vt 1.832442 0.942007
+vt 1.832442 0.498257
+vt 2.276192 0.498257
+vt 1.832679 1.163799
+vt 2.276192 1.163882
+vt 0.944942 2.273257
+vt 1.186275 0.343865
+vt 0.944952 0.512783
+vt 0.015272 0.283360
+vt 0.056112 0.497481
+vt 0.279317 1.163882
+vt -0.830058 2.273257
+vt 2.276192 -0.832993
+vt 0.944942 0.276382
+vt 2.276192 0.054507
+vt 0.057442 2.273257
+vt 0.259503 0.189742
+vt 0.015481 0.220589
+vt 0.276984 0.451169
+vt 2.276192 1.829507
+vt 2.276192 2.273257
+vt 2.276192 0.942007
+vt 0.710081 0.187858
+vt 1.167643 0.537232
+vn 0.0000 1.0000 0.0000
+vn -0.0041 1.0000 0.0041
+vn -0.0280 0.7654 0.6429
+vn 0.0311 0.9170 0.3977
+vn 0.0352 0.7640 0.6442
+vn 0.0003 1.0000 -0.0009
+vn 0.0032 1.0000 -0.0071
+vn -0.0470 0.9935 -0.1032
+vn 0.1285 0.9531 0.2741
+vn 0.0077 0.9999 0.0077
+vn 0.0390 0.9955 0.0863
+vn 0.0472 0.9890 -0.1397
+vn 0.1138 0.9664 -0.2306
+vn 0.0139 0.9982 -0.0584
+vn 0.1673 0.8612 -0.4799
+vn 0.0702 0.7542 -0.6528
+vn 0.1513 0.7386 -0.6569
+vn -0.0757 0.9255 0.3711
+vn 0.0071 0.9986 0.0525
+vn 0.0000 0.9995 0.0311
+vn -0.2796 0.8934 -0.3516
+vn -0.2991 0.9118 -0.2814
+vn -0.0750 0.9676 -0.2412
+vn -0.0254 0.9968 -0.0761
+vn -0.1038 0.9946 0.0070
+vn -0.2177 0.9758 -0.0207
+vn -0.2299 0.8993 -0.3718
+vn -0.3657 0.9112 -0.1896
+vn -0.1957 0.9270 -0.3198
+vn -0.0642 0.9944 -0.0833
+vn -0.0004 1.0000 -0.0001
+vn -0.0012 0.9999 -0.0081
+vn 0.0118 0.8947 -0.4466
+vn -0.0137 0.8055 -0.5924
+vn 0.0755 0.8497 -0.5217
+vn 0.0711 0.9830 -0.1693
+vn 0.0791 0.9728 -0.2176
+vn 0.0623 0.9827 -0.1741
+vn -0.1658 0.9531 -0.2533
+vn -0.2948 0.9184 -0.2639
+vn -0.1194 0.9437 -0.3084
+vn -0.1324 0.8350 0.5340
+vn -0.0449 0.9617 0.2702
+vn -0.1271 0.7659 0.6302
+vn -0.3567 0.9282 0.1055
+vn -0.0802 0.6955 0.7140
+vn -0.1629 0.9858 0.0399
+vn -0.1786 0.9652 0.1908
+vn -0.3193 0.7477 0.5822
+vn -0.3796 0.9192 0.1043
+vn 0.2663 0.8628 -0.4298
+vn 0.3296 0.7622 -0.5571
+vn 0.0763 0.9604 -0.2677
+vn 0.0088 0.9999 -0.0083
+vn 0.0061 1.0000 -0.0028
+vn 0.1135 0.9723 -0.2041
+vn 0.1961 0.9565 -0.2159
+vn 0.1315 0.9787 -0.1576
+vn 0.0042 0.9999 -0.0125
+vn 0.0125 0.9999 -0.0042
+vn 0.0039 0.9999 0.0117
+vn 0.0505 0.9987 0.0002
+vn 0.1036 0.9904 0.0908
+vn 0.0117 0.9999 0.0039
+vn 0.3255 0.9410 -0.0923
+vn 0.4235 0.8140 0.3976
+vn 0.2940 0.9144 0.2781
+vn 0.0044 0.9998 -0.0157
+vn -0.0250 0.9845 -0.1735
+vn 0.0241 0.9862 -0.1638
+vn 0.0914 0.7986 0.5949
+vn 0.0450 0.9783 0.2022
+vn 0.1658 0.8730 0.4586
+vn 0.3412 0.9269 -0.1565
+vn 0.3799 0.7636 0.5220
+vn 0.5435 0.7984 -0.2593
+vn 0.0262 0.9996 0.0049
+vn 0.0197 0.7261 0.6873
+vn 0.1619 0.9836 -0.0797
+vn -0.0415 0.9852 0.1661
+vn -0.0076 0.9999 0.0076
+vn -0.0073 0.9992 0.0377
+vn -0.3845 0.8881 0.2517
+vn -0.2176 0.9091 0.3553
+vn -0.2870 0.9142 0.2861
+vn -0.0431 0.9987 0.0268
+vn -0.1459 0.9867 0.0710
+vn -0.1496 0.9817 0.1178
+vn -0.2112 0.8492 0.4840
+vn -0.0982 0.9766 -0.1911
+vn 0.0033 0.9752 0.2212
+vn -0.0464 0.9978 0.0475
+vn 0.1746 0.7500 0.6380
+vn 0.3224 0.6670 -0.6716
+vn 0.4209 0.8711 -0.2529
+vn 0.2133 0.9106 -0.3539
+vn 0.0317 0.9975 0.0623
+vn -0.0001 1.0000 -0.0004
+vn 0.0449 0.9939 -0.1009
+vn 0.2064 0.9784 -0.0091
+vn 0.0753 0.9938 -0.0816
+vn 0.1536 0.9812 -0.1166
+vn 0.0002 1.0000 -0.0002
+vn -0.2493 0.7115 0.6569
+vn -0.2200 0.8729 -0.4355
+vn -0.0228 0.6960 0.7176
+vn -0.0359 0.9102 0.4125
+vn -0.0396 0.9765 -0.2118
+vn -0.1183 0.9883 -0.0957
+vn 0.0211 0.9845 -0.1739
+vn 0.0789 0.8694 -0.4877
+vn -0.0144 0.9997 -0.0191
+vn -0.0923 0.9720 -0.2162
+vn -0.0208 0.9998 -0.0069
+vn -0.0272 0.9932 0.1129
+vn -0.0047 0.9999 -0.0142
+vn 0.0000 0.9438 0.3305
+usemtl graveyard_terrain
+s 1
+f 84/1/1 141/2/1 289/3/2
+f 90/4/3 137/5/4 288/6/5
+f 91/7/6 144/8/7 287/9/1
+f 88/10/1 145/11/1 286/12/1
+f 106/13/1 133/14/8 285/15/1
+f 107/16/1 148/17/1 284/18/1
+f 100/19/1 149/20/1 283/21/1
+f 110/22/1 132/23/1 282/24/1
+f 111/25/1 152/26/1 281/27/1
+f 103/28/1 153/29/1 280/30/1
+f 114/31/9 125/32/10 279/33/11
+f 115/34/12 156/35/13 278/36/14
+f 277/37/15 18/38/16 157/39/17
+f 276/40/18 17/41/19 129/42/20
+f 119/43/21 160/44/22 275/45/23
+f 274/46/24 12/47/25 161/48/26
+f 273/49/27 65/50/28 121/51/29
+f 163/52/1 164/53/30 272/54/31
+f 136/55/1 165/56/32 271/57/1
+f 166/58/33 120/59/34 270/60/35
+f 269/61/36 67/62/37 168/63/38
+f 268/64/39 63/65/40 169/66/41
+f 170/67/42 89/68/43 267/69/44
+f 171/70/45 172/71/46 266/72/47
+f 158/73/48 173/74/49 265/75/50
+f 174/76/51 117/77/52 264/78/53
+f 175/79/54 176/80/55 263/81/1
+f 142/82/56 177/83/57 262/84/58
+f 178/85/59 116/86/60 261/87/1
+f 179/88/1 180/89/1 260/90/1
+f 155/91/1 181/92/1 259/93/1
+f 182/94/61 85/95/1 258/96/1
+f 257/97/62 71/98/63 184/99/64
+f 256/100/65 58/101/66 185/102/67
+f 186/103/1 113/104/1 255/105/1
+f 187/106/1 188/107/1 254/108/1
+f 143/109/1 189/110/1 253/111/1
+f 190/112/1 112/113/1 252/114/1
+f 191/115/1 192/116/1 251/117/1
+f 151/118/1 193/119/1 250/120/1
+f 194/121/1 92/122/1 249/123/1
+f 195/124/1 196/125/1 248/126/1
+f 150/127/1 197/128/1 247/129/1
+f 198/130/1 109/131/1 246/132/1
+f 199/133/1 200/134/1 245/135/1
+f 140/136/1 201/137/1 244/138/1
+f 202/139/1 108/140/1 243/141/1
+f 203/142/1 204/143/1 242/144/1
+f 147/145/1 205/146/1 241/147/1
+f 240/148/68 37/149/69 93/150/70
+f 207/151/1 208/152/1 239/153/1
+f 146/154/1 209/155/1 238/156/1
+f 210/157/1 105/158/1 237/159/1
+f 211/160/1 212/161/1 236/162/1
+f 128/163/1 213/164/1 235/165/1
+f 214/166/1 104/167/1 234/168/1
+f 215/169/1 216/170/1 233/171/1
+f 131/172/1 217/173/1 232/174/1
+f 218/175/71 97/176/72 231/177/73
+f 219/178/74 220/179/75 230/180/76
+f 130/181/77 221/182/78 229/183/79
+f 228/184/80 45/185/81 101/186/82
+f 223/187/83 224/188/84 227/189/85
+f 124/190/1 225/191/86 226/192/87
+f 223/187/83 225/191/86 81/193/88
+f 161/48/26 223/187/83 65/50/28
+f 12/47/25 226/192/87 161/48/26
+f 158/73/48 224/188/84 62/194/89
+f 121/51/29 158/73/48 25/195/90
+f 65/50/28 227/189/85 121/51/29
+f 118/196/91 101/186/82 17/41/19
+f 62/194/89 228/184/80 118/196/91
+f 224/188/84 222/197/92 228/184/80
+f 229/183/79 80/198/93 219/178/74
+f 157/199/17 219/178/74 61/200/94
+f 157/199/17 130/181/77 229/183/79
+f 154/201/95 220/179/75 58/101/66
+f 117/77/52 154/201/95 24/202/96
+f 61/200/94 230/180/76 117/77/52
+f 231/177/73 13/203/97 114/31/9
+f 58/204/66 231/205/73 114/206/9
+f 220/207/75 218/208/71 231/205/73
+f 232/174/1 79/209/1 215/169/1
+f 153/29/1 215/169/1 57/210/1
+f 19/211/1 232/174/1 153/29/1
+f 233/171/1 54/212/1 150/127/1
+f 113/104/1 150/127/1 23/213/1
+f 57/210/1 233/171/1 113/104/1
+f 234/168/1 20/214/1 110/22/1
+f 216/170/1 110/22/1 54/212/1
+f 79/209/1 234/168/1 216/170/1
+f 235/165/1 78/215/1 211/160/1
+f 149/20/1 211/160/1 53/216/1
+f 16/217/1 235/165/1 149/20/1
+f 236/162/1 50/218/1 146/154/1
+f 109/131/1 146/154/1 22/219/1
+f 53/216/1 236/162/1 109/131/1
+f 237/159/1 21/220/98 106/13/1
+f 212/161/1 106/13/1 50/218/1
+f 78/215/1 237/159/1 212/161/1
+f 238/156/1 77/221/1 207/151/1
+f 148/17/1 207/151/1 52/222/1
+f 22/219/1 238/156/1 148/17/1
+f 239/153/1 35/223/1 131/172/1
+f 108/140/1 131/172/1 19/211/1
+f 52/222/1 239/153/1 108/140/1
+f 240/148/68 9/224/99 91/7/6
+f 208/152/1 91/7/6 35/223/1
+f 77/221/1 240/148/68 208/152/1
+f 241/147/1 76/225/1 203/142/1
+f 95/226/1 203/142/1 39/227/1
+f 11/228/1 241/147/1 95/226/1
+f 242/144/1 47/229/1 143/109/1
+f 135/230/1 143/109/1 6/231/1
+f 39/227/1 242/144/1 135/230/1
+f 243/141/1 19/211/1 103/28/1
+f 204/143/1 103/28/1 47/229/1
+f 76/225/1 243/141/1 204/143/1
+f 244/138/1 75/232/1 199/133/1
+f 83/233/1 199/133/1 27/234/1
+f 2/235/1 244/138/1 83/233/1
+f 245/135/1 51/236/1 147/145/1
+f 123/237/1 147/145/1 11/228/1
+f 27/234/1 245/135/1 123/237/1
+f 246/132/1 22/219/1 107/16/1
+f 200/134/1 107/16/1 51/236/1
+f 75/232/1 246/132/1 200/134/1
+f 247/129/1 74/238/1 195/124/1
+f 152/26/1 195/124/1 56/239/1
+f 23/213/1 247/129/1 152/26/1
+f 248/126/1 38/240/1 94/241/1
+f 112/113/1 94/241/1 10/242/1
+f 56/239/1 248/126/1 112/113/1
+f 249/123/1 5/243/1 134/244/1
+f 196/125/1 134/244/1 38/240/1
+f 74/238/1 249/123/1 196/125/1
+f 250/120/1 73/245/1 191/115/1
+f 99/246/1 191/115/1 43/247/1
+f 15/248/1 250/120/1 99/246/1
+f 251/117/1 26/249/1 82/250/1
+f 139/251/1 82/250/1 1/252/1
+f 43/247/1 251/117/1 139/251/1
+f 252/114/1 10/242/1 122/253/1
+f 192/116/1 122/253/1 26/249/1
+f 73/245/1 252/114/1 192/116/1
+f 253/111/1 72/254/1 187/106/1
+f 87/255/1 187/106/1 31/256/1
+f 6/231/1 253/111/1 87/255/1
+f 254/108/1 55/257/1 151/118/1
+f 127/258/1 151/118/1 15/248/1
+f 31/256/1 254/108/1 127/258/1
+f 255/105/1 23/213/1 111/25/1
+f 188/107/1 111/25/1 55/257/1
+f 72/254/1 255/105/1 188/107/1
+f 183/259/100 185/102/67 71/98/63
+f 156/35/13 183/259/100 60/260/101
+f 24/202/96 256/100/65 156/35/13
+f 257/97/62 42/261/1 98/262/1
+f 116/86/60 98/262/1 14/263/1
+f 60/260/101 257/97/62 116/86/60
+f 258/96/1 3/264/1 138/265/1
+f 184/99/64 138/265/1 42/261/1
+f 184/99/64 182/94/61 258/96/1
+f 259/93/1 70/266/1 179/88/1
+f 132/23/1 179/88/1 36/267/1
+f 20/214/1 259/93/1 132/23/1
+f 260/90/1 30/268/1 86/269/1
+f 92/122/1 86/269/1 5/243/1
+f 36/267/1 260/90/1 92/122/1
+f 261/87/1 14/263/1 126/270/1
+f 180/89/1 126/270/1 30/268/1
+f 70/266/1 261/87/1 180/89/1
+f 262/84/58 69/271/102 175/79/54
+f 144/8/7 175/79/54 48/272/1
+f 9/224/99 262/84/58 144/8/7
+f 263/81/1 59/273/103 155/91/1
+f 104/167/1 155/91/1 20/214/1
+f 48/272/1 263/81/1 104/167/1
+f 115/34/12 117/77/52 24/202/96
+f 59/273/103 264/78/53 115/34/12
+f 69/271/102 264/78/53 176/80/55
+f 265/75/50 68/274/104 171/70/45
+f 64/275/105 265/75/50 171/70/45
+f 160/44/22 158/73/48 265/75/50
+f 266/72/47 34/276/106 130/181/77
+f 18/277/16 266/72/47 130/181/77
+f 120/59/34 171/70/45 266/72/47
+f 267/69/44 8/278/107 90/4/3
+f 172/279/46 90/280/3 34/281/106
+f 68/282/104 267/283/44 172/279/46
+f 268/64/39 67/62/37 167/284/108
+f 37/149/69 268/64/39 167/284/108
+f 133/14/8 159/285/109 268/64/39
+f 142/82/56 168/63/38 46/286/110
+f 93/150/70 142/82/56 9/224/99
+f 37/149/69 269/61/36 93/150/70
+f 270/287/35 18/38/16 102/288/111
+f 46/286/110 270/60/35 102/289/111
+f 67/62/37 270/60/35 168/63/38
+f 271/57/1 66/290/112 163/52/1
+f 145/11/1 163/52/1 49/291/1
+f 7/292/1 271/57/1 145/11/1
+f 159/285/109 164/53/30 63/65/40
+f 21/220/98 272/54/31 159/285/109
+f 49/291/1 272/54/31 105/158/1
+f 119/43/21 121/51/29 25/195/90
+f 63/65/40 273/49/27 119/43/21
+f 66/290/112 273/49/27 164/53/30
+f 162/293/113 161/48/26 65/50/28
+f 165/56/32 162/293/113 66/290/112
+f 165/56/32 96/294/114 274/46/24
+f 166/58/33 160/44/22 64/275/105
+f 169/66/41 166/58/33 67/62/37
+f 169/66/41 119/43/21 275/45/23
+f 276/40/18 33/295/115 170/67/42
+f 173/296/49 170/297/42 68/282/104
+f 62/194/89 276/40/18 173/74/49
+f 277/37/15 61/298/94 174/299/51
+f 177/83/57 174/76/51 69/271/102
+f 177/83/57 102/289/111 277/300/15
+f 278/36/14 60/260/101 178/85/59
+f 181/92/1 178/85/59 70/266/1
+f 59/273/103 278/36/14 181/92/1
+f 279/33/11 29/301/1 182/94/61
+f 71/98/63 279/33/11 182/94/61
+f 185/102/67 114/31/9 279/33/11
+f 280/30/1 57/210/1 186/103/1
+f 189/110/1 186/103/1 72/254/1
+f 47/229/1 280/30/1 189/110/1
+f 281/27/1 56/239/1 190/112/1
+f 193/119/1 190/112/1 73/245/1
+f 55/257/1 281/27/1 193/119/1
+f 282/24/1 36/267/1 194/121/1
+f 197/128/1 194/121/1 74/238/1
+f 54/212/1 282/24/1 197/128/1
+f 283/21/1 53/216/1 198/130/1
+f 201/137/1 198/130/1 75/232/1
+f 44/302/1 283/21/1 201/137/1
+f 284/18/1 52/222/1 202/139/1
+f 205/146/1 202/139/1 76/225/1
+f 51/236/1 284/18/1 205/146/1
+f 206/303/116 133/14/8 37/149/69
+f 209/155/1 206/303/116 77/221/1
+f 50/218/1 285/15/1 209/155/1
+f 286/12/1 49/291/1 210/157/1
+f 213/164/1 210/157/1 78/215/1
+f 32/304/1 286/12/1 213/164/1
+f 287/9/1 48/272/1 214/166/1
+f 217/173/1 214/166/1 79/209/1
+f 35/223/1 287/9/1 217/173/1
+f 218/175/71 137/5/4 41/305/117
+f 221/306/78 218/208/71 80/307/93
+f 34/281/106 288/308/5 221/306/78
+f 289/3/2 45/185/81 222/197/92
+f 81/193/88 289/3/2 222/197/92
+f 28/309/1 289/3/2 225/191/86
+f 84/1/1 4/310/1 141/2/1
+f 90/4/3 8/278/107 137/5/4
+f 91/7/6 9/224/99 144/8/7
+f 88/10/1 7/292/1 145/11/1
+f 106/13/1 21/220/98 133/14/8
+f 107/16/1 22/219/1 148/17/1
+f 100/19/1 16/217/1 149/20/1
+f 110/22/1 20/214/1 132/23/1
+f 111/25/1 23/213/1 152/26/1
+f 103/28/1 19/211/1 153/29/1
+f 114/31/9 13/203/97 125/32/10
+f 115/34/12 24/202/96 156/35/13
+f 277/37/15 102/288/111 18/38/16
+f 276/40/18 118/196/91 17/41/19
+f 119/43/21 25/195/90 160/44/22
+f 274/46/24 96/294/114 12/47/25
+f 273/49/27 162/293/113 65/50/28
+f 163/52/1 66/290/112 164/53/30
+f 136/55/1 40/311/1 165/56/32
+f 166/58/33 64/275/105 120/59/34
+f 269/61/36 167/284/108 67/62/37
+f 268/64/39 159/285/109 63/65/40
+f 170/67/42 33/295/115 89/68/43
+f 171/70/45 68/274/104 172/71/46
+f 158/73/48 62/194/89 173/74/49
+f 174/76/51 61/200/94 117/77/52
+f 175/79/54 69/271/102 176/80/55
+f 142/82/56 46/286/110 177/83/57
+f 178/85/59 60/260/101 116/86/60
+f 179/88/1 70/266/1 180/89/1
+f 155/91/1 59/273/103 181/92/1
+f 182/94/61 29/301/1 85/95/1
+f 257/97/62 183/259/100 71/98/63
+f 256/100/65 154/201/95 58/101/66
+f 186/103/1 57/210/1 113/104/1
+f 187/106/1 72/254/1 188/107/1
+f 143/109/1 47/229/1 189/110/1
+f 190/112/1 56/239/1 112/113/1
+f 191/115/1 73/245/1 192/116/1
+f 151/118/1 55/257/1 193/119/1
+f 194/121/1 36/267/1 92/122/1
+f 195/124/1 74/238/1 196/125/1
+f 150/127/1 54/212/1 197/128/1
+f 198/130/1 53/216/1 109/131/1
+f 199/133/1 75/232/1 200/134/1
+f 140/136/1 44/302/1 201/137/1
+f 202/139/1 52/222/1 108/140/1
+f 203/142/1 76/225/1 204/143/1
+f 147/145/1 51/236/1 205/146/1
+f 240/148/68 206/303/116 37/149/69
+f 207/151/1 77/221/1 208/152/1
+f 146/154/1 50/218/1 209/155/1
+f 210/157/1 49/291/1 105/158/1
+f 211/160/1 78/215/1 212/161/1
+f 128/163/1 32/304/1 213/164/1
+f 214/166/1 48/272/1 104/167/1
+f 215/169/1 79/209/1 216/170/1
+f 131/172/1 35/223/1 217/173/1
+f 218/175/71 41/305/117 97/176/72
+f 219/178/74 80/198/93 220/179/75
+f 130/181/77 34/276/106 221/182/78
+f 228/184/80 222/197/92 45/185/81
+f 223/187/83 81/193/88 224/188/84
+f 124/190/1 28/309/1 225/191/86
+f 223/187/83 226/192/87 225/191/86
+f 161/48/26 226/192/87 223/187/83
+f 12/47/25 124/190/1 226/192/87
+f 158/73/48 227/189/85 224/188/84
+f 121/51/29 227/189/85 158/73/48
+f 65/50/28 223/187/83 227/189/85
+f 118/196/91 228/184/80 101/186/82
+f 62/194/89 224/188/84 228/184/80
+f 224/188/84 81/193/88 222/197/92
+f 229/183/79 221/182/78 80/198/93
+f 157/199/17 229/183/79 219/178/74
+f 157/199/17 18/277/16 130/181/77
+f 154/201/95 230/180/76 220/179/75
+f 117/77/52 230/180/76 154/201/95
+f 61/200/94 219/178/74 230/180/76
+f 231/177/73 97/176/72 13/203/97
+f 58/204/66 220/207/75 231/205/73
+f 220/207/75 80/307/93 218/208/71
+f 232/174/1 217/173/1 79/209/1
+f 153/29/1 232/174/1 215/169/1
+f 19/211/1 131/172/1 232/174/1
+f 233/171/1 216/170/1 54/212/1
+f 113/104/1 233/171/1 150/127/1
+f 57/210/1 215/169/1 233/171/1
+f 234/168/1 104/167/1 20/214/1
+f 216/170/1 234/168/1 110/22/1
+f 79/209/1 214/166/1 234/168/1
+f 235/165/1 213/164/1 78/215/1
+f 149/20/1 235/165/1 211/160/1
+f 16/217/1 128/163/1 235/165/1
+f 236/162/1 212/161/1 50/218/1
+f 109/131/1 236/162/1 146/154/1
+f 53/216/1 211/160/1 236/162/1
+f 237/159/1 105/158/1 21/220/98
+f 212/161/1 237/159/1 106/13/1
+f 78/215/1 210/157/1 237/159/1
+f 238/156/1 209/155/1 77/221/1
+f 148/17/1 238/156/1 207/151/1
+f 22/219/1 146/154/1 238/156/1
+f 239/153/1 208/152/1 35/223/1
+f 108/140/1 239/153/1 131/172/1
+f 52/222/1 207/151/1 239/153/1
+f 240/148/68 93/150/70 9/224/99
+f 208/152/1 240/148/68 91/7/6
+f 77/221/1 206/303/116 240/148/68
+f 241/147/1 205/146/1 76/225/1
+f 95/226/1 241/147/1 203/142/1
+f 11/228/1 147/145/1 241/147/1
+f 242/144/1 204/143/1 47/229/1
+f 135/230/1 242/144/1 143/109/1
+f 39/227/1 203/142/1 242/144/1
+f 243/141/1 108/140/1 19/211/1
+f 204/143/1 243/141/1 103/28/1
+f 76/225/1 202/139/1 243/141/1
+f 244/138/1 201/137/1 75/232/1
+f 83/233/1 244/138/1 199/133/1
+f 2/235/1 140/136/1 244/138/1
+f 245/135/1 200/134/1 51/236/1
+f 123/237/1 245/135/1 147/145/1
+f 27/234/1 199/133/1 245/135/1
+f 246/132/1 109/131/1 22/219/1
+f 200/134/1 246/132/1 107/16/1
+f 75/232/1 198/130/1 246/132/1
+f 247/129/1 197/128/1 74/238/1
+f 152/26/1 247/129/1 195/124/1
+f 23/213/1 150/127/1 247/129/1
+f 248/126/1 196/125/1 38/240/1
+f 112/113/1 248/126/1 94/241/1
+f 56/239/1 195/124/1 248/126/1
+f 249/123/1 92/122/1 5/243/1
+f 196/125/1 249/123/1 134/244/1
+f 74/238/1 194/121/1 249/123/1
+f 250/120/1 193/119/1 73/245/1
+f 99/246/1 250/120/1 191/115/1
+f 15/248/1 151/118/1 250/120/1
+f 251/117/1 192/116/1 26/249/1
+f 139/251/1 251/117/1 82/250/1
+f 43/247/1 191/115/1 251/117/1
+f 252/114/1 112/113/1 10/242/1
+f 192/116/1 252/114/1 122/253/1
+f 73/245/1 190/112/1 252/114/1
+f 253/111/1 189/110/1 72/254/1
+f 87/255/1 253/111/1 187/106/1
+f 6/231/1 143/109/1 253/111/1
+f 254/108/1 188/107/1 55/257/1
+f 127/258/1 254/108/1 151/118/1
+f 31/256/1 187/106/1 254/108/1
+f 255/105/1 113/104/1 23/213/1
+f 188/107/1 255/105/1 111/25/1
+f 72/254/1 186/103/1 255/105/1
+f 183/259/100 256/100/65 185/102/67
+f 156/35/13 256/100/65 183/259/100
+f 24/202/96 154/201/95 256/100/65
+f 257/97/62 184/99/64 42/261/1
+f 116/86/60 257/97/62 98/262/1
+f 60/260/101 183/259/100 257/97/62
+f 258/96/1 85/95/1 3/264/1
+f 184/99/64 258/96/1 138/265/1
+f 184/99/64 71/98/63 182/94/61
+f 259/93/1 181/92/1 70/266/1
+f 132/23/1 259/93/1 179/88/1
+f 20/214/1 155/91/1 259/93/1
+f 260/90/1 180/89/1 30/268/1
+f 92/122/1 260/90/1 86/269/1
+f 36/267/1 179/88/1 260/90/1
+f 261/87/1 116/86/60 14/263/1
+f 180/89/1 261/87/1 126/270/1
+f 70/266/1 178/85/59 261/87/1
+f 262/84/58 177/83/57 69/271/102
+f 144/8/7 262/84/58 175/79/54
+f 9/224/99 142/82/56 262/84/58
+f 263/81/1 176/80/55 59/273/103
+f 104/167/1 263/81/1 155/91/1
+f 48/272/1 175/79/54 263/81/1
+f 115/34/12 264/78/53 117/77/52
+f 59/273/103 176/80/55 264/78/53
+f 69/271/102 174/76/51 264/78/53
+f 265/75/50 173/74/49 68/274/104
+f 64/275/105 160/44/22 265/75/50
+f 160/44/22 25/195/90 158/73/48
+f 266/72/47 172/71/46 34/276/106
+f 18/277/16 120/59/34 266/72/47
+f 120/59/34 64/275/105 171/70/45
+f 267/69/44 89/68/43 8/278/107
+f 172/279/46 267/283/44 90/280/3
+f 68/282/104 170/297/42 267/283/44
+f 268/64/39 169/66/41 67/62/37
+f 37/149/69 133/14/8 268/64/39
+f 133/14/8 21/220/98 159/285/109
+f 142/82/56 269/61/36 168/63/38
+f 93/150/70 269/61/36 142/82/56
+f 37/149/69 167/284/108 269/61/36
+f 270/287/35 120/312/34 18/38/16
+f 46/286/110 168/63/38 270/60/35
+f 67/62/37 166/58/33 270/60/35
+f 271/57/1 165/56/32 66/290/112
+f 145/11/1 271/57/1 163/52/1
+f 7/292/1 136/55/1 271/57/1
+f 159/285/109 272/54/31 164/53/30
+f 21/220/98 105/158/1 272/54/31
+f 49/291/1 163/52/1 272/54/31
+f 119/43/21 273/49/27 121/51/29
+f 63/65/40 164/53/30 273/49/27
+f 66/290/112 162/293/113 273/49/27
+f 162/293/113 274/46/24 161/48/26
+f 165/56/32 274/46/24 162/293/113
+f 165/56/32 40/311/1 96/294/114
+f 166/58/33 275/45/23 160/44/22
+f 169/66/41 275/45/23 166/58/33
+f 169/66/41 63/65/40 119/43/21
+f 276/40/18 129/42/20 33/295/115
+f 173/296/49 276/313/18 170/297/42
+f 62/194/89 118/196/91 276/40/18
+f 277/37/15 157/39/17 61/298/94
+f 177/83/57 277/300/15 174/76/51
+f 177/83/57 46/286/110 102/289/111
+f 278/36/14 156/35/13 60/260/101
+f 181/92/1 278/36/14 178/85/59
+f 59/273/103 115/34/12 278/36/14
+f 279/33/11 125/32/10 29/301/1
+f 71/98/63 185/102/67 279/33/11
+f 185/102/67 58/101/66 114/31/9
+f 280/30/1 153/29/1 57/210/1
+f 189/110/1 280/30/1 186/103/1
+f 47/229/1 103/28/1 280/30/1
+f 281/27/1 152/26/1 56/239/1
+f 193/119/1 281/27/1 190/112/1
+f 55/257/1 111/25/1 281/27/1
+f 282/24/1 132/23/1 36/267/1
+f 197/128/1 282/24/1 194/121/1
+f 54/212/1 110/22/1 282/24/1
+f 283/21/1 149/20/1 53/216/1
+f 201/137/1 283/21/1 198/130/1
+f 44/302/1 100/19/1 283/21/1
+f 284/18/1 148/17/1 52/222/1
+f 205/146/1 284/18/1 202/139/1
+f 51/236/1 107/16/1 284/18/1
+f 206/303/116 285/15/1 133/14/8
+f 209/155/1 285/15/1 206/303/116
+f 50/218/1 106/13/1 285/15/1
+f 286/12/1 145/11/1 49/291/1
+f 213/164/1 286/12/1 210/157/1
+f 32/304/1 88/10/1 286/12/1
+f 287/9/1 144/8/7 48/272/1
+f 217/173/1 287/9/1 214/166/1
+f 35/223/1 91/7/6 287/9/1
+f 218/175/71 288/6/5 137/5/4
+f 221/306/78 288/308/5 218/208/71
+f 34/281/106 90/280/3 288/308/5
+f 289/3/2 141/2/1 45/185/81
+f 81/193/88 225/191/86 289/3/2
+f 28/309/1 84/1/1 289/3/2
diff --git a/data/levels/cemetery/graveyard_terrain.wmb b/data/levels/cemetery/graveyard_terrain.wmb
new file mode 100644
index 0000000..0b0b25e
Binary files /dev/null and b/data/levels/cemetery/graveyard_terrain.wmb differ
diff --git a/data/levels/test/test.xml b/data/levels/test/test.xml
index b2a7dcd..7588553 100644
--- a/data/levels/test/test.xml
+++ b/data/levels/test/test.xml
@@ -5,10 +5,7 @@
-
-
-
-
+
diff --git a/data/scripts/actors/actor_player.lua b/data/scripts/actors/actor_player.lua
new file mode 100644
index 0000000..314654d
--- /dev/null
+++ b/data/scripts/actors/actor_player.lua
@@ -0,0 +1,40 @@
+-- базовый класс актора
+actor_base = inherit_table(game_object)
+
+-- инициализация FSM
+
+
+function actor_base:on_init()
+ game_object.on_init(self)
+end
+
+function actor_base:on_shutdown()
+ game_object.on_shutdown(self)
+end
+
+function actor_base:on_update(dt)
+ game_object.on_update(self, dt)
+end
+
+-- игрок
+actor_player = inherit_table(actor_base)
+
+function actor_player:on_init()
+ actor_base.on_init(self)
+
+ self:create_body()
+
+ self:activate_camera()
+end
+
+function actor_player:on_shutdown()
+ actor_base.on_shutdown(self)
+end
+
+function actor_player:on_update(dt)
+ actor_base.on_update(self, dt)
+
+ self:update_camera_look()
+ --self:update_camera_movement(dt)
+ self:update_body_movement(dt)
+end
\ No newline at end of file
diff --git a/data/scripts/game_init.lua b/data/scripts/game_init.lua
index cfd0924..abb819c 100644
--- a/data/scripts/game_init.lua
+++ b/data/scripts/game_init.lua
@@ -1,13 +1,19 @@
-- Game initialization script
-- загружаем скрипты
+load_script("game_utils.lua")
load_script("game_object.lua")
+load_script("test_object.lua")
+load_script("actors/actor_player.lua")
-- глобальная таблица сущностей
g_entity_table = {
- -- Lua class -- CPP class -- Description
+ -- Lua class -- CPP class -- Description
- { "game_object", "Entity", "Test Lua Entity" }
+ { "actor_player", "ActorBase", "Player entity" },
+
+ -- Simple entity
+ { "test_object", "Entity", "Test entity" },
}
\ No newline at end of file
diff --git a/data/scripts/game_utils.lua b/data/scripts/game_utils.lua
new file mode 100644
index 0000000..12cf69b
--- /dev/null
+++ b/data/scripts/game_utils.lua
@@ -0,0 +1,18 @@
+-- http://lua-users.org/wiki/InheritanceTutorial
+
+function merge_table( baseClass, newClass )
+ for k, v in pairs( baseClass ) do
+ if type( v ) == "table" then
+ newClass[ k ] = newClass[ k ] or {}
+ merge_table( v, newClass[ k ] )
+ else
+ newClass[ k ] = v
+ end
+ end
+end
+
+function inherit_table( baseClass )
+ local newClass = {}
+ merge_table( baseClass, newClass )
+ return newClass
+end
\ No newline at end of file
diff --git a/data/scripts/test_object.lua b/data/scripts/test_object.lua
new file mode 100644
index 0000000..464cbb6
--- /dev/null
+++ b/data/scripts/test_object.lua
@@ -0,0 +1,16 @@
+-- тестовый класс
+test_object = inherit_table(game_object)
+
+function test_object:on_init()
+ game_object.on_init(self)
+
+ self:load_model("data/models/scene_walls.obj")
+
+ self.m_test = 0.0
+end
+
+function test_object:on_update(dt)
+ game_object.on_update(self, dt)
+ self:set_position(self.m_test, 0.0, 0.0)
+ self.m_test = self.m_test + ( 0.2 * dt )
+end
\ No newline at end of file
diff --git a/data/shaders/lit_generic.ps b/data/shaders/lit_generic.ps
index 3f0299f..4a7e044 100644
--- a/data/shaders/lit_generic.ps
+++ b/data/shaders/lit_generic.ps
@@ -5,14 +5,26 @@ varying vec3 v_normal;
varying vec2 v_texcoord;
varying vec3 v_finalColor;
-uniform sampler2D u_albedoTexture;
uniform vec4 u_customColor;
+uniform vec4 u_sunAmbientColor;
+
+uniform sampler2D u_albedoTexture;
void main() {
//gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
//gl_FragColor = u_customColor * vec4(v_finalColor, 1.0) * texture2D(u_albedoTexture, v_texcoord);
//gl_FragColor = vec4(v_finalColor, 1.0) * texture2D(u_albedoTexture, v_texcoord);
- gl_FragColor = texture2D(u_albedoTexture, v_texcoord);
+ //gl_FragColor = texture2D(u_albedoTexture, v_texcoord);
//gl_FragColor = vec4( v_normal, 1.0 );
//gl_FragColor = texture2D(u_albedoTexture, v_texcoord);
+
+ // !!! NO AREF
+
+// vec3 color = texture2D(u_albedoTexture, v_texcoord).rgb * v_finalColor;
+
+ vec3 color = texture2D(u_albedoTexture, v_texcoord).rgb;
+ color = color * ( u_sunAmbientColor.rgb + v_finalColor.x );
+ color = color + v_finalColor.y;
+
+ gl_FragColor = vec4(color.x, color.y, color.z, 1.0);
}
\ No newline at end of file
diff --git a/data/shaders/lit_generic.vs b/data/shaders/lit_generic.vs
index 6b1ca53..f6bc675 100644
--- a/data/shaders/lit_generic.vs
+++ b/data/shaders/lit_generic.vs
@@ -13,34 +13,41 @@ uniform mat4 u_modelMatrix;
uniform mat4 u_viewMatrix;
uniform mat4 u_projectionMatrix;
uniform mat4 u_modelViewProjection;
+uniform vec4 u_sunDirection;
+uniform vec4 u_sunColor;
+uniform vec4 u_sunAmbientColor;
+uniform vec4 u_cameraPos;
-vec3 CalcOmniLight()
-{
- vec3 lightPos = vec3(0.1, 2.1, 0.1);
- float d = distance(lightPos, v_position);
- vec3 L = normalize(lightPos-v_position);
- vec3 N = normalize(v_normal);
- vec3 col = vec3( max(0, dot(N, L) / d) );
- col = col * 0.8 + 0.2;
- return col;
-}
+// #TODO: should use own uniforms
+#define u_ligthPosition u_sunDirection.xyz
+#define u_ligthRadius u_sunDirection.w
-vec3 CalcDirLight()
-{
- vec3 lightPos = vec3(5.0, 10.0, 1.0);
- //lightPos = -lightPos;
+// Calculate blinn-phong per-vertex lighting
+float CalcPhongLighting( vec3 worldPos, vec3 normal, vec3 lightPos ) {
+ vec3 lightDir = normalize( lightPos - worldPos );
+ vec3 viewDir = normalize( u_cameraPos.xyz - worldPos );
+ vec3 halfVec = normalize( lightDir + viewDir );
+
+ float diff = max( dot( normal, lightDir ), 0.0 );
- vec3 L = normalize(lightPos);
- vec3 N = normalize(v_normal);
- vec3 col = vec3( max(0, dot(N, L)) );
- col = col * 0.8 + 0.2;
- return col;
+ v_finalColor.x = diff;
+
+ float spec = pow( max( dot( normal, halfVec ), 0.0 ), 128.0 ) * 1.0;
+
+ v_finalColor.y = spec;
+
+ return diff + spec;
}
void main() {
v_position = vec3( u_modelMatrix * vec4(a_position, 1.0) );
v_normal = vec3( mat3(u_modelMatrix) * a_normal );
v_texcoord = a_texcoord;
- v_finalColor = CalcDirLight();
+
+ CalcPhongLighting( v_position, v_normal, u_ligthPosition );
+
+ //v_finalColor = u_sunAmbientColor.rgb + CalcPhongLighting( v_position, v_normal, u_ligthPosition );
+
+
gl_Position = u_modelViewProjection * vec4(a_position, 1);
}
\ No newline at end of file
diff --git a/data/shaders/unlit_generic.ps b/data/shaders/unlit_generic.ps
new file mode 100644
index 0000000..3f0299f
--- /dev/null
+++ b/data/shaders/unlit_generic.ps
@@ -0,0 +1,18 @@
+#version 120
+
+varying vec3 v_position;
+varying vec3 v_normal;
+varying vec2 v_texcoord;
+varying vec3 v_finalColor;
+
+uniform sampler2D u_albedoTexture;
+uniform vec4 u_customColor;
+
+void main() {
+ //gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
+ //gl_FragColor = u_customColor * vec4(v_finalColor, 1.0) * texture2D(u_albedoTexture, v_texcoord);
+ //gl_FragColor = vec4(v_finalColor, 1.0) * texture2D(u_albedoTexture, v_texcoord);
+ gl_FragColor = texture2D(u_albedoTexture, v_texcoord);
+ //gl_FragColor = vec4( v_normal, 1.0 );
+ //gl_FragColor = texture2D(u_albedoTexture, v_texcoord);
+}
\ No newline at end of file
diff --git a/data/shaders/unlit_generic.vs b/data/shaders/unlit_generic.vs
new file mode 100644
index 0000000..6b1ca53
--- /dev/null
+++ b/data/shaders/unlit_generic.vs
@@ -0,0 +1,46 @@
+#version 120
+
+attribute vec3 a_position;
+attribute vec3 a_normal;
+attribute vec2 a_texcoord;
+
+varying vec3 v_position;
+varying vec3 v_normal;
+varying vec2 v_texcoord;
+varying vec3 v_finalColor;
+
+uniform mat4 u_modelMatrix;
+uniform mat4 u_viewMatrix;
+uniform mat4 u_projectionMatrix;
+uniform mat4 u_modelViewProjection;
+
+vec3 CalcOmniLight()
+{
+ vec3 lightPos = vec3(0.1, 2.1, 0.1);
+ float d = distance(lightPos, v_position);
+ vec3 L = normalize(lightPos-v_position);
+ vec3 N = normalize(v_normal);
+ vec3 col = vec3( max(0, dot(N, L) / d) );
+ col = col * 0.8 + 0.2;
+ return col;
+}
+
+vec3 CalcDirLight()
+{
+ vec3 lightPos = vec3(5.0, 10.0, 1.0);
+ //lightPos = -lightPos;
+
+ vec3 L = normalize(lightPos);
+ vec3 N = normalize(v_normal);
+ vec3 col = vec3( max(0, dot(N, L)) );
+ col = col * 0.8 + 0.2;
+ return col;
+}
+
+void main() {
+ v_position = vec3( u_modelMatrix * vec4(a_position, 1.0) );
+ v_normal = vec3( mat3(u_modelMatrix) * a_normal );
+ v_texcoord = a_texcoord;
+ v_finalColor = CalcDirLight();
+ gl_Position = u_modelViewProjection * vec4(a_position, 1);
+}
\ No newline at end of file
diff --git a/data/textures/scenes/cemetery/grass_01.png b/data/textures/scenes/cemetery/grass_01.png
new file mode 100644
index 0000000..4d6dbad
Binary files /dev/null and b/data/textures/scenes/cemetery/grass_01.png differ
diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp
index 4bed262..8d388aa 100644
--- a/src/engine/engine.cpp
+++ b/src/engine/engine.cpp
@@ -8,6 +8,7 @@
#include "world.h"
#include "camera.h"
#include "inputmanager.h"
+#include "physics/physicsworld.h"
// renderer
#include "render.h"
@@ -221,6 +222,10 @@ void Engine::Frame()
// *** ImGui scope begin
g_ImGuiManager.BeginFrame();
+ // update physics
+ if (g_PhysicsWorld)
+ g_PhysicsWorld->Step(dt);
+
// update entities
if (g_world)
g_world->Update(dt);
@@ -300,6 +305,9 @@ void Engine::NewGame(const char* mapname)
// create entity container
Disconnect();
+ g_PhysicsWorld = new PhysicsWorld();
+ //g_PhysicsWorld->ToggleDebugDraw();
+
g_world = new World();
g_render->LoadSceneXML(mapname);
@@ -316,6 +324,11 @@ void Engine::Disconnect()
delete g_world;
g_world = nullptr;
}
+
+ if (g_PhysicsWorld) {
+ delete g_PhysicsWorld;
+ g_PhysicsWorld = nullptr;
+ }
}
SDL_Window* Engine::GetWindow()
diff --git a/src/engine/ientity.cpp b/src/engine/ientity.cpp
index f3558b7..72e1cb0 100644
--- a/src/engine/ientity.cpp
+++ b/src/engine/ientity.cpp
@@ -23,6 +23,11 @@ void IEntityBase::Render()
{
}
+void IEntityBase::SetPosition(const glm::vec3& pos)
+{
+ m_position = pos;
+}
+
const glm::mat4& IEntityBase::GetWorldTransform()
{
return m_worldTM;
diff --git a/src/engine/ientity.h b/src/engine/ientity.h
index 19cb03d..a4ada9e 100644
--- a/src/engine/ientity.h
+++ b/src/engine/ientity.h
@@ -17,6 +17,8 @@ public:
const BoundingBox& GetBoundingBox() { return m_boundingBox; }
+ void SetPosition(const glm::vec3& pos);
+
const glm::mat4& GetWorldTransform();
void UpdateTransform();
diff --git a/src/engine/physics/physicsworld.cpp b/src/engine/physics/physicsworld.cpp
index 66a4d5e..56674ad 100644
--- a/src/engine/physics/physicsworld.cpp
+++ b/src/engine/physics/physicsworld.cpp
@@ -1,4 +1,5 @@
#include "engine/core.h"
+#include "engine/log.h"
#include "engine/engine.h"
#include "engine/camera.h"
#include "engine/physics/physicsworld.h"
@@ -10,6 +11,8 @@
#include
#include
+PhysicsWorld* g_PhysicsWorld = nullptr;
+
static void InternalTickCallback(btDynamicsWorld* world, btScalar timeStep)
{
SDL_assert(world);
@@ -88,9 +91,9 @@ const std::vector& PhysicsWorld::GetRigidBodies()
void PhysicsWorld::Step(float delta)
{
- // m_world->stepSimulation(delta);
+ m_world->stepSimulation(delta);
// m_world->stepSimulation(delta, 12, m_stepTime);
-#if 1
+#if 0
if (delta < 0.01f)
{
m_accumulatedTime += delta;
@@ -178,3 +181,100 @@ void PhysicsWorld::InternalTick()
}
}
+void PhysicsWorld::AddCollisionModel(StaticMeshVertex* vertices, size_t verticesCount, uint32_t* indices, size_t indicesCount)
+{
+ int index = (int)m_collisionModels.size();
+ m_collisionModels.resize((size_t)index + 1);
+
+ // Check for is indices are 32 bits
+ bool is32Bits = true;// sizeof(index_t) == sizeof(uint32_t);
+
+ m_collisionModels[index].triangleMesh = new btTriangleMesh(is32Bits);
+ m_collisionModels[index].triangleMesh->preallocateVertices((int)verticesCount);
+ m_collisionModels[index].triangleMesh->preallocateIndices((int)indicesCount);
+
+ // Initialize triangle mesh
+ uint32_t trianglesCount = 0;
+ for (uint32_t n = 0; n < indicesCount; n += 3) {
+ m_collisionModels[index].triangleMesh->addTriangle(
+ glmVectorToBt(vertices[indices[n]].position),
+ glmVectorToBt(vertices[indices[n + 1]].position),
+ glmVectorToBt(vertices[indices[n + 2]].position),
+ true);
+
+ trianglesCount++;
+ }
+
+ // Create shape
+ m_collisionModels[index].shape = new btBvhTriangleMeshShape(m_collisionModels[index].triangleMesh, true);
+
+ // Create collision body
+ m_collisionModels[index].object = new btCollisionObject();
+ m_collisionModels[index].object->setCollisionShape(m_collisionModels[index].shape);
+ m_collisionModels[index].object->setUserPointer(&m_collisionModels[index]);
+
+ // Add to scene
+ m_world->addCollisionObject(m_collisionModels[index].object);
+
+ // Report
+ Msg("PhysicsSystem::AddCollisionModel: %i triangles %i bytes", trianglesCount, trianglesCount * sizeof(btVector3));
+}
+
+void PhysicsWorld::Reset()
+{
+ int numModels = (int)m_collisionModels.size();
+ for (int i = 0; i < numModels; i++)
+ {
+ if (m_collisionModels[i].object)
+ {
+ // remove object from world
+ m_world->removeCollisionObject(m_collisionModels[i].object);
+
+ // reset shape
+ m_collisionModels[i].object->setCollisionShape(nullptr);
+
+ // delete
+ delete m_collisionModels[i].object;
+ m_collisionModels[i].object = nullptr;
+ }
+
+ if (m_collisionModels[i].shape)
+ {
+ delete m_collisionModels[i].shape;
+ m_collisionModels[i].shape = nullptr;
+ }
+
+ if (m_collisionModels[i].triangleMesh)
+ {
+ delete m_collisionModels[i].triangleMesh;
+ m_collisionModels[i].triangleMesh = nullptr;
+ }
+ }
+
+ Msg("PhysicsSystem: Destroyed %d static collision models", numModels);
+
+ m_collisionModels.clear();
+}
+
+//
+ClosestRayResultCallback::ClosestRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, IEntityBase* entity) :
+ btCollisionWorld::ClosestRayResultCallback(rayFromWorld, rayToWorld),
+ m_entity(entity)
+{
+}
+
+ClosestRayResultCallback::~ClosestRayResultCallback()
+{
+ m_entity = nullptr;
+}
+
+bool ClosestRayResultCallback::needsCollision(btBroadphaseProxy* proxy0) const
+{
+ bool needsCollision = inherited::needsCollision(proxy0);
+
+ btCollisionObject* collisionObject = (btCollisionObject*)proxy0->m_clientObject;
+ if (m_entity && collisionObject->getUserPointer() == m_entity)
+ return false;
+
+ return needsCollision;
+}
\ No newline at end of file
diff --git a/src/engine/physics/physicsworld.h b/src/engine/physics/physicsworld.h
index be59581..6a335c0 100644
--- a/src/engine/physics/physicsworld.h
+++ b/src/engine/physics/physicsworld.h
@@ -6,7 +6,16 @@
#include
+struct StaticMeshVertex;
class RigidBody;
+class IEntityBase;
+
+struct SceneCollisionModel
+{
+ btCollisionObject* object;
+ btCollisionShape* shape;
+ btTriangleMesh* triangleMesh;
+};
class PhysicsWorld
{
@@ -29,8 +38,16 @@ public:
void InternalTick();
+ // Add static collision model.
+ void AddCollisionModel(StaticMeshVertex* vertices, size_t verticesCount,
+ uint32_t* indices, size_t indicesCount);
+
+ // Reset all collision models and dynamic bodies.
+ void Reset();
private:
+ std::vector m_collisionModels;
+
btDefaultCollisionConfiguration* m_collisionConfiguration;
btCollisionDispatcher* m_dispatcher;
btBroadphaseInterface* m_overlappingPairCache;
@@ -48,4 +65,20 @@ private:
bool m_debugDraw;
};
+class ClosestRayResultCallback : public btCollisionWorld::ClosestRayResultCallback
+{
+ typedef btCollisionWorld::ClosestRayResultCallback inherited;
+public:
+ ClosestRayResultCallback(const btVector3& rayFromWorld, const btVector3& rayToWorld, IEntityBase* entity);
+ ~ClosestRayResultCallback();
+
+ bool needsCollision(btBroadphaseProxy* proxy0) const override;
+
+private:
+ IEntityBase* m_entity;
+};
+
+
+extern PhysicsWorld* g_PhysicsWorld;
+
#endif // !PHYSICSWORLD_H
diff --git a/src/engine/world.cpp b/src/engine/world.cpp
index 60e2125..2ad2458 100644
--- a/src/engine/world.cpp
+++ b/src/engine/world.cpp
@@ -21,6 +21,9 @@ World::~World()
void World::DestroyWorld()
{
+ // Run destroyer
+ UpdateDestroyList();
+
for (int i = 0; i < m_entities.size(); ++i)
{
delete m_entities[i];
diff --git a/src/game/game.cpp b/src/game/game.cpp
index dbd74ce..97dcb26 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -30,21 +30,19 @@ void engineWarning(const char* msg)
LuaPlus::LuaObject engineCreateEntity(const char* classname)
{
- LuaPlus::LuaObject entityObject;
- entityObject.AssignNewTable(GetLuaState());
+ Entity* entity = static_cast(g_game->Lua_CreateEntity(classname));
+ SDL_assert_always(entity);
- //GameObject* entity = (GameObject*)g_entityManager->createEntity(classname);
- //entity->init_from_lua(entityObject);
- //entity->init();
-
- return entityObject;
+ return entity->GetLuaObject();
}
void engineAddEntityToWorld(LuaPlus::LuaObject& object)
{
- LuaPlus::LuaObject cppclass = object["__cpp_entity"];
+ LuaPlus::LuaObject cppclass = object["__object"];
+ SDL_assert_always(cppclass.IsLightUserdata());
- // todo
+ Entity* entity = static_cast(cppclass.GetLightUserdata());
+ g_world->AddEntity(entity);
}
void registerEngine()
@@ -108,6 +106,11 @@ void initializeEntityPrototypesFromLua()
prototype.m_description = description.ToString();
g_prototypes.push_back(prototype);
+ // get a prototype
+ LuaObject prototypeTable = GetLuaState().GetGlobal(luaname.ToString());
+ SDL_assert_always(!prototypeTable.IsNil());
+ prototypeTable.SetObject("__index", prototypeTable);
+
/*for (LuaTableIterator it2(entityTable); it2; it2.Next()) {
Logger::Msg("%s", it2.GetValue().ToString());
@@ -180,9 +183,9 @@ void Game::LoadLevelXML(const char* mapname)
// std::map properties;
- for (pugi::xml_node entity : doc.child("Level").child("Entities").children("Entity")) {
- pugi::xml_attribute entityname = entity.attribute("name");
- pugi::xml_attribute classname = entity.attribute("classname");
+ for (pugi::xml_node entitynode : doc.child("Level").child("Entities").children("Entity")) {
+ pugi::xml_attribute entityname = entitynode.attribute("name");
+ pugi::xml_attribute classname = entitynode.attribute("classname");
if (classname.empty()) {
if (!entityname.empty()) {
@@ -199,6 +202,16 @@ void Game::LoadLevelXML(const char* mapname)
if (!entity)
entity = g_entityManager->CreateEntity(classname.as_string());
+ pugi::xml_node position = entitynode.child("Position");
+ if (position)
+ {
+ float x = position.attribute("x").as_float();
+ float y = position.attribute("y").as_float();
+ float z = position.attribute("z").as_float();
+
+ entity->SetPosition(glm::vec3(x, y, z));
+ }
+
//IEntityBase* entity = g_entityManager->CreateEntity(classname.as_string());
g_world->AddEntity(entity);
}
@@ -235,7 +248,7 @@ IEntityBase* Game::Lua_CreateEntity(const char* classname)
// get a prototype
LuaObject prototype = GetLuaState().GetGlobal(pluaprototype->m_luaname.c_str());
SDL_assert_always(!prototype.IsNil());
- prototype.SetObject("__index", prototype);
+ //prototype.SetObject("__index", prototype);
// generate table
LuaObject factory = GetLuaState().GetGlobal("g_factory");
diff --git a/src/game/game_object.cpp b/src/game/game_object.cpp
index 5d33cb1..6342a1c 100644
--- a/src/game/game_object.cpp
+++ b/src/game/game_object.cpp
@@ -1,7 +1,19 @@
#include "inputmanager.h"
+#include "debugrender.h"
#include "game_object.h"
#include
+#define PLAYER_PHYS_MASS 80.0
+#define PLAYER_PHYS_RADIUS 0.40
+#define PLAYER_PHYS_HEIGHT 1.79
+#define PLAYER_PHYS_JUMPDIST PLAYER_PHYS_RADIUS
+#define PLAYER_PHYS_JUMPHEIGHT 2.0
+#define PLAYER_PHYS_JUMPSPEEDY 5.0
+#define PLAYER_PHYS_WALK_SPEED ( 5.5 )
+#define PLAYER_PHYS_RUN_SPEED_MUL 1.4
+#define PLAYER_PHYS_MOVE_SPEED_EXP 1.0
+#define PLAYER_PHYS_FLY_SPEED_EXP 4.0
+
// Lua wrappers
void Entity_LoadModel(LuaPlus::LuaState* state)
{
@@ -11,6 +23,46 @@ void Entity_LoadModel(LuaPlus::LuaState* state)
entity->LoadModel(stack[2].GetString());
}
+void Entity_SetVisible(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata();
+ entity->SetVisible(stack[2].GetBoolean());
+}
+
+bool Entity_GetVisible(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ Entity* entity = (Entity*)stack[1].GetByName("__object").GetLightUserdata();
+ return entity->GetVisible();
+}
+
+void ActorBase_UpdateCameraMovement(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata();
+ entity->UpdateCameraMovement(stack[2].GetFloat());
+}
+
+void ActorBase_UpdateCameraLook(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata();
+ entity->UpdateCameraLook();
+}
+
+void ActorBase_ActivateCamera(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ ActorBase* entity = (ActorBase*)stack[1].GetByName("__object").GetLightUserdata();
+ entity->ActivateCamera();
+}
+
REGISTER_ENTITY(Entity);
Entity::Entity() :
@@ -44,14 +96,31 @@ void Entity::Update(float dt)
if ( m_onUpdateFunction.IsFunction())
{
LuaPlus::LuaFunctionVoid function = m_onUpdateFunction;
- function(m_luaObject, dt);
+ function(m_luaObject, static_cast(dt));
}
}
void Entity::Render()
{
if (m_model)
+ {
m_model->Draw(GetWorldTransform());
+
+ BoundingBox bbox = m_model->GetBoundingBox();
+ bbox.TransformAABB(GetWorldTransform());
+
+ g_debugRender->DrawBoundingBox(bbox, glm::vec3(1.0f, 0.0f, 0.0f));
+ }
+}
+
+const std::string& Entity::GetName()
+{
+ return m_name;
+}
+
+void Entity::SetName(const std::string& name)
+{
+ m_name = name;
}
void Entity::LoadModel(const char* filename)
@@ -83,10 +152,11 @@ void Entity::InitFromTable(LuaPlus::LuaObject& _object)
// check
SDL_assert_always(m_onInitFunction.IsFunction() || m_onShutdownFunction.IsFunction() || m_onUpdateFunction.IsFunction());
+ // register base entity functions
+ RegisterBaseFunctions();
+
// register entity functions
- m_luaObject.RegisterDirect("load_model", &Entity_LoadModel);
- //m_luaObject.RegisterDirect("set_visible", &Entity::SetVisible);
- //m_luaObject.RegisterDirect("get_visible", &Entity::GetVisible);
+ RegisterFunctions();
// assign C++ object
m_luaObject.SetLightUserdata("__object", this);
@@ -96,29 +166,141 @@ void Entity::InitFromTable(LuaPlus::LuaObject& _object)
onInitFunction(m_luaObject);
}
-REGISTER_ENTITY(TempPlayer);
+void Entity::RegisterBaseFunctions()
+{
+ m_luaObject.Register("load_model", *this, &Entity::Lua_LoadModel);
+ m_luaObject.Register("translate", *this, &Entity::Lua_Translate);
+ m_luaObject.Register("set_position", *this, &Entity::Lua_SetPosition);
-TempPlayer::TempPlayer()
+// m_luaObject.RegisterDirect("load_model", &Entity_LoadModel);
+ //m_luaObject.RegisterDirect("set_visible", &Entity_SetVisible);
+ //m_luaObject.RegisterDirect("get_visible", &Entity_GetVisible);
+}
+
+void Entity::RegisterFunctions()
{
}
-TempPlayer::~TempPlayer()
+void Entity::Help_Translate(float x, float y, float z)
+{
+ m_position.x += x;
+ m_position.y += y;
+ m_position.z += z;
+}
+
+void Entity::Help_SetPosition(float x, float y, float z)
+{
+ m_position.x = x;
+ m_position.y = y;
+ m_position.z = z;
+}
+
+int Entity::Lua_LoadModel(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ if (stack.Count() > 1)
+ {
+ LoadModel(stack[2].GetString());
+ }
+ else
+ {
+ LoadModel(stack[1].GetString());
+ }
+
+ return 0;
+}
+
+int Entity::Lua_Translate(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ float x = stack[2].GetNumber();
+ float y = stack[3].GetNumber();
+ float z = stack[4].GetNumber();
+
+ Help_Translate(x, y, z);
+
+ return 0;
+}
+
+int Entity::Lua_SetPosition(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ float x = stack[2].GetNumber();
+ float y = stack[3].GetNumber();
+ float z = stack[4].GetNumber();
+
+ Help_SetPosition(x, y, z);
+
+ return 0;
+}
+
+const LuaPlus::LuaObject& Entity::GetLuaObject()
+{
+ return m_luaObject;
+}
+
+REGISTER_ENTITY(ActorBase);
+
+ActorBase::ActorBase() :
+ m_shape(nullptr),
+ m_rigidBody(nullptr),
+ m_bodyDirty(false)
{
}
-void TempPlayer::Update(float dt)
+ActorBase::~ActorBase()
{
- g_cameraManager.SetActiveCamera(&m_camera);
+ if (m_rigidBody) {
+ g_PhysicsWorld->GetWorld()->removeRigidBody(m_rigidBody);
- UpdateCameraLook();
+ delete m_rigidBody;
+ m_rigidBody = nullptr;
- UpdateCameraMovement(dt);
+ m_ph_motion_state.setBody(nullptr);
+ }
+
+ if (m_shape) {
+ delete m_shape;
+ m_shape = nullptr;
+ }
}
-void TempPlayer::UpdateCameraMovement(float dt)
+void ActorBase::Update(float dt)
+{
+ static bool s_test = true;
+
+ if (s_test) {
+ UpdateBody();
+ Entity::Update(dt);
+ AfterEngineStep();
+ } else {
+ ActivateCamera();
+
+ UpdateCameraLook();
+
+ UpdateCameraMovement(dt);
+
+ }
+
+ return;
+}
+
+void ActorBase::AfterEngineStep()
+{
+ //btTransform xform = m_rigidBody->getWorldTransform();
+ //m_position = btVectorToGlm(xform.getOrigin());
+
+ m_position = btVectorToGlm(m_ph_motion_state.m_transform.getOrigin());
+ m_camera.SetPosition(m_position);
+}
+
+void ActorBase::UpdateCameraMovement(float dt)
{
// calculate player movement
- float speed = 19.0f * dt;
+ float speed = 12.0f * dt;
uint32_t movementDir = GenMovementDir();
@@ -135,10 +317,41 @@ void TempPlayer::UpdateCameraMovement(float dt)
m_camera.SetPosition(m_position);
}
-void TempPlayer::UpdateCameraLook()
+void ActorBase::UpdateBodyMovement(float dt)
{
- g_inputManager.SetRelativeMouseMode(true);
+ glm::vec3 dir = glm::vec3(0.0f);
+
+ glm::vec3 camFront = m_camera.GetFront();
+ camFront.y = 0.0f;
+ camFront = glm::normalize(camFront);
+
+ // calculate player movement
+ float speed = 4.f;
+
+ uint32_t movementDir = GenMovementDir();
+
+ if (movementDir & EMovementDir_Forward)
+ dir += camFront;
+ if (movementDir & EMovementDir_Backward)
+ dir -= camFront;
+ if (movementDir & EMovementDir_Left)
+ dir -= glm::normalize(glm::cross(camFront, m_camera.GetUp()));
+ if (movementDir & EMovementDir_Right)
+ dir += glm::normalize(glm::cross(camFront, m_camera.GetUp()));
+
+ glm::vec3 velocity = dir * speed;
+
+ if (glm::length(velocity) > 0.1f && OnGround() && !(movementDir & EMovementDir_Jump))
+ m_rigidBody->setLinearVelocity(glmVectorToBt(velocity));
+
+ if ((movementDir & EMovementDir_Jump) && OnGround()) {
+ m_rigidBody->applyCentralImpulse(btVector3(0.0f, PLAYER_PHYS_JUMPSPEEDY*25, 0.0f));
+ }
+}
+
+void ActorBase::UpdateCameraLook()
+{
glm::ivec2 mousePos = g_inputManager.GetMousePos();
// calculate yaw and pitch
@@ -158,7 +371,132 @@ void TempPlayer::UpdateCameraLook()
m_camera.SetYawPitch(yaw, pitch);
}
-uint32_t TempPlayer::GenMovementDir()
+void ActorBase::UpdateBody()
+{
+ if (m_bodyDirty)
+ {
+ btTransform xform;
+ xform.setIdentity();
+ xform.setOrigin(glmVectorToBt(m_position));
+ m_rigidBody->setWorldTransform(xform);
+
+ m_bodyDirty = false;
+ }
+}
+
+void ActorBase::ActivateCamera()
+{
+ g_inputManager.SetRelativeMouseMode(true);
+
+ g_cameraManager.SetActiveCamera(&m_camera);
+}
+
+void ActorBase::CreateBody()
+{
+
+ m_shape = new btCapsuleShape(PLAYER_PHYS_RADIUS, PLAYER_PHYS_HEIGHT - PLAYER_PHYS_RADIUS * 2.0);
+
+ m_mass = 80.0f;
+ btVector3 local_inertia(0.0f, 0.0f, 0.0f);
+ if (m_mass > 0.f) {
+ m_shape->calculateLocalInertia(m_mass, local_inertia);
+ }
+
+ btRigidBody::btRigidBodyConstructionInfo rigid_body_ci(m_mass, nullptr, m_shape, local_inertia);
+
+ m_rigidBody = new btRigidBody(rigid_body_ci);
+ m_rigidBody->setUserPointer(this);
+ m_rigidBody->setMotionState(&m_ph_motion_state);
+ m_ph_motion_state.setBody(m_rigidBody);
+
+ // I'm sure that position is valid
+ btTransform xform;
+ xform.setIdentity();
+ xform.setOrigin(glmVectorToBt(m_position));
+ m_rigidBody->setWorldTransform(xform);
+
+ // ACTOR STUFF
+ m_rigidBody->setAngularFactor(btVector3(0.0f, 0.0f, 0.0f));
+ m_rigidBody->setFriction(2.5f);
+ m_rigidBody->setActivationState(DISABLE_DEACTIVATION);
+
+ // #TODO: body filter and mask
+ g_PhysicsWorld->GetWorld()->addRigidBody(m_rigidBody);
+
+ m_bodyDirty = true;
+}
+
+bool ActorBase::OnGround()
+{
+ float rayLength = (PLAYER_PHYS_HEIGHT / 2.0f) + 0.1f;
+
+ btTransform xform = m_rigidBody->getWorldTransform();
+
+ btVector3 rayStart = xform.getOrigin();
+ btVector3 rayEnd = rayStart - btVector3(0.0f, rayLength, 0.0f);
+
+ ClosestRayResultCallback RayResultCallback(rayStart, rayEnd, this);
+ g_PhysicsWorld->GetWorld()->rayTest(rayStart, rayEnd, RayResultCallback);
+ if (RayResultCallback.hasHit()) {
+ btVector3 hitNormal = RayResultCallback.m_hitNormalWorld;
+ if (hitNormal.y() > 0.7f) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+void ActorBase::RegisterFunctions()
+{
+ m_luaObject.Register("activate_camera", *this, &ActorBase::Lua_ActivateCamera);
+ m_luaObject.Register("update_camera_look", *this, &ActorBase::Lua_UpdateCameraLook);
+ m_luaObject.Register("update_camera_movement", *this, &ActorBase::Lua_UpdateCameraMovement);
+ m_luaObject.Register("create_body", *this, &ActorBase::Lua_CreateBody);
+ m_luaObject.Register("update_body_movement", *this, &ActorBase::Lua_UpdateBodyMovement);
+
+ //m_luaObject.RegisterDirect("activate_camera", &ActorBase_ActivateCamera);
+ //m_luaObject.RegisterDirect("update_camera_look", &ActorBase_UpdateCameraLook);
+ //m_luaObject.RegisterDirect("update_camera_movement", &ActorBase_UpdateCameraMovement);
+}
+
+int ActorBase::Lua_UpdateCameraMovement(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ UpdateCameraMovement(stack[2].GetFloat());
+
+ return 0;
+}
+
+int ActorBase::Lua_UpdateBodyMovement(LuaPlus::LuaState* state)
+{
+ LuaPlus::LuaStack stack(state);
+
+ UpdateBodyMovement(stack[2].GetFloat());
+
+ return 0;
+}
+
+int ActorBase::Lua_UpdateCameraLook(LuaPlus::LuaState* state)
+{
+ UpdateCameraLook();
+ return 0;
+}
+
+int ActorBase::Lua_ActivateCamera(LuaPlus::LuaState* state)
+{
+ ActivateCamera();
+ return 0;
+}
+
+int ActorBase::Lua_CreateBody(LuaPlus::LuaState* state)
+{
+ CreateBody();
+ return 0;
+}
+
+uint32_t ActorBase::GenMovementDir()
{
uint32_t movementDir = EMovementDir_None;
@@ -178,6 +516,10 @@ uint32_t TempPlayer::GenMovementDir()
movementDir |= EMovementDir_Right;
}
+ if (g_inputManager.GetKeyboard().IsKeyDown(SDLK_SPACE)) {
+ movementDir |= EMovementDir_Jump;
+ }
+
return movementDir;
}
diff --git a/src/game/game_object.h b/src/game/game_object.h
index 423f9c6..d3391c8 100644
--- a/src/game/game_object.h
+++ b/src/game/game_object.h
@@ -1,8 +1,11 @@
#ifndef GAME_OBJECT_H
#define GAME_OBJECT_H
+#include
+
#include "engine/ientity.h"
#include "engine/camera.h"
+#include "engine/physics/physicsworld.h"
#include "render/model.h"
#include "render/modelsystem.h"
@@ -15,9 +18,47 @@ enum EMovmentDir
EMovementDir_Forward = 1 << 1,
EMovementDir_Backward = 1 << 2,
EMovementDir_Left = 1 << 3,
- EMovementDir_Right = 1 << 4
+ EMovementDir_Right = 1 << 4,
+ EMovementDir_Jump = 1 << 5,
};
+struct ph_motion_state : public btMotionState {
+ btRigidBody* m_body;
+ btTransform m_transform;
+
+ ph_motion_state() : m_body(nullptr) {}
+ ph_motion_state(btRigidBody* body) : m_body(body) {}
+
+ void setBody(btRigidBody* body) { m_body = body; }
+
+ // getWorldTransform() relays transform from external logic to Bullet.
+ // It is called by Bullet in two places:
+ // (1) Once when the Body is created and added to the world.
+ // (2) Once per substep iff the Body is Kinematic and active.
+ //
+ void getWorldTransform(btTransform& worldTrans) const {
+ // Note: worldTrans is passed by reference
+ // It is our duty here to copy into it the correct transform as known
+ // to external logic and Bullet will harvest
+ //
+ // m_gameObject->getWorldTransform( worldTrans );
+ }
+
+ // setWorldTransform() relays Body transform from the Bullet simulation to the GameObject
+ // and is called once per substep iff the Body is Dynamic and active.
+ //
+ void setWorldTransform(const btTransform& worldTrans) {
+ // It is our duty here to apply worldTrans to GameObject.
+ // Note: worldTrans is NOT necessarily the Body's transform as known to Bullet.
+ // It is an extrapolated transform based on the Body's state at the
+ // end of the last substep... extrapolated forward into the future (e.g. the remainder
+ // not yet stepped) according the current Body velocities.
+ //
+ m_transform = worldTrans;
+ }
+};
+
+
class Entity : public IEntityBase
{
public:
@@ -28,14 +69,32 @@ public:
virtual void Render();
// Game entity extensions
+ const std::string& GetName();
+ void SetName(const std::string& name);
+
virtual void LoadModel(const char* filename);
void SetVisible(bool visible);
bool GetVisible();
+ // Game entity lua bindings
void InitFromTable(LuaPlus::LuaObject& _object);
+ void RegisterBaseFunctions();
+ virtual void RegisterFunctions();
+
+ // Game entity lua wrappers
+ void Help_Translate(float x, float y, float z);
+ void Help_SetPosition(float x, float y, float z);
+
+ int Lua_LoadModel(LuaPlus::LuaState* state);
+ int Lua_Translate(LuaPlus::LuaState* state);
+ int Lua_SetPosition(LuaPlus::LuaState* state);
+
+ const LuaPlus::LuaObject& GetLuaObject();
protected:
+ std::string m_name;
+
Model* m_model;
LuaPlus::LuaObject m_luaObject;
@@ -44,23 +103,52 @@ protected:
LuaPlus::LuaObject m_onUpdateFunction;
};
-class TempPlayer : public Entity
+class ActorBase : public Entity
{
public:
- TempPlayer();
- ~TempPlayer();
+ ActorBase();
+ ~ActorBase();
virtual void Update(float dt);
+ void AfterEngineStep();
+
void UpdateCameraMovement(float dt);
+ void UpdateBodyMovement(float dt);
+
void UpdateCameraLook();
+ void UpdateBody();
+
+ void ActivateCamera();
+
+ void CreateBody();
+
+ bool OnGround();
+
+ // Lua bindings
+
+ virtual void RegisterFunctions();
+
+ int Lua_UpdateCameraMovement(LuaPlus::LuaState* state);
+ int Lua_UpdateBodyMovement(LuaPlus::LuaState* state);
+ int Lua_UpdateCameraLook(LuaPlus::LuaState* state);
+ int Lua_ActivateCamera(LuaPlus::LuaState* state);
+ int Lua_CreateBody(LuaPlus::LuaState* state);
+
private:
uint32_t GenMovementDir();
private:
Camera m_camera;
+
+private:
+ btCollisionShape* m_shape;
+ btRigidBody* m_rigidBody;
+ ph_motion_state m_ph_motion_state;
+ float m_mass;
+ bool m_bodyDirty;
};
class Weapon : public Entity
diff --git a/src/render/model.cpp b/src/render/model.cpp
index 46e591c..3c4e102 100644
--- a/src/render/model.cpp
+++ b/src/render/model.cpp
@@ -12,7 +12,7 @@
#include "modelsystem.h"
#include "texturesmanager.h"
-extern Shader* g_litShader;
+extern Shader* g_unlitShader;
static std::string getFileNameWithoutExtension(const std::string& filename)
{
@@ -220,7 +220,7 @@ void Model::LoadMtl(const char* filename)
void Model::Draw(const glm::mat4& model, bool isTransparent /*= false*/)
{
- SDL_assert(g_litShader);
+ SDL_assert(g_unlitShader);
glFrontFace(GL_CCW);
glDepthFunc(GL_LESS);
@@ -236,20 +236,20 @@ void Model::Draw(const glm::mat4& model, bool isTransparent /*= false*/)
g_renderDevice->SetBlendingFunction(BF_SRC_ALPHA, BF_ONE_MINUS_SRC_ALPHA);
glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, .5f);
- g_shaderSystem->SetUniformFloat4(g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color));
+ g_shaderSystem->SetUniformFloat4(g_unlitShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color));
}
else
{
g_renderDevice->SetBlending(false);
//glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, 1.f);
- //g_shaderSystem->SetUniformFloat4(g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color));
+ //g_shaderSystem->SetUniformFloat4(g_unlitShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color));
}
g_renderDevice->SetVerticesBuffer(m_data.vb);
- g_shaderSystem->SetShader(g_litShader);
- g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MODEL_MATRIX, &model[0]);
+ g_shaderSystem->SetShader(g_unlitShader);
+ g_shaderSystem->SetUniformMatrix(g_unlitShader, UNIFORM_MODEL_MATRIX, &model[0]);
//static float test = 0.0f;
//test += g_systemTimer->GetDelta() * 6.0f;
@@ -277,10 +277,10 @@ void Model::Draw(const glm::mat4& model, bool isTransparent /*= false*/)
glm::mat4 mvp = glm::identity();
mvp = g_render->GetProjectionMatrix() * g_render->GetViewMatrix() * model;
- g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]);
+ g_shaderSystem->SetUniformMatrix(g_unlitShader, UNIFORM_MVP_MATRIX, &mvp[0]);
g_texturesManager->SetTexture(0, m_AlbedoTexture);
- g_shaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0);
+ g_shaderSystem->SetUniformSampler(g_unlitShader, SAMPLER_ALBEDO, 0);
g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_data.vbcount);
diff --git a/src/render/modelsystem.cpp b/src/render/modelsystem.cpp
index dd67dae..5cca027 100644
--- a/src/render/modelsystem.cpp
+++ b/src/render/modelsystem.cpp
@@ -26,6 +26,7 @@ static InputLayoutDesc_t g_skinnedVertexLayout[] = {
{ VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD }
};
+Shader* g_unlitShader = nullptr;
Shader* g_litShader = nullptr;
static std::string getFileNameWithoutExtension(const std::string& filename)
@@ -48,7 +49,11 @@ ModelSystem::~ModelSystem()
void ModelSystem::Init()
{
- // Load model generic shader
+ // Load unlighted model generic shader
+ g_unlitShader = g_shaderSystem->CreateShader("unlit_generic", "data/shaders/unlit_generic.vs", "data/shaders/unlit_generic.ps",
+ g_staticVertexLayout, sizeof(g_staticVertexLayout) / sizeof(g_staticVertexLayout[0]));
+
+ // Load lighted model generic shader
g_litShader = g_shaderSystem->CreateShader("lit_generic", "data/shaders/lit_generic.vs", "data/shaders/lit_generic.ps",
g_staticVertexLayout, sizeof(g_staticVertexLayout) / sizeof(g_staticVertexLayout[0]));
}
diff --git a/src/render/render_shared.h b/src/render/render_shared.h
index 4da68e6..cf97195 100644
--- a/src/render/render_shared.h
+++ b/src/render/render_shared.h
@@ -206,6 +206,7 @@ enum ShaderUniform_t
UNIFORM_SUN_DIRECTION,
UNIFORM_SUN_COLOR,
UNIFORM_SUN_AMBIENT,
+ UNIFORM_CAMERA_POS,
UNIFORM_MAX,
};
diff --git a/src/render/scenemanager.cpp b/src/render/scenemanager.cpp
index b1120a5..95c00c3 100644
--- a/src/render/scenemanager.cpp
+++ b/src/render/scenemanager.cpp
@@ -12,6 +12,9 @@
#include "render/shadersystem.h"
#include "render/render.h"
#include "render/debugrender.h"
+#include "render/gpu_buffer.h"
+#include "engine/camera.h"
+#include "engine/physics/physicsworld.h"
#include
@@ -54,6 +57,37 @@ static std::string getFilenameWithoutPathAndExtension(const std::string& filenam
return string;
}
+template
+void TReadFile(FileHandle_t handle, T* value)
+{
+ GetFileSystem()->ReadFile(handle, (void*)value, sizeof(T));
+}
+
+template
+void TWriteFile(FileHandle_t handle, const T* value)
+{
+ GetFileSystem()->WriteFile(handle, (void*)value, sizeof(T));
+}
+
+static void WriteString(FileHandle_t handle, const std::string& string)
+{
+ uint16_t size = string.length();
+ TWriteFile(handle, &size);
+
+ GetFileSystem()->WriteFile(handle, (void*)string.c_str(), size);
+}
+
+static void ReadString(FileHandle_t handle, std::string& string)
+{
+ uint16_t size;
+ TReadFile(handle, &size);
+
+ //string.resize(size + 1);
+ string.resize(size);
+ GetFileSystem()->ReadFile(handle, (void*)string.c_str(), size);
+ //string[size] = '\0';
+}
+
//#ifdef NDEBUG
//#pragma comment(lib, "assimp-vc141-mt.lib")
//#else
@@ -329,7 +363,13 @@ void SceneManager::loadStaticMesh(const char* filename)
if (GetFileSystem()->IsExist(filenamebuf)) {
SceneStaticMesh* staticMesh = new SceneStaticMesh();
- staticMesh->LoadObj(filenamebuf);
+
+ const char* ext = strrchr(filenamebuf, '.');
+ if (ext && strcmp(ext, ".obj") == 0)
+ staticMesh->LoadObj(filenamebuf);
+ else if (ext && strcmp(ext, ".wmb") == 0)
+ staticMesh->LoadBin(filenamebuf);
+
m_sceneMeshes.push_back(staticMesh);
}
}
@@ -593,6 +633,42 @@ void SceneStaticMesh::LoadObj(const char* filename)
}
}
+ // Fill face indices
+ std::vector indices;
+ for (uint32_t i = 0; i < vertices.size(); i++) {
+ indices.push_back(i);
+ }
+
+ std::string binaryCache = getFileNameWithoutExtension(filename);
+ binaryCache += ".wmb";
+
+ if (!GetFileSystem()->IsExist(binaryCache.c_str()))
+ {
+ FileHandle_t handle = GetFileSystem()->OpenFile(binaryCache.c_str(), "wb");
+
+ // write header
+ WriteString(handle, "StaticSceneMeshFile");
+ WriteString(handle, "0.1");
+
+ // write material file
+
+ std::string mtlfilename = getFileNameWithoutExtension(filename);
+ mtlfilename += ".mtl";
+ WriteString(handle, mtlfilename);
+
+ // write vertices
+ uint32_t vbcount = vertices.size();
+ TWriteFile(handle, &vbcount);
+ GetFileSystem()->WriteFile(handle, vertices.data(), vertices.size() * sizeof(StaticMeshVertex));
+
+ // write indices
+ uint32_t ibcount = indices.size();
+ TWriteFile(handle, &ibcount);
+ GetFileSystem()->WriteFile(handle, indices.data(), indices.size() * sizeof(uint32_t));
+
+ GetFileSystem()->CloseFile(handle);
+ }
+
// m_Vertices = vertices;
m_vb = g_renderDevice->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size());
@@ -601,6 +677,75 @@ void SceneStaticMesh::LoadObj(const char* filename)
std::string mtlfilename = getFileNameWithoutExtension(filename);
mtlfilename += ".mtl";
LoadMtl(mtlfilename.c_str());
+
+ if (g_PhysicsWorld) {
+ g_PhysicsWorld->AddCollisionModel(vertices.data(), vertices.size(), indices.data(), indices.size());
+ }
+}
+
+void SceneStaticMesh::LoadBin(const char* filename)
+{
+ FileHandle_t handle = GetFileSystem()->OpenFile(filename, "rb");
+
+ std::string header;
+ ReadString(handle, header);
+ if (header != "StaticSceneMeshFile")
+ Core::Error(" SceneStaticMesh::LoadBin: Error during scene loading!\n%s is not a proper scene mesh.\n%s (should be %s)", filename, header.c_str(), "StaticSceneMeshFile");
+
+ std::string version;
+ ReadString(handle, version);
+ if (version != "0.1")
+ Core::Error(" SceneStaticMesh::LoadBin: Error during scene loading!\n%s is outdated.\nversion %s (current is %s)", filename, version.c_str(), "0.1");
+
+ std::string mtlfilename;
+ ReadString(handle, mtlfilename);
+
+ LoadMtl(mtlfilename.c_str());
+
+ // read vertices
+ uint32_t vbcount;
+ TReadFile(handle, &vbcount);
+
+ std::vector vertices;
+ vertices.resize(vbcount);
+ GetFileSystem()->ReadFile(handle, vertices.data(), vertices.size() * sizeof(StaticMeshVertex));
+
+ // read indices
+ uint32_t ibcount;
+ TReadFile(handle, &ibcount);
+
+ std::vector vertexIndices;
+ vertexIndices.resize(ibcount);
+ GetFileSystem()->ReadFile(handle, vertexIndices.data(), vertexIndices.size() * sizeof(unsigned int));
+
+ // bbox calculation
+ for (unsigned int i = 0; i < vertices.size(); i++)
+ {
+
+ if (i == 0)
+ {
+ m_boundingBox.m_min = vertices[i].position;
+ m_boundingBox.m_max = vertices[i].position;
+ }
+ else
+ {
+ m_boundingBox.m_min = glm::min(m_boundingBox.m_min, vertices[i].position);
+ m_boundingBox.m_max = glm::max(m_boundingBox.m_max, vertices[i].position);
+ }
+ }
+
+
+ // create vb
+ m_vb = g_renderDevice->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size());
+ m_vbcount = vertices.size();
+
+ // create ib ??
+
+ if (g_PhysicsWorld) {
+ g_PhysicsWorld->AddCollisionModel(vertices.data(), vertices.size(), vertexIndices.data(), vertexIndices.size());
+ }
+
+ GetFileSystem()->CloseFile(handle);
}
void SceneStaticMesh::LoadMtl(const char* filename)
@@ -643,12 +788,57 @@ void SceneStaticMesh::LoadMtl(const char* filename)
fclose(file);
}
-void SceneStaticMesh::RenderObjects()
+static glm::mat4 s_identity = glm::mat4(1.0f);
+
+void R_SceneStaticMesh_BindShader(const glm::mat4& worldMatrix, Texture2D* albedoTexture)
{
+ extern Shader* g_unlitShader;
extern Shader* g_litShader;
+ SDL_assert(g_unlitShader);
SDL_assert(g_litShader);
+ Shader* shader = g_litShader;
+
+ g_shaderSystem->SetShader(shader);
+
+ g_shaderSystem->SetUniformMatrix(shader, UNIFORM_MODEL_MATRIX, &worldMatrix[0]);
+
+ glm::mat4 mvp = g_render->GetProjectionMatrix() * g_render->GetViewMatrix() * worldMatrix;
+ g_shaderSystem->SetUniformMatrix(shader, UNIFORM_MVP_MATRIX, &mvp[0]);
+
+ Camera* camera = g_cameraManager.GetActiveCamera();
+ if (camera && shader->HasUniform(UNIFORM_CAMERA_POS))
+ {
+ glm::vec4 campos = glm::vec4(camera->GetPosition(), 1.0f);
+ g_shaderSystem->SetUniformFloat4(shader, UNIFORM_CAMERA_POS, &campos);
+ }
+
+ if (shader->HasUniform(UNIFORM_SUN_DIRECTION))
+ {
+ glm::vec4 lightPos = glm::vec4(1.0f, 1.0f, 1.0f, 0.0f);
+
+ g_debugRender->DrawAxis(glm::vec3(lightPos));
+
+ Camera* camera = g_cameraManager.GetActiveCamera();
+ if (camera)
+ lightPos = glm::vec4(camera->GetPosition(), 1.0f);
+
+ g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_DIRECTION, &lightPos);
+ }
+
+ if (shader->HasUniform(UNIFORM_SUN_AMBIENT))
+ {
+ glm::vec4 lightColor = glm::vec4(0.1f);
+ g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_AMBIENT, &lightColor);
+ }
+
+ g_texturesManager->SetTexture(0, albedoTexture);
+ g_shaderSystem->SetUniformSampler(shader, SAMPLER_ALBEDO, 0);
+}
+
+void SceneStaticMesh::RenderObjects()
+{
glFrontFace(GL_CCW);
glDepthFunc(GL_LESS);
@@ -660,17 +850,7 @@ void SceneStaticMesh::RenderObjects()
g_renderDevice->SetVerticesBuffer(m_vb);
- g_shaderSystem->SetShader(g_litShader);
-
- static glm::mat4 s_identity = glm::mat4(1.0f);
- g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MODEL_MATRIX, &s_identity[0]);
-
- glm::mat4 mvp = glm::identity();
- mvp = g_render->GetProjectionMatrix() * g_render->GetViewMatrix();
- g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]);
-
- g_texturesManager->SetTexture(0, m_albedoTexture);
- g_shaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0);
+ R_SceneStaticMesh_BindShader(s_identity, m_albedoTexture);
g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_vbcount);
}
diff --git a/src/render/scenemanager.h b/src/render/scenemanager.h
index 4b5ee99..fa05071 100644
--- a/src/render/scenemanager.h
+++ b/src/render/scenemanager.h
@@ -15,6 +15,7 @@ public:
~SceneStaticMesh();
void LoadObj(const char* filename);
+ void LoadBin(const char* filename);
void LoadMtl(const char* filename);
const BoundingBox& GetBoundingBox() { return m_boundingBox; }
diff --git a/src/render/shadersystem.cpp b/src/render/shadersystem.cpp
index e51d18c..cc0caaf 100644
--- a/src/render/shadersystem.cpp
+++ b/src/render/shadersystem.cpp
@@ -12,6 +12,7 @@ static const char* g_uniformNameTable[UNIFORM_MAX] =
"u_sunDirection",
"u_sunColor",
"u_sunAmbientColor",
+ "u_cameraPos",
};
static const char* g_samplersNameTable[SAMPLER_MAX] =