1
+2
+3
+4
+5
+6
+7
+8
+9
+10
+11
+12
+13
+14
+15
+16
+17
+18
+19
+20
+21
+22
+23
+24
+25
+26
+27
+28
+29
+30
+31
+32
+33
+34
+35
+36
+37
+38
+39
+40
+41
+42
+43
+44
+45
+46
+47
+48
+49
+50
+51
+52
+53
+54
+55
+56
+57
+58
+59
+60
+61
+62
+63
+64
+65
+66
+67
+68
+69
+70
+71
+72
+73
+74
+75
+76
+77
+78
+79
+80
+81
+82
+83
+84
+85
+86
+87
+88
+89
+90
+91
+92
+93
+94
+95
+96
+97
+98
+99
+100
+101
+102
+103
+104
+105
+106
+107
+108
+109
+110
+111
+112
+113
+114
+115
+116
+117
+118
+119
+120
+121
+122
+123
+124
+125
+126
+127
+128
+129
+130
+131
+132
+133
+134
+135
+136
+137
+138
+139
+140
+141
+142
+143
+144
+145
+146
+147
+148
+149
+150
+151
+152
+153
+154
+155
+156
+157
+158
+159
+160
+161
+162
+163
+164
+165
+166
+167
+168
+169
+170
+171
+172
+173
+174
+175
+176
+177
+178
+179
+180
+181
+182
+183
+184
+185
+186
+187
+188
+189
+190
+191
+192
+193
+194
+195
+196
+197
+198
+199
+200
+201
+202
+203
+204
+205
+206
+207
+208
+209
+210
+211
+212
+213
+214
+215
+216
+217
+218
+219
+220
+221
+222
+223
+224
+225
+226
+227
+228
+229
+230
+231
+232
+233
+234
+235
+236
+237
+238
+239
+240
+241
+242
+243
+244
+245
+246
+247
+248
+249
+250
+251
+252
+253
+254
+255
+256
+257
+258
+259
+260
+261
+262
+263
+264
+265
+266
+267
+268
+269
+270
+271
+272
+273
+274
+275
+276
+277
+278
+279
+280
+281
+282
+283
+284
+285
+286
+287
+288
+289
+290
+291
+292
+293
+294
+295
+296
+297
+298
+299
+300
+301
+302
+303
+304
+305
+306
+307
+308
+309
+310
+311
+312
+313
+314
+315
+316
+317
+318
+319
+320
+321
+322
+323
+324
+325
+326
+327
+328
+329
+330
+331
+332
+333
+334
+335
+336
+337
+338
+339
+340
+341
+342
+343
+344
+345
+346
+347
+348
+349
+350
+351
+352
+353
+354
+355
+356
+357
+358
+359
+360
+361
+362
+363
+364
+365
+366
+367
+368
+369
+370
+371
+372
+373
+374
+375
+376
+377
+378
+379
+380
+381
+382
+383
+384
+385
+386
+387
+388
+389
+390
+391
+392
+393
+394
+395
+396
+397
+398
+399
+400
+401
+402
+403
+404
+405
+406
+407
+408
+409
+410
+411
+412
+413
+414
+415
+416
+417
+418
+419
+420
+421
+422
+423
+424
+425
+426
+427
+428
+429
+430
+431
+432
+433
+434
+435
+436
+437
+438
+439
+440
+441
+442
+443
+444
+445
+446
+447
+448
+449
+450
+451
+452
+453
+454
+455
+456
+457
+458
+459
+460
+461
+462
+463
+464
+465
+466
+467
+468
+469
+470
+471
+472
+473
+474
+475
+476
+477
+478
+479
+480
+481
+482
+483
+484
+485
+486
+487
+488
+489
+490
+491
+492
+493
+494
+495
+496
+497
+498
+499
+500
+501
+502
+503
+504
+505
+506
+507
+508
+509
+510
+511
+512
+513
+514
+515
+516
+517
+518
+519
+520
+521
+522
+523
+524
+525
+526
+527
+528
+529
+530
+531
+532
+533
+534
+535
+536
+537
+538
+539
+540
+541
+542
+543
+544
+545
+546
+547
+548
+549
+550
+551
+552
+553
+554
+555
+556
+557
+558
+559
+560
+561
+562
+563
+564
+565
+566
+567
+568
+569
+570
+571
+572
+573
+574
+575
+576
+577
+578
+579
+580
+581
+582
+583
+584
+585
+586
+587
+588
+589
+590
+591
+592
+593
+594
+595
+596
+597
+598
+599
+600
+601
+602
+603
+604
+605
+606
+607
+608
+609
+610
+611
+612
+613
+614
+615
+616
+617
+618
+619
+620
+621
+622
+623
+624
+625
+626
+627
+628
+629
+630
+631
+632
+633
+634
+635
+636
+637
+638
+639
+640
+641
+642
+643
+644
+645
+646
+647
+648
+649
+650
+651
+652
+653
+654
+655
+656
+657
+658
+659
+660
+661
+662
+663
+664
+665
+666
+667
+668
+669
+670
+671
+672
+673
+674
+675
+676
+677
+678
+679
+680
+681
+682
+683
+684
+685
+686
+687
+688
+689
+690
+691
+692
+693
+694
+695
+696
+697
+698
+699
+700
+701
+702
+703
+704
+705
+706
+707
+708
+709
+710
+711
+712
+713
+714
+715
+716
+717
+718
+719
+720
+721
+722
+723
+724
+725
+726
+727
+728
+729
+730
+731
+732
+733
+734
+735
+736
+737
+738
+739
+740
+741
+742
+743
+744
+745
+746
+747
+748
+749
+750
+751
+752
+753
+754
+755
+756
+757
+758
+759
+760
+761
+762
+763
+764
+765
+766
+767
+768
+769
+770
+771
+772
+773
+774
+775
+776
+777
+778
+779
+780
+781
+782
+783
+784
+785
+786
+787
+788
+789
+790
+791
+792
+793
+794
+795
+796
+797
+798
+799
+800
+801
+802
+803
+804
+805
+806
+807
+808
+809
+810
+811
+812
+813
+814
+815
+816
+817
+818
+819
+820
+821
+822
+823
+824
+825
+826
+827
+828
+829
+830
+831
+832
+833
+834
+835
+836
+837
+838
+839
+840
+841
+842
+843
+844
+845
+846
+847
+848
+849
+850
+851
+852
+853
+854
+855
+856
+857
+858
+859
+860
+861
+862
+863
+864
+865
+866
+867
+868
+869
+870
+871
+872
+873
+874
+875
+876
+877
+878
+879
+880
+881
+882
+883
+884
+885
+886
+887
+888
+889
+890
+891
+892
+893
+894
+895
+896
+897
+898
+899
+900
+901
+902
+903
+904
+905
+906
+907
+908
+909
+910
+911
+912
+913
+914
+915
+916
+917
+918
+919
+920
+921
+922
+923
+924
+925
+926
+927
+928
+929
+930
+931
+932
+933
+934
+935
+936
+937
+938
+939
+940
+941
+942
+943
+944
+945
+946
+947
+948
+949
+950
+951
+952
+953
+954
+955
+956
+957
+958
+959
+960
+961
+962
+963
+964
+965
+966
+967
+968
+969
+970
+971
+972
+973
+974
+975
+976
+977
+978
+979
+980
+981
+982
+983
+984
+985
+986
+987
+988
+989
+990
+991
+992
+993
+994
+995
+996
+997
+998
+999
+1000
+1001
+1002
+1003
+1004
+1005
+1006
+1007
+1008
+1009
+1010
+1011
+1012
+1013
+1014
+1015
+1016
+1017
+1018
+1019
+1020
+1021
+1022
+1023
+1024
+1025
+1026
+1027
+1028
+1029
+1030
+1031
+1032
+1033
+1034
+1035
+1036
+1037
+1038
+1039
+1040
+1041
+1042
+1043
+1044
+1045
+1046
+1047
+1048
+1049
+1050
+1051
+1052
+1053
+1054
+1055
+1056
+1057
+1058
+1059
+1060
+1061
+1062
+1063
+1064
+1065
+1066
+1067
+1068
+1069
+1070
+1071
+1072
+1073
+1074
+1075
+1076
+1077
+1078
+1079
+1080
+1081
+1082
+1083
+1084
+1085
+1086
+1087
+1088
+1089
+1090
+1091
+1092
+1093
+1094
+1095
+1096
+1097
+1098
+1099
+1100
+1101
+1102
+1103
+1104
+1105
+1106
+1107
+1108
+1109
+1110
+1111
+1112
+1113
+1114
+1115
+1116
+1117
+1118
+1119
+1120
+1121
+1122
+1123
+1124
+1125
+1126
+1127
+1128
+1129
+1130
+1131
+1132
+1133
+1134
+1135
+1136
+1137
+1138
+1139
+1140
+1141
+1142
+1143
+1144
+1145
+1146
+1147
+1148
+1149
+1150
+1151
+1152
+1153
+1154
+1155
+1156
+1157
+1158
+1159
+1160
+1161
+1162
+1163
+1164
+1165
+1166
+1167
+1168
+1169
+1170
+1171
+1172
+1173
+1174
+1175
+1176
+1177
+1178
+1179
+1180
+1181
+1182
+1183
+1184
+1185
+1186
+1187
+1188
+1189
+1190
+1191
+1192
+1193
+1194
+1195
+1196
+1197
+1198
+1199
+1200
+1201
+1202
+1203
+1204
+1205
+1206
+1207
+1208
+1209
+1210
+1211
+1212
+1213
+1214
+1215
+1216
+1217
+1218
+1219
+1220
+1221
+1222
+1223
+1224
+1225
+1226
+1227
+1228
+1229
+1230
+1231
+1232
+1233
+1234
+1235
+1236
+1237
+1238
+1239
+1240
+1241
+1242
+1243
+1244
+1245
+1246
+1247
+1248
+1249
+1250
+1251
+1252
+1253
+1254
+1255
+1256
+1257
+1258
+1259
+1260
+1261
+1262
+1263
+1264
+1265
+1266
+1267
+1268
+1269
+1270
+1271
+1272
+1273
+1274
+1275
+1276
+1277
+1278
+1279
+1280
+1281
+1282
+1283
+1284
+1285
+1286
+1287
+1288
+1289
+1290
+1291
+1292
+1293
+1294
+1295
+1296
+1297
+1298
+1299
+1300
+1301
+1302
+1303
+1304
+1305
+1306
+1307
+1308
+1309
+1310
+1311
+1312
+1313
+1314
+1315
+1316
+1317
+1318
+1319
+1320
+1321
+1322
+1323
+1324
+1325
+1326
+1327
+1328
+1329
+1330
+1331
+1332
+1333
+1334
+1335
+1336
+1337
+1338
+1339
+1340
+1341
+1342
+1343
+1344
+1345
+1346
+1347
+1348
+1349
+1350
+1351
+1352
+1353
+1354
+1355
+1356
+1357
+1358
+1359
+1360
+1361
+1362
+1363
+1364
+1365
+1366
+1367
+1368
+1369
+1370
+1371
+1372
+1373
+1374
+1375
+1376
+1377
+1378
+1379
+1380
+1381
+1382
+1383
+1384
+1385
+1386
+1387
+1388
+1389
+1390
+1391
+1392
+1393
+1394
+1395
+1396
+1397
+1398
+1399
+1400
+1401
+1402
+1403
+1404
+1405
+1406
+1407
+1408
+1409
+1410
+1411
+1412
+1413
+1414
+1415
+1416
+1417
+1418
+1419
+1420
+1421
+1422
+1423
+1424
+1425
+1426
+1427
+1428
+1429
+1430
+1431
+1432
+1433
+1434
+1435
+1436
+1437
+1438
+1439
+1440
+1441
+1442
+1443
+1444
+1445
+1446
+1447
+1448
+1449
+1450
+1451
+1452
+1453
+1454
+1455
+1456
+1457
+1458
+1459
+1460
+1461
+1462
+1463
+1464
+1465
+1466
+1467
+1468
+1469
+1470
+1471
+1472
+1473
+1474
+1475
+1476
+1477
+1478
+1479
+1480
+1481
+1482
+1483
+1484
+1485
+1486
+1487
+1488
+1489
+1490
+1491
+1492
+1493
+1494
+1495
+1496
+1497
+1498
+1499
+1500
+1501
+1502
+1503
+1504
+1505
+1506
+1507
+1508
+1509
+1510
+1511
+1512
+1513
+1514
+1515
+1516
+1517
+1518
+1519
+1520
+1521
+1522
+1523
+1524
+1525
+1526
+1527
+1528
+1529
+1530
+1531
+1532
+1533
+1534
+1535
+1536
+1537
+1538
+1539
+1540
+1541
+1542
+1543
+1544
+1545
+1546
+1547
+1548
+1549
+1550
+1551
+1552
+1553
+1554
+1555
+1556
+1557
+1558
+1559
+1560
+1561
+1562
+1563
+1564
+1565
+1566
+1567
+1568
+1569
+1570
+1571
+1572
+1573
+1574
+1575
+1576
+1577
+1578
+1579
+1580
+1581
+1582
+1583
+1584
+1585
+1586
+1587
+1588
+1589
+1590
+1591
+1592
+1593
+1594
+1595
+1596
+1597
+1598
+1599
+1600
+1601
+1602
+1603
+1604
+1605
+1606
+1607
+1608
+1609
+1610
+1611
+1612
+1613
+1614
+1615
+1616
+1617
+1618
+1619
+1620
+1621
+1622
+1623
+1624
+1625
+1626
+1627
+1628
+1629
+1630
+1631
+1632
+1633
+1634
+1635
+1636
+1637
+1638
+1639
+1640
+1641
+1642
+1643
+1644
+1645
+1646
+1647
+1648
+1649
+1650
+1651
+1652
+1653
+1654
+1655
+1656
+1657
+1658
+1659
+1660
+1661
+1662
+1663
+1664
+1665
+1666
+1667
+1668
+1669
+1670
+1671
+1672
+1673
+1674
+1675
+1676
+1677
+1678
+1679
+1680
+1681
+1682
+1683
+1684
+1685
+1686
+1687
+1688
+1689
+1690
+1691
+1692
+1693
+1694
+1695
+1696
+1697
+1698
+1699
+1700
+1701
+1702
+1703
+1704
+1705
+1706
+1707
+1708
+1709
+1710
+1711
+1712
+1713
+1714
+1715
+1716
+1717
+1718
+1719
+1720
+1721
+1722
+1723
+1724
+1725
+1726
+1727
+1728
+1729
+1730
+1731
+1732
+1733
+1734
+1735
+1736
+1737
+1738
+1739
+1740
+1741
+1742
+1743
+1744
+1745
+1746
+1747
+1748
+1749
+1750
+1751
+1752
+1753
+1754
+1755
+1756
+1757
+1758
+1759
+1760
+1761
+1762
+1763
+1764
+1765
+1766
+1767
+1768
+1769
+1770
+1771
+1772
+1773
+1774
+1775
+1776
+1777
+1778
+1779
+1780
+1781
+1782
+1783
+1784
+1785
+1786
+1787
+1788
+1789
+1790
+1791
+1792
+1793
+1794
+1795
+1796
+1797
+1798
+1799
+1800
+1801
+1802
+1803
+1804
+1805
+1806
+1807
+1808
+1809
+1810
+1811
+1812
+1813
+1814
+1815
+1816
+1817
+1818
+1819
+1820
+1821
+1822
+1823
+1824
+1825
+1826
+1827
+1828
+1829
+1830
+1831
+1832
+1833
+1834
+1835
+1836
+1837
+1838
+1839
+1840
+1841
+1842
+1843
+1844
+1845
+1846
+1847
+1848
+1849
+1850
+1851
+1852
+1853
+1854
+1855
+1856
+1857
+1858
+1859
+1860
+1861
+1862
+1863
+1864
+1865
+1866
+1867
+1868
+1869
+1870
+1871
+1872
+1873
+1874
+1875
+1876
+1877
+1878
+1879
+1880
+1881
+1882
+1883
+1884
+1885
+1886
+1887
+1888
+1889
+1890
+1891
+1892
+1893
+1894
+1895
+1896
+1897
+1898
+1899
+1900
+1901
+1902
+1903
+1904
+1905
+1906
+1907
+1908
+1909
+1910
+1911
+1912
+1913
+1914
+1915
+1916
+1917
+1918
+1919
+1920
+1921
+1922
+1923
+1924
+1925
+1926
+1927
+1928
+1929
+1930
+1931
+1932
+1933
+1934
+1935
+1936
+1937
+1938
+1939
+1940
+1941
+1942
+1943
+1944
+1945
+1946
+1947
+1948
+1949
+1950
+1951
+1952
+1953
+1954
+1955
+1956
+1957
+1958
+1959
+1960
+1961
+1962
+1963
+1964
+1965
+1966
+1967
+1968
+1969
+1970
+1971
+1972
+1973
+1974
+1975
+1976
+1977
+1978
+1979
+1980
+1981
+1982
+1983
+1984
+1985
+1986
+1987
+1988
+1989
+1990
+1991
+1992
+1993
+1994
+1995
+1996
+1997
+1998
+1999
+2000
+2001
+2002
+2003
+2004
+2005
+2006
+2007
+2008
+2009
+2010
+2011
+2012
+2013
+2014
+2015
+2016
+2017
+2018
+2019
+2020
+2021
+2022
+2023
+2024
+2025
+2026
+2027
+2028
+2029
+2030
+2031
+2032
+2033
+2034
+2035
+2036
+2037
+2038
+2039
+2040
+2041
+2042
+2043
+2044
+2045
+2046
+2047
+2048
+2049
+2050
+2051
+2052
+2053
+2054
+2055
+2056
+2057
+2058
+2059
+2060
+2061
+2062
+2063
+2064
+2065
+2066
+2067
+2068
+2069
+2070
+2071
+2072
+2073
+2074
+2075
+2076
+2077
+2078
+2079
+2080
+2081
+2082
+2083
+2084
+2085
+2086
+2087
+2088
+2089
+2090
+2091
+2092
+2093
+2094
+2095
+2096
+2097
+2098
+2099
+2100
+2101
+2102
+2103
+2104
+2105
+2106
+2107
+2108
+2109
+2110
+2111
+2112
+2113
+2114
+2115
+2116
+2117
+2118
+2119
+2120
+2121
+2122
+2123
+2124
+2125
+2126
+2127
+2128
+2129
+2130
+2131
+2132
+2133
+2134
+2135
+2136
+2137
+2138
+2139
+2140
+2141
+2142
+2143
+2144
+2145
+2146
+2147
+2148
+2149
+2150
+2151
+2152
+2153
+2154
+2155
+2156
+2157
+2158
+2159
+2160
+2161
+2162
+2163
+2164
+2165
+2166
+2167
+2168
+2169
+2170
+2171
+2172
+2173
+2174
+2175
+2176
+2177
+2178
+2179
+2180
+2181
+2182
+2183
+2184
+2185
+2186
+2187
+2188
+2189
+2190
+2191
+2192
+2193
+2194
+2195
+2196
+2197
+2198
+2199
+2200
+2201
+2202
+2203
+2204
+2205
+2206
+2207
+2208
+2209
+2210
+2211
+2212
+2213
+2214
+2215
+2216
+2217
+2218
+2219
+2220
+2221
+2222
+2223
+2224
+2225
+2226
+2227
+2228
+2229
+2230
+2231
+2232
+2233
+2234
+2235
+2236
+2237
+2238
+2239
+2240
+2241
+2242
+2243
+2244
+2245
+2246
+2247
+2248
+2249
+2250
+2251
+2252
+2253
+2254
+2255
+2256
+2257
+2258
+2259
+2260
+2261
+2262
+2263
+2264
+2265
+2266
+2267
+2268
+2269
+2270
+2271
+2272
+2273
+2274
+2275
+2276
+2277
+2278
+2279
+2280
+2281
+2282
+2283
+2284
+2285
+2286
+2287
+2288
+2289
+2290
+2291
+2292
+2293
+2294
+2295
+2296
+2297
+2298
+2299
+2300
+2301
+2302
+2303
+2304
+2305
+2306
+2307
+2308
+2309
+2310
+2311
+2312
+2313
+2314
+2315
+2316
+2317
+2318
+2319
+2320
+2321
+2322
+2323
+2324
+2325
+2326
+2327
+2328
+2329
+2330
+2331
+2332
+2333
+2334
+2335
+2336
+2337
+2338
+2339
+2340
+2341
+2342
+2343
+2344
+2345
+2346
+2347
+2348
+2349
+2350
+2351
+2352
+2353
+2354
+2355
+2356
+2357
+2358
+2359
+2360
+2361
+2362
+2363
+2364
+2365
+2366
+2367
+2368
+2369
+2370
+2371
+2372
+2373
+2374
+2375
+2376
+2377
+2378
+2379
+2380
+2381
+2382
+2383
+2384
+2385
+2386
+2387
+2388
+2389
+2390
+2391
+2392
+2393
+2394
+2395
+2396
+2397
+2398
+2399
+2400
+2401
+2402
+2403
+2404
+2405
+2406
+2407
+2408
+2409
+2410
+2411
+2412
+2413
+2414
+2415
+2416
+2417
+2418
+2419
+2420
+2421
+2422
+2423
+2424
+2425
+2426
+2427
+2428
+2429
+2430
+2431
+2432
+2433
+2434
+2435
+2436
+2437
+2438
+2439
+2440
+2441
+2442
+2443
+2444
+2445
+2446
+2447
+2448
+2449
+2450
+2451
+2452
+2453
+2454
+2455
+2456
+2457
+2458
+2459
+2460
+2461
+2462
+2463
+2464
+2465
+2466
+2467
+2468
+2469
+2470
+2471
+2472
+2473
+2474
+2475
+2476
+2477
+2478
+2479
+2480
+2481
+2482
+2483
+2484
+2485
+2486
+2487
+2488
+2489
+2490
+2491
+2492
+2493
+2494
+2495
+2496
+2497
+2498
+2499
+2500
+2501
+2502
+2503
+2504
+2505
+2506
+2507
+2508
+2509
+2510
+2511
+2512
+2513
+2514
+2515
+2516
+2517
+2518
+2519
+2520
+2521
+2522
+2523
+2524
+2525
+2526
+2527
+2528
+2529
+2530
+2531
+2532
+2533
+2534
+2535
+2536
+2537
+2538
+2539
+2540
+2541
+2542
+2543
+2544
+2545
+2546
+2547
+2548
+2549
+2550
+2551
+2552
+2553
+2554
+2555
+2556
+2557
+2558
+2559
+2560
+2561
+2562
+2563
+2564
+2565
+2566
+2567
+2568
+2569
+2570
+2571
+2572
+2573
+2574
+2575
+2576
+2577
+2578
+2579
+2580
+2581
+2582
+2583
+2584
+2585
+2586
+2587
+2588
+2589
+2590
+2591
+2592
+2593
+2594
+2595
+2596
+2597
+2598
+2599
+2600
+2601
+2602
+2603
+2604
+2605
+2606
+2607
+2608
+2609
+2610
+2611
+2612
+2613
+2614
+2615
+2616
+2617
+2618
+2619
+2620
+2621
+2622
+2623
+2624
+2625
+2626
+2627
+2628
+2629
+2630
+2631
+2632
+2633
+2634
+2635
+2636
+2637
+2638
+2639
+2640
+2641
+2642
+2643
+2644
+2645
+2646
+2647
+2648
+2649
+2650
+2651
+2652
+2653
+2654
+2655
+2656
+2657
+2658
+2659
+2660
+2661
+2662
+2663
+2664
+2665
+2666
+2667
+2668
+2669
+2670
+2671
+2672
+2673
+2674
+2675
+2676
+2677
+2678
+2679
+2680
+2681
+2682
+2683
+2684
+2685
+2686
+2687
+2688
+2689
+2690
+2691
+2692
+2693
+2694
+2695
+2696
+2697
+2698
+2699
+2700
+2701
+2702
+2703
+2704
+2705
+2706
+2707
+2708
+2709
+2710
+2711
+2712
+2713
+2714
+2715
+2716
+2717
+2718
+2719
+2720
+2721
+2722
+2723
+2724
+2725
+2726
+2727
+2728
+2729
+2730
+2731
+2732
+2733
+2734
+2735
+2736
+2737
+2738
+2739
+2740
+2741
+2742
+2743
+2744
+2745
+2746
+2747
+2748
+2749
+2750
+2751
+2752
+2753
+2754
+2755
+2756
+2757
+2758
+2759
+2760
+2761
+2762
+2763
+2764
+2765
+2766
+2767
+2768
+2769
+2770
+2771
+2772
+2773
+2774
+2775
+2776
+2777
+2778
+2779
+2780
+2781
+2782
+2783
+2784
+2785
+2786
+2787
+2788
+2789
+2790
+2791
+2792
+2793
+2794
+2795
+2796
+2797
+2798
+2799
+2800
+2801
+2802
+2803
+2804
+2805
+2806
+2807
+2808
+2809
+2810
+2811
+2812
+2813
+2814
+2815
+2816
+2817
+2818
+2819
+2820
+2821
+2822
+2823
+2824
+2825
+2826
+2827
+2828
+2829
+2830
+2831
+2832
+2833
+2834
+2835
+2836
+2837
+2838
+2839
+2840
+2841
+2842
+2843
+2844
+2845
+2846
+2847
+2848
+2849
+2850
+2851
+2852
+2853
+2854
+2855
+2856
+2857
+2858
+2859
+2860
+2861
+2862
+2863
+2864
+2865
+2866
+2867
+2868
+2869
+2870
+2871
+2872
+2873
+2874
+2875
+2876
+2877
+2878
+2879
+2880
+2881
+2882
+2883
+2884
+2885
+2886
+2887
+2888
+2889
+2890
+2891
+2892
+2893
+2894
+2895
+2896
+2897
+2898
+2899
+2900
+2901
+2902
+2903
+2904
+2905
+2906
+2907
+2908
+2909
+2910
+2911
+2912
+2913
+2914
+2915
+2916
+2917
+2918
+2919
+2920
+2921
+2922
+2923
+2924
+2925
+2926
+2927
+2928
+2929
+2930
+2931
+2932
+2933
+2934
+2935
+2936
+2937
+2938
+2939
+2940
+2941
+2942
+2943
+2944
+2945
+2946
+2947
+2948
+2949
+2950
+2951
+2952
+2953
+2954
+2955
+2956
+2957
+2958
+2959
+2960
+2961
+2962
+2963
+2964
+2965
+2966
+2967
+2968
+2969
+2970
+2971
+2972
+2973
+2974
+2975
+2976
+2977
+2978
+2979
+2980
+2981
+2982
+2983
+2984
+2985
+2986
+2987
+2988
+2989
+2990
+2991
+2992
+2993
+2994
+2995
+2996
+2997
+2998
+2999
+3000
+3001
+3002
+3003
+3004
+3005
+3006
+3007
+3008
+3009
+3010
+3011
+3012
+3013
+3014
+3015
+3016
+3017
+3018
+3019
+3020
+3021
+3022
+3023
+3024
+3025
+3026
+3027
+3028
+3029
+3030
+3031
+3032
+3033
+3034
+3035
+3036
+3037
+3038
+3039
+3040
+3041
+3042
+3043
+3044
+3045
+3046
+3047
+3048
+3049
+3050
+3051
+3052
+3053
+3054
+3055
+3056
+3057
+3058
+3059
+3060
+3061
+3062
+3063
+3064
+3065
+3066
+3067
+3068
+3069
+3070
+3071
+3072
+3073
+3074
+3075
+3076
+3077
+3078
+3079
+3080
+3081
+3082
+3083
+3084
+3085
+3086
+3087
+3088
+3089
+3090
+3091
+3092
+3093
+3094
+3095
+3096
+3097
+3098
+3099
+3100
+3101
+3102
+3103
+3104
+3105
+3106
+3107
+3108
+3109
+3110
+3111
+3112
+3113
+3114
+3115
+3116
+3117
+3118
+3119
+3120
+3121
+3122
+3123
+3124
+3125
+3126
+3127
+3128
+3129
+3130
+3131
+3132
+3133
+3134
+3135
+3136
+3137
+3138
+3139
+3140
+3141
+3142
+3143
+3144
+3145
+3146
+3147
+3148
+3149
+3150
+3151
+3152
+3153
+3154
+3155
+3156
+3157
+3158
+3159
+3160
+3161
+3162
+3163
+3164
+3165
+3166
+3167
+3168
+3169
+3170
+3171
+3172
+3173
+3174
+3175
+3176
+3177
+3178
+3179
+3180
+3181
+3182
+3183
+3184
+3185
+3186
+3187
+3188
+3189
+3190
+3191
+3192
+3193
+3194
+3195
+3196
+3197
+3198
+3199
+3200
+3201
+3202
+3203
+3204
+3205
+3206
+3207
+3208
+3209
+3210
+3211
+3212
+3213
+3214
+3215
+3216
+3217
+3218
+3219
+3220
+3221
+3222
+3223
+3224
+3225
+3226
+3227
+3228
+3229
+3230
+3231
+3232
+3233
+3234
+3235
+3236
+3237
+3238
+3239
+3240
+3241
+3242
+3243
+3244
+3245
+3246
+3247
+3248
+3249
+3250
+3251
+3252
+3253
+3254
+3255
+3256
+3257
+3258
+3259
+3260
+3261
+3262
+3263
+3264
+3265
+3266
+3267
+3268
+3269
+3270
+3271
+3272
+3273
+3274
+3275
+3276
+3277
+3278
+3279
+3280
+3281
+3282
+3283
+3284
+3285
+3286
+3287
+3288
+3289
+3290
+3291
+3292
+3293
+3294
+3295
+3296
+3297
+3298
+3299
+3300
+3301
+3302
+3303
+3304
+3305
+3306
+3307
+3308
+3309
+3310
+3311
+3312
+3313
+3314
+3315
+3316
+3317
+3318
+3319
+3320
+3321
+3322
+3323
+3324
+3325
+3326
+3327
+3328
+3329
+3330
+3331
+3332
+3333
+3334
+3335
+3336
+3337
+3338
+3339
+3340
+3341
+3342
+3343
+3344
+3345
+3346
+3347
+3348
+3349
+3350
+3351
+3352
+3353
+3354
+3355
+3356
+3357
+3358
+3359
+3360
+3361
+3362
+3363
+3364
+3365
+3366
+3367
+3368
+3369
+3370
+3371
+3372
+3373
+3374
+3375
+3376
+3377
+3378
+3379
+3380
+3381
+3382
+3383
+3384
+3385
+3386
+3387
+3388
+3389
+3390
+3391
+3392
+3393
+3394
+3395
+3396
+3397
+3398
+3399
+3400
+3401
+3402
+3403
+3404
+3405
+3406
+3407
+3408
+3409
+3410
+3411
+3412
+3413
+3414
+3415
+3416
+3417
+3418
+3419
+3420
+3421
+3422
+3423
+3424
+3425
+3426
+3427
+3428
+3429
+3430
+3431
+3432
+3433
+3434
+3435
+3436
+3437
+3438
+3439
+3440
+3441
+3442
+3443
+3444
+3445
+3446
+3447
+3448
+3449
+3450
+3451
+3452
+3453
+3454
+3455
+3456
+3457
+3458
+3459
+3460
+3461
+3462
+3463
+3464
+3465
+3466
+3467
+3468
+3469
+3470
+3471
+3472
+3473
+3474
+3475
+3476
+3477
+3478
+3479
+3480
+3481
+3482
+3483
+3484
+3485
+3486
+3487
+3488
+3489
+3490
+3491
+3492
+3493
+3494
+3495
+3496
+3497
+3498
+3499
+3500
+3501
+3502
+3503
+3504
+3505
+3506
+3507
+3508
+3509
+3510
+3511
+3512
+3513
+3514
+3515
+3516
+3517
+3518
+3519
+3520
+3521
+3522
+3523
+3524
+3525
+3526
+3527
+3528
+3529
+3530
+3531
+3532
+3533
+3534
+3535
+3536
+3537
+3538
+3539
+3540
+3541
+3542
+3543
+3544
+3545
+3546
+3547
+3548
+3549
+3550
+3551
+3552
+3553
+3554
+3555
+3556
+3557
+3558
+3559
+3560
+3561
+3562
+3563
+3564
+3565
+3566
+3567
+3568
+3569
+3570
+3571
+3572
+3573
+3574
+3575
+3576
+3577
+3578
+3579
+3580
+3581
+3582
+3583
+3584
+3585
+3586
+3587
+3588
+3589
+3590
+3591
+3592
+3593
+3594
+3595
+3596
+3597
+3598
+3599
+3600
+3601
+3602
+3603
+3604
+3605
+3606
+3607
+3608
+3609
+3610
+3611
+3612
+3613
+3614
+3615
+3616
+3617
+3618
+3619
+3620
+3621
+3622
+3623
+3624
+3625
+3626
+3627
+3628
+3629
+3630
+3631
+3632
+3633
+3634
+3635
+3636
+3637
+3638
+3639
+3640
+3641
+3642
+3643
+3644
+3645
+3646
+3647
+3648
+3649
+3650
+3651
+3652
+3653
+3654
+3655
+3656
+3657
+3658
+3659
+3660
+3661
+3662
+3663
+3664
+3665
+3666
+3667
+3668
+3669
+3670
+3671
+3672
+3673
+3674
+3675
+3676
+3677
+3678
+3679
+3680
+3681
+3682
+3683
+3684
+3685
+3686
+3687
+3688
+3689
+3690
+3691
+3692
+3693
+3694
+3695
+3696
+3697
+3698
+3699
+3700
+3701
+3702
+3703
+3704
+3705
+3706
+3707
+3708
+3709
+3710
+3711
+3712
+3713
+3714
+3715
+3716
+3717
+3718
+3719
+3720
+3721
+3722
+3723
+3724
+3725
+3726
+3727
+3728
+3729
+3730
+3731
+3732
+3733
+3734
+3735
+3736
+3737
+3738
+3739
+3740
+3741
+3742
+3743
+3744
+3745
+3746
+3747
+3748
+3749
+3750
+3751
+3752
+3753
+3754
+3755
+3756
+3757
+3758
+3759
+3760
+3761
+3762
+3763
+3764
+3765
+3766
+3767
+3768
+3769
+3770
+3771
+3772
+3773
+3774
+3775
+3776
+3777
+3778
+3779
+3780
+3781
+3782
+3783
+3784
+3785
+3786
+3787
+3788
+3789
+3790
+3791
+3792
+3793
+3794
+3795
+3796
+3797
+3798
+3799
+3800
+3801
+3802
+3803
+3804
+3805
+3806
+3807
+3808
+3809
+3810
+3811
+3812
+3813
+3814
+3815
+3816
+3817
+3818
+3819
+3820
+3821
+3822
+3823
+3824
+3825
+3826
+3827
+3828
+3829
+3830
+3831
+3832
+3833
+3834
+3835
+3836
+3837
+3838
+3839
+3840
+3841
+3842
+3843
+3844
+3845
+3846
+3847
+3848
+3849
+3850
+3851
+3852
+3853
+3854
+3855
+3856
+3857
+3858
+3859
+3860
+3861
+3862
+3863
+3864
+3865
+3866
+3867
+3868
+3869
+3870
+3871
+3872
+3873
+3874
+3875
+3876
+3877
+3878
+3879
+3880
+3881
+3882
+3883
+3884
+3885
+3886
+3887
+3888
+3889
+3890
+3891
+3892
+3893
+3894
+3895
+3896
+3897
+3898
+3899
+3900
+3901
+3902
+3903
+3904
+3905
+3906
+3907
+3908
+3909
+3910
+3911
+3912
+3913
+3914
+3915
+3916
+3917
+3918
+3919
+3920
+3921
+3922
+3923
+3924
+3925
+3926
+3927
+3928
+3929
+3930
+3931
+3932
+3933
+3934
+3935
+3936
+3937
+3938
+3939
+3940
+3941
+3942
+3943
+3944
+3945
+3946
+3947
+3948
+3949
+3950
+3951
+3952
+3953
+3954
+3955
+3956
+3957
+3958
+3959
+3960
+3961
+3962
+3963
+3964
+3965
+3966
+3967
+3968
+3969
+3970
+3971
+3972
+3973
+3974
+3975
+3976
+3977
+3978
+3979
+3980
+3981
+3982
+3983
+3984
+3985
+3986
+3987
+3988
+3989
+3990
+3991
+3992
+3993
+3994
+3995
+3996
+3997
+3998
+3999
+4000
+4001
+4002
+4003
+4004
+4005
+4006
+4007
+4008
+4009
+4010
+4011
+4012
+4013
+4014
+4015
+4016
+4017
+4018
+4019
+4020
+4021
+4022
+4023
+4024
+4025
+4026
+4027
+4028
+4029
+4030
+4031
+4032
+4033
+4034
+4035
+4036
+4037
+4038
+4039
+4040
+4041
+4042
+4043
+4044
+4045
+4046
+4047
+4048
+4049
+4050
+4051
+4052
+4053
+4054
+4055
+4056
+4057
+4058
+4059
+4060
+4061
+4062
+4063
+4064
+4065
+4066
+4067
+4068
+4069
+4070
+4071
+4072
+4073
+4074
+4075
+4076
+4077
+4078
+4079
+4080
+4081
+4082
+4083
+4084
+4085
+4086
+4087
+4088
+4089
+4090
+4091
+4092
+4093
+4094
+4095
+4096
+4097
+4098
+4099
+4100
+4101
+4102
+4103
+4104
+4105
+4106
+4107
+4108
+4109
+4110
+4111
+4112
+4113
+4114
+4115
+4116
+4117
+4118
+4119
+4120
+4121
+4122
+4123
+4124
+4125
+4126
+4127
+4128
+4129
+4130
+4131
+4132
+4133
+4134
+4135
+4136
+4137
+4138
+4139
+4140
+4141
+4142
+4143
+4144
+4145
+4146
+4147
+4148
+4149
+4150
+4151
+4152
+4153
+4154
+4155
+4156
+4157
+4158
+4159
+4160
+4161
+4162
+4163
+4164
+4165
+4166
+4167
+4168
+4169
+4170
+4171
+4172
+4173
+4174
+4175
+4176
+4177
+4178
+4179
+4180
+4181
+4182
+4183
+4184
+4185
+4186
+4187
+4188
+4189
+4190
+4191
+4192
+4193
+4194
+4195
+4196
+4197
+4198
+4199
+4200
+4201
+4202
+4203
+4204
+4205
+4206
+4207
+4208
+4209
+4210
+4211
+4212
+4213
+4214
+4215
+4216
+4217
+4218
+4219
+4220
+4221
+4222
+4223
+4224
+4225
+4226
+4227
+4228
+4229
+4230
+4231
+4232
+4233
+4234
+4235
+4236
+4237
+4238
+4239
+4240
+4241
+4242
+4243
+4244
+4245
+4246
+4247
+4248
+4249
+4250
+4251
+4252
+4253
+4254
+4255
+4256
+4257
+4258
+4259
+4260
+4261
+4262
+4263
+4264
+4265
+4266
+4267
+4268
+4269
+4270
+4271
+4272
+4273
+4274
+4275
+4276
+4277
+4278
+4279
+4280
+4281
+4282
+4283
+4284
+4285
+4286
+4287
+4288
+4289
+4290
+4291
+4292
+4293
+4294
+4295
+4296
+4297
+4298
+4299
+4300
+4301
+4302
+4303
+4304
+4305
+4306
+4307
+4308
+4309
+4310
+4311
+4312
+4313
+4314
+4315
+4316
+4317
+4318
+4319
+4320
+4321
+4322
+4323
+4324
+4325
+4326
+4327
+4328
+4329
+4330
+4331
+4332
+4333
+4334
+4335
+4336
+4337
+4338
+4339
+4340
+4341
+4342
+4343
+4344
+4345
+4346
+4347
+4348
+4349
+4350
+4351
+4352
+4353
+4354
+4355
+4356
+4357
+4358
+4359
+4360
+4361
+4362
+4363
+4364
+4365
+4366
+4367
+4368
+4369
+4370
+4371
+4372
+4373
+4374
+4375
+4376
+4377
+4378
+4379
+4380
+4381
+4382
+4383
+4384
+4385
+4386
+4387
+4388
+4389
+4390
+4391
+4392
+4393
+4394
+4395
+4396
+4397
+4398
+4399
+4400
+4401
+4402
+4403
+4404
+4405
+4406
+4407
+4408
+4409
+4410
+4411
+4412
+4413
+4414
+4415
+4416
+4417
+4418
+4419
+4420
+4421
+4422
+4423
+4424
+4425
+4426
+4427
+4428
+4429
+4430
+4431
+4432
+4433
+4434
+4435
+4436
+4437
+4438
+4439
+4440
+4441
+4442
+4443
+4444
+4445
+4446
+4447
+4448
+4449
+4450
+4451
+4452
+4453
+4454
+4455
+4456
+4457
+4458
+4459
+4460
+4461
+4462
+4463
+4464
+4465
+4466
+4467
+4468
+4469
+4470
+4471
+4472
+4473
+4474
+4475
+4476
+4477
+4478
+4479
+4480
+4481
+4482
+4483
+4484
+4485
+4486
+4487
+4488
+4489
+4490
+4491
+4492
+4493
+4494
+4495
+4496
+4497
+4498
+4499
+4500
+4501
+4502
+4503
+4504
+4505
+4506
+4507
+4508
+4509
+4510
+4511
+4512
+4513
+4514
+4515
+4516
+4517
+4518
+4519
+4520
+4521
+4522
+4523
+4524
+4525
+4526
+4527
+4528
+4529
+4530
+4531
+4532
+4533
+4534
+4535
+4536
+4537
+4538
+4539
+4540
+4541
+4542
+4543
+4544
+4545
+4546
+4547
+4548
+4549
+4550
+4551
+4552
+4553
+4554
+4555
+4556
+4557
+4558
+4559
+4560
+4561
+4562
+4563
+4564
+4565
+4566
+4567
+4568
+4569
+4570
+4571
+4572
+4573
+4574
+4575
+4576
+4577
+4578
+4579
+4580
+4581
+4582
+4583
+4584
+4585
+4586
+4587
+4588
+4589
+4590
+4591
+4592
+4593
+4594
+4595
+4596
+4597
+4598
+4599
+4600
+4601
+4602
+4603
+4604
+4605
+4606
+4607
+4608
+4609
+4610
+4611
+4612
+4613
+4614
+4615
+4616
+4617
+4618
+4619
+4620
+4621
+4622
+4623
+4624
+4625
+4626
+4627
+4628
+4629
+4630
+4631
+4632
+4633
+4634
+4635
+4636
+4637
+4638
+4639
+4640
+4641
+4642
+4643
+4644
+4645
+4646
+4647
+4648
+4649
+4650
+4651
+4652
+4653
+4654
+4655
+4656
+4657
+4658
+4659
+4660
+4661
+4662
+4663
+4664
+4665
+4666
+4667
+4668 | 1×
+1×
+
+
+1×
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+1×
+
+1×
+
+
+1×
+
+1×
+1×
+
+1×
+
+1×
+1×
+
+1×
+
+1×
+1×
+
+1×
+
+1×
+1×
+
+1×
+
+1×
+1×
+
+1×
+
+1×
+1×
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+1×
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+1×
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+1×
+1×
+1×
+1×
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+4×
+4×
+4×
+
+4×
+1×
+
+
+4×
+2×
+
+
+4×
+1×
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+1×
+1×
+1×
+1×
+
+1×
+
+
+
+1×
+
+
+
+1×
+
+
+
+1×
+
+
+
+
+1×
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+1×
+1×
+ | Iif (typeof GameLib == 'undefined') {
+ function GameLib() {}
+}
+
+Eif (typeof GameLib.D3 == 'undefined') {
+ GameLib.D3 = function(){};
+}
+/**
+ * BoneWeight object - associates a vertex to a bone with some weight
+ * @param boneIndex int
+ * @param weight float
+ * @constructor
+ */
+GameLib.D3.BoneWeight = function(
+ boneIndex,
+ weight
+) {
+ this.boneIndex = boneIndex;
+ this.weight = weight;
+};
+/**
+ * Bone Superset
+ * @param id
+ * @param name string
+ * @param boneId
+ * @param childBoneIds
+ * @param parentBoneId
+ * @param quaternion
+ * @param position
+ * @param rotation
+ * @param scale GameLib.D3.Vector3
+ * @param up
+ * @constructor
+ */
+GameLib.D3.Bone = function(
+ id,
+ boneId,
+ name,
+ childBoneIds,
+ parentBoneId,
+ quaternion,
+ position,
+ rotation,
+ scale,
+ up
+) {
+ this.id = id;
+ this.name = name;
+ this.boneId = boneId;
+
+ Iif (typeof childBoneIds == 'undefined') {
+ childBoneIds = [];
+ }
+ this.childBoneIds = childBoneIds;
+
+ Eif (typeof parentBoneId == 'undefined') {
+ parentBoneId = null;
+ }
+ this.parentBoneId = parentBoneId;
+
+ Eif (typeof quaternion == 'undefined') {
+ quaternion = new GameLib.D3.Vector4();
+ }
+ this.quaternion = quaternion;
+
+ Eif (typeof position == 'undefined') {
+ position = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.position = position;
+
+ Eif (typeof rotation == 'undefined') {
+ rotation = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.rotation = rotation;
+
+ Eif (typeof scale == 'undefined') {
+ scale = new GameLib.D3.Vector3(1,1,1);
+ }
+ this.scale = scale;
+
+ Eif (typeof up == 'undefined') {
+ up = new GameLib.D3.Vector3(0,1,0);
+ }
+ this.up = up;
+};
+/**
+ * Physics Broadphase Superset
+ * @param id
+ * @param name String
+ * @param broadphaseType Number
+ * @param engine GameLib.D3.Engine
+ * @param createInstance Boolean
+ * @constructor
+ */
+GameLib.D3.Broadphase = function(
+ id,
+ name,
+ broadphaseType,
+ engine,
+ createInstance
+) {
+ this.id = id;
+
+ if (typeof name == 'undefined') {
+ name = 'broadphase-' + broadphaseType;
+ }
+ this.name = name;
+
+ if (typeof broadphaseType == 'undefined') {
+ broadphaseType = GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE;
+ }
+ this.broadphaseType = broadphaseType;
+
+ if (typeof engine == 'undefined') {
+ engine = null;
+ }
+ this.engine = engine;
+
+ this.instance = null;
+
+ if (createInstance) {
+ this.createInstance();
+ }
+};
+
+/**
+ * Creates a custom Broadphase instance based on the engine type
+ */
+GameLib.D3.Broadphase.prototype.createInstance = function() {
+
+ if (!(this.engine instanceof GameLib.D3.Engine)) {
+ console.warn('No Engine');
+ throw new Error('No Engine');
+ }
+
+ this.engine.isNotCannonThrow();
+
+ var instance = null;
+
+ if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE) {
+ instance = new this.engine.instance.NaiveBroadphase();
+ } else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID) {
+ instance = new this.engine.instance.GridBroadphase();
+ } else if (this.broadphaseType == GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP) {
+ instance = new this.engine.instance.SAPBroardphase();
+ } else {
+ console.warn('Unsupported broadphase type: ' + this.broadphaseType);
+ throw new Error('Unsupported broadphase type: ' + this.broadphaseType);
+ }
+
+ this.instance = instance;
+
+ return instance;
+};
+
+/**
+ * Broadphase Types
+ * @type {number}
+ */
+GameLib.D3.Broadphase.BROADPHASE_TYPE_NAIVE = 0x1;
+GameLib.D3.Broadphase.BROADPHASE_TYPE_GRID = 0x2;
+GameLib.D3.Broadphase.BROADPHASE_TYPE_SAP = 0x3;
+/**
+ * Color Superset
+ * @param r
+ * @param g
+ * @param b
+ * @param a
+ * @constructor
+ */
+GameLib.D3.Color = function(r, g, b, a) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.a = a;
+};
+/**
+ * Engine Superset
+ * @param engineType
+ * @param instance {CANNON | Ammo | Goblin}
+ * @constructor
+ */
+GameLib.D3.Engine = function(
+ engineType,
+ instance
+) {
+ this.engineType = engineType;
+ this.instance = instance;
+};
+
+/**
+ * True if CANNON physics
+ * @returns {boolean}
+ */
+GameLib.D3.Engine.prototype.isCannon = function() {
+ return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_CANNON)
+};
+
+/**
+ * Logs a warning and throws an error if not cannon
+ */
+GameLib.D3.Engine.prototype.isNotCannonThrow = function() {
+ if (this.engineType != GameLib.D3.Engine.ENGINE_TYPE_CANNON) {
+ console.warn('Only CANNON supported for this function');
+ throw new Error('Only CANNON supported for this function');
+ }
+};
+
+/**
+ * True if Ammo physics
+ * @returns {boolean}
+ */
+GameLib.D3.Engine.prototype.isAmmo = function() {
+ return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_AMMO)
+};
+
+/**
+ * True if Goblin physics
+ * @returns {boolean}
+ */
+GameLib.D3.Engine.prototype.isGoblin = function() {
+ return (this.engineType == GameLib.D3.Engine.ENGINE_TYPE_GOBLIN)
+};
+
+/**
+ * Physics GameLib.D3.Engine Types
+ * @type {number}
+ */
+GameLib.D3.Engine.ENGINE_TYPE_CANNON = 0x1;
+GameLib.D3.Engine.ENGINE_TYPE_AMMO = 0x2;
+GameLib.D3.Engine.ENGINE_TYPE_GOBLIN = 0x3;
+/**
+ * Fly Controls
+ * @param camera
+ * @param THREE
+ * @param canvas
+ * @constructor
+ */
+GameLib.D3.FlyControls = function(
+ camera,
+ THREE,
+ canvas
+) {
+ this.flySpeed = 100;
+
+ this.canvas = canvas;
+
+ this.THREE = THREE;
+
+ this.yaw = 0;
+ this.pitch = 0;
+ this.canRotate = false;
+
+ this.moveForward = false;
+ this.moveBackward = false;
+ this.moveLeft = false;
+ this.moveRight = false;
+ this.moveUp = false;
+ this.moveDown = false;
+
+ this.mouseUpCallback = this.onMouseUp.bind(this);
+ this.mouseDownCallback = this.onMouseDown.bind(this);
+ this.mouseMoveCallback = this.onMouseMove.bind(this);
+ this.mouseWheelCallback = this.onMouseWheel.bind(this);
+ this.keyDownCallback = this.onKeyDown.bind(this);
+ this.keyUpCallback = this.onKeyUp.bind(this);
+
+ this.camera = camera;
+
+ this.canvas.addEventListener('keydown', this.keyDownCallback, false);
+ this.canvas.addEventListener('keyup', this.keyUpCallback, false);
+ this.canvas.addEventListener('mousedown', this.mouseDownCallback, false);
+ this.canvas.addEventListener('mouseup', this.mouseUpCallback, false);
+ this.canvas.addEventListener('mousewheel', this.mouseWheelCallback, false);
+
+ this.havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document;
+ this.element = document.body;
+
+ if (this.havePointerLock) {
+ this.element.requestPointerLock = this.element.requestPointerLock || this.element.mozRequestPointerLock || this.element.webkitRequestPointerLock;
+ document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock || document.webkitExitPointerLock;
+ }
+};
+
+/**
+ * Go forward / backward on mouse wheel
+ * @param event
+ */
+GameLib.D3.FlyControls.prototype.onMouseWheel = function(event) {
+ this.moveForward = true;
+ this.applyTranslation(event.wheelDelta * 0.001);
+ event.preventDefault();
+ this.moveForward = false;
+};
+
+/**
+ * Start rotating the camera on mouse middle button down
+ * @param event
+ */
+GameLib.D3.FlyControls.prototype.onMouseDown = function(event) {
+ if (event.button == 1) {
+ this.canRotate = true;
+ this.canvas.addEventListener('mousemove', this.mouseMoveCallback, false);
+ }
+};
+
+/**
+ * Stop rotating on middle mouse button down
+ * @param event
+ */
+GameLib.D3.FlyControls.prototype.onMouseUp = function(event) {
+ if (event.button == 1) {
+ this.canRotate = false;
+ this.canvas.removeEventListener('mousemove', this.mouseMoveCallback);
+ }
+};
+
+/**
+ * Apply current yaw and pitch to camera
+ */
+GameLib.D3.FlyControls.prototype.applyRotation = function() {
+ this.camera.rotation.set(this.pitch, this.yaw, 0, "YXZ");
+};
+
+/**
+ * Apply current position to camera
+ * @param deltaTime
+ */
+GameLib.D3.FlyControls.prototype.applyTranslation = function(deltaTime) {
+ var direction = new this.THREE.Vector3(0, 0, -1);
+ var rotation = new this.THREE.Euler(0, 0, 0, "YXZ");
+ rotation.set(this.pitch, this.yaw, 0, "YXZ");
+
+ direction = direction.applyEuler(rotation);
+
+ var forward = direction.normalize();
+ var right = forward.cross(new this.THREE.Vector3(0, 1, 0));
+
+ if(this.moveForward) {
+
+ this.camera.position.x += forward.x * (deltaTime * this.flySpeed);
+ this.camera.position.y += forward.y * (deltaTime * this.flySpeed);
+ this.camera.position.z += forward.z * (deltaTime * this.flySpeed);
+
+ } else if(this.moveBackward) {
+
+ this.camera.position.x -= forward.x * (deltaTime * this.flySpeed);
+ this.camera.position.y -= forward.y * (deltaTime * this.flySpeed);
+ this.camera.position.z -= forward.z * (deltaTime * this.flySpeed);
+ }
+
+ if(this.moveLeft) {
+
+ this.camera.position.x -= right.x * (deltaTime * this.flySpeed);
+ this.camera.position.y -= right.y * (deltaTime * this.flySpeed);
+ this.camera.position.z -= right.z * (deltaTime * this.flySpeed);
+
+ } else if(this.moveRight) {
+
+ this.camera.position.x += right.x * (deltaTime * this.flySpeed);
+ this.camera.position.y += right.y * (deltaTime * this.flySpeed);
+ this.camera.position.z += right.z * (deltaTime * this.flySpeed);
+ }
+
+ if(this.moveUp) {
+
+ this.camera.position.y += (deltaTime * this.flySpeed);
+
+ } else if(this.moveDown) {
+
+ this.camera.position.y -= (deltaTime * this.flySpeed);
+
+ }
+};
+
+/**
+ * This update function should be called from the animation function in order to apply the 'frame rate independent'
+ * movement to the camera
+ * @param deltaTime
+ */
+GameLib.D3.FlyControls.prototype.update = function(deltaTime) {
+ this.applyRotation();
+ this.applyTranslation(deltaTime);
+};
+
+/**
+ * Rotate on mouse move
+ * @param event
+ */
+GameLib.D3.FlyControls.prototype.onMouseMove = function ( event ) {
+ if (this.canRotate) {
+ var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0;
+ var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0;
+
+ this.yaw -= movementX * 0.002;
+ this.pitch -= movementY * 0.002;
+ }
+};
+
+/**
+ * Keyboard controls
+ * @param event
+ */
+GameLib.D3.FlyControls.prototype.onKeyDown = function ( event ) {
+ switch ( event.keyCode ) {
+
+ case 87: // w
+ this.moveForward = true;
+ break;
+
+ case 65: // a
+ this.moveLeft = true;
+ break;
+
+ case 83: // s
+ this.moveBackward = true;
+ break;
+
+ case 68: // d
+ this.moveRight = true;
+ break;
+
+ case 104: // keypad up arrow
+ this.moveUp = true;
+ break;
+
+ case 98: // keypad down arrow
+ this.moveDown = true;
+ break;
+ }
+};
+
+/**
+ * Keyboard controls
+ * @param event
+ */
+GameLib.D3.FlyControls.prototype.onKeyUp = function ( event ) {
+ switch ( event.keyCode ) {
+
+ case 38: // up
+ case 87: // w
+ this.moveForward = false;
+ break;
+
+ case 37: // left
+ case 65: // a
+ this.moveLeft = false;
+ break;
+
+ case 40: // down
+ case 83: // s
+ this.moveBackward = false;
+ break;
+
+ case 39: // right
+ case 68: // d
+ this.moveRight = false;
+ break;
+
+ case 104: // keypad up arrow
+ this.moveUp = false;
+ break;
+
+ case 98: // keypad down arrow
+ this.moveDown = false;
+ break;
+ }
+};
+GameLib.D3.Game = function (
+
+) {
+ this.scenes = {};
+ this.physicsWorlds = [];
+ this.sceneToPhysicsWorldsMap = {};
+};
+
+GameLib.D3.Game.prototype.AddScene = function(
+ scene
+) {
+ this.scenes[scene.name] = scene;
+};
+
+GameLib.D3.Game.prototype.AddPhysicsWorld = function(
+ physicsWorld
+) {
+ this.physicsWorlds.push(physicsWorld);
+};
+
+GameLib.D3.Game.prototype.LinkPhysicsWorldToScene = function(
+ physicsWorld,
+ scene
+) {
+ this.sceneToPhysicsWorldsMap[scene.name] = this.sceneToPhysicsWorldsMap[scene.name] || [];
+ this.sceneToPhysicsWorldsMap[scene.name].push(physicsWorld);
+};
+
+GameLib.D3.Game.prototype.GetPhysicsWorldsForScene = function (
+ scene
+) {
+ return this.sceneToPhysicsWorldsMap[scene.name];
+};
+
+GameLib.D3.Game.prototype.ProcessPhysics = function (
+ timestep
+) {
+ for(var s in this.sceneToPhysicsWorldsMap) {
+
+ var physicsWorldArray = this.sceneToPhysicsWorldsMap[s];
+ var scene = this.scenes[s];
+
+ if(scene && physicsWorldArray) {
+
+ for(var i = 0, l = physicsWorldArray.length; i < l; i++) {
+
+ var physicsWorld = physicsWorldArray[i];
+ physicsWorld.Step(timestep);
+
+ for(var p in physicsWorld.linkedPairs) {
+ var pair = physicsWorld.linkedPairs[p];
+ var mesh = pair.threeMesh;
+ var body = pair.physicsBody;
+
+ if(mesh) {
+ if(physicsWorld.engineType === GameLib.D3.Physics.TYPE_CANNON) {
+
+ var quaternion = new THREE.Quaternion();
+ quaternion.copy(body.rigidBodyInstance.quaternion);
+
+ var quaternionCopy = quaternion.clone();
+
+ var position = new THREE.Vector3();
+ position.copy(body.rigidBodyInstance.position);
+
+ if(mesh.permutate) {
+
+ if(mesh.permutate.offset) {
+ if(mesh.permutate.offset.quaternion) {
+ var offsetQuaternion = new THREE.Quaternion();
+ offsetQuaternion.copy(mesh.permutate.offset.quaternion);
+ quaternion = quaternion.multiply(offsetQuaternion).normalize();
+ }
+
+ if(mesh.permutate.offset.position) {
+ var offsetPosition = new THREE.Vector3();
+ offsetPosition.copy(mesh.permutate.offset.position);
+ //position = position.add(offsetPosition);
+ position = position.add(offsetPosition.applyQuaternion(quaternionCopy));
+ }
+ }
+ }
+
+ mesh.position.copy(position);
+ mesh.quaternion.copy(quaternion);
+ }
+ }
+ }
+ }
+ }
+
+ }
+};
+
+GameLib.D3.Game.prototype.LinkPair = function (
+ threeMesh,
+ physicsBody,
+ physicsWorld
+) {
+ physicsWorld.linkedPairs = physicsWorld.linkedPairs || [];
+
+ physicsWorld.linkedPairs.push({
+ threeMesh : threeMesh,
+ physicsBody : physicsBody
+ });
+};
+/**
+ *
+ * @param sizeX Number
+ * @param sizeY Number
+ * @param matrix matrix 2D Array with height data (Column Major)
+ * @constructor
+ */
+GameLib.D3.Heightmap = function(
+ sizeX,
+ sizeY,
+ matrix
+) {
+ if (typeof sizeX == 'undefined') {
+ sizeX = 0;
+ }
+ this.sizeX = sizeX;
+
+ if (typeof sizeY == 'undefined') {
+ sizeY = 0;
+ }
+ this.sizeY = sizeY;
+
+ if (typeof matrix == 'undefined') {
+ matrix = [];
+ }
+ this.matrix = matrix;
+};
+
+GameLib.D3.Heightmap.prototype.generateThreeMeshFromHeightField = function(
+ THREE,
+ heightFieldShape,
+ engine
+) {
+ var geometry = new THREE.Geometry();
+
+ var v0 = new this.physics.CANNON.Vec3();
+ var v1 = new this.physics.CANNON.Vec3();
+ var v2 = new this.physics.CANNON.Vec3();
+
+ var shape = heightFieldShape;
+ for (var xi = 0; xi < shape.data.length - 1; xi++) {
+ for (var yi = 0; yi < shape.data[xi].length - 1; yi++) {
+ for (var k = 0; k < 2; k++) {
+ shape.getConvexTrianglePillar(xi, yi, k===0);
+ v0.copy(shape.pillarConvex.vertices[0]);
+ v1.copy(shape.pillarConvex.vertices[1]);
+ v2.copy(shape.pillarConvex.vertices[2]);
+ v0.vadd(shape.pillarOffset, v0);
+ v1.vadd(shape.pillarOffset, v1);
+ v2.vadd(shape.pillarOffset, v2);
+ geometry.vertices.push(
+ new THREE.Vector3(v0.x, v0.y, v0.z),
+ new THREE.Vector3(v1.x, v1.y, v1.z),
+ new THREE.Vector3(v2.x, v2.y, v2.z)
+ );
+ var i = geometry.vertices.length - 3;
+ geometry.faces.push(new THREE.Face3(i, i+1, i+2));
+ }
+ }
+ }
+ geometry.computeBoundingSphere();
+ geometry.computeFaceNormals();
+
+ return new THREE.Mesh(geometry, new THREE.MeshNormalMaterial({ wireframe : false, shading : THREE.SmoothShading }));
+};
+
+
+GameLib.D3.Heightmap.prototype.generateHeightmapDataFromImage = function (
+ imagePath,
+ callback // receives HeightmapData instance as the first argument
+) {
+ var img = new Image();
+
+ img.onload = function () {
+
+ var canvas = document.createElement('canvas');
+ canvas.width = img.width;
+ canvas.height = img.height;
+
+ var context = canvas.getContext('2d');
+ context.drawImage(img, 0, 0);
+
+ var imgd = context.getImageData(0, 0, img.width, img.height);
+ var pixels = imgd.data;
+
+ var heightList = [];
+ for (var i = 0, n = pixels.length; i < n; i += (4)) {
+ heightList.push(pixels[i]);
+ }
+
+ var matrix = [];
+ var sizeX = img.width,
+ sizeY = img.height;
+
+ for (var i = 0; i < sizeX; i++) {
+ matrix.push([]);
+ for (var j = 0; j < sizeY; j++) {
+ var height = (heightList[(sizeX - i) + j * sizeY] / 255) * 15;
+ matrix[i].push(height);
+ }
+ }
+
+
+ // todo: delete canvas here
+
+ callback(new GameLib.D3.HeightmapData(sizeX, sizeY, matrix));
+ };
+
+ img.src = imagePath;
+};
+/**
+ * Image
+ * @param id
+ * @param textureLink
+ * @param filename
+ * @param size
+ * @param contentType
+ * @constructor
+ */
+GameLib.D3.Image = function(
+ id,
+ textureLink,
+ filename,
+ size,
+ contentType
+) {
+ this.id = id;
+
+ this.filename = filename;
+
+ this.textureLink = textureLink;
+
+ if (typeof size == 'undefined') {
+ size = 0;
+ }
+ this.size = size;
+
+ if (typeof contentType == 'undefined') {
+
+ contentType = 'application/octet-stream';
+
+ if (this.filename.match(/(png)$/i)) {
+ contentType = 'image/png';
+ }
+
+ if (this.filename.match(/(jpg|jpeg)$/i)) {
+ contentType = 'image/jpeg';
+ }
+
+ if (this.filename.match(/(gif)$/i)) {
+ contentType = 'image/gif';
+ }
+ }
+ this.contentType = contentType;
+};
+/**
+ * Light Superset
+ * @param id
+ * @param lightType
+ * @param name
+ * @param color
+ * @param intensity
+ * @param position
+ * @param targetPosition
+ * @param quaternion
+ * @param rotation
+ * @param scale
+ * @param distance
+ * @param decay
+ * @param power
+ * @param angle
+ * @param penumbra
+ * @constructor
+ */
+GameLib.D3.Light = function(
+ id,
+ lightType,
+ name,
+ color,
+ intensity,
+ position,
+ targetPosition,
+ quaternion,
+ rotation,
+ scale,
+ distance,
+ decay,
+ power,
+ angle,
+ penumbra
+) {
+ this.id = id;
+ this.lightType = lightType;
+ this.name = name;
+ this.color = color;
+ this.intensity = intensity;
+
+ if (typeof position == 'undefined') {
+ position = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.position = position;
+
+ if (typeof targetPosition == 'undefined') {
+ targetPosition = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.targetPosition = targetPosition;
+
+ if (typeof quaternion == 'undefined'){
+ quaternion = new GameLib.D3.Vector4();
+ }
+ this.quaternion = quaternion;
+
+ if (typeof rotation == 'undefined'){
+ rotation = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.rotation = rotation;
+
+ if (typeof scale == 'undefined'){
+ scale = new GameLib.D3.Vector3(1,1,1);
+ }
+ this.scale = scale;
+
+ if (typeof distance == 'undefined'){
+ distance = 0;
+ }
+ this.distance = distance;
+
+ if (typeof decay == 'undefined'){
+ decay = 1;
+ }
+ this.decay = decay;
+
+ if (typeof power == 'undefined'){
+ power = 4 * Math.PI;
+ }
+ this.power = power;
+
+ if (typeof angle == 'undefined'){
+ angle = Math.PI / 3;
+ }
+ this.angle = angle;
+
+ if (typeof penumbra == 'undefined'){
+ penumbra = 0;
+ }
+ this.penumbra = penumbra;
+};
+/**
+ * Material Superset
+ * @param id
+ * @param name
+ * @param materialType
+ * @param opacity
+ * @param side
+ * @param transparent
+ * @param maps
+ * @param specular
+ * @param lightMapIntensity
+ * @param aoMapIntensity
+ * @param color
+ * @param emissive
+ * @param emissiveIntensity
+ * @param combine
+ * @param shininess
+ * @param reflectivity
+ * @param refractionRatio
+ * @param fog
+ * @param wireframe
+ * @param wireframeLineWidth
+ * @param wireframeLineCap
+ * @param wireframeLineJoin
+ * @param vertexColors
+ * @param skinning
+ * @param morphTargets
+ * @param morphNormals
+ * @param lineWidth
+ * @param lineCap
+ * @param lineJoin
+ * @param dashSize
+ * @param gapWidth
+ * @param blending
+ * @param blendSrc
+ * @param blendDst
+ * @param blendEquation
+ * @param depthTest
+ * @param depthFunc
+ * @param depthWrite
+ * @param polygonOffset
+ * @param polygonOffsetFactor
+ * @param polygonOffsetUnits
+ * @param alphaTest
+ * @param clippingPlanes
+ * @param clipShadows
+ * @param visible
+ * @param overdraw
+ * @param shading
+ * @param bumpScale
+ * @param normalScale
+ * @param displacementScale
+ * @param displacementBias
+ * @param roughness
+ * @param metalness
+ * @param pointSize
+ * @param pointSizeAttenuation
+ * @param spriteRotation
+ * @param envMapIntensity
+ * @constructor
+ */
+GameLib.D3.Material = function(
+ id,
+ name,
+ materialType,
+ opacity,
+ side,
+ transparent,
+ maps,
+ specular,
+ lightMapIntensity,
+ aoMapIntensity,
+ color,
+ emissive,
+ emissiveIntensity,
+ combine,
+ shininess,
+ reflectivity,
+ refractionRatio,
+ fog,
+ wireframe,
+ wireframeLineWidth,
+ wireframeLineCap,
+ wireframeLineJoin,
+ vertexColors,
+ skinning,
+ morphTargets,
+ morphNormals,
+ lineWidth,
+ lineCap,
+ lineJoin,
+ dashSize,
+ gapWidth,
+ blending,
+ blendSrc,
+ blendDst,
+ blendEquation,
+ depthTest,
+ depthFunc,
+ depthWrite,
+ polygonOffset,
+ polygonOffsetFactor,
+ polygonOffsetUnits,
+ alphaTest,
+ clippingPlanes,
+ clipShadows,
+ visible,
+ overdraw,
+ shading,
+ bumpScale,
+ normalScale,
+ displacementScale,
+ displacementBias,
+ roughness,
+ metalness,
+ pointSize,
+ pointSizeAttenuation,
+ spriteRotation,
+ envMapIntensity
+) {
+ this.id = id;
+ this.name = name;
+ if (typeof materialType == 'undefined') {
+ materialType = GameLib.D3.Material.TYPE_MESH_STANDARD;
+ }
+ this.materialType = materialType;
+
+ if (typeof opacity == 'undefined') {
+ opacity = 1.0;
+ }
+ this.opacity = opacity;
+
+ if (typeof side == 'undefined') {
+ side = GameLib.D3.Material.TYPE_FRONT_SIDE;
+ }
+ this.side = side;
+
+ if (typeof transparent == 'undefined') {
+ transparent = false;
+ }
+ this.transparent = transparent;
+
+ if (typeof maps == 'undefined') {
+ maps = {
+ alpha: null,
+ ao: null,
+ bump: null,
+ diffuse: null,
+ displacement: null,
+ emissive: null,
+ environment: null,
+ light: null,
+ metalness: null,
+ normal: null,
+ roughness: null,
+ specular: null
+ };
+ }
+ this.maps = maps;
+
+ if (typeof specular == 'undefined') {
+ specular = new GameLib.D3.Color(0.06, 0.06, 0.06, 0.06);
+ }
+ this.specular = specular;
+
+ if (typeof lightMapIntensity == 'undefined') {
+ lightMapIntensity = 1;
+ }
+ this.lightMapIntensity = lightMapIntensity;
+
+ if (typeof aoMapIntensity == 'undefined') {
+ aoMapIntensity = 1;
+ }
+ this.aoMapIntensity = aoMapIntensity;
+
+ if (typeof color == 'undefined') {
+ color = new GameLib.D3.Color(1, 1, 1, 1)
+ }
+ this.color = color;
+
+ if (typeof emissive == 'undefined') {
+ emissive = new GameLib.D3.Color(0, 0, 0, 0);
+ }
+ this.emissive = emissive;
+
+ if (typeof emissiveIntensity == 'undefined') {
+ emissiveIntensity = 1;
+ }
+ this.emissiveIntensity = emissiveIntensity;
+
+ if (typeof combine == 'undefined') {
+ combine = GameLib.D3.Material.TYPE_MULTIPLY_OPERATION;
+ }
+ this.combine = combine;
+
+ if (typeof shininess == 'undefined') {
+ shininess = 30;
+ }
+ this.shininess = shininess;
+
+ if (typeof reflectivity == 'undefined') {
+ reflectivity = 1;
+ }
+ this.reflectivity = reflectivity;
+
+ if (typeof refractionRatio == 'undefined') {
+ refractionRatio = 0.98;
+ }
+ this.refractionRatio = refractionRatio;
+
+ if (typeof fog == 'undefined') {
+ fog = true;
+ }
+ this.fog = fog;
+
+ if (typeof wireframe == 'undefined') {
+ wireframe = false;
+ }
+ this.wireframe = wireframe;
+
+ if (typeof wireframeLineWidth == 'undefined') {
+ wireframeLineWidth = 1;
+ }
+ this.wireframeLineWidth = wireframeLineWidth;
+
+ if (typeof wireframeLineCap == 'undefined') {
+ wireframeLineCap = 'round';
+ }
+ this.wireframeLineCap = wireframeLineCap;
+
+ if (typeof wireframeLineJoin == 'undefined') {
+ wireframeLineJoin = 'round';
+ }
+ this.wireframeLineJoin = wireframeLineJoin;
+
+ if (typeof vertexColors == 'undefined') {
+ vertexColors = GameLib.D3.Material.TYPE_NO_COLORS;
+ }
+ this.vertexColors = vertexColors;
+
+ if (typeof skinning == 'undefined') {
+ skinning = false;
+ }
+ this.skinning = skinning;
+
+ if (typeof morphTargets == 'undefined') {
+ morphTargets = false;
+ }
+ this.morphTargets = morphTargets;
+
+ if (typeof morphNormals == 'undefined') {
+ morphNormals = false;
+ }
+ this.morphNormals = morphNormals;
+
+ if (typeof overdraw == 'undefined') {
+ overdraw = 0;
+ }
+ this.overdraw = overdraw;
+
+ if (typeof lineWidth == 'undefined') {
+ lineWidth = 1;
+ }
+ this.lineWidth = lineWidth;
+
+ if (typeof lineCap == 'undefined') {
+ lineCap = 'round';
+ }
+ this.lineCap = lineCap;
+
+ if (typeof lineJoin == 'undefined') {
+ lineJoin = 'round';
+ }
+ this.lineJoin = lineJoin;
+
+ if (typeof dashSize == 'undefined') {
+ dashSize = 3;
+ }
+ this.dashSize = dashSize;
+
+ if (typeof gapWidth == 'undefined') {
+ gapWidth = 1;
+ }
+ this.gapWidth = gapWidth;
+
+ if (typeof blending == 'undefined') {
+ blending = GameLib.D3.Material.TYPE_NORMAL_BLENDING;
+ }
+ this.blending = blending;
+
+ if (typeof blendSrc == 'undefined') {
+ blendSrc = GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR;
+ }
+ this.blendSrc = blendSrc;
+
+ if (typeof blendDst == 'undefined') {
+ blendDst = GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR;
+ }
+ this.blendDst = blendDst;
+
+ if (typeof blendEquation == 'undefined') {
+ blendEquation = GameLib.D3.Material.TYPE_ADD_EQUATION;
+ }
+ this.blendEquation = blendEquation;
+
+ if (typeof depthTest == 'undefined') {
+ depthTest = true;
+ }
+ this.depthTest = depthTest;
+
+ if (typeof depthFunc == 'undefined') {
+ depthFunc = GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH;
+ }
+ this.depthFunc = depthFunc;
+
+ if (typeof depthWrite == 'undefined') {
+ depthWrite = true;
+ }
+ this.depthWrite = depthWrite;
+
+ if (typeof polygonOffset == 'undefined') {
+ polygonOffset = false;
+ }
+ this.polygonOffset = polygonOffset;
+
+ if (typeof polygonOffsetFactor == 'undefined') {
+ polygonOffsetFactor = 1;
+ }
+ this.polygonOffsetFactor = polygonOffsetFactor;
+
+ if (typeof polygonOffsetUnits == 'undefined') {
+ polygonOffsetUnits = 1;
+ }
+ this.polygonOffsetUnits = polygonOffsetUnits;
+
+ if (typeof alphaTest == 'undefined') {
+ alphaTest = 0;
+ }
+ this.alphaTest = alphaTest;
+
+ if (typeof clippingPlanes == 'undefined') {
+ clippingPlanes = [];
+ }
+ this.clippingPlanes = clippingPlanes;
+
+ if (typeof clipShadows == 'undefined') {
+ clipShadows = false;
+ }
+ this.clipShadows = clipShadows;
+
+ if (typeof visible == 'undefined') {
+ visible = true;
+ }
+ this.visible = visible;
+
+ if (typeof shading == 'undefined') {
+ shading = GameLib.D3.Material.TYPE_FLAT_SHADING;
+ }
+ this.shading = shading;
+
+ if (typeof bumpScale == 'undefined') {
+ bumpScale = 1;
+ }
+ this.bumpScale = bumpScale;
+
+ if (typeof normalScale == 'undefined') {
+ normalScale = 1;
+ }
+ this.normalScale = normalScale;
+
+ if (typeof displacementScale == 'undefined') {
+ displacementScale = 1;
+ }
+ this.displacementScale = displacementScale;
+
+ if (typeof displacementBias == 'undefined') {
+ displacementBias = 0;
+ }
+ this.displacementBias = displacementBias;
+
+ if (typeof roughness == 'undefined') {
+ roughness = 0.5;
+ }
+ this.roughness = roughness;
+
+ if (typeof metalness == 'undefined') {
+ metalness = 0.5;
+ }
+ this.metalness = metalness;
+
+ if (typeof pointSize == 'undefined') {
+ pointSize = 1;
+ }
+ this.pointSize = pointSize;
+
+ if (typeof pointSizeAttenuation == 'undefined') {
+ pointSizeAttenuation = true;
+ }
+ this.pointSizeAttenuation = pointSizeAttenuation;
+
+ if (typeof spriteRotation == 'undefined') {
+ spriteRotation = 0;
+ }
+ this.spriteRotation = spriteRotation;
+
+ if (typeof envMapIntensity == 'undefined') {
+ envMapIntensity = 1.0;
+ }
+ this.envMapIntensity = envMapIntensity;
+
+};
+
+/**
+ * Combine Method
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_MULTIPLY_OPERATION = 0;
+GameLib.D3.Material.TYPE_MIX_OPERATION = 1;
+GameLib.D3.Material.TYPE_ADD_OPERATION = 2;
+
+/**
+ * Vertex Color Mode
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_NO_COLORS = 0;
+GameLib.D3.Material.TYPE_FACE_COLORS = 1;
+GameLib.D3.Material.TYPE_VERTEX_COLORS = 2;
+
+/**
+ * Blending Mode
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_NORMAL_BLENDING = 1;
+GameLib.D3.Material.TYPE_ADDITIVE_BLENDING = 2;
+GameLib.D3.Material.TYPE_SUBTRACTIVE_BLENDING = 3;
+GameLib.D3.Material.TYPE_MULTIPLY_BLENDING = 4;
+GameLib.D3.Material.TYPE_CUSTOM_BLENDING = 5;
+
+/**
+ * Blend Source and Destination
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_ZERO_FACTOR = 200;
+GameLib.D3.Material.TYPE_ONE_FACTOR = 201;
+GameLib.D3.Material.TYPE_SRC_COLOR_FACTOR = 202;
+GameLib.D3.Material.TYPE_ONE_MINUS_SRC_COLOR_FACTOR = 203;
+GameLib.D3.Material.TYPE_SRC_ALPHA_FACTOR = 204;
+GameLib.D3.Material.TYPE_ONE_MINUS_SRC_ALPHA_FACTOR = 205;
+GameLib.D3.Material.TYPE_DST_ALPHA_FACTOR = 206;
+GameLib.D3.Material.TYPE_ONE_MINUS_DST_ALPHA_FACTOR = 207;
+GameLib.D3.Material.TYPE_DST_COLOR_FACTOR = 208;
+GameLib.D3.Material.TYPE_ONE_MINUS_DST_COLOR_FACTOR = 209;
+GameLib.D3.Material.TYPE_SRC_ALPHA_SATURATE_FACTOR = 210;
+
+/**
+ * Blend Operation
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_ADD_EQUATION = 100;
+GameLib.D3.Material.TYPE_SUBTRACT_EQUATION = 101;
+GameLib.D3.Material.TYPE_REVERSE_SUBTRACT_EQUATION = 102;
+GameLib.D3.Material.TYPE_MIN_EQUATION = 103;
+GameLib.D3.Material.TYPE_MAX_EQUATION = 104;
+
+/**
+ * Depth Function
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_NEVER_DEPTH = 0;
+GameLib.D3.Material.TYPE_ALWAYS_DEPTH = 1;
+GameLib.D3.Material.TYPE_LESS_DEPTH = 2;
+GameLib.D3.Material.TYPE_LESS_EQUAL_DEPTH = 3;
+GameLib.D3.Material.TYPE_EQUAL_DEPTH = 4;
+GameLib.D3.Material.TYPE_GREATER_EQUAL_DEPTH = 5;
+GameLib.D3.Material.TYPE_GREATER_DEPTH = 6;
+GameLib.D3.Material.TYPE_NOT_EQUAL_DEPTH = 7;
+
+/**
+ * Culling Mode
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_FRONT_SIDE = 0;
+GameLib.D3.Material.TYPE_BACK_SIDE = 1;
+GameLib.D3.Material.TYPE_DOUBLE_SIDE = 2;
+
+/**
+ * Shading Type
+ * @type {number}
+ */
+GameLib.D3.Material.TYPE_FLAT_SHADING = 1;
+GameLib.D3.Material.TYPE_SMOOTH_SHADING = 2;
+
+/**
+ * Material Type
+ * @type {string}
+ */
+GameLib.D3.Material.TYPE_LINE_BASIC = "LineBasicMaterial";
+GameLib.D3.Material.TYPE_LINE_DASHED = "LineDashedMaterial";
+GameLib.D3.Material.TYPE_MESH_BASIC = "MeshBasicMaterial";
+GameLib.D3.Material.TYPE_MESH_DEPTH = "MeshDepthMaterial";
+GameLib.D3.Material.TYPE_MESH_LAMBERT = "MeshLambertMaterial";
+GameLib.D3.Material.TYPE_MESH_NORMAL = "MeshNormalMaterial";
+GameLib.D3.Material.TYPE_MESH_PHONG = "MeshPhongMaterial";
+GameLib.D3.Material.TYPE_MESH_STANDARD = "MeshStandardMaterial";
+GameLib.D3.Material.TYPE_POINTS = "PointsMaterial";
+GameLib.D3.Material.TYPE_SPRITE = "SpriteMaterial";
+GameLib.D3.Material.TYPE_MULTI_MATERIAL= "MultiMaterial";
+
+/**
+ * Creates a THREE.Material from a GameLib.D3.Material
+ * @param blenderMaterial GameLib.D3.Material
+ * @param THREE THREE.js
+ */
+GameLib.D3.prototype.createThreeMaterial = function(blenderMaterial, THREE) {
+
+ var defer = this.Q.defer();
+
+ var threeMaterial = null;
+
+ var blenderMaps = [];
+
+ if (blenderMaterial.materialType == GameLib.D3.Material.TYPE_MESH_STANDARD) {
+
+ threeMaterial = new THREE.MeshStandardMaterial({
+ name: blenderMaterial.name,
+ opacity: blenderMaterial.opacity,
+ transparent: blenderMaterial.transparent,
+ blending: blenderMaterial.blending,
+ blendSrc: blenderMaterial.blendSrc,
+ blendDst: blenderMaterial.blendDst,
+ blendEquation: blenderMaterial.blendEquation,
+ depthTest: blenderMaterial.depthTest,
+ depthFunc: blenderMaterial.depthFunc,
+ depthWrite: blenderMaterial.depthWrite,
+ polygonOffset: blenderMaterial.polygonOffset,
+ polygonOffsetFactor: blenderMaterial.polygonOffsetFactor,
+ polygonOffsetUnits: blenderMaterial.polygonOffsetUnits,
+ alphaTest: blenderMaterial.alphaTest,
+ clippingPlanes: blenderMaterial.clippingPlanes,
+ clipShadows: blenderMaterial.clipShadows,
+ overdraw: blenderMaterial.overdraw,
+ visible: blenderMaterial.visible,
+ side: blenderMaterial.side,
+ color: new THREE.Color(
+ blenderMaterial.color.r,
+ blenderMaterial.color.g,
+ blenderMaterial.color.b
+ ),
+ roughness: blenderMaterial.roughness,
+ metalness: blenderMaterial.metalness,
+ lightMapIntensity: blenderMaterial.lightMapIntensity,
+ aoMapIntensity: blenderMaterial.aoMapIntensity,
+ emissive: new THREE.Color(
+ blenderMaterial.emissive.r,
+ blenderMaterial.emissive.g,
+ blenderMaterial.emissive.b
+ ),
+ emissiveIntensity: blenderMaterial.emissiveIntensity,
+ bumpScale: blenderMaterial.bumpScale,
+ normalScale: blenderMaterial.normalScale,
+ displacementScale: blenderMaterial.displacementScale,
+ refractionRatio: blenderMaterial.refractionRatio,
+ fog: blenderMaterial.fog,
+ shading: blenderMaterial.shading,
+ wireframe: blenderMaterial.wireframe,
+ wireframeLinewidth: blenderMaterial.wireframeLineWidth,
+ wireframeLinecap: blenderMaterial.wireframeLineCap,
+ wireframeLinejoin: blenderMaterial.wireframeLineJoin,
+ vertexColors: blenderMaterial.vertexColors,
+ skinning: blenderMaterial.skinning,
+ morphTargets: blenderMaterial.morphTargets,
+ morphNormals: blenderMaterial.morphNormals
+ });
+
+ blenderMaps.push(
+ 'diffuse',
+ 'light',
+ 'ao',
+ 'emissive',
+ 'bump',
+ 'normal',
+ 'displacement',
+ 'roughness',
+ 'metalness',
+ 'alpha',
+ 'environment'
+ );
+ } else if (blenderMaterial.materialType == GameLib.D3.Material.TYPE_MESH_PHONG) {
+
+ threeMaterial = new THREE.MeshPhongMaterial({
+ name: blenderMaterial.name,
+ opacity: blenderMaterial.opacity,
+ transparent: blenderMaterial.transparent,
+ blending: blenderMaterial.blending,
+ blendSrc: blenderMaterial.blendSrc,
+ blendDst: blenderMaterial.blendDst,
+ blendEquation: blenderMaterial.blendEquation,
+ depthTest: blenderMaterial.depthTest,
+ depthFunc: blenderMaterial.depthFunc,
+ depthWrite: blenderMaterial.depthWrite,
+ polygonOffset: blenderMaterial.polygonOffset,
+ polygonOffsetFactor: blenderMaterial.polygonOffsetFactor,
+ polygonOffsetUnits: blenderMaterial.polygonOffsetUnits,
+ alphaTest: blenderMaterial.alphaTest,
+ clippingPlanes: blenderMaterial.clippingPlanes,
+ clipShadows: blenderMaterial.clipShadows,
+ overdraw: blenderMaterial.overdraw,
+ visible: blenderMaterial.visible,
+ side: blenderMaterial.side,
+ color: new THREE.Color(
+ blenderMaterial.color.r,
+ blenderMaterial.color.g,
+ blenderMaterial.color.b
+ ),
+ specular: new THREE.Color(
+ blenderMaterial.specular.r,
+ blenderMaterial.specular.g,
+ blenderMaterial.specular.b
+ ),
+ shininess: blenderMaterial.shininess,
+ lightMapIntensity: blenderMaterial.lightMapIntensity,
+ aoMapIntensity: blenderMaterial.aoMapIntensity,
+ emissive: new THREE.Color(
+ blenderMaterial.emissive.r,
+ blenderMaterial.emissive.g,
+ blenderMaterial.emissive.b
+ ),
+ emissiveIntensity: blenderMaterial.emissiveIntensity,
+ bumpScale: blenderMaterial.bumpScale,
+ normalScale: blenderMaterial.normalScale,
+ displacementScale: blenderMaterial.displacementScale,
+ combine: blenderMaterial.combine,
+ refractionRatio: blenderMaterial.refractionRatio,
+ fog: blenderMaterial.fog,
+ shading: blenderMaterial.shading,
+ wireframe: blenderMaterial.wireframe,
+ wireframeLinewidth: blenderMaterial.wireframeLineWidth,
+ wireframeLinecap: blenderMaterial.wireframeLineCap,
+ wireframeLinejoin: blenderMaterial.wireframeLineJoin,
+ vertexColors: blenderMaterial.vertexColors,
+ skinning: blenderMaterial.skinning,
+ morphTargets: blenderMaterial.morphTargets,
+ morphNormals: blenderMaterial.morphNormals
+ });
+
+ blenderMaps.push(
+ 'diffuse',
+ 'light',
+ 'ao',
+ 'emissive',
+ 'bump',
+ 'normal',
+ 'displacement',
+ 'specular',
+ 'alpha',
+ 'environment'
+ );
+
+ } else {
+ console.log("material type is not implemented yet: " + blenderMaterial.materialType + " - material indexes could be screwed up");
+ }
+
+ if (blenderMaps.length > 0) {
+ var textureMaps = this.loadMaps(blenderMaterial, blenderMaps, threeMaterial);
+ Q.all(textureMaps).then(
+ function(){
+ defer.resolve(threeMaterial);
+ }
+ ).catch(
+ function(error){
+ console.log(error);
+ defer.reject(error);
+ }
+ )
+ } else {
+ defer.resolve(threeMaterial);
+ }
+
+ return defer.promise;
+};
+/**
+ * Matrix 3 Maths
+ * @param row0 GameLib.D3.Vector3
+ * @param row1 GameLib.D3.Vector3
+ * @param row2 GameLib.D3.Vector3
+ * @constructor
+ */
+GameLib.D3.Matrix3 = function(
+ row0,
+ row1,
+ row2
+) {
+ this.identity();
+
+ if (row0) {
+ this.rows[0] = row0;
+ }
+
+ if (row1) {
+ this.rows[1] = row1;
+ }
+
+ if (row2) {
+ this.rows[2] = row2;
+ }
+};
+
+/**
+ * Set matrix to identity
+ */
+GameLib.D3.Matrix3.prototype.identity = function () {
+ this.rows = [
+ new GameLib.D3.Vector4(1, 0, 0),
+ new GameLib.D3.Vector4(0, 1, 0),
+ new GameLib.D3.Vector4(0, 0, 1)
+ ];
+};
+GameLib.D3.Matrix4 = function(
+ row0,
+ row1,
+ row2,
+ row3
+) {
+
+ this.identity();
+
+ if (row0) {
+ this.rows[0] = row0;
+ }
+
+ if (row1) {
+ this.rows[1] = row1;
+ }
+
+ if (row2) {
+ this.rows[2] = row2;
+ }
+
+ if (row3) {
+ this.rows[3] = row3;
+ }
+};
+
+GameLib.D3.Matrix4.prototype.rotationMatrixX = function (radians) {
+ this.identity();
+ this.rows[1] = new GameLib.D3.Vector4(0, Math.cos(radians), -1 * Math.sin(radians), 0);
+ this.rows[2] = new GameLib.D3.Vector4(0, Math.sin(radians), Math.cos(radians), 0);
+ return this;
+};
+
+GameLib.D3.Matrix4.prototype.rotationMatrixY = function (radians) {
+ this.identity();
+ this.rows[0] = new GameLib.D3.Vector4(
+ Math.cos(radians),
+ 0,
+ Math.sin(radians),
+ 0
+ );
+ this.rows[2] = new GameLib.D3.Vector4(
+ -1 * Math.sin(radians),
+ 0,
+ Math.cos(radians),
+ 0
+ );
+ return this;
+};
+
+GameLib.D3.Matrix4.prototype.rotationMatrixZ = function (radians) {
+ this.identity();
+ this.rows[0] = new GameLib.D3.Vector4(Math.cos(radians), -1 * Math.sin(radians), 0, 0);
+ this.rows[1] = new GameLib.D3.Vector4(Math.sin(radians), Math.cos(radians), 0, 0);
+ return this;
+};
+
+GameLib.D3.Matrix4.prototype.rotateX = function (radians, point) {
+ this.identity();
+ this.rotationMatrixX(radians);
+ return this.multiply(point);
+};
+
+GameLib.D3.Matrix4.prototype.rotateY = function (radians, point) {
+ this.identity();
+ this.rotationMatrixY(radians);
+ return this.multiply(point);
+};
+
+GameLib.D3.Matrix4.prototype.rotateZ = function (radians, point) {
+ this.identity();
+ this.rotationMatrixZ(radians);
+ return this.multiply(point);
+};
+
+GameLib.D3.Matrix4.prototype.multiply = function (mvp) {
+ if (mvp instanceof GameLib.D3.Vector4) {
+ return new GameLib.D3.Vector4(
+ this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z + this.rows[0].w * mvp.w,
+ this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z + this.rows[1].w * mvp.w,
+ this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z + this.rows[2].w * mvp.w,
+ this.rows[3].x * mvp.x + this.rows[3].y * mvp.y + this.rows[3].z * mvp.z + this.rows[3].w * mvp.w
+ );
+ } else if (mvp instanceof GameLib.D3.Vector3) {
+ return new GameLib.D3.Vector3(
+ this.rows[0].x * mvp.x + this.rows[0].y * mvp.y + this.rows[0].z * mvp.z,
+ this.rows[1].x * mvp.x + this.rows[1].y * mvp.y + this.rows[1].z * mvp.z,
+ this.rows[2].x * mvp.x + this.rows[2].y * mvp.y + this.rows[2].z * mvp.z
+ );
+ }
+};
+
+GameLib.D3.Matrix4.prototype.identity = function () {
+ this.rows = [
+ new GameLib.D3.Vector4(1, 0, 0, 0),
+ new GameLib.D3.Vector4(0, 1, 0, 0),
+ new GameLib.D3.Vector4(0, 0, 1, 0),
+ new GameLib.D3.Vector4(0, 0, 0, 1)
+ ];
+};
+
+GameLib.D3.Matrix4.prototype.lookAt = function (position, target, up) {
+
+ var pv = new GameLib.D3.Vector3(position.x, position.y, position.z);
+
+ var z = pv.subtract(target).normalize();
+
+ if (z.squared() === 0) {
+ z.z = 1;
+ }
+
+ var x = up.cross(z).normalize();
+
+ if (x.squared() === 0) {
+ z.x += 0.0001;
+ x = up.cross(z).normalize();
+ }
+
+ var y = z.cross(x);
+
+ this.rows[0].x = x.x;
+ this.rows[0].y = x.y;
+ this.rows[0].z = x.z;
+
+ this.rows[1].x = y.x;
+ this.rows[1].y = y.y;
+ this.rows[1].z = y.z;
+
+ this.rows[2].x = z.x;
+ this.rows[2].y = z.y;
+ this.rows[2].z = z.z;
+
+ return this;
+
+ // te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
+ // te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
+ // te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
+
+
+ // var matrix4 = new Matrix4();
+ //
+ // matrix4.rows[0] = side.negative();
+ // matrix4.rows[1] = _up;
+ // matrix4.rows[2] = forward;
+
+ //
+ // matrix4.setColumn(0, side.negative());
+ // matrix4.setColumn(1, _up);
+ // matrix4.setColumn(2, forward);
+
+ //return matrix4;
+
+ // return new Matrix4(
+ // new Vector4(
+ // side.x,
+ // side.y,
+ // side.z,
+ // side.negative().dot(position)
+ // ),
+ // new Vector4(
+ // _up.x,
+ // _up.y,
+ // _up.z,
+ // _up.negative().dot(position)
+ // ),
+ // new Vector4(
+ // forward.negative().x,
+ // forward.negative().y,
+ // forward.negative().z,
+ // forward.dot(position)
+ // )
+ // )
+};
+
+/**
+ * Mesh Superset
+ * @param id
+ * @param path
+ * @param name
+ * @param meshType
+ * @param vertices
+ * @param faces
+ * @param skeleton
+ * @param faceVertexUvs
+ * @param skinIndices
+ * @param skinWeights
+ * @param materials
+ * @param position
+ * @param quaternion
+ * @param rotation
+ * @param scale
+ * @param up
+ * @param physics
+ * @param parentMeshId
+ * @param parentSceneId
+ * @param rawData
+ * @constructor
+ */
+GameLib.D3.Mesh = function(
+ id,
+ path,
+ name,
+ meshType,
+ vertices,
+ faces,
+ skeleton,
+ faceVertexUvs,
+ skinIndices,
+ skinWeights,
+ materials,
+ position,
+ quaternion,
+ rotation,
+ scale,
+ up,
+ physics,
+ parentMeshId,
+ parentSceneId,
+ rawData
+) {
+ this.id = id;
+ this.path = path;
+ this.name = name;
+ this.meshType = meshType;
+ this.vertices = vertices;
+ this.faces = faces;
+
+ if (typeof skeleton == 'undefined') {
+ skeleton = null;
+ }
+ this.skeleton = skeleton;
+
+ if (typeof faceVertexUvs == 'undefined') {
+ faceVertexUvs = [];
+ }
+ this.faceVertexUvs = faceVertexUvs;
+
+ if (typeof skinIndices == 'undefined') {
+ skinIndices = [];
+ }
+ this.skinIndices = skinIndices;
+
+ if (typeof skinWeights == 'undefined') {
+ skinWeights = [];
+ }
+ this.skinWeights = skinWeights;
+
+ if (typeof materials == 'undefined') {
+ materials = [];
+ }
+ this.materials = materials;
+
+ if (typeof position == 'undefined') {
+ position = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.position = position;
+
+ if (typeof quaternion == 'undefined') {
+ new GameLib.D3.Vector4();
+ }
+ this.quaternion = quaternion;
+
+ if (typeof rotation == 'undefined') {
+ rotation = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.rotation = rotation;
+
+ if (typeof scale == 'undefined') {
+ scale = new GameLib.D3.Vector3(1,1,1);
+ }
+ this.scale = scale;
+
+ if (typeof up == 'undefined') {
+ up = new GameLib.D3.Vector3(0,1,0);
+ }
+ this.up = up;
+
+ this.physics = physics;
+
+ this.parentMeshId = parentMeshId;
+
+ this.parentSceneId = parentSceneId;
+
+ this.rawData = null;// rawData;
+};
+
+
+/**
+ * Mesh Type
+ * @type {number}
+ */
+GameLib.D3.Mesh.TYPE_NORMAL = 0;
+GameLib.D3.Mesh.TYPE_SKINNED = 1;
+
+
+/**
+ * Creates a THREE Mesh from GameLib.D3.Mesh
+ * @param gameLibMesh
+ * @param threeGeometry
+ * @param threeMaterial
+ * @returns {*}
+ */
+GameLib.D3.prototype.createThreeMesh = function(gameLibMesh, threeGeometry, threeMaterial) {
+
+ var threeMesh = null;
+
+ if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_NORMAL) {
+ threeMesh = new this.THREE.Mesh(threeGeometry, threeMaterial);
+ }
+
+ if (gameLibMesh.meshType == GameLib.D3.Mesh.TYPE_SKINNED) {
+
+ var bones = gameLibMesh.skeleton.bones;
+
+ var skinIndices = gameLibMesh.skinIndices;
+
+ var skinWeights = gameLibMesh.skinWeights;
+
+ var threeBones = [];
+
+ for (var bi = 0; bi < bones.length; bi++) {
+
+ var bone = new this.THREE.Bone();
+
+ bone.name = bones[bi].name;
+
+ bone.position.x = bones[bi].position.x;
+ bone.position.y = bones[bi].position.y;
+ bone.position.z = bones[bi].position.z;
+
+ bone.rotation.x = bones[bi].rotation.x;
+ bone.rotation.y = bones[bi].rotation.y;
+ bone.rotation.z = bones[bi].rotation.z;
+
+ bone.quaternion.x = bones[bi].quaternion.x;
+ bone.quaternion.y = bones[bi].quaternion.y;
+ bone.quaternion.z = bones[bi].quaternion.z;
+ bone.quaternion.w = bones[bi].quaternion.w;
+
+ bone.scale.x = bones[bi].scale.x;
+ bone.scale.y = bones[bi].scale.y;
+ bone.scale.z = bones[bi].scale.z;
+
+ bone.up.x = bones[bi].up.x;
+ bone.up.y = bones[bi].up.y;
+ bone.up.z = bones[bi].up.z;
+
+ threeBones.push(bone);
+ }
+
+ /**
+ * Setup the bone relationships
+ */
+ for (var br = 0; br < bones.length; br++) {
+ for (var cbi = 0; cbi < bones[br].childBoneIds.length; cbi++) {
+ threeBones[br].add(threeBones[bones[br].childBoneIds[cbi]]);
+ }
+ }
+
+ /**
+ * Setup bones (indexes)
+ */
+ for (var si = 0; si < skinIndices.length; si++) {
+ threeGeometry.skinIndices.push(
+ new this.THREE.Vector4(
+ skinIndices[si].x,
+ skinIndices[si].y,
+ skinIndices[si].z,
+ skinIndices[si].w
+ )
+ );
+ }
+
+ /**
+ * Setup bones (weights)
+ */
+ for (var sw = 0; sw < skinWeights.length; sw++) {
+ threeGeometry.skinWeights.push(
+ new this.THREE.Vector4(
+ skinWeights[sw].x,
+ skinWeights[sw].y,
+ skinWeights[sw].z,
+ skinWeights[sw].w
+ )
+ );
+ }
+
+ threeMesh = new this.THREE.SkinnedMesh(threeGeometry, threeMaterial);
+
+ var skeleton = new this.THREE.Skeleton(threeBones);
+
+ skeleton.useVertexTexture = gameLibMesh.skeleton.useVertexTexture;
+
+ for (var i = 0; i < bones.length; i++) {
+ if (bones[i].parentBoneId === null) {
+ threeMesh.add(threeBones[i]);
+ break;
+ }
+ }
+
+ threeMesh.bind(skeleton);
+
+ threeMesh.pose();
+
+ threeMesh.skeleton.skeletonHelper = new this.THREE.SkeletonHelper(threeMesh);
+ threeMesh.skeleton.skeletonHelper.material.linewidth = 5;
+ }
+
+ if (threeMesh == null) {
+ console.log('cannot handle meshes of type ' + gameLibMesh.meshType + ' yet.');
+ }
+
+ gameLibMesh.threeMeshId = threeMesh.id;
+
+ return threeMesh;
+};
+
+GameLib.D3.prototype.invertWindingOrder = function(triangles) {
+
+ for (var i = 0; i < triangles.length; i++) {
+ var v1 = triangles[i].v1;
+ triangles[i].v1 = triangles[i].v2;
+ triangles[i].v2 = v1;
+
+ var backupUV = triangles[i].triangle.v1uv;
+ triangles[i].triangle.v1uv = triangles[i].triangle.v2uv;
+ triangles[i].triangle.v2uv = backupUV;
+ }
+
+ return triangles;
+};
+
+/**
+ * This function resets a the winding order of a mesh from a reference point V (the average center of the mesh)
+ */
+GameLib.D3.prototype.resetWindingOrder = function(faces, vertices) {
+
+ var vertexList = new GameLib.D3.Vector3.Points();
+
+ for (var v = 0; v < vertices.length; v++) {
+ vertexList.add(new GameLib.D3.Vector3(
+ vertices[v].position.x,
+ vertices[v].position.y,
+ vertices[v].position.z
+ ));
+ }
+
+ var V = vertexList.average();
+
+ var triangles = [];
+
+ for (var s = 0; s < faces.length; s += 3) {
+
+ var v0 = faces[s];
+ var v1 = faces[s+1];
+ var v2 = faces[s+2];
+
+ triangles.push(
+ {
+ v0 : v0,
+ v1 : v1,
+ v2 : v2,
+ edges : [
+ {v0: v0, v1: v1},
+ {v0: v1, v1: v2},
+ {v0: v2, v1: v0}
+ ],
+ winding : 0,
+ edgeIndex : -1,
+ processed : false
+ }
+ );
+ }
+
+ for (var i = 0; i < triangles.length; i++) {
+ if (
+ GameLib.D3.Vector3.clockwise(
+ vertices[triangles[i].v0].position,
+ vertices[triangles[i].v1].position,
+ vertices[triangles[i].v2].position,
+ V
+ )
+ ) {
+ console.log('clockwise');
+ var bv1 = triangles[i].v1;
+ triangles[i].v1 = triangles[i].v2;
+ triangles[i].v2 = bv1;
+ } else {
+ console.log('not clockwise');
+ }
+ }
+
+ return triangles;
+};
+
+/**
+ * This function resets the winding order for triangles in faces, given an initial triangle and orientation edge
+ * used pseudocode from
+ * http://stackoverflow.com/questions/17036970/how-to-correct-winding-of-triangles-to-counter-clockwise-direction-of-a-3d-mesh
+ * We need to use a graph traversal algorithm,
+ * lets assume we have method that returns neighbor of triangle on given edge
+ *
+ * neighbor_on_egde( next_tria, edge )
+ *
+ * to_process = set of pairs triangle and orientation edge, initial state is one good oriented triangle with any edge on it
+ * processed = set of processed triangles; initial empty
+ *
+ * while to_process is not empty:
+ * next_tria, orientation_edge = to_process.pop()
+ * add next_tria in processed
+ * if next_tria is not opposite oriented than orientation_edge:
+ * change next_tria (ABC) orientation (B<->C)
+ * for each edge (AB) in next_tria:
+ * neighbor_tria = neighbor_on_egde( next_tria, edge )
+ * if neighbor_tria exists and neighbor_tria not in processed:
+ * to_process add (neighbor_tria, edge opposite oriented (BA))
+ * @param faces GameLib.D3.TriangleFace[]
+ * @param orientationEdge GameLib.D3.Vector2
+ * @returns {Array}
+ */
+GameLib.D3.fixWindingOrder = function(faces, orientationEdge) {
+
+ /**
+ * Checks if a TriangleFace belonging to a TriangleEdge has already been processed
+ * @param processed TriangleEdge[]
+ * @param triangle TriangleFace
+ * @returns {boolean}
+ */
+ function inProcessed(processed, triangle) {
+
+ for (var i = 0; i < processed.length; i++) {
+ if (processed[i].triangle.equals(triangle)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Returns a neighbouring triangle on a specific edge - preserving the edge orientation
+ * @param edge GameLib.D3.Vector2
+ * @param faces GameLib.D3.TriangleFace[]
+ * @param currentTriangle
+ * @returns {*}
+ */
+ function neighbourOnEdge(edge, faces, currentTriangle) {
+
+ for (var i = 0; i < faces.length; i++) {
+ if (
+ (faces[i].v0 == edge.x && faces[i].v1 == edge.y) ||
+ (faces[i].v1 == edge.x && faces[i].v2 == edge.y) ||
+ (faces[i].v2 == edge.x && faces[i].v0 == edge.y) ||
+ (faces[i].v0 == edge.y && faces[i].v1 == edge.x) ||
+ (faces[i].v1 == edge.y && faces[i].v2 == edge.x) ||
+ (faces[i].v2 == edge.y && faces[i].v0 == edge.x)
+ ) {
+
+ var triangle = new GameLib.D3.TriangleFace(
+ faces[i].v0,
+ faces[i].v1,
+ faces[i].v2,
+ faces[i].materialIndex,
+ faces[i].v0uv,
+ faces[i].v1uv,
+ faces[i].v2uv
+ );
+
+ if (triangle.equals(currentTriangle)) {
+ continue;
+ }
+
+ return new GameLib.D3.TriangleEdge(
+ triangle,
+ edge
+ );
+ }
+ }
+
+ return null;
+ }
+
+ var toProcess = [
+ new GameLib.D3.TriangleEdge(
+ new GameLib.D3.TriangleFace(
+ faces[0].v0,
+ faces[0].v1,
+ faces[0].v2,
+ faces[0].materialIndex,
+ faces[0].v0uv,
+ faces[0].v1uv,
+ faces[0].v2uv
+ ),
+ orientationEdge
+ )
+ ];
+
+ var processed = [];
+
+ while (toProcess.length > 0) {
+
+ var triangleEdge = toProcess.pop();
+
+ /**
+ * If edge is the same orientation (i.e. the edge order is the same as the given triangle edge) it needs to be reversed
+ * to have the same winding order)
+ */
+ if (
+ (triangleEdge.triangle.v0 == triangleEdge.edge.x &&
+ triangleEdge.triangle.v1 == triangleEdge.edge.y) ||
+ (triangleEdge.triangle.v1 == triangleEdge.edge.x &&
+ triangleEdge.triangle.v2 == triangleEdge.edge.y) ||
+ (triangleEdge.triangle.v2 == triangleEdge.edge.x &&
+ triangleEdge.triangle.v0 == triangleEdge.edge.y)
+ ) {
+ var backupV = triangleEdge.triangle.v1;
+ triangleEdge.triangle.v1 = triangleEdge.triangle.v2;
+ triangleEdge.triangle.v2 = backupV;
+
+ var backupUV = triangleEdge.triangle.v1uv;
+ triangleEdge.triangle.v1uv = triangleEdge.triangle.v2uv;
+ triangleEdge.triangle.v2uv = backupUV;
+ }
+
+ processed.push(triangleEdge);
+
+ var edges = [
+ new GameLib.D3.Vector2(
+ triangleEdge.triangle.v0,
+ triangleEdge.triangle.v1
+ ),
+ new GameLib.D3.Vector2(
+ triangleEdge.triangle.v1,
+ triangleEdge.triangle.v2
+ ),
+ new GameLib.D3.Vector2(
+ triangleEdge.triangle.v2,
+ triangleEdge.triangle.v0
+ )
+ ];
+
+ for (var j = 0; j < edges.length; j++) {
+ var neighbour = neighbourOnEdge(edges[j], faces, triangleEdge.triangle);
+ if (neighbour && !inProcessed(processed, neighbour.triangle)) {
+ toProcess.push(neighbour);
+ }
+ }
+ }
+
+ /**
+ * In processed - we will have some duplicates - only add the unique ones
+ * @type {Array}
+ */
+ var triangles = [];
+ for (var i = 0; i < processed.length; i++) {
+ var found = false;
+ for (var k = 0; k < triangles.length; k++) {
+ if (triangles[k].equals(processed[i].triangle)){
+ found = true;
+ break;
+ }
+ }
+ if (!found) {
+ triangles.push(processed[i].triangle);
+ }
+ }
+
+ return triangles;
+};
+
+/**
+ * This is a work-around function to fix polys which don't triangulate because
+ * they could lie on Z-plane (XZ or YZ)) - we translate the poly to the origin, systematically rotate the poly around
+ * Z then Y axis
+ * @param verticesFlat []
+ * @param grain is the amount to systematically rotate the poly by - a finer grain means a more accurate maximum XY
+ * @return []
+ */
+GameLib.D3.fixPolyZPlane = function(verticesFlat, grain) {
+
+ if ((verticesFlat.length % 3) != 0 && !(verticesFlat.length > 9)) {
+ console.log("The vertices are not in the right length : " + verticesFlat.length);
+ }
+
+ var vertices = [];
+
+ var points = new GameLib.D3.Vector4.Points();
+
+ for (var i = 0; i < verticesFlat.length; i += 3) {
+ points.add(new GameLib.D3.Vector3(
+ verticesFlat[i],
+ verticesFlat[i + 1],
+ verticesFlat[i + 2]
+ ));
+ }
+
+ points.toOrigin();
+
+ points.maximizeXDistance(grain);
+
+ points.maximizeYDistance(grain);
+
+ for (i = 0; i < points.vectors.length; i++) {
+ vertices.push(
+ [
+ points.vectors[i].x,
+ points.vectors[i].y
+ ]
+ );
+ }
+
+ return vertices;
+};
+/**
+ * Physics SuperSet Namespace Object
+ * @param id
+ * @param name
+ * @param engine GameLib.D3.Engine
+ * @param worlds
+ * @returns {{World: World}}
+ * @constructor
+ */
+GameLib.D3.Physics = function(
+ id,
+ name,
+ engine,
+ worlds
+) {
+ this.id = id;
+ this.name = name;
+ this.engine = engine;
+
+ if (typeof worlds == 'undefined') {
+ worlds = [];
+ }
+ this.worlds = worlds;
+};
+
+
+/**
+ * Solver Types
+ * @type {number}
+ */
+GameLib.D3.Physics.SPLIT_SOLVER = 0x1;
+GameLib.D3.Physics.GS_SOLVER = 0x2;
+/**
+ * Contains a Poly vertex data structure
+ * @param localIndex
+ * @param mvertIndex
+ * @param uv GameLib.D3.Vector2
+ * @param materialIndex
+ * @param edgeIndex
+ * @constructor
+ */
+GameLib.D3.PolyVertex = function(
+ localIndex,
+ mvertIndex,
+ uv,
+ materialIndex,
+ edgeIndex
+) {
+ this.localIndex = localIndex;
+ this.mvertIndex = mvertIndex;
+ this.uv = uv;
+ this.materialIndex = materialIndex;
+ this.edgeIndex = edgeIndex;
+};
+
+/**
+ * Clone a PolyVertex
+ * @returns {GameLib.D3.PolyVertex}
+ */
+GameLib.D3.PolyVertex.prototype.clone = function() {
+ return new GameLib.D3.PolyVertex(
+ this.localIndex,
+ this.mvertIndex,
+ this.uv.copy(),
+ this.materialIndex,
+ this.edgeIndex
+ )
+};
+/**
+ * Physics Raycast Vehicle Superset
+ * TODO: body + wheels[]
+ * @constructor
+ */
+GameLib.D3.RaycastVehicle = function(
+) {
+ this.vehicleObject = null;
+};
+
+GameLib.D3.RaycastVehicle.prototype.GetWheelInfo = function(
+
+) {
+ // note: need a way to determine which engine we are currently using
+ return this.vehicleObject.wheelInfos;
+};
+
+/**
+ * Physics Rigid Body Vehicle Superset
+ * TODO: body + wheels[]
+ * @constructor
+ */
+GameLib.D3.RigidVehicle = function(
+) {
+ this.vehicleObject = null;
+};
+
+GameLib.D3.RigidVehicle.prototype.GetWheelInfo = function(
+
+) {
+ // note: need a way to determine which engine we are currently using
+ return this.vehicleObject.wheelBodies;
+};
+
+/**
+ * RigidBody Superset
+ * @param mass
+ * @param friction
+ * @param position
+ * @param quaternion
+ * @param velocity
+ * @param angularVelocity
+ * @param linearDamping
+ * @param angularDamping
+ * @param allowSleep
+ * @param sleepSpeedLimit
+ * @param sleepTimeLimit
+ * @param collisionFilterGroup
+ * @param collisionFilterMask
+ * @param fixedRotation
+ * @param shape
+ * @returns {GameLib.D3.Physics.RigidBody}
+ * @constructor
+ */
+GameLib.D3.RigidBody = function(
+ mass,
+ friction,
+ position,
+ quaternion,
+ velocity,
+ angularVelocity,
+ linearDamping,
+ angularDamping,
+ allowSleep,
+ sleepSpeedLimit,
+ sleepTimeLimit,
+ collisionFilterGroup,
+ collisionFilterMask,
+ fixedRotation,
+ shape
+) {
+
+ this.position = position || new GameLib.D3.Vector3();
+ this.velocity = velocity || new GameLib.D3.Vector3();
+ this.angularVelocity = angularVelocity || new GameLib.D3.Vector3();
+ this.quaternion = quaternion || new GameLib.D3.Vector4(0, 0, 0, 1);
+ this.mass = typeof mass == "undefined" ? 0 : mass;
+ this.friction = typeof friction == "undefined" ? 5 : friction;
+ this.linearDamping = typeof linearDamping == "undefined" ? 0.01 : linearDamping;
+ this.angularDamping = typeof angularDamping == "undefined" ? 0.01 : angularDamping;
+ this.allowSleep = typeof allowSleep == "undefined" ? true : allowSleep;
+ this.sleepSpeedLimit = typeof sleepSpeedLimit == "undefined" ? 0.1 : sleepSpeedLimit;
+ this.sleepTimeLimit = typeof sleepTimeLimit == "undefined" ? 1.0 : sleepTimeLimit;
+ this.collisionFilterGroup = typeof collisionFilterGroup == "undefined" ? 1 : collisionFilterGroup;
+ this.collisionFilterMask = typeof collisionFilterMask == "undefined" ? 1 : collisionFilterMask;
+ this.fixedRotation = typeof fixedRotation == "undefined" ? false : fixedRotation;
+ this.shape = typeof shape == "undefined" ? null : shape;
+
+ this.rigidBodyInstance = this.createRigidBodyInstance();
+};
+
+/**
+ *
+ * @returns {*}
+ */
+GameLib.D3.RigidBody.prototype.createRigidBodyInstance = function() {
+
+ var rigidBody = null;
+
+ // Create the bodyObject
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ rigidBody = new this.physics.CANNON.Body(
+ {
+ mass: mass,
+ friction: friction,
+ position: new this.physics.CANNON.Vec3(position.x, position.y, position.z),
+ velocity: new this.physics.CANNON.Vec3(velocity.x, velocity.y, velocity.z),
+ quaternion: new this.physics.CANNON.Quaternion(quaternion.x, quaternion.y, quaternion.z, quaternion.w),
+ angularVelocity: new this.physics.CANNON.Vec3(angularVelocity.x, angularVelocity.y, angularVelocity.z),
+ linearDamping: linearDamping,
+ angularDamping: angularDamping,
+ allowSleep: allowSleep,
+ sleepSpeedLimit: sleepSpeedLimit,
+ sleepTimeLimit: sleepTimeLimit,
+ collisionFilterGroup: collisionFilterGroup,
+ collisionFilterMask: collisionFilterMask,
+ fixedRotation: fixedRotation,
+ shape: shape
+ }
+ );
+
+ }
+
+ return rigidBody;
+};
+
+
+/**
+ * Scenes are objects putting meshes into 'world space'
+ * @param id
+ * @param path String
+ * @param name String
+ * @param meshes GameLib.D3.Mesh[]
+ * @param quaternion
+ * @param position
+ * @param rotation
+ * @param scale
+ * @param parentSceneId
+ * @param lights
+ * @constructor
+ */
+GameLib.D3.Scene = function(
+ id,
+ path,
+ name,
+ meshes,
+ quaternion,
+ position,
+ rotation,
+ scale,
+ parentSceneId,
+ lights,
+ physics
+) {
+ this.id = id;
+ this.path = path;
+ this.name = name;
+ if (this.name.trim() == "") {
+ this.name = 'unnamed';
+ }
+ this.meshes = meshes;
+
+ if (typeof quaternion == 'undefined') {
+ quaternion = new GameLib.D3.Vector4();
+ }
+ this.quaternion = quaternion;
+
+ if (typeof position == 'undefined') {
+ position = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.position = position;
+
+ if (typeof rotation == 'undefined') {
+ rotation = new GameLib.D3.Vector3(0,0,0);
+ }
+ this.rotation = rotation;
+
+ if (typeof scale == 'undefined') {
+ scale = new GameLib.D3.Vector3(1,1,1);
+ }
+ this.scale = scale;
+
+ if (typeof parentSceneId == 'undefined') {
+ parentSceneId = null;
+ }
+ this.parentSceneId = parentSceneId;
+
+ if (typeof lights == 'undefined') {
+ lights = [];
+ }
+ this.lights = lights;
+
+ if (typeof physics == 'undefined') {
+ physics = [];
+ }
+ this.physics = physics;
+};
+
+/**
+ * Loads a scene directly from the API
+ * @param sceneName
+ * @param onLoaded callback
+ */
+GameLib.D3.prototype.loadSceneFromApi = function(scene, onLoaded) {
+
+ /**
+ * First check if this is a client or server side request
+ */
+ if (typeof XMLHttpRequest == 'undefined') {
+ console.warn('implement server side loading from API here');
+ return onLoaded(null, new Error('not implemented'));
+ }
+
+ var xhr = new XMLHttpRequest();
+ xhr.open(
+ 'GET',
+ this.apiUrl + '/scene/load' + scene.path + '/' + scene.name
+ );
+
+ xhr.onreadystatechange = function(xhr, gameLibD3) {
+ return function() {
+ if (xhr.readyState == 4) {
+
+ var response = JSON.parse(xhr.responseText);
+
+ if (!response.scene || response.scene.length == 0) {
+ return onLoaded(null, null, new Error('Could not load scene'));
+ }
+
+ var scene = response.scene[0];
+
+ var physics3ds = [];
+
+ if (scene.physics && scene.physics.length > 0) {
+
+ for (var p = 0; p < scene.physics.length; p++) {
+
+ var physics = scene.physics[p];
+
+ var physics3d = new GameLib.D3.Physics(
+ physics.id,
+ physics.name,
+ physics.engineType,
+ gameLibD3.CANNON,
+ null,
+ null
+ );
+
+ var worlds3d = [];
+
+ for (var w = 0; w < physics.worlds.length; w++) {
+
+ var world = physics.worlds[w];
+
+ var broadphase = world.broadphase;
+
+ var broadphase3d = new GameLib.D3.Physics.Broadphase(
+ broadphase.id,
+ broadphase.name,
+ broadphase.broadphaseType
+ );
+
+ var solver = world.solver;
+
+ var solver3d = new GameLib.D3.Physics.Solver(
+ solver.id,
+ solver.name,
+ solver.solverType,
+ solver.iterations,
+ solver.tolerance
+ );
+
+ var bodies = world.rigidBodies;
+
+ var bodies3d = [];
+
+ for (var b = 0; b < bodies.length; b++) {
+
+ var body = bodies[b];
+
+ //TODO: add all body properties here
+ var body3d = new GameLib.D3.Physics.RigidBody(
+ body.id,
+ body.name
+ );
+
+ bodies3d.push(body3d);
+ }
+
+ var world3d = new GameLib.D3.Physics.World(
+ null,
+ world.name,
+ physics3d,
+ new GameLib.D3.Vector3(
+ world.gravity.x,
+ world.gravity.y,
+ world.gravity.z
+ ),
+ broadphase3d,
+ solver3d,
+ bodies3d
+ );
+
+ worlds3d.push(world3d);
+ }
+
+ physics3ds.push(physics3d);
+ }
+ }
+
+ var lights3d = [];
+
+ for (var l = 0; l < scene.lights.length; l++) {
+
+ var light = scene.lights[l];
+
+ var light3d = new GameLib.D3.Light(
+ light.id,
+ light.lightType,
+ light.name,
+ new GameLib.D3.Color(
+ light.color.r,
+ light.color.g,
+ light.color.b,
+ light.color.a
+ ),
+ light.intensity,
+ new GameLib.D3.Vector3(
+ light.position.x,
+ light.position.y,
+ light.position.z
+ ),
+ new GameLib.D3.Vector3(
+ light.targetPosition.x,
+ light.targetPosition.y,
+ light.targetPosition.z
+ ),
+ new GameLib.D3.Vector4(
+ light.quaternion.x,
+ light.quaternion.y,
+ light.quaternion.z,
+ light.quaternion.w
+ ),
+ new GameLib.D3.Vector3(
+ light.rotation.x,
+ light.rotation.y,
+ light.rotation.z
+ ),
+ new GameLib.D3.Vector3(
+ light.scale.x,
+ light.scale.y,
+ light.scale.z
+ ),
+ light.distance,
+ light.decay,
+ light.power,
+ light.angle,
+ light.penumbra
+ );
+
+ lights3d.push(light3d);
+ };
+
+ var scene3d = new GameLib.D3.Scene(
+ scene._id || scene.id,
+ scene.path,
+ scene.name,
+ scene.meshes,
+ new GameLib.D3.Vector4(
+ scene.quaternion.x,
+ scene.quaternion.y,
+ scene.quaternion.z,
+ scene.quaternion.w
+ ),
+ new GameLib.D3.Vector3(
+ scene.position.x,
+ scene.position.y,
+ scene.position.z
+ ),
+ new GameLib.D3.Vector3(
+ scene.rotation.x,
+ scene.rotation.y,
+ scene.rotation.z
+ ),
+ new GameLib.D3.Vector3(
+ scene.scale.x,
+ scene.scale.y,
+ scene.scale.z
+ ),
+ scene.parentSceneId,
+ lights3d,
+ physics3ds
+ );
+
+ gameLibD3.loadScene(scene3d, onLoaded, false);
+ }
+ }
+ }(xhr, this);
+
+ xhr.send();
+};
+
+
+/**
+ * Loads a GameLib.D3.Scene object into a ThreeJS Scene object
+ * @param gameLibScene GameLib.D3.Scene
+ * @param onLoaded callback when all meshes have loaded
+ * @param computeNormals set to true to compute new face and vertex normals during load
+ */
+GameLib.D3.prototype.loadScene = function(gameLibScene, onLoaded, computeNormals) {
+
+ console.log("loading scene " + gameLibScene.name);
+
+ this.path = gameLibScene.path;
+
+ var meshQ = [];
+
+ for (var m = 0; m < gameLibScene.meshes.length; m++) {
+
+ var mesh = gameLibScene.meshes[m];
+
+ console.log("loading mesh " + mesh.name);
+
+ var geometry = new this.THREE.Geometry();
+
+ var vertices = mesh.vertices;
+
+ var faces = mesh.faces;
+
+ var faceVertexUvs = mesh.faceVertexUvs;
+
+ var materials = mesh.materials;
+
+ /**
+ * Setup vertices
+ */
+ for (var v = 0; v < vertices.length; v++) {
+ geometry.vertices.push(
+ new this.THREE.Vector3(
+ vertices[v].position.x,
+ vertices[v].position.y,
+ vertices[v].position.z
+ )
+ )
+ }
+
+ /**
+ * Setup faces
+ */
+ for (var f = 0; f < faces.length; f++) {
+
+ var face = new this.THREE.Face3(
+ faces[f].v0,
+ faces[f].v1,
+ faces[f].v2,
+ new this.THREE.Vector3(
+ faces[f].normal.x,
+ faces[f].normal.y,
+ faces[f].normal.z
+ ),
+ new this.THREE.Color(
+ faces[f].color.r,
+ faces[f].color.g,
+ faces[f].color.b
+ ),
+ faces[f].materialIndex
+ );
+
+ face.vertexColors = [
+ new this.THREE.Color(
+ faces[f].vertexColors[0].r,
+ faces[f].vertexColors[0].g,
+ faces[f].vertexColors[0].b
+ ),
+ new this.THREE.Color(
+ faces[f].vertexColors[1].r,
+ faces[f].vertexColors[1].g,
+ faces[f].vertexColors[1].b
+ ),
+ new this.THREE.Color(
+ faces[f].vertexColors[2].r,
+ faces[f].vertexColors[2].g,
+ faces[f].vertexColors[2].b
+ )
+ ];
+
+ face.normal = new this.THREE.Vector3(
+ faces[f].normal.x,
+ faces[f].normal.y,
+ faces[f].normal.z
+ );
+
+ face.vertexNormals = [
+ new this.THREE.Vector3(
+ faces[f].vertexNormals[0].x,
+ faces[f].vertexNormals[0].y,
+ faces[f].vertexNormals[0].z
+ ),
+ new this.THREE.Vector3(
+ faces[f].vertexNormals[1].x,
+ faces[f].vertexNormals[1].y,
+ faces[f].vertexNormals[1].z
+ ),
+ new this.THREE.Vector3(
+ faces[f].vertexNormals[2].x,
+ faces[f].vertexNormals[2].y,
+ faces[f].vertexNormals[2].z
+ )
+ ];
+
+ geometry.faces.push(face);
+ }
+
+ geometry.faceVertexUvs = [];
+
+ /**
+ * Setup face UVs
+ */
+ for (var fm = 0; fm < faceVertexUvs.length; fm++) {
+
+ var faceMaterialVertexUvs = faceVertexUvs[fm];
+
+ geometry.faceVertexUvs[fm] = [];
+
+ for (var fuv = 0; fuv < faceMaterialVertexUvs.length; fuv++) {
+ geometry.faceVertexUvs[fm][fuv] = [];
+ geometry.faceVertexUvs[fm][fuv].push(
+ new this.THREE.Vector2(
+ faceMaterialVertexUvs[fuv][0].x,
+ faceMaterialVertexUvs[fuv][0].y
+ ),
+ new this.THREE.Vector2(
+ faceMaterialVertexUvs[fuv][1].x,
+ faceMaterialVertexUvs[fuv][1].y
+ ),
+ new this.THREE.Vector2(
+ faceMaterialVertexUvs[fuv][2].x,
+ faceMaterialVertexUvs[fuv][2].y
+ )
+ );
+ }
+ }
+
+ /**
+ * Re-calculate normals (if we have to)
+ * @type {Array}
+ */
+ if (computeNormals) {
+ geometry.computeFaceNormals();
+ geometry.computeVertexNormals();
+ }
+
+ var threeMaterialLoaders = [];
+
+ /**
+ * Setup materials
+ */
+ for (var mi = 0; mi < materials.length; mi++) {
+ threeMaterialLoaders.push(this.createThreeMaterial(materials[mi]));
+ }
+
+ var result = this.Q.all(threeMaterialLoaders).then(
+ function(gl3d, mesh, geometry) {
+ return function(materials) {
+
+ console.log("loaded material : " + materials[0].name);
+
+ /**
+ * We don't support MultiMaterial atm - it doesn't work with raycasting
+ */
+ var material = materials[0];
+
+ var threeMesh = gl3d.createThreeMesh(mesh, geometry, material);
+ threeMesh.name = mesh.name;
+
+ threeMesh.position.x = mesh.position.x;
+ threeMesh.position.y = mesh.position.y;
+ threeMesh.position.z = mesh.position.z;
+
+ threeMesh.rotation.x = mesh.rotation.x;
+ threeMesh.rotation.y = mesh.rotation.y;
+ threeMesh.rotation.z = mesh.rotation.z;
+
+ threeMesh.scale.x = mesh.scale.x;
+ threeMesh.scale.y = mesh.scale.y;
+ threeMesh.scale.z = mesh.scale.z;
+
+ threeMesh.quaternion.x = mesh.quaternion.x;
+ threeMesh.quaternion.y = mesh.quaternion.y;
+ threeMesh.quaternion.z = mesh.quaternion.z;
+ threeMesh.quaternion.w = mesh.quaternion.w;
+
+ return threeMesh;
+ };
+ }(this, mesh, geometry)
+ ).catch(function(error){
+ console.log(error);
+ });
+
+ meshQ.push(result);
+ }
+
+ this.Q.all(meshQ).then(function(threeMeshes){
+ console.log("all meshes have loaded");
+ if (typeof onLoaded != 'undefined') {
+
+ var threeLights = [];
+
+ for (var sli = 0; sli < gameLibScene.lights.length; sli++) {
+
+ var blenderLight = gameLibScene.lights[sli];
+
+ var light = null;
+
+ if (blenderLight.lightType == 'AmbientLight') {
+ light = new this.THREE.AmbientLight(blenderLight.color, blenderLight.intensity);
+ }
+
+ if (blenderLight.lightType == 'DirectionalLight') {
+ light = new this.THREE.DirectionalLight(blenderLight.color, blenderLight.intensity);
+ }
+
+ if (blenderLight.lightType == 'PointLight') {
+ light = new this.THREE.PointLight(blenderLight.color, blenderLight.intensity);
+ light.distance = blenderLight.distance;
+ light.decay = blenderLight.decay;
+ }
+
+ if (blenderLight.lightType == 'SpotLight') {
+ light = new this.THREE.SpotLight(blenderLight.color, blenderLight.intensity);
+ light.distance = blenderLight.distance;
+ light.angle = blenderLight.angle;
+ light.penumbra = blenderLight.penumbra;
+ light.decay = blenderLight.decay;
+ }
+
+ light.position.x = blenderLight.position.x;
+ light.position.y = blenderLight.position.y;
+ light.position.z = blenderLight.position.z;
+
+ light.rotation.x = blenderLight.rotation.x;
+ light.rotation.y = blenderLight.rotation.y;
+ light.rotation.z = blenderLight.rotation.z;
+
+ // light.scale.x = blenderLight.scale.x;
+ // light.scale.y = blenderLight.scale.y;
+ // light.scale.z = blenderLight.scale.z;
+
+ if (light == null) {
+ console.warn('Does not support lights of type :' + blenderLight.lightType + ', not imported');
+ } else {
+ light.name = blenderLight.name;
+ threeLights.push(light);
+ }
+ }
+
+ var threeScene = new this.THREE.Scene();
+
+ threeScene.name = gameLibScene.name;
+
+ threeScene.position.x = gameLibScene.position.x;
+ threeScene.position.y = gameLibScene.position.y;
+ threeScene.position.z = gameLibScene.position.z;
+
+ threeScene.rotation.x = gameLibScene.rotation.x;
+ threeScene.rotation.y = gameLibScene.rotation.y;
+ threeScene.rotation.z = gameLibScene.rotation.z;
+
+ threeScene.scale.x = gameLibScene.scale.x;
+ threeScene.scale.y = gameLibScene.scale.y;
+ threeScene.scale.z = gameLibScene.scale.z;
+
+ threeScene.quaternion.x = gameLibScene.quaternion.x;
+ threeScene.quaternion.y = gameLibScene.quaternion.y;
+ threeScene.quaternion.z = gameLibScene.quaternion.z;
+ threeScene.quaternion.w = gameLibScene.quaternion.w;
+
+ for (var m = 0; m < threeMeshes.length; m++) {
+ threeScene.add(threeMeshes[m]);
+ }
+
+ for (var l = 0; l < threeLights.length; l++) {
+ threeScene.add(threeLights[l]);
+ }
+
+ onLoaded(
+ gameLibScene,
+ {
+ scene: threeScene,
+ lights: threeLights,
+ meshes: threeMeshes
+ }
+ );
+ }
+ }.bind(this)).catch(function(error){
+ console.log(error);
+ });
+};
+/**
+ * Physics Shape Superset
+ * @constructor
+ */
+GameLib.D3.Physics.Shape = function(
+ shapeObject, // Physics engine specific
+ shapeType
+) {
+ this.shapeObject = shapeObject;
+ this.shapeType = shapeType;
+ this.scale = new GameLib.D3.Vector3(1, 1, 1);
+};
+
+GameLib.D3.Physics.SHAPE_TYPE_SPHERE = 1;
+GameLib.D3.Physics.SHAPE_TYPE_BOX = 2;
+GameLib.D3.Physics.SHAPE_TYPE_TRIMESH = 3;
+GameLib.D3.Physics.SHAPE_TYPE_CYLINDER = 4;
+
+
+GameLib.D3.Physics.Shape.prototype.Update = function() {
+ if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
+ if(this.shapeType === GameLib.D3.Physics.SHAPE_TYPE_TRIMESH) {
+ this.shapeObject.setScale(
+ new this.physics.CANNON.Vec3(
+ this.scale.x,
+ this.scale.y,
+ this.scale.z
+ )
+ );
+ this.shapeObject.updateAABB();
+ this.shapeObject.updateNormals();
+ this.shapeObject.updateEdges();
+ this.shapeObject.updateBoundingSphereRadius();
+ this.shapeObject.updateTree();
+ }
+ }
+};
+
+/**
+ * Skeleton Superset
+ * @param id
+ * @param bones GameLib.D3.Bone
+ * @param boneInverses
+ * @param useVertexTexture
+ * @param boneTextureWidth
+ * @param boneTextureHeight
+ * @param boneMatrices
+ * @param boneTexture
+ * @constructor
+ */
+GameLib.D3.Skeleton = function(
+ id,
+ bones,
+ boneInverses,
+ useVertexTexture,
+ boneTextureWidth,
+ boneTextureHeight,
+ boneMatrices,
+ boneTexture
+) {
+ this.id = id;
+
+ this.bones = bones;
+
+ /**
+ * An array of Matrix4s that represent the inverse of the matrixWorld of the individual bones.
+ * @type GameLib.D3.Matrix4[]
+ */
+ if (typeof boneInverses == 'undefined') {
+ boneInverses = [];
+ }
+ this.boneInverses = boneInverses;
+
+ /**
+ * Use a vertex texture in the shader - allows for more than 4 bones per vertex, not supported by all devices
+ * @type {boolean}
+ */
+ if (typeof useVertexTexture == 'undefined') {
+ useVertexTexture = false;
+ }
+ this.useVertexTexture = useVertexTexture;
+
+ if (this.useVertexTexture == true) {
+ console.warn('support for vertex texture bones is not supported yet - something could break somewhere');
+ }
+
+ if (typeof boneTextureWidth == 'undefined') {
+ boneTextureWidth = 0;
+ }
+ this.boneTextureWidth = boneTextureWidth;
+
+ if (typeof boneTextureHeight == 'undefined') {
+ boneTextureHeight = 0;
+ }
+ this.boneTextureHeight = boneTextureHeight;
+
+ if (typeof boneMatrices == 'undefined') {
+ boneMatrices = [];
+ }
+ this.boneMatrices = boneMatrices;
+
+ if (typeof boneTexture == 'undefined') {
+ boneTexture = [];
+ }
+ this.boneTexture = boneTexture;
+};
+
+
+GameLib.D3.SkyBox = function (
+
+) {
+ this.id = null;
+ this.texturesFolder = null;
+};
+
+GameLib.D3.SkyBox.prototype.Load = function (
+ texturesFolder
+) {
+ this.texturesFolder = texturesFolder;
+ this.textures = [];
+ this.materials = [];
+ this.mesh = {};
+ this.scene = new THREE.Scene();
+ this.textureCube = null;
+
+ var textureLoader = new THREE.TextureLoader();
+
+ // this textures are used to display the skybox
+ this.textures.push(textureLoader.load(this.texturesFolder + "px.png"));
+ this.textures.push(textureLoader.load(this.texturesFolder + "nx.png"));
+ this.textures.push(textureLoader.load(this.texturesFolder + "py.png"));
+ this.textures.push(textureLoader.load(this.texturesFolder + "ny.png"));
+ this.textures.push(textureLoader.load(this.texturesFolder + "pz.png"));
+ this.textures.push(textureLoader.load(this.texturesFolder + "nz.png"));
+
+ // assign textures to each cube face
+ for (var i = 0; i < 6; i ++) {
+ this.materials.push(new THREE.MeshBasicMaterial({ map: this.textures[i] }));
+ }
+
+ // create cube geometry
+ this.mesh = new THREE.Mesh(new THREE.CubeGeometry(1, 1, 1), new THREE.MeshFaceMaterial(this.materials));
+ this.mesh.applyMatrix(new THREE.Matrix4().makeScale(1, 1, -1));
+ this.scene.add(this.mesh);
+
+ // Load env textureCube
+ // this is used for reflections on meshes
+ // mesh.material.envMap = this.textureCube;
+ this.textureCube = new THREE.CubeTextureLoader().load([
+ this.texturesFolder + "px.png", this.texturesFolder + "nx.png",
+ this.texturesFolder + "py.png", this.texturesFolder + "ny.png",
+ this.texturesFolder + "pz.png", this.texturesFolder + "nz.png"
+ ]);
+};
+
+GameLib.D3.SkyBox.prototype.Render = function (
+ threeRenderer,
+ threeCamera
+) {
+ var cameraPosition = new THREE.Vector3(threeCamera.position.x, threeCamera.position.y, threeCamera.position.z);
+
+ threeCamera.position.set(0, 0, 0);
+
+ var gl = threeRenderer.context;
+
+ gl.disable(gl.DEPTH_TEST);
+
+ threeRenderer.render(this.scene, threeCamera);
+
+ gl.enable(gl.DEPTH_TEST);
+
+ threeCamera.position.copy(cameraPosition);
+};
+
+/**
+ * Physics Solver Superset
+ * @param id
+ * @param name
+ * @param solverType
+ * @param iterations
+ * @param tolerance
+ * @constructor
+ */
+GameLib.D3.Physics.Solver = function(
+ id,
+ name,
+ solverType,
+ iterations,
+ tolerance
+) {
+ this.id = id;
+ if (typeof name == 'undefined') {
+ if (solverType == GameLib.D3.Physics.SPLIT_SOLVER) {
+ name = 'split solver';
+ } else if (solverType == GameLib.D3.Physics.GS_SOLVER) {
+ name = 'gs solver';
+ } else {
+ name = 'unknown solver';
+ }
+ }
+ this.name = name;
+ this.solverType = solverType;
+ this.iterations = iterations;
+ this.tolerance = tolerance;
+};
+
+/**
+ * Solver Types
+ * @type {number}
+ */
+GameLib.D3.Physics.SPLIT_SOLVER = 0x1;
+GameLib.D3.Physics.GS_SOLVER = 0x2;
+
+/**
+ * Texture Superset
+ * @param id
+ * @param name
+ * @param image
+ * @param wrapS
+ * @param wrapT
+ * @param repeat
+ * @param data
+ * @param format
+ * @param mapping
+ * @param magFilter
+ * @param minFilter
+ * @param textureType
+ * @param anisotropy
+ * @param offset
+ * @param generateMipmaps
+ * @param flipY
+ * @param mipmaps
+ * @param unpackAlignment
+ * @param premultiplyAlpha
+ * @param encoding
+ * @constructor
+ */
+GameLib.D3.Texture = function(
+ id,
+ name,
+ image,
+ wrapS,
+ wrapT,
+ repeat,
+ data,
+ format,
+ mapping,
+ magFilter,
+ minFilter,
+ textureType,
+ anisotropy,
+ offset,
+ generateMipmaps,
+ flipY,
+ mipmaps,
+ unpackAlignment,
+ premultiplyAlpha,
+ encoding
+) {
+ this.id = id;
+ this.name = name;
+ this.image = image;
+
+ if (typeof wrapS == 'undefined') {
+ wrapS = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING;
+ }
+ this.wrapS = wrapS;
+
+ if (typeof wrapT == 'undefined') {
+ wrapT = GameLib.D3.Texture.TYPE_REPEAT_WRAPPING;
+ }
+ this.wrapT = wrapT;
+
+ if (typeof repeat == 'undefined') {
+ repeat = new GameLib.D3.Vector2(1, 1);
+ }
+ this.repeat = repeat;
+
+ if (typeof data == 'undefined') {
+ data = null;
+ }
+ this.data = data;
+
+ if (typeof format == 'undefined') {
+ format = GameLib.D3.Texture.TYPE_RGBA_FORMAT;
+ }
+ this.format = format;
+
+ if (typeof mapping == 'undefined') {
+ mapping = GameLib.D3.Texture.TYPE_UV_MAPPING;
+ }
+ this.mapping = mapping;
+
+ if (typeof magFilter == 'undefined') {
+ magFilter = GameLib.D3.Texture.TYPE_LINEAR_FILTER;
+ }
+ this.magFilter = magFilter;
+
+ if (typeof minFilter == 'undefined') {
+ minFilter = GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER;
+ }
+ this.minFilter = minFilter;
+
+ if (typeof textureType == 'undefined') {
+ textureType = GameLib.D3.Texture.TYPE_UNSIGNED_BYTE;
+ }
+ this.textureType = textureType;
+
+ if (typeof anisotropy == 'undefined') {
+ anisotropy = 1;
+ }
+ this.anisotropy = anisotropy;
+
+ if (typeof offset == 'undefined') {
+ offset = new GameLib.D3.Vector2(0, 0);
+ }
+ this.offset = offset;
+
+ if (typeof generateMipmaps == 'undefined') {
+ generateMipmaps = true;
+ }
+ this.generateMipmaps = generateMipmaps;
+
+ if (typeof flipY == 'undefined') {
+ flipY = true;
+ }
+ this.flipY = flipY;
+
+ if (typeof mipmaps == 'undefined') {
+ mipmaps = [];
+ }
+ this.mipmaps = mipmaps;
+
+ if (typeof unpackAlignment == 'undefined') {
+ unpackAlignment = 4;
+ }
+ this.unpackAlignment = unpackAlignment;
+
+ if (typeof premultiplyAlpha == 'undefined') {
+ premultiplyAlpha = false;
+ }
+ this.premultiplyAlpha = premultiplyAlpha;
+
+ if (typeof encoding == 'undefined') {
+ encoding = GameLib.D3.Texture.TYPE_LINEAR_ENCODING;
+ }
+ this.encoding = encoding;
+};
+
+/**
+ * Texture Formats
+ * @type {number}
+ */
+GameLib.D3.Texture.TYPE_ALPHA_FORMAT = 1019;
+GameLib.D3.Texture.TYPE_RGB_FORMAT = 1020;
+GameLib.D3.Texture.TYPE_RGBA_FORMAT = 1021;
+GameLib.D3.Texture.TYPE_LUMINANCE_FORMAT = 1022;
+GameLib.D3.Texture.TYPE_LUMINANCE_ALPHA_FORMAT = 1023;
+GameLib.D3.Texture.TYPE_DEPTH_FORMAT = 1026;
+
+/**
+ * Mapping modes
+ * @type {number}
+ */
+GameLib.D3.Texture.TYPE_UV_MAPPING = 300;
+GameLib.D3.Texture.TYPE_CUBE_REFLECTION_MAPPING = 301;
+GameLib.D3.Texture.TYPE_CUBE_REFRACTION_MAPPING = 302;
+GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFLECTION_MAPPING = 303;
+GameLib.D3.Texture.TYPE_EQUI_RECTANGULAR_REFRACTION_MAPPING = 304;
+GameLib.D3.Texture.TYPE_SPHERICAL_REFLECTION_MAPPING = 305;
+GameLib.D3.Texture.TYPE_CUBE_UV_REFLECTION_MAPPING = 306;
+GameLib.D3.Texture.TYPE_CUBE_UV_REFRACTION_MAPPING = 307;
+
+/**
+ * Wrapping Modes
+ * @type {number}
+ */
+GameLib.D3.Texture.TYPE_REPEAT_WRAPPING = 1000;
+GameLib.D3.Texture.TYPE_CLAMP_TO_EDGE_WRAPPING = 1001;
+GameLib.D3.Texture.TYPE_MIRRORED_REPEAT_WRAPPING = 1002;
+
+/**
+ * Mipmap Filters
+ * @type {number}
+ */
+GameLib.D3.Texture.TYPE_NEAREST_FILTER = 1003;
+GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_NEAREST_FILTER = 1004;
+GameLib.D3.Texture.TYPE_NEAREST_MIPMAP_LINEAR_FILTER = 1005;
+GameLib.D3.Texture.TYPE_LINEAR_FILTER = 1006;
+GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_NEAREST_FILTER = 1007;
+GameLib.D3.Texture.TYPE_LINEAR_MIPMAP_LINEAR_FILTER = 1008;
+
+/**
+ * Texture Data Types
+ * @type {number}
+ */
+GameLib.D3.Texture.TYPE_UNSIGNED_BYTE = 1009;
+GameLib.D3.Texture.TYPE_BYTE = 1010;
+GameLib.D3.Texture.TYPE_SHORT = 1011;
+GameLib.D3.Texture.TYPE_UNSIGNED_SHORT = 1012;
+GameLib.D3.Texture.TYPE_INT = 1013;
+GameLib.D3.Texture.TYPE_UNSIGNED_INT = 1014;
+GameLib.D3.Texture.TYPE_FLOAT = 1015;
+GameLib.D3.Texture.TYPE_HALF_FLOAT = 1025;
+
+/**
+ * Encoding Modes
+ * @type {number}
+ */
+GameLib.D3.Texture.TYPE_LINEAR_ENCODING = 3000; // NO ENCODING AT ALL.
+GameLib.D3.Texture.TYPE_SRGB_ENCODING = 3001;
+GameLib.D3.Texture.TYPE_GAMMA_ENCODING = 3007; // USES GAMMA_FACTOR, FOR BACKWARDS COMPATIBILITY WITH WEBGLRENDERER.GAMMAINPUT/GAMMAOUTPUT
+GameLib.D3.Texture.TYPE_RGBE_ENCODING = 3002; // AKA RADIANCE.
+GameLib.D3.Texture.TYPE_LOG_LUV_ENCODING = 3003;
+GameLib.D3.Texture.TYPE_RGBM7_ENCODING = 3004;
+GameLib.D3.Texture.TYPE_RGBM16_ENCODING = 3005;
+GameLib.D3.Texture.TYPE_RGBD_ENCODING = 3006; // MAXRANGE IS 256.
+
+
+
+/**
+ * Defers loading of an image and resolves once image is loaded
+ * @param gameLibTexture
+ * @param threeMaterial
+ * @param threeMaterialMapType
+ * @returns {Promise}
+ */
+GameLib.D3.prototype.loadMap = function(gameLibTexture, threeMaterial, threeMaterialMapType) {
+
+ var q = this.Q.defer();
+
+ var imagePath = null;
+
+ if (gameLibTexture && gameLibTexture.image && gameLibTexture.image.filename) {
+ /**
+ * Else, load from upload source
+ */
+ imagePath = this.editorUrl + '/uploads' + this.path + '/' + gameLibTexture.image.filename;
+ }
+
+ if (imagePath) {
+
+ this.textureLoader.crossOrigin = '';
+
+ this.textureLoader.load(
+ imagePath,
+ function(texture) {
+ /**
+ * onLoad
+ */
+ threeMaterial[threeMaterialMapType] = texture;
+ threeMaterial[threeMaterialMapType].name = gameLibTexture.name;
+ threeMaterial[threeMaterialMapType].anisotropy = gameLibTexture.anisotropy;
+ threeMaterial[threeMaterialMapType].encoding = gameLibTexture.encoding;
+ threeMaterial[threeMaterialMapType].flipY = gameLibTexture.flipY;
+ /**
+ * We don't restore the format since this changing from OS to OS and breaks the implementation sometimes
+ */
+ threeMaterial[threeMaterialMapType].generateMipmaps = gameLibTexture.generateMipmaps;
+ threeMaterial[threeMaterialMapType].magFilter = gameLibTexture.magFilter;
+ threeMaterial[threeMaterialMapType].minFilter = gameLibTexture.minFilter;
+ threeMaterial[threeMaterialMapType].mapping = gameLibTexture.mapping;
+ threeMaterial[threeMaterialMapType].mipmaps = gameLibTexture.mipmaps;
+ threeMaterial[threeMaterialMapType].offset = new this.THREE.Vector2(
+ gameLibTexture.offset.x,
+ gameLibTexture.offset.y
+ );
+ threeMaterial[threeMaterialMapType].premultiplyAlpha = gameLibTexture.premultiplyAlpha;
+ threeMaterial[threeMaterialMapType].textureType = gameLibTexture.textureType;
+ threeMaterial[threeMaterialMapType].wrapS = gameLibTexture.wrapS;
+ threeMaterial[threeMaterialMapType].wrapT = gameLibTexture.wrapT;
+ threeMaterial[threeMaterialMapType].unpackAlignment = gameLibTexture.unpackAlignment;
+ threeMaterial.needsUpdate = true;
+ q.resolve(true);
+ },
+ function(xhr) {
+ /**
+ * onProgress
+ */
+ if (this.editor) {
+ this.editor.setServerStatus(Math.round(xhr.loaded / xhr.total * 100) + '% complete', 'success');
+ }
+ },
+ function(error) {
+ /**
+ * onError
+ */
+ console.log("an error occurred while trying to load the image : " + imagePath);
+ q.resolve(null);
+ }
+ );
+
+ } else {
+ q.resolve(null);
+ }
+
+ return q.promise;
+};
+
+
+/**
+ * Returns an array of image loading Promises
+ * @param blenderMaterial
+ * @param blenderMaps
+ * @param threeMaterial
+ * @returns Q[]
+ */
+GameLib.D3.prototype.loadMaps = function(blenderMaterial, blenderMaps, threeMaterial) {
+
+ var textureMaps = [];
+
+ for (var ti = 0; ti < blenderMaps.length; ti++) {
+
+ var map = blenderMaps[ti];
+
+ if (blenderMaterial.maps.hasOwnProperty(map)) {
+
+ var blenderTexture = blenderMaterial.maps[map];
+
+ if (
+ blenderTexture &&
+ blenderTexture.image &&
+ blenderTexture.image.filename
+ ) {
+
+ var threeMap = null;
+
+ if (map == 'alpha') {
+ threeMap = 'alhpaMap';
+ }
+
+ if (map == 'ao') {
+ threeMap = 'aoMap';
+ }
+
+ if (map == 'bump') {
+ threeMap = 'bumpMap';
+ }
+
+ if (map == 'displacement') {
+ threeMap = 'displacementMap';
+ }
+
+ if (map == 'emissive') {
+ threeMap = 'emissiveMap';
+ }
+
+ if (map == 'environment') {
+ threeMap = 'envMap';
+ }
+
+ if (map == 'light') {
+ threeMap = 'lightMap';
+ }
+
+ if (map == 'specular') {
+ threeMap = 'specularMap';
+ }
+
+ if (map == 'diffuse') {
+ threeMap = 'map';
+ }
+
+ if (map == 'roughness') {
+ threeMap = 'roughnessMap';
+ }
+
+ if (map == 'metalness') {
+ threeMap = 'metalnessMap';
+ }
+
+ if (threeMap == null) {
+ console.warn("unsupported map type : " + map);
+ }
+
+ textureMaps.push(this.loadMap(blenderMaterial.maps[map], threeMaterial, threeMap));
+ }
+ }
+ }
+
+ return textureMaps;
+};
+
+/**
+ * TriangleEdge
+ * @param triangle
+ * @param edge
+ * @constructor
+ */
+GameLib.D3.TriangleEdge = function(
+ triangle,
+ edge
+) {
+ this.triangle = triangle;
+ this.edge = edge;
+};
+/**
+ * TriangleFace
+ * @param v0
+ * @param v1
+ * @param v2
+ * @param materialIndex
+ * @param v0uv
+ * @param v1uv
+ * @param v2uv
+ * @param color
+ * @param vertexColors
+ * @param vertexNormals
+ * @param normal
+ * @constructor
+ */
+GameLib.D3.TriangleFace = function(
+ v0,
+ v1,
+ v2,
+ materialIndex,
+ v0uv,
+ v1uv,
+ v2uv,
+ color,
+ vertexColors,
+ vertexNormals,
+ normal
+) {
+ this.v0 = v0;
+ this.v1 = v1;
+ this.v2 = v2;
+ this.materialIndex = materialIndex;
+ this.v0uv = v0uv;
+ this.v1uv = v1uv;
+ this.v2uv = v2uv;
+ if (!color) {
+ color = new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff);
+ }
+ this.color = color;
+
+ if (!vertexColors) {
+ vertexColors = [
+ new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff),
+ new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff),
+ new GameLib.D3.Color(0xff, 0xff, 0xff, 0xff)
+ ];
+ }
+ this.vertexColors = vertexColors;
+
+ if (!vertexNormals) {
+ vertexNormals = [
+ new GameLib.D3.Vector3(),
+ new GameLib.D3.Vector3(),
+ new GameLib.D3.Vector3()
+ ]
+ }
+ this.vertexNormals = vertexNormals;
+
+ if (!normal) {
+ normal = new GameLib.D3.Vector3(0);
+ }
+
+ this.normal = normal;
+};
+
+/**
+ * Clone a TriangleFace
+ * @returns {GameLib.D3.TriangleFace}
+ */
+GameLib.D3.TriangleFace.prototype.clone = function(){
+ return new GameLib.D3.TriangleFace(
+ this.v0,
+ this.v1,
+ this.v2,
+ this.materialIndex,
+ this.v0uv.copy(),
+ this.v1uv.copy(),
+ this.v2uv.copy()
+ );
+};
+
+/**
+ * Returns true if two triangles are equal (their vertex indices match in some order)
+ * @param triangle
+ * @returns {boolean}
+ */
+GameLib.D3.TriangleFace.prototype.equals = function(triangle) {
+ return !!(
+ (
+ (this.v0 == triangle.v0) &&
+ (this.v1 == triangle.v1) &&
+ (this.v2 == triangle.v2)
+ )
+ ||
+ (
+ (this.v0 == triangle.v0) &&
+ (this.v1 == triangle.v2) &&
+ (this.v2 == triangle.v1)
+ )
+ ||
+ (
+ (this.v0 == triangle.v1) &&
+ (this.v1 == triangle.v0) &&
+ (this.v2 == triangle.v2)
+ )
+ ||
+ (
+ (this.v0 == triangle.v1) &&
+ (this.v1 == triangle.v2) &&
+ (this.v2 == triangle.v0)
+ )
+ ||
+ (
+ (this.v0 == triangle.v2) &&
+ (this.v1 == triangle.v0) &&
+ (this.v2 == triangle.v1)
+ )
+ ||
+ (
+ (this.v0 == triangle.v2) &&
+ (this.v1 == triangle.v1) &&
+ (this.v2 == triangle.v0)
+ ));
+};
+
+
+GameLib.D3.Vector2 = function(x, y) {
+
+ this.x = 0;
+ this.y = 0;
+
+ if (x) {
+ this.x = x;
+ }
+
+ if (y) {
+ this.y = y;
+ }
+};
+
+GameLib.D3.Vector2.prototype.copy = function() {
+ return new GameLib.D3.Vector2(
+ this.x,
+ this.y
+ );
+};
+
+GameLib.D3.Vector2.prototype.equals = function(v) {
+ return !!(((this.x == v.x) &&
+ (this.y == v.y)) ||
+ ((this.y == v.x) &&
+ (this.x == v.y)));
+};
+
+GameLib.D3.Vector3 = function(x, y, z) {
+
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+
+ if (x) {
+ this.x = x;
+ }
+
+ if (y) {
+ this.y = y;
+ }
+
+ if (z) {
+ this.z = z;
+ }
+};
+
+GameLib.D3.Vector3.prototype.subtract = function (v) {
+
+ if (v instanceof GameLib.D3.Vector3) {
+ this.x -= v.x;
+ this.y -= v.y;
+ this.z -= v.z;
+ }
+
+ if (v instanceof GameLib.D3.Vector4) {
+ console.warn("trying to subtract vector of bigger length (4 vs 3))");
+ }
+
+ return this;
+};
+
+GameLib.D3.Vector3.prototype.cross = function (v) {
+ return new GameLib.D3.Vector3(
+ this.y * v.z - this.z * v.y,
+ this.z * v.x - this.x * v.z,
+ this.x * v.y - this.y * v.x
+ );
+};
+
+GameLib.D3.Vector3.prototype.negative = function () {
+ this.x *= -1;
+ this.y *= -1;
+ this.z *= -1;
+ return this;
+};
+
+GameLib.D3.Vector3.clockwise = function (u, v, w, viewPoint) {
+
+ var normal = GameLib.D3.Vector3.normal(u, v, w);
+
+ var uv = u.copy();
+
+ var winding = normal.dot(uv.subtract(viewPoint));
+
+ return (winding > 0);
+};
+
+GameLib.D3.Vector3.normal = function (u, v, w) {
+ var vv = v.copy();
+ var wv = w.copy();
+ return vv.subtract(u).cross(wv.subtract(u));
+};
+
+GameLib.D3.Vector3.prototype.lookAt = function (at, up) {
+
+ var lookAtMatrix = GameLib.D3.Matrix4.lookAt(this, at, up);
+
+ this.multiply(lookAtMatrix);
+};
+
+GameLib.D3.Vector3.prototype.translate = function (v) {
+ this.x += v.x;
+ this.y += v.y;
+ this.z += v.z;
+ return this;
+};
+
+GameLib.D3.Vector3.prototype.squared = function () {
+ return this.x * this.x + this.y * this.y + this.z * this.z;
+};
+
+GameLib.D3.Vector3.prototype.copy = function () {
+ return new GameLib.D3.Vector3(
+ this.x,
+ this.y,
+ this.z
+ );
+};
+
+GameLib.D3.Vector3.prototype.multiply = function (s) {
+ if (s instanceof GameLib.D3.Vector3) {
+ this.x *= s.x;
+ this.y *= s.y;
+ this.z *= s.z;
+ } else if (s instanceof GameLib.D3.Matrix4) {
+ var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z;
+ var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z;
+ var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ } else {
+ console.log("functionality not implemented - please do this");
+ throw new Error("not implemented");
+ }
+ return this;
+};
+
+
+GameLib.D3.Vector3.prototype.dot = function (v) {
+ return (this.x * v.x) + (this.y * v.y) + (this.z * v.z);
+};
+
+GameLib.D3.Vector3.prototype.normalize = function () {
+
+ var EPSILON = 0.000001;
+
+ var v2 = this.squared();
+
+ if (v2 < EPSILON) {
+ return this; //do nothing for zero vector
+ }
+
+ var invLength = 1 / Math.sqrt(v2);
+
+ this.x *= invLength;
+ this.y *= invLength;
+ this.z *= invLength;
+
+ return this;
+};
+
+GameLib.D3.Vector4 = function(x, y, z, w) {
+
+ this.x = 0;
+ this.y = 0;
+ this.z = 0;
+ this.w = 0;
+
+ Iif (x) {
+ this.x = x;
+ }
+
+ Iif (y) {
+ this.y = y;
+ }
+
+ Iif (z) {
+ this.z = z;
+ }
+
+ Iif (w) {
+ this.w = w;
+ }
+};
+
+GameLib.D3.Vector4.prototype.translate = function (v) {
+ this.x += v.x;
+ this.y += v.y;
+ this.z += v.z;
+ return this;
+};
+
+GameLib.D3.Vector4.prototype.copy = function () {
+ return new GameLib.D3.Vector4(
+ this.x,
+ this.y,
+ this.z,
+ this.w
+ );
+};
+
+GameLib.D3.Vector4.prototype.multiply = function (s) {
+ if (s instanceof GameLib.D3.Vector3) {
+ this.x *= s.x;
+ this.y *= s.y;
+ this.z *= s.z;
+ } else if (s instanceof GameLib.D3.Matrix4) {
+ var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z + s.rows[0].w * this.w;
+ var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z + s.rows[1].w * this.w;
+ var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z + s.rows[2].w * this.w;
+ var w = s.rows[3].x * this.x + s.rows[3].y * this.y + s.rows[3].z * this.z + s.rows[3].w * this.w;
+ this.x = x;
+ this.y = y;
+ this.z = z;
+ this.w = w;
+ } else {
+ console.log("functionality not implemented - please do this");
+ throw new Error("not implemented");
+ }
+};
+
+
+GameLib.D3.Vector4.prototype.normalize = function () {
+
+ // note - leave w untouched
+ var EPSILON = 0.000001;
+
+ var v2 = this.x * this.x + this.y * this.y + this.z * this.z;
+
+ if (v2 < EPSILON) {
+ return this; //do nothing for zero vector
+ }
+
+ var invLength = 1 / Math.sqrt(v2);
+
+ this.x *= invLength;
+ this.y *= invLength;
+ this.z *= invLength;
+
+ return this;
+};
+
+GameLib.D3.Vector4.prototype.subtract = function (v) {
+
+ if (v instanceof GameLib.D3.Vector3) {
+ this.x -= v.x;
+ this.y -= v.y;
+ this.z -= v.z;
+ }
+
+ if (v instanceof GameLib.D3.Vector4) {
+ this.x -= v.x;
+ this.y -= v.y;
+ this.z -= v.z;
+ this.w -= v.w;
+ }
+
+ return this;
+};
+
+GameLib.D3.Vector4.Points = function () {
+ this.vectors = [];
+};
+
+GameLib.D3.Vector4.Points.prototype.add = function (vector) {
+
+ if (vector instanceof GameLib.D3.Vector3) {
+ vector = new GameLib.D3.Vector4(
+ vector.x,
+ vector.y,
+ vector.z,
+ 1
+ )
+ }
+
+ if (!vector instanceof GameLib.D3.Vector4) {
+ console.warn("Vector needs to be of type Vector4");
+ throw new Error("Vector needs to be of type Vector4");
+ }
+
+ this.vectors.push(vector);
+
+ return this;
+};
+
+GameLib.D3.Vector4.Points.prototype.copy = function () {
+
+ var vectors = [];
+
+ for (var i = 0; i < this.vectors.length; i++) {
+ vectors.push(this.vectors[i].copy());
+ }
+
+ return vectors;
+};
+
+GameLib.D3.Vector4.Points.prototype.maximizeXDistance = function (grain) {
+
+// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
+
+ var multiplier = 0;
+
+ var rotationMatrixY = new GameLib.D3.Matrix4().rotationMatrixY(grain);
+
+ var totalRadians = 0;
+
+ var backupVectors = this.copy();
+
+ var maxXDistance = 0;
+
+ for (var i = 0; i < Math.PI * 2; i += grain) {
+
+ multiplier++;
+
+ for (var j = 0; j < this.vectors.length; j++) {
+ this.vectors[j] = rotationMatrixY.multiply(this.vectors[j]);
+ }
+
+ var distances = this.distances();
+
+ if (distances.x > maxXDistance) {
+
+ maxXDistance = distances.x;
+ totalRadians = multiplier * grain;
+ }
+ }
+
+ this.vectors = backupVectors;
+
+// console.log("distance: " + maxXDistance + " radians : " + totalRadians);
+
+ var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixY(totalRadians);
+
+ for (var k = 0; k < this.vectors.length; k++) {
+ this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
+ }
+
+// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
+
+};
+
+GameLib.D3.Vector4.Points.prototype.maximizeYDistance = function (grain) {
+
+// console.log("vectors (before): " + JSON.stringify(this.vectors, null, 2));
+
+ var multiplier = 0;
+
+ var rotationMatrixX = new GameLib.D3.Matrix4().rotationMatrixX(grain);
+
+ var totalRadians = 0;
+
+ var backupVectors = this.copy();
+
+ var maxYDistance = 0;
+
+ for (var i = 0; i < Math.PI * 2; i += grain) {
+
+ multiplier++;
+
+ for (var j = 0; j < this.vectors.length; j++) {
+ this.vectors[j] = rotationMatrixX.multiply(this.vectors[j]);
+ }
+
+ var distances = this.distances();
+
+ if (distances.y > maxYDistance) {
+ maxYDistance = distances.y;
+ totalRadians = multiplier * grain;
+ }
+ }
+
+ this.vectors = backupVectors;
+
+// console.log("distance: " + maxYDistance + " radians : " + totalRadians);
+
+ var maxRotationMatrix = new GameLib.D3.Matrix4().rotationMatrixX(totalRadians);
+
+ for (var k = 0; k < this.vectors.length; k++) {
+ this.vectors[k] = maxRotationMatrix.multiply(this.vectors[k]);
+ }
+
+// console.log("vectors (after): " + JSON.stringify(this.vectors, null, 2));
+
+};
+
+
+GameLib.D3.Vector4.Points.prototype.lookAt = function (at, up) {
+
+ var polyCenter = this.average();
+
+ console.log("poly center : " + JSON.stringify(polyCenter));
+
+ var lookAtMatrix = new GameLib.D3.Matrix4().lookAt(polyCenter, at, up);
+
+ lookAtMatrix.rows[0] = new GameLib.D3.Vector4(1, 0, 0, 0);
+ lookAtMatrix.rows[1] = new GameLib.D3.Vector4(0, 0, 1, 0);
+ lookAtMatrix.rows[2] = new GameLib.D3.Vector4(0, 1, 0, 0);
+
+ console.log("look at matrix : " + JSON.stringify(lookAtMatrix, null, 2));
+
+ for (var i = 0; i < this.vectors.length; i++) {
+ console.log("vector " + i + " (before): " + JSON.stringify(this.vectors[i]));
+ this.vectors[i] = lookAtMatrix.multiply(this.vectors[i]);
+ console.log("vector " + i + " (after) : " + JSON.stringify(this.vectors[i]));
+ }
+};
+
+GameLib.D3.Vector4.Points.prototype.distances = function () {
+
+ var minX = this.vectors[0].x;
+ var minY = this.vectors[0].y;
+ var minZ = this.vectors[0].z;
+
+ var maxX = this.vectors[0].x;
+ var maxY = this.vectors[0].y;
+ var maxZ = this.vectors[0].z;
+
+ for (var i = 0; i < this.vectors.length; i++) {
+ if (this.vectors[i].x < minX) {
+ minX = this.vectors[i].x;
+ }
+ if (this.vectors[i].y < minY) {
+ minY = this.vectors[i].y;
+ }
+ if (this.vectors[i].z < minZ) {
+ minZ = this.vectors[i].z;
+ }
+
+ if (this.vectors[i].x > maxX) {
+ maxX = this.vectors[i].x;
+ }
+ if (this.vectors[i].y > maxY) {
+ maxY = this.vectors[i].y;
+ }
+ if (this.vectors[i].z > maxZ) {
+ maxZ = this.vectors[i].z;
+ }
+ }
+
+ return new GameLib.D3.Vector3(
+ Math.abs(maxX - minX),
+ Math.abs(maxY - minY),
+ Math.abs(maxY - minZ)
+ )
+};
+
+GameLib.D3.Vector4.Points.prototype.average = function () {
+ var averageX = 0;
+ var averageY = 0;
+ var averageZ = 0;
+
+ for (var i = 0; i < this.vectors.length; i++) {
+ averageX += this.vectors[i].x;
+ averageY += this.vectors[i].y;
+ averageZ += this.vectors[i].z;
+ }
+
+ return new GameLib.D3.Vector3(
+ averageX / this.vectors.length,
+ averageY / this.vectors.length,
+ averageZ / this.vectors.length
+ );
+};
+
+GameLib.D3.Vector4.Points.prototype.negative = function () {
+
+ for (var i = 0; i < this.vectors.length; i++) {
+ this.vectors[i].x *= -1;
+ this.vectors[i].y *= -1;
+ this.vectors[i].z *= -1;
+ }
+
+ return this;
+};
+
+
+GameLib.D3.Vector4.Points.prototype.toOrigin = function () {
+
+ var distanceFromOrigin = this.average().negative();
+
+ for (var i = 0; i < this.vectors.length; i++) {
+ this.vectors[i].translate(distanceFromOrigin);
+ }
+};
+
+/**
+ * The normal gets assigned when the face calculates its normal
+ * @param position
+ * @param boneWeights GameLib.D3.BoneWeight[]
+ * @constructor
+ */
+GameLib.D3.Vertex = function(
+ position,
+ boneWeights
+) {
+ this.position = position;
+ this.boneWeights = boneWeights;
+};
+/**
+ * World SuperSet - contains the custom world instance
+ * @param id
+ * @param name
+ * @param engine
+ * @param gravity
+ * @param broadphase
+ * @param solver
+ * @param rigidBodies
+ * @constructor
+ */
+GameLib.D3.World = function(
+ id,
+ name,
+ engine,
+ gravity,
+ broadphase,
+ solver,
+ rigidBodies
+) {
+
+ this.id = id;
+
+ this.name = name;
+
+ if (typeof gravity == 'undefined') {
+ gravity = new GameLib.D3.Vector3(0, -9.81, 0);
+ }
+ this.gravity = gravity;
+
+ if (typeof broadphase == 'undefined') {
+ broadphase = new GameLib.D3.Physics.Broadphase(
+ null,
+ 'broadPhaseNaive',
+ GameLib.D3.Physics.BROADPHASE_TYPE_NAIVE
+ );
+ }
+ this.broadphase = broadphase;
+
+ if (typeof solver == 'undefined') {
+ solver = new GameLib.D3.Physics.Solver(
+ null,
+ 'GSSolver',
+ GameLib.D3.Physics.GS_SOLVER
+ );
+ }
+ this.solver = solver;
+
+ if (typeof rigidBodies == 'undefined') {
+ rigidBodies = [];
+ }
+ this.rigidBodies = rigidBodies;
+
+ this.engine = null;
+
+ this.worldInstance = null;
+
+ /**
+ * We only set the physics property if we pass it in the constructor,
+ * because we don't always want the physics object (ex. when we store this world to the API - we also don't then
+ * want to store the custom worlds - we want to generate them after loading from API)
+ */
+ if (engine) {
+ this.engine = engine;
+ this.worldInstance = this.createWorldInstance();
+ }
+};
+
+
+GameLib.D3.World.prototype.createWorldInstance = function() {
+
+ this.engine.isNotCannonThrow();
+
+ var customWorld = new this.engine.instance.World();
+
+ var cannonBroadphase = null;
+
+
+ customWorld.broadphase = cannonBroadphase;
+
+ var cannonSolver = null;
+
+ if (this.solver.solverType == GameLib.D3.Physics.SPLIT_SOLVER) {
+ cannonSolver = new this.engine.instance.SplitSolver();
+ } else if (this.solver.solverType == GameLib.D3.Physics.GS_SOLVER) {
+ cannonSolver = new this.engine.instance.GSSolver();
+ cannonSolver.iterations = this.solver.iterations;
+ }
+
+ customWorld.solver = cannonSolver;
+
+ customWorld.gravity.x = this.gravity.x;
+ customWorld.gravity.y = this.gravity.y;
+ customWorld.gravity.z = this.gravity.z;
+
+ for (var b = 0; b < this.rigidBodies.length; b++) {
+
+ var customBody = this.createCustomBody(this.rigidBodies[b]);
+
+ //customWorld.AddRigidBody();
+ }
+
+ customWorld.name = this.name;
+
+ return customWorld;
+};
+
+GameLib.D3.World.prototype.AddShape = function(
+ shape, // d3.physics.shape
+ rigidBody,
+ offset, // vec3
+ orientation //quaternion
+) {
+ shape.shape = shape;
+
+ /**
+ * TODO:: fix this?
+ */
+ if (this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
+
+ var _offset = null;
+ var _orientation = null;
+
+ if(offset != null && typeof offset !== 'undefined') {
+ _offset = new this.physics.CANNON.Vec3(offset.x, offset.y, offset.z);
+ }
+
+ if(orientation != null && typeof orientation !== 'undefined') {
+ _orientation = new this.physics.CANNON.Quaternion(orientation.x, orientation.y, orientation.z, orientation.w);
+ }
+
+ rigidBody.bodyObject.addShape(shape.shapeObject, _offset, _orientation);
+ }
+};
+
+GameLib.D3.World.prototype.Wheel = function() {
+
+};
+
+GameLib.D3.World.prototype.CreateRigidVehicle = function(
+ chassisBody // Physics.RigidBody
+) {
+ var rigidVehicle = new GameLib.D3.Physics.RigidVehicle();
+
+ if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ var vehicle = new this.physics.CANNON.RigidVehicle({
+ chassisBody: chassisBody.bodyObject
+ });
+ rigidVehicle.vehicleObject = vehicle;
+ return rigidVehicle;
+ }
+};
+
+GameLib.D3.World.prototype.CreateRaycastVehicle = function(
+ chassisBody // Physics.RigidBody
+) {
+ var raycastVehicle = new GameLib.D3.Physics.RaycastVehicle();
+
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ var vehicle = new this.physics.CANNON.RaycastVehicle({
+ chassisBody: chassisBody.bodyObject
+ });
+ raycastVehicle.vehicleObject = vehicle;
+ return raycastVehicle;
+ }
+};
+
+GameLib.D3.World.prototype.AddWheelToRigidVehicle = function(
+ vehicle,
+ rigidBody,
+ position,
+ axis,
+ direction
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ vehicle.vehicleObject.addWheel({
+ body: rigidBody.bodyObject,
+ position: new this.physics.CANNON.Vec3(position.x, position.y, position.z),
+ axis: new this.physics.CANNON.Vec3(axis.x, axis.y, axis.z),
+ direction: new this.physics.CANNON.Vec3(direction.x, direction.y, direction.z)
+ });
+ }
+};
+
+GameLib.D3.World.prototype.AddWheelToRaycastVehicle = function (
+ vehicle, // physics.raycastvehicle
+ options // cannon options
+) {
+ if (this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ vehicle.vehicleObject.addWheel(options);
+ } else {
+ console.log("function for engine not implemented");
+ }
+};
+
+
+
+GameLib.D3.World.prototype.CreateTriMeshShape = function(
+ vertices, // flat list of floats
+ indices // flat list of floats
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Trimesh(vertices, indices), GameLib.D3.Physics.SHAPE_TYPE_TRIMESH);
+ }
+};
+
+GameLib.D3.World.prototype.CreateSphereShape = function (
+ radius
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Sphere(radius), GameLib.D3.Physics.SHAPE_TYPE_SPHERE);
+ }
+};
+
+GameLib.D3.World.prototype.CreateBoxShape = function(
+ halfExtensions // vec3
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Box(new this.physics.CANNON.Vec3(halfExtensions.x, halfExtensions.y, halfExtensions.z)), GameLib.D3.Physics.SHAPE_TYPE_BOX);
+ }
+};
+
+GameLib.D3.World.prototype.CreateCylinderShape = function(
+ radiusTop,
+ radiusBottom,
+ height,
+ numSegments
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ return new GameLib.D3.Physics.Shape(new this.physics.CANNON.Cylinder(radiusTop, radiusBottom, height, numSegments), GameLib.D3.Physics.SHAPE_TYPE_CYLINDER);
+ }
+};
+
+GameLib.D3.World.prototype.AddRigidBody = function(
+ rigidBody // Physics.RigidBody
+) {
+ if(this.physics.engineType === GameLib.D3.Physics.TYPE_CANNON) {
+ this.worldObject.addBody(rigidBody.bodyObject);
+ }
+};
+
+GameLib.D3.World.prototype.AddVehicle = function(
+ vehicle // note: physics.vehicle
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ vehicle.vehicleObject.addToWorld(this.worldObject);
+ }
+};
+
+GameLib.D3.World.prototype.Step = function(
+ timeStep
+) {
+ if(this.physics.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+
+ // todo: figure out, why this call to internal step is more stable for trimesh collisions.....
+ //this.worldObject.internalStep(timeStep);
+ //return;
+
+ var now = performance.now() / 1000;
+
+ if(!this.lastCallTime){
+ // last call time not saved, cant guess elapsed time. Take a simple step.
+ this.worldObject.step(timeStep);
+ this.lastCallTime = now;
+ return;
+ }
+
+ var timeSinceLastCall = now - this.lastCallTime;
+
+ this.worldObject.step(timeStep, timeSinceLastCall);
+
+ this.lastCallTime = now;
+ }
+};
+
+GameLib.D3.World.prototype.GetIndexedVertices = function(
+ triangleMeshShape
+) {
+
+ if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+
+ return {
+ vertices : triangleMeshShape.vertices,
+ indices : triangleMeshShape.indices
+ };
+
+ } else {
+ // todo: implement this for other physics engines.
+ return null;
+ }
+
+};
+
+GameLib.D3.World.prototype.GenerateWireframeViewMesh = function(
+ triangleMeshShape,
+ normalLength,
+ scale,
+ opacity,
+ wireframeColor
+) {
+ var geometryTHREE = new THREE.Geometry();
+ var wireframeTHREEMesh = new THREE.Mesh
+ (
+ geometryTHREE,
+ new THREE.MeshBasicMaterial({
+ color: wireframeColor ? wireframeColor : 0xfefefe,
+ wireframe: true,
+ opacity: opacity ? opacity : 0.5
+ })
+ );
+
+ var data = this.GetIndexedVertices(triangleMeshShape);
+
+ for(var i = 0, l = data.vertices.length / 3; i < l; i++) {
+ geometryTHREE.vertices.push(new THREE.Vector3(data.vertices[i * 3], data.vertices[i * 3 + 1], data.vertices[i * 3 + 2]));
+ }
+
+ for(var i = 0, l = data.indices.length / 3; i < l; i++) {
+ var i0 = data.indices[i * 3];
+ var i1 = data.indices[i * 3 + 1];
+ var i2 = data.indices[i * 3 + 2];
+
+ geometryTHREE.faces.push(new THREE.Face3(i0, i1, i2));
+
+ // Create debug view for normals
+
+ // Center point on the mesh itself
+ var centroid = new THREE.Vector3()
+ .add(geometryTHREE.vertices[i0])
+ .add(geometryTHREE.vertices[i1])
+ .add(geometryTHREE.vertices[i2])
+ .divideScalar(3);
+
+ var normal = null;
+ if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+ var normal = new this.physics.CANNON.Vec3();
+ triangleMeshShape.getNormal(i, normal);
+ } else {
+ // todo: calculate the normal for v0, v1 & v2 here.
+ }
+
+ var arrow = new THREE.ArrowHelper(new THREE.Vector3(normal.x, normal.y, normal.z), centroid, normalLength, new THREE.Color(normal.x, normal.y, normal.z));
+ wireframeTHREEMesh.add( arrow );
+ }
+
+ wireframeTHREEMesh.scale.x = scale.x;
+ wireframeTHREEMesh.scale.y = scale.y;
+ wireframeTHREEMesh.scale.z = scale.z;
+
+ return wireframeTHREEMesh;
+};
+
+GameLib.D3.World.prototype.GenerateTriangleCollisionMesh = function(
+ threeMesh,
+ mass, // default = 0
+ friction, // default = 10
+ createCollisionSubMeshes, // boolean. default = false
+ facesPerSubsection, // int. default = 0
+ subsectionsToMerge // int. default = 0
+) {
+ var processedFaces = 0;
+ var facesPerSubSection = facesPerSubsection || 0;
+ var subMeshesToMerge = subsectionsToMerge || 0;
+ var totalAmtFaces = threeMesh.geometry.faces.length;
+ var facesToProcess = createCollisionSubMeshes ? (subMeshesToMerge * facesPerSubSection) : totalAmtFaces;
+
+ var pairs = []; // output
+
+ var vertices = [];
+ var indicies = [];
+
+ for(var i = 0; i <= totalAmtFaces; i++) {
+ if(processedFaces == facesToProcess || i == totalAmtFaces) {
+
+ var body = null;
+
+ if(this.engine.engineType == GameLib.D3.Physics.TYPE_CANNON) {
+
+ var meshShape = new this.physics.CANNON.Trimesh(vertices, indicies);
+ meshShape.setScale(new this.physics.CANNON.Vec3(threeMesh.scale.x, threeMesh.scale.y, threeMesh.scale.z));
+ meshShape.updateAABB();
+ meshShape.updateNormals();
+ meshShape.updateEdges();
+ meshShape.updateBoundingSphereRadius();
+ meshShape.updateTree();
+
+ body = new this.physics.CANNON.Body({ mass: mass ? mass : 0, friction: friction ? friction : 10 });
+ body.addShape(meshShape);
+
+ } else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_AMMO) {
+
+ } else if (this.engine.engineType == GameLib.D3.Physics.Engine.TYPE_GOBLIN) {
+
+ }
+
+ pairs.push({
+ threeObject : createCollisionSubMeshes ? null : threeMesh,
+ physicsObject : body
+ });
+
+ vertices = [];
+ indicies = [];
+ processedFaces = 0;
+
+ if(i == totalAmtFaces) {
+ return pairs;
+ }
+ }
+
+ var face = threeMesh.geometry.faces[i];
+ indicies.push(indicies.length);
+ indicies.push(indicies.length);
+ indicies.push(indicies.length);
+
+ var v0 = threeMesh.geometry.vertices[face.a];
+ var v1 = threeMesh.geometry.vertices[face.b];
+ var v2 = threeMesh.geometry.vertices[face.c];
+
+ vertices.push(v0.x, v0.y, v0.z);
+ vertices.push(v1.x, v1.y, v1.z);
+ vertices.push(v2.x, v2.y, v2.z);
+
+ processedFaces++;
+ }
+};
+
+Eif (typeof module !== 'undefined') {
+ module.exports = GameLib;
+} |
+