Kaynağa Gözat

Merge remote-tracking branch 'upstream/master' into Development

Sebastien Vandenberghe 8 yıl önce
ebeveyn
işleme
a30af289d1
36 değiştirilmiş dosya ile 4380 ekleme ve 3601 silme
  1. BIN
      Exporters/Blender/Blender2Babylon-5.3.zip
  2. 14 0
      Exporters/Blender/src/babylon-js/json_exporter.py
  3. 1 1
      Exporters/Blender/src/babylon-js/material.py
  4. 18 13
      Exporters/Blender/src/babylon-js/mesh.py
  5. 104 0
      Exporters/Blender/src/babylon-js/shape_key_group.py
  6. 33 18
      Playground/css/index.css
  7. 215 37
      Playground/debug.html
  8. 216 37
      Playground/index-local.html
  9. 215 37
      Playground/index.html
  10. 216 38
      Playground/index2_5.html
  11. 0 9
      Playground/js/actions.js
  12. 126 58
      Playground/js/index.js
  13. 1123 1119
      dist/preview release/babylon.d.ts
  14. 24 24
      dist/preview release/babylon.js
  15. 64 22
      dist/preview release/babylon.max.js
  16. 1123 1119
      dist/preview release/babylon.module.d.ts
  17. 24 24
      dist/preview release/babylon.worker.js
  18. 1 0
      dist/preview release/gui/babylon.gui.d.ts
  19. 10 1
      dist/preview release/gui/babylon.gui.js
  20. 1 1
      dist/preview release/gui/babylon.gui.min.js
  21. 247 247
      dist/preview release/inspector/babylon.inspector.bundle.js
  22. 1 1
      dist/preview release/inspector/babylon.inspector.min.js
  23. 2 2
      dist/preview release/loaders/babylon.glTF1FileLoader.min.js
  24. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.d.ts
  25. 167 235
      dist/preview release/loaders/babylon.glTF2FileLoader.js
  26. 1 1
      dist/preview release/loaders/babylon.glTF2FileLoader.min.js
  27. 1 1
      dist/preview release/loaders/babylon.glTFFileLoader.d.ts
  28. 167 235
      dist/preview release/loaders/babylon.glTFFileLoader.js
  29. 2 2
      dist/preview release/loaders/babylon.glTFFileLoader.min.js
  30. 183 270
      loaders/src/glTF/2.0/babylon.glTFLoader.ts
  31. 1 1
      loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts
  32. 33 0
      src/Bones/babylon.bone.ts
  33. 24 25
      src/Cameras/babylon.arcRotateCamera.ts
  34. 5 5
      src/Cameras/babylon.targetCamera.ts
  35. 1 1
      src/Mesh/babylon.abstractMesh.ts
  36. 16 16
      src/babylon.scene.ts

BIN
Exporters/Blender/Blender2Babylon-5.3.zip


+ 14 - 0
Exporters/Blender/src/babylon-js/json_exporter.py

@@ -62,6 +62,7 @@ class JsonExporter:
             self.skeletons = []
             skeletonId = 0
             self.meshesAndNodes = []
+            self.morphTargetMngrs = []
             self.materials = []
             self.multiMaterials = []
             self.sounds = []
@@ -106,6 +107,8 @@ class JsonExporter:
                         
                         if hasattr(mesh, 'instances'):
                             self.meshesAndNodes.append(mesh)
+                            if hasattr(mesh, 'morphTargetManagerId'):
+                                self.morphTargetMngrs.append(mesh)
                         else:
                             break
 
@@ -209,6 +212,17 @@ class JsonExporter:
             mesh.to_scene_file(file_handler)
         file_handler.write(']')
 
+        # Morph targets
+        file_handler.write(',\n"morphTargetManagers":[')
+        first = True
+        for mesh in self.morphTargetMngrs:
+            if first != True:
+                file_handler.write(',')
+
+            first = False
+            mesh.write_morphing_file(file_handler)
+        file_handler.write(']')
+
         # Cameras
         file_handler.write(',\n"cameras":[')
         first = True

+ 1 - 1
Exporters/Blender/src/babylon-js/material.py

@@ -187,7 +187,7 @@ class BakingRecipe:
 
         # accumulators set by Blender Game
         self.backFaceCulling = True  # used only when baking
-        self.isBillboard = len(mesh.material_slots) == 1 and mesh.material_slots[0].material.game_settings.face_orientation == 'BILLBOARD'
+        self.isBillboard = len(mesh.material_slots) == 1 and mesh.material_slots[0] is not None and mesh.material_slots[0].material.game_settings.face_orientation == 'BILLBOARD'
 
         # Cycles specific, need to get the node trees of each material
         self.nodeTrees = []

+ 18 - 13
Exporters/Blender/src/babylon-js/mesh.py

@@ -9,6 +9,7 @@ from .shape_key_group import *
 import bpy
 import math
 from mathutils import Vector
+from random import randint
 import shutil
 
 # output related constants
@@ -435,6 +436,7 @@ class Mesh(FCurveAnimatable):
         if hasShapeKeys:
             Mesh.sort(keyOrderMap)
             self.rawShapeKeys = []
+            self.morphTargetManagerId = randint(0, 1000000) # not used for TOB implementation
             groupNames = []
             Logger.log('Shape Keys:', 2)
 
@@ -675,24 +677,27 @@ class Mesh(FCurveAnimatable):
         file_handler.write(']')
         
         # Shape Keys
-        if hasattr(self, 'rawShapeKeys'):
-            first = True
-            file_handler.write('\n,"MorphTargetManager":{')
-            write_string(file_handler, 'id', self.name, True)
-            file_handler.write('\n,"targets":[')
-            for key in self.rawShapeKeys:
-                if first == False:
-                    file_handler.write(',')
-
-                key.to_scene_file(file_handler)
-
-                first = False
-            file_handler.write(']}')
+        if hasattr(self, 'morphTargetManagerId'):
+            write_int(file_handler, 'morphTargetManagerId', self.morphTargetManagerId)
 
         # Close mesh
         file_handler.write('}\n')
         self.alreadyExported = True
 #===============================================================================
+    def write_morphing_file(self, file_handler):
+        first = True
+        file_handler.write('{')
+        write_int(file_handler, 'id', self.morphTargetManagerId, True)
+        file_handler.write('\n,"targets":[')
+        for key in self.rawShapeKeys:
+            if first == False:
+                file_handler.write(',')
+
+            key.to_scene_file(file_handler)
+
+            first = False
+        file_handler.write(']}')
+#===============================================================================
 class MeshInstance:
      def __init__(self, instancedMesh, rotation, rotationQuaternion):
         self.name = instancedMesh.name

+ 104 - 0
Exporters/Blender/src/babylon-js/shape_key_group.py

@@ -0,0 +1,104 @@
+from .logger import *
+from .package_level import *
+
+import bpy
+#===============================================================================
+# extract data in Mesh order, no optimization from group analysis yet; mapped into a copy of position
+# 
+class RawShapeKey:
+    def __init__(self, keyBlock, group, state, keyOrderMap, basis):
+        self.group = group
+        self.state = state
+        self.vertices = []
+
+        retSz = len(keyOrderMap)
+        for i in range(retSz):
+            self.vertices.append(None)
+
+        nDifferent = 0
+        for i in range(retSz):
+            pair = keyOrderMap[i]
+            value = keyBlock.data[pair[0]].co
+            self.vertices[pair[1]] = value
+            if not similar_vertex(value, basis.data[pair[0]].co):
+                nDifferent += 1
+
+        # only log when groups / allowVertReduction
+        if state != 'BASIS' and group is not None:
+            Logger.log('shape key "' + group + '-' + state + '":  n verts different from basis: ' + str(nDifferent), 3)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_scene_file(self, file_handler):
+        file_handler.write('{')
+        write_string(file_handler, 'name', self.state, True)
+        write_vector_array(file_handler, 'positions', self.vertices)
+        write_int(file_handler, 'influence', 0)
+        file_handler.write('}')
+#===============================================================================
+class ShapeKeyGroup:
+    def __init__(self, group, rawShapeKeys, basisVerts):
+        self.group = group
+        self.basisVerts = basisVerts
+        self.stateNames = []
+        self.stateVertices = []
+        self.affectedIndices = []
+
+        nRawKeys = len(rawShapeKeys)
+        nSize = len(self.basisVerts)
+
+        sameForAll = []
+        for i in range(nSize):
+            sameForAll.append(True)
+
+        # first pass to determine which vertices are not the same across all members of a group & also Basis
+        for i in range(nSize):
+            for key in rawShapeKeys:
+                # no need for more checking once 1 difference is found
+                if not sameForAll[i]:
+                    break;
+
+                # skip key if not member of the current group being processed
+                if group != key.group:
+                    continue;
+
+                # check vertex not different from Basis
+                if not similar_vertex(key.vertices[i],  self.basisVerts[i]):
+                    sameForAll[i] = False
+                    break;
+
+        affectedWholeVertices = []
+
+        # pass to convert sameForAll into self.affectedIndices, build 'BASIS' state at the same time
+        for i in range(nSize):
+            if not sameForAll[i]:
+                affectedWholeVertices.append(i)
+                self.affectedIndices.append(i * 3 + 0)
+                self.affectedIndices.append(i * 3 + 1)
+                self.affectedIndices.append(i * 3 + 2)
+
+        Logger.log('Shape-key group, ' + group + ', # of affected vertices: '+ str(len(affectedWholeVertices)) + ', out of ' + str(nSize), 2)
+
+        # pass to convert rawShapeKeys in this group, to stateVertices of only affected indices
+        for key in rawShapeKeys:
+            if group != key.group:
+                continue;
+
+            affectedVertices = []
+            for idx in affectedWholeVertices:
+                # clone vert, so key can be deleted in pass 1, and not affect pass2
+                # encode as a difference to basis, so more compact
+                vert = key.vertices[idx].copy()
+                vert.x -= self.basisVerts[idx].x
+                vert.y -= self.basisVerts[idx].y
+                vert.z -= self.basisVerts[idx].z
+                affectedVertices.append(vert)
+
+            self.stateNames.append(key.state)
+            self.stateVertices.append(affectedVertices)
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+    def to_script_file(self, file_handler, var, indent):
+        writeInt32Array(file_handler, '_i', indent, self.affectedIndices, True)
+        file_handler.write(indent  + 'shapeKeyGroup = new QI.ShapeKeyGroup(' + var + ', "' + self.group + '", _i);\n')
+
+        for state_idx in range(len(self.stateVertices)):
+            writeFloat32Array(file_handler, '_i', indent, self.stateVertices[state_idx], True)
+            file_handler.write(indent  + 'shapeKeyGroup._addShapeKey("' + self.stateNames[state_idx] + '", true, _i);\n')

+ 33 - 18
Playground/css/index.css

@@ -155,6 +155,7 @@ body {
     left: 0;
     top: 25px;
     min-width: 100%;
+    width: 150px;
     display: none;
 }
 
@@ -203,7 +204,8 @@ body {
     z-index: 10;
     top: 32px;
     width:550px;
-    max-height:350px;
+    max-height:390px;
+    overflow-y: auto;
     right:0;
     position:absolute;
     font-size:0.8em;
@@ -451,32 +453,45 @@ body {
 
 /*Media queries*/
 
-@media (max-width: 1600px) {
-    .desktopOnly {
-        display: none !important;
+@media (min-width: 1475px) {
+    .navBar1600 { display: block; }
+    .navBar1475 { display: none; }
+    .navBar1030 { display: none; }
+    .navBar750 { display: none; }
+
+    .navbar .select .toDisplayBig ul {
+        column-count: 3;
     }
 }
 @media (max-width: 1475px) {
-    .desktopOnly {
-        display: none !important;
-    }
-    .desktopTabletOnly {
-        display: none !important;
+    .navBar1600 { display: none; }
+    .navBar1475 { display: block; }
+    .navBar1030 { display: none; }
+    .navBar750 { display: none; }
+
+    .navbar .select .toDisplayBig ul {
+        column-count: 3;
     }
 }
-@media (max-width: 975px) {
-    .title {
-        display : none !important;
-    }
-    .version {
-        display : none !important;
+@media (max-width: 1030px) {
+    .navBar1600 { display: none; }
+    .navBar1475 { display: none; }
+    .navBar1030 { display: block; }
+    .navBar750 { display: none; }
+
+    .navbar .select .toDisplayBig ul {
+        column-count: 2;
     }
 }
-@media (max-width: 660px) {
+@media (max-width: 750px) {
+    .navBar1600 { display: none; }
+    .navBar1475 { display: none; }
+    .navBar1030 { display: none; }
+    .navBar750 { display: block; }
     .removeOnPhone {
         display : none !important;
     }
-    .category {
-        margin:0 !important;
+    .navbar .select .toDisplayBig ul {
+        column-count: 1;
     }
 }

+ 215 - 37
Playground/debug.html

@@ -60,7 +60,7 @@
 </head>
 
 <body>
-     <div class="navbar">
+    <div class="navbar navBar1600">
         <div class="title">
             Babylon.js Playground
         </div>
@@ -69,51 +69,105 @@
         </div>
 
         <div class="category">
-            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1600">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1600">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
         </div>
 
-
-        <!--<div class="category desktopOnly">-->
-
-        <!--<div class="button select"><span id="currentFontSize">Font: 14</span>
+        <div class="category">
+            <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option" onclick="setFontSize(12);">12</div>
-                    <div class="option" onclick="setFontSize(14);">14</div>
-                    <div class="option" onclick="setFontSize(16);">16</div>
-                    <div class="option" onclick="setFontSize(18);">18</div>
-                    <div class="option" onclick="setFontSize(20);">20</div>
-                    <div class="option" onclick="setFontSize(22);">22</div>
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1600">Dark</div>
+                            <div class="option" id="lightTheme1600">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1600">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1600">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1600">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                    <div class="option" id="formatButton1600">Format code</div>
                 </div>
-            </div>-->
+            </div>
+
+            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
+            <div class="button" id="metadataButton1600">Metadata</div>
+        </div>
+
+
 
-        <!--<div class="button select">Theme
+        <div class="category right">
+            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
                 <div class="toDisplay">
-                    <div class="option" id="darkTheme">Dark</div>
-                    <div class="option" id="lightTheme">Light</div>
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
                 </div>
-            </div>-->
-        <!--</div>-->
-        <div class="category desktopTabletOnly">
+            </div>
+            <div class="button select"> <span id="currentScript1600">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1600">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar1475">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1475">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1475">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
-                            <div class="option" id="darkTheme">Dark</div>
-                            <div class="option" id="lightTheme">Light</div>
+                            <div class="option" id="darkTheme1475">Dark</div>
+                            <div class="option" id="lightTheme1475">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect"><span id="currentFontSize1475">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -123,30 +177,154 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id='safemodeToggle1475'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1475">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                    <div class="option" id="formatButton1475">Format code</div>
+                    <div class="option" id="debugButton1475">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1475">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
                     </div>
-                    <div class="option" id="fullscreenButton">Fullscreen</div>
-                    <div class="option" id="formatButton">Format code</div>
                 </div>
             </div>
+        </div>
+
+        <div class="category right">
+            <div class="button select"> <span id="currentScript1475">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1475">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
 
-            <div class="button check uncheck" id="debugButton">Debug layer</div>
-            <div class="button" id="metadataButton">Metadata</div>
+    <div class="navbar navBar1030">
+        <div class="category">
+            <div class="button run" id="runButton1030">Run <i class="fa fa-play" aria-hidden="true"></i></div>
         </div>
 
 
+        <div class="category">
+            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1030">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1030">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1030">Dark</div>
+                            <div class="option" id="lightTheme1030">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1030">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1030">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1030">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                    <div class="option" id="formatButton1030">Format code</div>
+                    <div class="option" id="debugButton1030">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1030">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
 
         <div class="category right">
-            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+            <div class="button select"> <span id="currentScript1030">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1030">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar750">
+        <div class="category">
+            <div class="button select">File
                 <div class="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                    <div class="option" id="runButton750">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+                    <div class="option" id="newButton750">New <i class="fa fa-file" aria-hidden="true"></i></div>
+                    <div class="option" id="clearButton750">Clear <i class="fa fa-trash" aria-hidden="true"></i></div>
+                    <div class="option" id="saveButton750">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+                    <div class="option" id="zipButton750">Zip <i class="fa fa-download" aria-hidden="true"></i></div>
                 </div>
             </div>
-            <div class="button select"> <span id="currentScript">Scenes</span>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme750">Dark</div>
+                            <div class="option" id="lightTheme750">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize750">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle750">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div style="display:none;" class="option checked" id="editorButton750">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton750">Fullscreen</div>
+                    <div class="option" id="formatButton750">Format code</div>
+                    <div class="option" id="debugButton750">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton750">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="category right">
+            <div class="button select"> <span id="currentScript750">Scenes</span>
                 <div class="toDisplayBig">
-                    <ul id="scriptsList">
+                    <ul id="scriptsList750">
                     </ul>
                 </div>
             </div>

+ 216 - 37
Playground/index-local.html

@@ -24,7 +24,7 @@
 </head>
 
 <body>
-   <div class="navbar">
+    <div class="navbar navBar1600">
         <div class="title">
             Babylon.js Playground
         </div>
@@ -33,51 +33,105 @@
         </div>
 
         <div class="category">
-            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1600">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1600">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
         </div>
 
-
-        <!--<div class="category desktopOnly">-->
-
-        <!--<div class="button select"><span id="currentFontSize">Font: 14</span>
+        <div class="category">
+            <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option" onclick="setFontSize(12);">12</div>
-                    <div class="option" onclick="setFontSize(14);">14</div>
-                    <div class="option" onclick="setFontSize(16);">16</div>
-                    <div class="option" onclick="setFontSize(18);">18</div>
-                    <div class="option" onclick="setFontSize(20);">20</div>
-                    <div class="option" onclick="setFontSize(22);">22</div>
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1600">Dark</div>
+                            <div class="option" id="lightTheme1600">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1600">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1600">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1600">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                    <div class="option" id="formatButton1600">Format code</div>
                 </div>
-            </div>-->
+            </div>
+
+            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
+            <div class="button" id="metadataButton1600">Metadata</div>
+        </div>
+
+
 
-        <!--<div class="button select">Theme
+        <div class="category right">
+            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
                 <div class="toDisplay">
-                    <div class="option" id="darkTheme">Dark</div>
-                    <div class="option" id="lightTheme">Light</div>
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                </div>
+            </div>
+            <div class="button select"> <span id="currentScript1600">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1600">
+                    </ul>
                 </div>
-            </div>-->
-        <!--</div>-->
-        <div class="category desktopTabletOnly">
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar1475">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1475">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1475">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
-                            <div class="option" id="darkTheme">Dark</div>
-                            <div class="option" id="lightTheme">Light</div>
+                            <div class="option" id="darkTheme1475">Dark</div>
+                            <div class="option" id="lightTheme1475">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect"><span id="currentFontSize1475">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -87,30 +141,154 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id='safemodeToggle1475'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1475">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                    <div class="option" id="formatButton1475">Format code</div>
+                    <div class="option" id="debugButton1475">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1475">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
                     </div>
-                    <div class="option" id="fullscreenButton">Fullscreen</div>
-                    <div class="option" id="formatButton">Format code</div>
                 </div>
             </div>
+        </div>
 
-            <div class="button check uncheck" id="debugButton">Debug layer</div>
-            <div class="button" id="metadataButton">Metadata</div>
+        <div class="category right">
+            <div class="button select"> <span id="currentScript1475">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1475">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
         </div>
+    </div>
 
+    <div class="navbar navBar1030">
+        <div class="category">
+            <div class="button run" id="runButton1030">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
 
 
+        <div class="category">
+            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1030">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1030">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1030">Dark</div>
+                            <div class="option" id="lightTheme1030">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1030">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1030">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1030">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                    <div class="option" id="formatButton1030">Format code</div>
+                    <div class="option" id="debugButton1030">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1030">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
         <div class="category right">
-            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+            <div class="button select"> <span id="currentScript1030">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1030">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar750">
+        <div class="category">
+            <div class="button select">File
                 <div class="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                    <div class="option" id="runButton750">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+                    <div class="option" id="newButton750">New <i class="fa fa-file" aria-hidden="true"></i></div>
+                    <div class="option" id="clearButton750">Clear <i class="fa fa-trash" aria-hidden="true"></i></div>
+                    <div class="option" id="saveButton750">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+                    <div class="option" id="zipButton750">Zip <i class="fa fa-download" aria-hidden="true"></i></div>
                 </div>
             </div>
-            <div class="button select"> <span id="currentScript">Scenes</span>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme750">Dark</div>
+                            <div class="option" id="lightTheme750">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize750">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle750">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div style="display:none;" class="option checked" id="editorButton750">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton750">Fullscreen</div>
+                    <div class="option" id="formatButton750">Format code</div>
+                    <div class="option" id="debugButton750">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton750">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="category right">
+            <div class="button select"> <span id="currentScript750">Scenes</span>
                 <div class="toDisplayBig">
-                    <ul id="scriptsList">
+                    <ul id="scriptsList750">
                     </ul>
                 </div>
             </div>
@@ -164,6 +342,7 @@
             </div>
         </div>
     </div>
+
     <script src="https://code.jquery.com/jquery.js"></script>
 
     <script src="js/actions.js"></script>

+ 215 - 37
Playground/index.html

@@ -59,7 +59,7 @@
 </head>
 
 <body>
-    <div class="navbar">
+    <div class="navbar navBar1600">
         <div class="title">
             Babylon.js Playground
         </div>
@@ -68,51 +68,105 @@
         </div>
 
         <div class="category">
-            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1600">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1600">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
         </div>
 
-
-        <!--<div class="category desktopOnly">-->
-
-        <!--<div class="button select"><span id="currentFontSize">Font: 14</span>
+        <div class="category">
+            <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option" onclick="setFontSize(12);">12</div>
-                    <div class="option" onclick="setFontSize(14);">14</div>
-                    <div class="option" onclick="setFontSize(16);">16</div>
-                    <div class="option" onclick="setFontSize(18);">18</div>
-                    <div class="option" onclick="setFontSize(20);">20</div>
-                    <div class="option" onclick="setFontSize(22);">22</div>
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1600">Dark</div>
+                            <div class="option" id="lightTheme1600">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1600">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1600">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1600">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                    <div class="option" id="formatButton1600">Format code</div>
                 </div>
-            </div>-->
+            </div>
+
+            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
+            <div class="button" id="metadataButton1600">Metadata</div>
+        </div>
+
+
 
-        <!--<div class="button select">Theme
+        <div class="category right">
+            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
                 <div class="toDisplay">
-                    <div class="option" id="darkTheme">Dark</div>
-                    <div class="option" id="lightTheme">Light</div>
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
                 </div>
-            </div>-->
-        <!--</div>-->
-        <div class="category desktopTabletOnly">
+            </div>
+            <div class="button select"> <span id="currentScript1600">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1600">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar1475">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            v3.0-alpha
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1475">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1475">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
-                            <div class="option" id="darkTheme">Dark</div>
-                            <div class="option" id="lightTheme">Light</div>
+                            <div class="option" id="darkTheme1475">Dark</div>
+                            <div class="option" id="lightTheme1475">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect"><span id="currentFontSize1475">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -122,30 +176,154 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id='safemodeToggle1475'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1475">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                    <div class="option" id="formatButton1475">Format code</div>
+                    <div class="option" id="debugButton1475">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1475">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
                     </div>
-                    <div class="option" id="fullscreenButton">Fullscreen</div>
-                    <div class="option" id="formatButton">Format code</div>
                 </div>
             </div>
+        </div>
+
+        <div class="category right">
+            <div class="button select"> <span id="currentScript1475">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1475">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
 
-            <div class="button check uncheck" id="debugButton">Debug layer</div>
-            <div class="button" id="metadataButton">Metadata</div>
+    <div class="navbar navBar1030">
+        <div class="category">
+            <div class="button run" id="runButton1030">Run <i class="fa fa-play" aria-hidden="true"></i></div>
         </div>
 
 
+        <div class="category">
+            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1030">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1030">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1030">Dark</div>
+                            <div class="option" id="lightTheme1030">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1030">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1030">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1030">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                    <div class="option" id="formatButton1030">Format code</div>
+                    <div class="option" id="debugButton1030">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1030">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
 
         <div class="category right">
-            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+            <div class="button select"> <span id="currentScript1030">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1030">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar750">
+        <div class="category">
+            <div class="button select">File
                 <div class="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                    <div class="option" id="runButton750">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+                    <div class="option" id="newButton750">New <i class="fa fa-file" aria-hidden="true"></i></div>
+                    <div class="option" id="clearButton750">Clear <i class="fa fa-trash" aria-hidden="true"></i></div>
+                    <div class="option" id="saveButton750">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+                    <div class="option" id="zipButton750">Zip <i class="fa fa-download" aria-hidden="true"></i></div>
                 </div>
             </div>
-            <div class="button select"> <span id="currentScript">Scenes</span>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme750">Dark</div>
+                            <div class="option" id="lightTheme750">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize750">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle750">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div style="display:none;" class="option checked" id="editorButton750">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton750">Fullscreen</div>
+                    <div class="option" id="formatButton750">Format code</div>
+                    <div class="option" id="debugButton750">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton750">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
+        <div class="category right">
+            <div class="button select"> <span id="currentScript750">Scenes</span>
                 <div class="toDisplayBig">
-                    <ul id="scriptsList">
+                    <ul id="scriptsList750">
                     </ul>
                 </div>
             </div>

+ 216 - 38
Playground/index2_5.html

@@ -31,60 +31,114 @@
 </head>
 
 <body>
-      <div class="navbar">
+    <div class="navbar navBar1600">
         <div class="title">
             Babylon.js Playground
         </div>
         <div class="version" id="mainTitle">
-            v3.0-alpha
+            2.5
         </div>
 
         <div class="category">
-            <div class="button run" id="runButton">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+            <div class="button run" id="runButton1600">Run <i class="fa fa-play" aria-hidden="true"></i></div>
         </div>
 
 
         <div class="category">
-            <div class="button" id="newButton">New<i class="fa fa-file" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="clearButton">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+            <div class="button" id="newButton1600">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1600">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
         </div>
 
         <div class="category">
-            <div class="button" id="saveButton">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
-            <div class="button removeOnPhone" id="zipButton">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+            <div class="button" id="saveButton1600">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1600">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
         </div>
 
-
-        <!--<div class="category desktopOnly">-->
-
-        <!--<div class="button select"><span id="currentFontSize">Font: 14</span>
+        <div class="category">
+            <div class="button select">Settings
                 <div class="toDisplay">
-                    <div class="option" onclick="setFontSize(12);">12</div>
-                    <div class="option" onclick="setFontSize(14);">14</div>
-                    <div class="option" onclick="setFontSize(16);">16</div>
-                    <div class="option" onclick="setFontSize(18);">18</div>
-                    <div class="option" onclick="setFontSize(20);">20</div>
-                    <div class="option" onclick="setFontSize(22);">22</div>
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1600">Dark</div>
+                            <div class="option" id="lightTheme1600">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1600">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1600">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1600">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1600">Fullscreen</div>
+                    <div class="option" id="formatButton1600">Format code</div>
                 </div>
-            </div>-->
+            </div>
+
+            <div class="button uncheck" id="debugButton1600">Debug layer <i class="fa fa-square-o" aria-hidden="true"></i></div>
+            <div class="button" id="metadataButton1600">Metadata</div>
+        </div>
+
+
 
-        <!--<div class="button select">Theme
+        <div class="category right">
+            <div class="button select"><span id="currentVersion1600">Version: Latest</span>
                 <div class="toDisplay">
-                    <div class="option" id="darkTheme">Dark</div>
-                    <div class="option" id="lightTheme">Light</div>
+                    <div class="option" onclick="setVersion('latest');">Latest</div>
+                    <div class="option" onclick="setVersion('2.5');">2.5</div>
                 </div>
-            </div>-->
-        <!--</div>-->
-        <div class="category desktopTabletOnly">
+            </div>
+            <div class="button select"> <span id="currentScript1600">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1600">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar1475">
+        <div class="title">
+            Babylon.js Playground
+        </div>
+        <div class="version" id="mainTitle">
+            2.5
+        </div>
+
+        <div class="category">
+            <div class="button run" id="runButton1475">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
+
+
+        <div class="category">
+            <div class="button" id="newButton1475">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1475">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1475">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1475">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
             <div class="button select">Settings
                 <div class="toDisplay">
                     <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
-                            <div class="option" id="darkTheme">Dark</div>
-                            <div class="option" id="lightTheme">Light</div>
+                            <div class="option" id="darkTheme1475">Dark</div>
+                            <div class="option" id="lightTheme1475">Light</div>
                         </div>
                     </div>
-                    <div class="option subSelect"><span id="currentFontSize">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                    <div class="option subSelect"><span id="currentFontSize1475">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
                         <div class="toDisplaySub">
                             <div class="option" onclick="setFontSize(12);">12</div>
                             <div class="option" onclick="setFontSize(14);">14</div>
@@ -94,30 +148,154 @@
                             <div class="option" onclick="setFontSize(22);">22</div>
                         </div>
                     </div>
-                    <div class="option" id='safemodeToggle'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
-                    <div class="option checked" id="editorButton">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    <div class="option" id='safemodeToggle1475'>Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1475">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1475">Fullscreen</div>
+                    <div class="option" id="formatButton1475">Format code</div>
+                    <div class="option" id="debugButton1475">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1475">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1475">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
                     </div>
-                    <div class="option" id="fullscreenButton">Fullscreen</div>
-                    <div class="option" id="formatButton">Format code</div>
                 </div>
             </div>
+        </div>
 
-            <div class="button check uncheck" id="debugButton">Debug layer</div>
-            <div class="button" id="metadataButton">Metadata</div>
+        <div class="category right">
+            <div class="button select"> <span id="currentScript1475">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1475">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
         </div>
+    </div>
 
+    <div class="navbar navBar1030">
+        <div class="category">
+            <div class="button run" id="runButton1030">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+        </div>
 
 
+        <div class="category">
+            <div class="button" id="newButton1030">New<i class="fa fa-file" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="clearButton1030">Clear<i class="fa fa-trash" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button" id="saveButton1030">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+            <div class="button removeOnPhone" id="zipButton1030">Zip<i class="fa fa-download" aria-hidden="true"></i></div>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme1030">Dark</div>
+                            <div class="option" id="lightTheme1030">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize1030">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle1030">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option checked" id="editorButton1030">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton1030">Fullscreen</div>
+                    <div class="option" id="formatButton1030">Format code</div>
+                    <div class="option" id="debugButton1030">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton1030">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion1030">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
+                </div>
+            </div>
+        </div>
+
         <div class="category right">
-            <div class="button select desktopTabletOnly"><span id="currentVersion">Version: Latest</span>
+            <div class="button select"> <span id="currentScript1030">Scenes</span>
+                <div class="toDisplayBig">
+                    <ul id="scriptsList1030">
+                    </ul>
+                </div>
+            </div>
+        </div>
+        <div class="save-message" id="saveMessage">
+            This PG has missing metadata. Click save to add them.
+        </div>
+    </div>
+
+    <div class="navbar navBar750">
+        <div class="category">
+            <div class="button select">File
                 <div class="toDisplay">
-                    <div class="option" onclick="setVersion('latest');">Latest</div>
-                    <div class="option" onclick="setVersion('2.5');">2.5</div>
+                    <div class="option" id="runButton750">Run <i class="fa fa-play" aria-hidden="true"></i></div>
+                    <div class="option" id="newButton750">New <i class="fa fa-file" aria-hidden="true"></i></div>
+                    <div class="option" id="clearButton750">Clear <i class="fa fa-trash" aria-hidden="true"></i></div>
+                    <div class="option" id="saveButton750">Save <i class="fa fa-floppy-o" aria-hidden="true"></i></div>
+                    <div class="option" id="zipButton750">Zip <i class="fa fa-download" aria-hidden="true"></i></div>
+                </div>
+            </div>
+        </div>
+
+        <div class="category">
+            <div class="button select">Settings
+                <div class="toDisplay">
+                    <div class="option subSelect">Theme <i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" id="darkTheme750">Dark</div>
+                            <div class="option" id="lightTheme750">Light</div>
+                        </div>
+                    </div>
+                    <div class="option subSelect"><span id="currentFontSize750">Font: 14</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setFontSize(12);">12</div>
+                            <div class="option" onclick="setFontSize(14);">14</div>
+                            <div class="option" onclick="setFontSize(16);">16</div>
+                            <div class="option" onclick="setFontSize(18);">18</div>
+                            <div class="option" onclick="setFontSize(20);">20</div>
+                            <div class="option" onclick="setFontSize(22);">22</div>
+                        </div>
+                    </div>
+                    <div class="option" id="safemodeToggle750">Safe mode <i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div style="display:none;" class="option checked" id="editorButton750">Editor <i class="fa fa-check-square" aria-hidden="true"></i>
+                    </div>
+                    <div class="option" id="fullscreenButton750">Fullscreen</div>
+                    <div class="option" id="formatButton750">Format code</div>
+                    <div class="option" id="debugButton750">Debug layer<i class="fa fa-square-o" aria-hidden="true"></i></div>
+                    <div class="option" id="metadataButton750">Metadata</div>
+                    <div class="option subSelect"><span id="currentVersion750">Vers. : Latest</span><i class="fa fa-chevron-right" aria-hidden="true"></i>
+                        <div class="toDisplaySub">
+                            <div class="option" onclick="setVersion('latest');">Latest</div>
+                            <div class="option" onclick="setVersion('2.5');">2.5</div>
+                        </div>
+                    </div>
                 </div>
             </div>
-            <div class="button select"> <span id="currentScript">Scenes</span>
+        </div>
+
+        <div class="category right">
+            <div class="button select"> <span id="currentScript750">Scenes</span>
                 <div class="toDisplayBig">
-                    <ul id="scriptsList">
+                    <ul id="scriptsList750">
                     </ul>
                 </div>
             </div>

+ 0 - 9
Playground/js/actions.js

@@ -80,13 +80,4 @@
         })
 
     }
-
-    document.querySelector('#safemodeToggle').addEventListener('click', function () {
-        this.classList.toggle('checked');
-        if (this.classList.contains('checked')) {
-            this.innerHTML = 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>';
-        } else {
-            this.innerHTML = 'Safe mode <i class="fa fa-square-o" aria-hidden="true"></i>';
-        }
-    })
 })();

+ 126 - 58
Playground/js/index.js

@@ -1,5 +1,29 @@
 var jsEditor;
 (function () {
+
+    var multipleSize = [1600, 1475, 1030, 750];
+    var setToMultipleID = function (id, thingToDo, param) {
+        multipleSize.forEach(function (size) {
+
+            if (thingToDo == "innerHTML") {
+                document.getElementById(id + size).innerHTML = param
+            }
+            else if (thingToDo == "click") {
+                document.getElementById(id + size).addEventListener("click", param);
+            }
+            else if (thingToDo == "addClass") {
+                document.getElementById(id + size).classList.add(param);
+            }
+            else if (thingToDo == "removeClass") {
+                document.getElementById(id + size).classList.remove(param);
+            }
+            else if (thingToDo == "display") {
+                document.getElementById(id + size).style.display = param;
+            }
+        });
+    };
+
+
     var fontSize = 14;
 
     var splitInstance = Split(['#jsEditor', '#canvasZone']);
@@ -19,15 +43,16 @@
     var run = function () {
         var blockEditorChange = false;
 
-        var markDirty = function() {
+        var markDirty = function () {
             if (blockEditorChange) {
                 return;
             }
 
-            document.getElementById("currentScript").innerHTML = "Custom";
-            document.getElementById('safemodeToggle').classList.add('checked');
 
-            document.getElementById('safemodeToggle').innerHTML = 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>';
+            setToMultipleID("currentScript", "innerHTML", "Custom");
+            setToMultipleID("safemodeToggle", "addClass", "checked");
+
+            setToMultipleID('safemodeToggle', 'innerHTML', 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
         }
 
         jsEditor.onKeyUp(function (evt) {
@@ -45,15 +70,15 @@
         var zipCode;
         BABYLON.Engine.ShadersRepository = "/src/Shaders/";
 
-        var currentVersionElement = document.getElementById("currentVersion");
+        var currentVersionElement = document.getElementById("currentVersion1600");
 
         if (currentVersionElement) {
             switch (BABYLON.Engine.Version) {
                 case "2.5":
-                    currentVersionElement.innerHTML = "Version: " + BABYLON.Engine.Version;
+                    setToMultipleID("currentVersion", "innerHTML", "Version: " + BABYLON.Engine.Version);
                     break;
                 default:
-                    currentVersionElement.innerHTML = "Version: Latest";
+                    setToMultipleID("currentVersion", "innerHTML", "Version: Latest");
                     break;
             }
         }
@@ -73,7 +98,7 @@
                         blockEditorChange = false;
                         compileAndRun();
 
-                        document.getElementById("currentScript").innerHTML = title;
+                        setToMultipleID("currentScript", "innerHTML", title);
 
                         currentSnippetToken = null;
                     }
@@ -105,20 +130,25 @@
                 if (xhr.readyState === 4) {
                     if (xhr.status === 200) {
                         scripts = xhr.responseText.split("\n");
-                        var ul = document.getElementById("scriptsList");
-                        var index;
-                        for (index = 0; index < scripts.length; index++) {
-                            var option = document.createElement("li");
-                            var a = document.createElement("a");
-                            a.href = "#";
-                            a.innerHTML = (index + 1) + " - " + scripts[index];
-                            a.scriptLinkIndex = index + 1;
-                            a.onclick = onScriptClick;
-                            option.scriptLinkIndex = index + 1;
-                            option.onclick = onScriptClick;
-
-                            option.appendChild(a);
-                            ul.appendChild(option);
+
+                        for (var i = 0; i < multipleSize.length; i++) {
+                            var ul = document.getElementById("scriptsList" + multipleSize[i]);
+
+                            var index;
+                            for (index = 0; index < scripts.length; index++) {
+                                var option = document.createElement("li");
+                                var a = document.createElement("a");
+                                a.href = "#";
+                                a.innerHTML = (index + 1) + " - " + scripts[index];
+                                a.scriptLinkIndex = index + 1;
+                                a.onclick = onScriptClick;
+                                option.scriptLinkIndex = index + 1;
+                                option.onclick = onScriptClick;
+
+                                option.appendChild(a);
+
+                                ul.appendChild(option);
+                            }
                         }
 
                         if (!location.hash) {
@@ -152,8 +182,6 @@
                         }
                         var mq = window.matchMedia("(max-width: 850px)");
                         mq.addListener(removeEditorForSmallScreen);
-
-
                     }
                 }
             };
@@ -237,7 +265,6 @@
             document.getElementById("saveFormButtons").style.display = "block";
             document.getElementById("saveFormButtonOk").style.display = "inline-block";
             document.getElementById("saveMessage").style.display = "block";
-            // document.getElementById("metadataButton").style.display = "none";
         };
         showNoMetadata();
         document.getElementById("saveMessage").style.display = "none";
@@ -248,7 +275,7 @@
             document.getElementById("saveFormTags").readOnly = true;
             document.getElementById("saveFormButtonOk").style.display = "none";
             document.getElementById("saveMessage").style.display = "none";
-            document.getElementById("metadataButton").style.display = "inline-block";
+            setToMultipleID("metadataButton", "display", "inline-block");
         };
 
         compileAndRun = function () {
@@ -432,7 +459,7 @@
             var name = textures[index].name;
             // var name = url.substr(url.lastIndexOf("/") + 1);
 
-            if(url != null) {
+            if (url != null) {
                 addContentToZip(folder,
                     name,
                     url,
@@ -529,10 +556,26 @@
         setFontSize = function (size) {
             fontSize = size;
             document.querySelector(".view-lines").style.fontSize = size + "px";
-            document.getElementById("currentFontSize").innerHTML = "Font: " + size;
+            setToMultipleID("currentFontSize", "innerHTML", "Font: " + size);
         };
 
         // Fullscreen
+        document.getElementById("renderCanvas").addEventListener("webkitfullscreenchange", function () {
+            if(document.webkitIsFullScreen) goFullPage();
+            else exitFullPage();
+        }, false);
+
+        var goFullPage = function () {
+            var canvasElement = document.getElementById("renderCanvas");
+            canvasElement.style.position = "absolute";
+            canvasElement.style.top = 0;
+            canvasElement.style.left = 0;
+            canvasElement.style.zIndex = 100;
+        }
+        var exitFullPage = function () {
+            document.getElementById("renderCanvas").style.position = "relative";
+            document.getElementById("renderCanvas").style.zIndex = 0;
+        }
         var goFullscreen = function () {
             if (engine) {
                 engine.switchFullscreen(true);
@@ -540,18 +583,18 @@
         }
 
         var toggleEditor = function () {
-            var editorButton = document.getElementById("editorButton");
+            var editorButton = document.getElementById("editorButton1600");
             var scene = engine.scenes[0];
 
             // If the editor is present
             if (editorButton.classList.contains('checked')) {
-                editorButton.classList.remove('checked');
+                setToMultipleID("editorButton", "removeClass", 'checked');
                 splitInstance.collapse(0);
-                editorButton.innerHTML = 'Editor <i class="fa fa-square-o" aria-hidden="true"></i>';
+                setToMultipleID("editorButton", "innerHTML", 'Editor <i class="fa fa-square-o" aria-hidden="true"></i>');
             } else {
-                editorButton.classList.add('checked');
+                setToMultipleID("editorButton", "addClass", 'checked');
                 splitInstance.setSizes([50, 50]);  // Reset
-                editorButton.innerHTML = 'Editor <i class="fa fa-check-square" aria-hidden="true"></i>';
+                setToMultipleID("editorButton", "innerHTML", 'Editor <i class="fa fa-check-square" aria-hidden="true"></i>');
             }
             engine.resize();
 
@@ -611,22 +654,22 @@
         }
 
         var toggleDebug = function () {
-            var debugButton = document.getElementById("debugButton");
+            var debugButton = document.getElementById("debugButton1600");
             var scene = engine.scenes[0];
 
             if (debugButton.classList.contains('uncheck')) {
-                debugButton.classList.remove('uncheck');
+                setToMultipleID("debugButton", "removeClass", 'uncheck');
+                setToMultipleID("debugButton", "innerHTML", 'Debug layer<i class="fa fa-check-square" aria-hidden="true"></i>');
                 scene.debugLayer.show();
             } else {
-                debugButton.classList.add('uncheck');
+                setToMultipleID("debugButton", "addClass", 'uncheck');
+                setToMultipleID("debugButton", "innerHTML", 'Debug layer<i class="fa fa-square-o" aria-hidden="true"></i>');
                 scene.debugLayer.hide();
             }
         }
 
         var toggleMetadata = function () {
-            // var metadataButton = document.getElementById("metadataButton");
             var scene = engine.scenes[0];
-            // metadataButton.classList.add('checked');
             document.getElementById("saveLayer").style.display = "block";
         }
 
@@ -634,26 +677,10 @@
             jsEditor.getAction('editor.action.format').run();
         }
 
-        // UI
-        document.getElementById("runButton").addEventListener("click", compileAndRun);
-        document.getElementById("zipButton").addEventListener("click", getZip);
-        document.getElementById("fullscreenButton").addEventListener("click", goFullscreen);
-        document.getElementById("newButton").addEventListener("click", createNewScript);
-        document.getElementById("clearButton").addEventListener("click", clear);
-        document.getElementById("editorButton").addEventListener("click", toggleEditor);
-        document.getElementById("debugButton").addEventListener("click", toggleDebug);
-        document.getElementById("metadataButton").addEventListener("click", toggleMetadata);
-        document.getElementById("darkTheme").addEventListener("click", toggleTheme.bind(this, 'dark'));
-        document.getElementById("lightTheme").addEventListener("click", toggleTheme.bind(this, 'light'));
-        document.getElementById("formatButton").addEventListener("click", formatCode);
-
-        // Restore theme
-        var theme = localStorage.getItem("bjs-playground-theme") || 'light';
-        toggleTheme(theme);
 
         //Navigation Overwrites
         var exitPrompt = function (e) {
-            var safeToggle = document.getElementById("safemodeToggle");
+            var safeToggle = document.getElementById("safemodeToggle1600");
             if (safeToggle.classList.contains('checked')) {
                 e = e || window.event;
                 var message =
@@ -713,7 +740,7 @@
             xmlHttp.send(JSON.stringify(dataToSend));
         }
 
-        document.getElementById("saveButton").addEventListener("click", function () {
+        var askForSave = function () {
             if (currentSnippetTitle == null
                 || currentSnippetDescription == null
                 || currentSnippetTags == null) {
@@ -723,7 +750,7 @@
             else {
                 save();
             }
-        });
+        };
         document.getElementById("saveFormButtonOk").addEventListener("click", function () {
             document.getElementById("saveLayer").style.display = "none";
             save();
@@ -799,7 +826,7 @@
                                     blockEditorChange = false;
                                     compileAndRun();
 
-                                    document.getElementById("currentScript").innerHTML = "Custom";
+                                    setToMultipleID("currentScript", "innerHTML", "Custom");
                                 } else if (firstTime) {
                                     location.href = location.href.replace(location.hash, "");
                                     if (scripts) {
@@ -825,6 +852,47 @@
         }
 
         checkHash(true);
+
+
+        // ---------- UI
+
+        // Run
+        setToMultipleID("runButton", "click", compileAndRun);
+        // New
+        setToMultipleID("newButton", "click", createNewScript);
+        // Clear 
+        setToMultipleID("clearButton", "click", clear);
+        // Save
+        setToMultipleID("saveButton", "click", askForSave);
+        // Zip
+        setToMultipleID("zipButton", "click", getZip);
+        // Themes
+        setToMultipleID("darkTheme", "click", toggleTheme.bind(this, 'dark'));
+        setToMultipleID("lightTheme", "click", toggleTheme.bind(this, 'light'));
+        // Safe mode
+        setToMultipleID("safemodeToggle", 'click', function () {
+            document.getElementById("safemodeToggle1600").classList.toggle('checked');
+            if (document.getElementById("safemodeToggle1600").classList.contains('checked')) {
+                setToMultipleID("safemodeToggle", "innerHTML", 'Safe mode <i class="fa fa-check-square" aria-hidden="true"></i>');
+            } else {
+                setToMultipleID("safemodeToggle", "innerHTML", 'Safe mode <i class="fa fa-square-o" aria-hidden="true"></i>');
+            }
+        });
+        // Editor
+        setToMultipleID("editorButton", "click", toggleEditor);
+        // FullScreen
+        setToMultipleID("fullscreenButton", "click", goFullscreen);
+        // Format
+        setToMultipleID("formatButton", "click", formatCode);
+        // Debug
+        setToMultipleID("debugButton", "click", toggleDebug);
+        // Metadata
+        setToMultipleID("metadataButton", "click", toggleMetadata);
+
+
+        // Restore theme
+        var theme = localStorage.getItem("bjs-playground-theme") || 'light';
+        toggleTheme(theme);
     }
 
     // Monaco

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1123 - 1119
dist/preview release/babylon.d.ts


Dosya farkı çok büyük olduğundan ihmal edildi
+ 24 - 24
dist/preview release/babylon.js


+ 64 - 22
dist/preview release/babylon.max.js

@@ -17551,24 +17551,25 @@ var BABYLON;
             }
             // Camera
             if (!this.activeCamera) {
-                // Compute position
                 var worldExtends = this.getWorldExtends();
-                var worldCenter = worldExtends.min.add(worldExtends.max.subtract(worldExtends.min).scale(0.5));
+                var worldSize = worldExtends.max.subtract(worldExtends.min);
+                var worldCenter = worldExtends.min.add(worldSize.scale(0.5));
                 var camera;
+                var radius = worldSize.length() * 1.5;
                 if (createArcRotateCamera) {
-                    camera = new BABYLON.ArcRotateCamera("default camera", 0, 0, 10, BABYLON.Vector3.Zero(), this);
-                    camera.setPosition(new BABYLON.Vector3(worldCenter.x, worldCenter.y, worldExtends.min.z - (worldExtends.max.z - worldExtends.min.z)));
-                    camera.lowerRadiusLimit = 0.5;
-                    camera.setTarget(worldCenter);
+                    var arcRotateCamera = new BABYLON.ArcRotateCamera("default camera", 4.712, 1.571, radius, worldCenter, this);
+                    arcRotateCamera.lowerRadiusLimit = radius * 0.01;
+                    arcRotateCamera.wheelPrecision = 100 / radius;
+                    camera = arcRotateCamera;
                 }
                 else {
-                    camera = new BABYLON.FreeCamera("default camera", BABYLON.Vector3.Zero(), this);
-                    camera.position = new BABYLON.Vector3(worldCenter.x, worldCenter.y, worldExtends.min.z - (worldExtends.max.z - worldExtends.min.z));
-                    camera.setTarget(worldCenter);
+                    var freeCamera = new BABYLON.FreeCamera("default camera", new BABYLON.Vector3(worldCenter.x, worldCenter.y, this.useRightHandedSystem ? -radius : radius), this);
+                    freeCamera.setTarget(worldCenter);
+                    camera = freeCamera;
                 }
-                camera.minZ = 0.1;
-                var maxDist = worldExtends.max.subtract(worldExtends.min).length();
-                camera.wheelPrecision = 100.0 / maxDist;
+                camera.minZ = radius * 0.01;
+                camera.maxZ = radius * 100;
+                camera.speed = radius * 0.2;
                 this.activeCamera = camera;
             }
         };
@@ -30559,22 +30560,22 @@ var BABYLON;
             }
             // Inertia
             if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < BABYLON.Epsilon) {
+                if (Math.abs(this.cameraDirection.x) < this.speed * BABYLON.Epsilon) {
                     this.cameraDirection.x = 0;
                 }
-                if (Math.abs(this.cameraDirection.y) < BABYLON.Epsilon) {
+                if (Math.abs(this.cameraDirection.y) < this.speed * BABYLON.Epsilon) {
                     this.cameraDirection.y = 0;
                 }
-                if (Math.abs(this.cameraDirection.z) < BABYLON.Epsilon) {
+                if (Math.abs(this.cameraDirection.z) < this.speed * BABYLON.Epsilon) {
                     this.cameraDirection.z = 0;
                 }
                 this.cameraDirection.scaleInPlace(this.inertia);
             }
             if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < BABYLON.Epsilon) {
+                if (Math.abs(this.cameraRotation.x) < this.speed * BABYLON.Epsilon) {
                     this.cameraRotation.x = 0;
                 }
-                if (Math.abs(this.cameraRotation.y) < BABYLON.Epsilon) {
+                if (Math.abs(this.cameraRotation.y) < this.speed * BABYLON.Epsilon) {
                     this.cameraRotation.y = 0;
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);
@@ -31582,11 +31583,11 @@ var BABYLON;
                 this.inertialAlphaOffset *= this.inertia;
                 this.inertialBetaOffset *= this.inertia;
                 this.inertialRadiusOffset *= this.inertia;
-                if (Math.abs(this.inertialAlphaOffset) < BABYLON.Epsilon)
+                if (Math.abs(this.inertialAlphaOffset) < this.speed * BABYLON.Epsilon)
                     this.inertialAlphaOffset = 0;
-                if (Math.abs(this.inertialBetaOffset) < BABYLON.Epsilon)
+                if (Math.abs(this.inertialBetaOffset) < this.speed * BABYLON.Epsilon)
                     this.inertialBetaOffset = 0;
-                if (Math.abs(this.inertialRadiusOffset) < BABYLON.Epsilon)
+                if (Math.abs(this.inertialRadiusOffset) < this.speed * BABYLON.Epsilon)
                     this.inertialRadiusOffset = 0;
             }
             // Panning inertia
@@ -31597,9 +31598,9 @@ var BABYLON;
                 }
                 this.inertialPanningX *= this.inertia;
                 this.inertialPanningY *= this.inertia;
-                if (Math.abs(this.inertialPanningX) < BABYLON.Epsilon)
+                if (Math.abs(this.inertialPanningX) < this.speed * BABYLON.Epsilon)
                     this.inertialPanningX = 0;
-                if (Math.abs(this.inertialPanningY) < BABYLON.Epsilon)
+                if (Math.abs(this.inertialPanningY) < this.speed * BABYLON.Epsilon)
                     this.inertialPanningY = 0;
                 this._localDirection.copyFromFloats(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
                 this._localDirection.multiplyInPlace(this.panningAxis);
@@ -49437,6 +49438,47 @@ var BABYLON;
         Bone.prototype.getAbsoluteTransform = function () {
             return this._absoluteTransform;
         };
+        Object.defineProperty(Bone.prototype, "position", {
+            // Properties (matches AbstractMesh properties)
+            get: function () {
+                return this.getPosition();
+            },
+            set: function (newPosition) {
+                this.setPosition(newPosition);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Bone.prototype, "rotation", {
+            get: function () {
+                return this.getRotation();
+            },
+            set: function (newRotation) {
+                this.setRotation(newRotation);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Bone.prototype, "rotationQuaternion", {
+            get: function () {
+                return this.getRotationQuaternion();
+            },
+            set: function (newRotation) {
+                this.setRotationQuaternion(newRotation);
+            },
+            enumerable: true,
+            configurable: true
+        });
+        Object.defineProperty(Bone.prototype, "scaling", {
+            get: function () {
+                return this.getScale();
+            },
+            set: function (newScaling) {
+                this.setScale(newScaling.x, newScaling.y, newScaling.z);
+            },
+            enumerable: true,
+            configurable: true
+        });
         // Methods
         Bone.prototype.updateMatrix = function (matrix, updateDifferenceMatrix) {
             if (updateDifferenceMatrix === void 0) { updateDifferenceMatrix = true; }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1123 - 1119
dist/preview release/babylon.module.d.ts


Dosya farkı çok büyük olduğundan ihmal edildi
+ 24 - 24
dist/preview release/babylon.worker.js


+ 1 - 0
dist/preview release/gui/babylon.gui.d.ts

@@ -243,6 +243,7 @@ declare module BABYLON.GUI {
     class Button extends Rectangle {
         name: string;
         constructor(name: string);
+        _processPicking(x: number, y: number, type: number): boolean;
         static CreateImageButton(name: string, text: string, imageUrl: string): Button;
     }
 }

+ 10 - 1
dist/preview release/gui/babylon.gui.js

@@ -687,7 +687,8 @@ var BABYLON;
                 if (!this._contains(x, y)) {
                     return false;
                 }
-                return this._processObservables(type);
+                this._processObservables(type);
+                return true;
             };
             Control.prototype._processObservables = function (type) {
                 if (type === BABYLON.PointerEventTypes.POINTERMOVE && this.onPointerMoveObservable.hasObservers()) {
@@ -1330,6 +1331,14 @@ var BABYLON;
                 _this.name = name;
                 return _this;
             }
+            // While being a container, the button behaves like a control.
+            Button.prototype._processPicking = function (x, y, type) {
+                if (!this._contains(x, y)) {
+                    return false;
+                }
+                this._processObservables(type);
+                return true;
+            };
             // Statics
             Button.CreateImageButton = function (name, text, imageUrl) {
                 var result = new Button(name);

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/gui/babylon.gui.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 247 - 247
dist/preview release/inspector/babylon.inspector.bundle.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/inspector/babylon.inspector.min.js


Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 2
dist/preview release/loaders/babylon.glTF1FileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.d.ts

@@ -347,7 +347,7 @@ declare module BABYLON.GLTF2 {
          * @param runtime: the GLTF runtime
          * @param accessor: the GLTF accessor
          */
-        static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): any;
+        static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): ArrayBufferView;
         /**
          * Decodes a buffer view into a string
          * @param view: the buffer view

+ 167 - 235
dist/preview release/loaders/babylon.glTF2FileLoader.js

@@ -284,203 +284,146 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF2;
     (function (GLTF2) {
-        /**
-        * Values
-        */
-        var glTFAnimationPaths = ["translation", "rotation", "scale", "weights"];
-        var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling", "influence"];
-        /**
-        * Utils
-        */
-        var normalizeUVs = function (buffer) {
-            if (!buffer) {
-                return;
-            }
-            for (var i = 0; i < buffer.length / 2; i++) {
-                buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
-            }
-        };
-        var createStringId = function (index) {
+        var getNodeID = function (index) {
             return "node" + index;
         };
-        /**
-        * Returns the animation path (glTF -> Babylon)
-        */
-        var getAnimationPath = function (path) {
-            var index = glTFAnimationPaths.indexOf(path);
-            if (index !== -1) {
-                return babylonAnimationPaths[index];
+        var loadAnimation = function (runtime, animation, animationIndex) {
+            for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
+                var channel = animation.channels[channelIndex];
+                if (!channel) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + "] Channel " + channelIndex + " does not exist");
+                    continue;
+                }
+                var samplerIndex = channel.sampler;
+                if (samplerIndex === undefined) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + samplerIndex + "] Sampler is not defined");
+                    continue;
+                }
+                var sampler = animation.samplers[samplerIndex];
+                if (!sampler) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler " + samplerIndex + " does not exist");
+                    continue;
+                }
+                if (!channel.target) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target does not exist");
+                    continue;
+                }
+                var targetNode = runtime.babylonScene.getNodeByID(getNodeID(channel.target.node));
+                if (!targetNode) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target node " + channel.target.node + " does not exist");
+                    continue;
+                }
+                var targetPath = {
+                    "translation": "position",
+                    "rotation": "rotationQuaternion",
+                    "scale": "scaling",
+                    "weights": "influence"
+                }[channel.target.path];
+                if (!targetPath) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target path " + channel.target.path + " is invalid");
+                    continue;
+                }
+                var inputBuffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.input]);
+                var outputBuffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.output]);
+                var outputBufferOffset = 0;
+                var animationType = {
+                    "position": BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
+                    "rotationQuaternion": BABYLON.Animation.ANIMATIONTYPE_QUATERNION,
+                    "scale": BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
+                    "influence": BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                }[targetPath];
+                var getNextOutputValue = {
+                    "position": function () {
+                        var value = BABYLON.Vector3.FromArray(outputBuffer, outputBufferOffset);
+                        outputBufferOffset += 3;
+                        return value;
+                    },
+                    "rotationQuaternion": function () {
+                        var value = BABYLON.Quaternion.FromArray(outputBuffer, outputBufferOffset);
+                        outputBufferOffset += 4;
+                        return value;
+                    },
+                    "scale": function () {
+                        var value = BABYLON.Vector3.FromArray(outputBuffer, outputBufferOffset);
+                        outputBufferOffset += 3;
+                        return value;
+                    },
+                    "influence": function () {
+                        var numTargets = targetNode.morphTargetManager.numTargets;
+                        var value = new Array(numTargets);
+                        for (var i = 0; i < numTargets; i++) {
+                            value[i] = outputBuffer[outputBufferOffset++];
+                        }
+                        return value;
+                    },
+                }[targetPath];
+                var getNextKey = {
+                    "LINEAR": function (frameIndex) { return ({
+                        frame: inputBuffer[frameIndex],
+                        value: getNextOutputValue()
+                    }); },
+                    "CUBICSPLINE": function (frameIndex) { return ({
+                        frame: inputBuffer[frameIndex],
+                        inTangent: getNextOutputValue(),
+                        value: getNextOutputValue(),
+                        outTangent: getNextOutputValue()
+                    }); },
+                }[sampler.interpolation];
+                if (!getNextKey) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler interpolation '" + sampler.interpolation + "' is invalid");
+                    continue;
+                }
+                var keys = new Array(inputBuffer.length);
+                for (var frameIndex = 0; frameIndex < inputBuffer.length; frameIndex++) {
+                    keys[frameIndex] = getNextKey(frameIndex);
+                }
+                if (targetPath === "influence") {
+                    var targetMesh = targetNode;
+                    for (var targetIndex = 0; targetIndex < targetMesh.morphTargetManager.numTargets; targetIndex++) {
+                        var morphTarget = targetMesh.morphTargetManager.getTarget(targetIndex);
+                        var animationName = (animation.name || "anim" + animationIndex) + "_" + targetIndex;
+                        var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
+                        babylonAnimation.setKeys(keys.map(function (key) { return ({
+                            frame: key.frame,
+                            inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
+                            value: key.value[targetIndex],
+                            outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
+                        }); }));
+                        morphTarget.animations.push(babylonAnimation);
+                        runtime.babylonScene.beginAnimation(morphTarget, 0, inputBuffer[inputBuffer.length - 1], true);
+                    }
+                }
+                else {
+                    var animationName = animation.name || "anim" + animationIndex;
+                    var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
+                    babylonAnimation.setKeys(keys);
+                    targetNode.animations.push(babylonAnimation);
+                    runtime.babylonScene.beginAnimation(targetNode, 0, inputBuffer[inputBuffer.length - 1], true);
+                }
             }
-            return path;
         };
         /**
         * Loads and creates animations
         */
         var loadAnimations = function (runtime) {
             var animations = runtime.gltf.animations;
-            if (!animations) {
+            if (!animations || animations.length === 0) {
                 return;
             }
             for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
                 var animation = animations[animationIndex];
-                if (!animation || !animation.channels || !animation.samplers) {
+                if (!animation) {
+                    BABYLON.Tools.Warn("Animation " + animationIndex + " not found");
                     continue;
                 }
-                var lastAnimation = null;
-                for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
-                    var channel = animation.channels[channelIndex];
-                    if (!channel) {
-                        continue;
-                    }
-                    var sampler = animation.samplers[channel.sampler];
-                    if (!sampler) {
-                        continue;
-                    }
-                    var inputData = sampler.input;
-                    var outputData = sampler.output;
-                    var bufferInput = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[inputData]);
-                    var bufferOutput = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[outputData]);
-                    var targetID = channel.target.node;
-                    var targetNode = runtime.babylonScene.getNodeByID(createStringId(targetID));
-                    if (targetNode === null) {
-                        BABYLON.Tools.Warn("Creating animation index " + animationIndex + " but cannot find node index " + targetID + " to attach to");
-                        continue;
-                    }
-                    var isBone = targetNode instanceof BABYLON.Bone;
-                    var numTargets = 0;
-                    // Get target path (position, rotation, scaling, or weights)
-                    var targetPath = channel.target.path;
-                    var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
-                    if (targetPathIndex !== -1) {
-                        targetPath = babylonAnimationPaths[targetPathIndex];
-                    }
-                    var isMorph = targetPath === "influence";
-                    // Determine animation type
-                    var animationType = BABYLON.Animation.ANIMATIONTYPE_MATRIX;
-                    if (!isBone) {
-                        if (targetPath === "rotationQuaternion") {
-                            animationType = BABYLON.Animation.ANIMATIONTYPE_QUATERNION;
-                            targetNode.rotationQuaternion = new BABYLON.Quaternion();
-                        }
-                        else if (isMorph) {
-                            animationType = BABYLON.Animation.ANIMATIONTYPE_FLOAT;
-                            numTargets = targetNode.morphTargetManager.numTargets;
-                        }
-                        else {
-                            animationType = BABYLON.Animation.ANIMATIONTYPE_VECTOR3;
-                        }
-                    }
-                    // Create animation and key frames
-                    var babylonAnimation = null;
-                    var keys = [];
-                    var arrayOffset = 0;
-                    var modifyKey = false;
-                    if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
-                        babylonAnimation = lastAnimation;
-                        modifyKey = true;
-                    }
-                    // Each morph animation may have more than one more, so we need a
-                    // multi dimensional array.
-                    if (isMorph) {
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            keys[influence] = [];
-                        }
-                    }
-                    // For each frame
-                    for (var frameIndex = 0; frameIndex < bufferInput.length; frameIndex++) {
-                        var value = null;
-                        if (targetPath === "rotationQuaternion") {
-                            value = BABYLON.Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
-                            arrayOffset += 4;
-                        }
-                        else if (isMorph) {
-                            value = [];
-                            // There is 1 value for each morph target for each frame
-                            for (var influence = 0; influence < numTargets; influence++) {
-                                value.push(bufferOutput[arrayOffset + influence]);
-                            }
-                            arrayOffset += numTargets;
-                        }
-                        else {
-                            value = BABYLON.Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
-                            arrayOffset += 3;
-                        }
-                        if (isBone) {
-                            var bone = targetNode;
-                            var translation = BABYLON.Vector3.Zero();
-                            var rotationQuaternion = new BABYLON.Quaternion();
-                            var scaling = BABYLON.Vector3.Zero();
-                            // Warning on decompose
-                            var mat = bone.getBaseMatrix();
-                            if (modifyKey) {
-                                mat = lastAnimation.getKeys()[frameIndex].value;
-                            }
-                            mat.decompose(scaling, rotationQuaternion, translation);
-                            if (targetPath === "position") {
-                                translation = value;
-                            }
-                            else if (targetPath === "rotationQuaternion") {
-                                rotationQuaternion = value;
-                            }
-                            else {
-                                scaling = value;
-                            }
-                            value = BABYLON.Matrix.Compose(scaling, rotationQuaternion, translation);
-                        }
-                        if (!modifyKey) {
-                            if (isMorph) {
-                                for (var influence = 0; influence < numTargets; influence++) {
-                                    keys[influence].push({
-                                        frame: bufferInput[frameIndex],
-                                        value: value[influence]
-                                    });
-                                }
-                            }
-                            else {
-                                keys.push({
-                                    frame: bufferInput[frameIndex],
-                                    value: value
-                                });
-                            }
-                        }
-                        else {
-                            lastAnimation.getKeys()[frameIndex].value = value;
-                        }
-                    }
-                    // Finish
-                    if (!modifyKey) {
-                        if (isMorph) {
-                            for (var influence = 0; influence < numTargets; influence++) {
-                                var morphTarget = targetNode.morphTargetManager.getTarget(influence);
-                                if (morphTarget.animations === undefined) {
-                                    morphTarget.animations = [];
-                                }
-                                var animationName = (animation.name || "anim" + animationIndex) + "_" + influence;
-                                babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
-                                babylonAnimation.setKeys(keys[influence]);
-                                morphTarget.animations.push(babylonAnimation);
-                            }
-                        }
-                        else {
-                            var animationName = animation.name || "anim" + animationIndex;
-                            babylonAnimation = new BABYLON.Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
-                            babylonAnimation.setKeys(keys);
-                            targetNode.animations.push(babylonAnimation);
-                        }
-                    }
-                    lastAnimation = babylonAnimation;
-                    if (isMorph) {
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            var morph = targetNode.morphTargetManager.getTarget(influence);
-                            runtime.babylonScene.stopAnimation(morph);
-                            runtime.babylonScene.beginAnimation(morph, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                        }
-                    }
-                    else {
-                        runtime.babylonScene.stopAnimation(targetNode);
-                        runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                    }
+                if (!animation.channels || animation.channels.length === 0) {
+                    BABYLON.Tools.Warn("Animation " + animationIndex + " has no channels");
                 }
+                if (!animation.samplers || animation.samplers.length === 0) {
+                    BABYLON.Tools.Warn("Animation " + animationIndex + " has no samplers");
+                    continue;
+                }
+                loadAnimation(runtime, animation, animationIndex);
             }
         };
         /**
@@ -504,7 +447,7 @@ var BABYLON;
         */
         var getParentBone = function (runtime, skin, index, newSkeleton) {
             // Try to find
-            var nodeStringID = createStringId(index);
+            var nodeStringID = getNodeID(index);
             for (var i = 0; i < newSkeleton.bones.length; i++) {
                 if (newSkeleton.bones[i].id === nodeStringID) {
                     return newSkeleton.bones[i].getParent();
@@ -524,8 +467,8 @@ var BABYLON;
                     }
                     if (childID === index) {
                         var mat = configureBoneTransformation(parent);
-                        var bone = new BABYLON.Bone(parent.name || createStringId(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
-                        bone.id = createStringId(parentID);
+                        var bone = new BABYLON.Bone(parent.name || getNodeID(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
+                        bone.id = getNodeID(parentID);
                         return bone;
                     }
                 }
@@ -585,8 +528,8 @@ var BABYLON;
                 }
                 // Create node to root bone
                 var mat = configureBoneTransformation(node);
-                var bone = new BABYLON.Bone(node.name || createStringId(i), newSkeleton, null, mat);
-                bone.id = createStringId(i);
+                var bone = new BABYLON.Bone(node.name || getNodeID(i), newSkeleton, null, mat);
+                bone.id = getNodeID(i);
                 nodesToRoot.push({ bone: bone, node: node, index: i });
             }
             // Parenting
@@ -639,7 +582,7 @@ var BABYLON;
                     continue;
                 }
                 var index = jointNode.index;
-                var stringID = createStringId(index);
+                var stringID = getNodeID(index);
                 // Optimize, if the bone already exists...
                 var existingBone = runtime.babylonScene.getBoneByID(stringID);
                 if (existingBone) {
@@ -689,7 +632,7 @@ var BABYLON;
                 if (!jointNode) {
                     continue;
                 }
-                var jointNodeStringId = createStringId(jointNode.index);
+                var jointNodeStringId = getNodeID(jointNode.index);
                 for (var j = 0; j < bones.length; j++) {
                     if (bones[j].id === jointNodeStringId) {
                         babylonSkeleton.bones.push(bones[j]);
@@ -744,7 +687,7 @@ var BABYLON;
             var verticesCounts = [];
             var indexStarts = [];
             var indexCounts = [];
-            var morphTargetManager = new BABYLON.MorphTargetManager();
+            var morphTargetManager;
             // Positions, normals and UVs
             for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
                 // Temporary vertex data
@@ -762,37 +705,28 @@ var BABYLON;
                     accessor = runtime.gltf.accessors[attributes[semantic]];
                     buffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
                     if (semantic === "NORMAL") {
-                        tempVertexData.normals = new Float32Array(buffer.length);
-                        tempVertexData.normals.set(buffer);
+                        tempVertexData.normals = buffer;
                     }
                     else if (semantic === "POSITION") {
-                        tempVertexData.positions = new Float32Array(buffer.length);
-                        tempVertexData.positions.set(buffer);
+                        tempVertexData.positions = buffer;
                         verticesCounts.push(tempVertexData.positions.length);
                     }
                     else if (semantic === "TANGENT") {
-                        tempVertexData.tangents = new Float32Array(buffer.length);
-                        tempVertexData.tangents.set(buffer);
+                        tempVertexData.tangents = buffer;
                     }
                     else if (semantic.indexOf("TEXCOORD_") !== -1) {
                         var channel = Number(semantic.split("_")[1]);
                         var uvKind = BABYLON.VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
-                        var uvs = new Float32Array(buffer.length);
-                        uvs.set(buffer);
-                        normalizeUVs(uvs);
-                        tempVertexData.set(uvs, uvKind);
+                        tempVertexData.set(buffer, uvKind);
                     }
                     else if (semantic === "JOINT") {
-                        tempVertexData.matricesIndices = new Float32Array(buffer.length);
-                        tempVertexData.matricesIndices.set(buffer);
+                        tempVertexData.matricesIndices = buffer;
                     }
                     else if (semantic === "WEIGHT") {
-                        tempVertexData.matricesWeights = new Float32Array(buffer.length);
-                        tempVertexData.matricesWeights.set(buffer);
+                        tempVertexData.matricesWeights = buffer;
                     }
                     else if (semantic === "COLOR_0") {
-                        tempVertexData.colors = new Float32Array(buffer.length);
-                        tempVertexData.colors.set(buffer);
+                        tempVertexData.colors = buffer;
                     }
                     else {
                         BABYLON.Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
@@ -802,17 +736,15 @@ var BABYLON;
                 accessor = runtime.gltf.accessors[primitive.indices];
                 if (accessor) {
                     buffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
-                    tempVertexData.indices = new Int32Array(buffer.length);
-                    tempVertexData.indices.set(buffer);
+                    tempVertexData.indices = buffer;
                     indexCounts.push(tempVertexData.indices.length);
                 }
                 else {
                     // Set indices on the fly
-                    var indices = [];
-                    for (var index = 0; index < tempVertexData.positions.length / 3; index++) {
-                        indices.push(index);
+                    tempVertexData.indices = new Uint32Array(tempVertexData.positions.length / 3);
+                    for (var index = 0; index < tempVertexData.indices.length; index++) {
+                        tempVertexData.indices[index] = index;
                     }
-                    tempVertexData.indices = new Int32Array(indices);
                     indexCounts.push(tempVertexData.indices.length);
                 }
                 vertexData.merge(tempVertexData);
@@ -821,22 +753,22 @@ var BABYLON;
                 var material = getMaterial(runtime, primitive.material);
                 multiMat.subMaterials.push(material);
                 // Morph Targets
-                if (primitive.targets !== undefined) {
+                if (primitive.targets) {
                     for (var targetsIndex = 0; targetsIndex < primitive.targets.length; targetsIndex++) {
                         var target = primitive.targets[targetsIndex];
                         var weight = 0.0;
-                        if (node.weights !== undefined) {
+                        if (node.weights) {
                             weight = node.weights[targetsIndex];
                         }
-                        else if (mesh.weights !== undefined) {
+                        else if (mesh.weights) {
                             weight = mesh.weights[targetsIndex];
                         }
                         var morph = new BABYLON.MorphTarget("morph" + targetsIndex, weight);
                         for (var semantic in target) {
                             // Link accessor and buffer view
                             accessor = runtime.gltf.accessors[target[semantic]];
-                            buffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
-                            if (accessor.name !== undefined) {
+                            var values = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
+                            if (accessor.name) {
                                 morph.name = accessor.name;
                             }
                             // glTF stores morph target information as deltas
@@ -844,34 +776,38 @@ var BABYLON;
                             // As a result we have to add the original data to the delta to calculate
                             // the final data.
                             if (semantic === "NORMAL") {
-                                for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                    buffer[bufferIndex] += vertexData.normals[bufferIndex];
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.normals[i];
                                 }
-                                morph.setNormals(buffer);
+                                morph.setNormals(values);
                             }
                             else if (semantic === "POSITION") {
-                                for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                    buffer[bufferIndex] += vertexData.positions[bufferIndex];
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.positions[i];
                                 }
-                                morph.setPositions(buffer);
+                                morph.setPositions(values);
                             }
                             else if (semantic === "TANGENT") {
                                 // Tangent data for morph targets is stored as xyz delta.
                                 // The vertexData.tangent is stored as xyzw.
                                 // So we need to skip every fourth vertexData.tangent.
-                                for (var bufferIndex = 0, tangentsIndex = 0; bufferIndex < buffer.length; bufferIndex++, tangentsIndex++) {
-                                    buffer[bufferIndex] += vertexData.tangents[tangentsIndex];
-                                    if ((bufferIndex + 1) % 3 == 0) {
-                                        tangentsIndex++;
+                                for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                    values[i] += vertexData.tangents[j];
+                                    if ((i + 1) % 3 == 0) {
+                                        j++;
                                     }
                                 }
-                                morph.setTangents(buffer);
+                                morph.setTangents(values);
                             }
                             else {
                                 BABYLON.Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
                             }
                         }
-                        if (morph.getPositions() !== undefined) {
+                        if (morph.getPositions()) {
+                            if (!morphTargetManager) {
+                                morphTargetManager = new BABYLON.MorphTargetManager();
+                                babylonMesh.morphTargetManager = morphTargetManager;
+                            }
                             morphTargetManager.addTarget(morph);
                         }
                         else {
@@ -886,10 +822,6 @@ var BABYLON;
             // Apply geometry
             geometry.setAllVerticesData(vertexData, false);
             babylonMesh.computeWorldMatrix(true);
-            // Set morph target manager after all vertices data has been processed
-            if (morphTargetManager !== undefined && morphTargetManager.numTargets > 0) {
-                babylonMesh.morphTargetManager = morphTargetManager;
-            }
             // Apply submeshes
             babylonMesh.subMeshes = [];
             for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
@@ -1017,7 +949,7 @@ var BABYLON;
             if (meshIncluded) {
                 newNode = importNode(runtime, node);
                 if (newNode !== null) {
-                    newNode.id = createStringId(index);
+                    newNode.id = getNodeID(index);
                     newNode.parent = parent;
                 }
             }
@@ -1288,7 +1220,7 @@ var BABYLON;
                 var sampler = (texture.sampler === undefined ? {} : runtime.gltf.samplers[texture.sampler]);
                 var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = GLTF2.GLTFUtils.GetTextureFilterMode(sampler.minFilter);
-                var babylonTexture = new BABYLON.Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(url, runtime.babylonScene, noMipMaps, false, samplingMode, function () {
                     onSuccess(babylonTexture);
                 }, onError);
                 babylonTexture.coordinatesIndex = texCoord;
@@ -1405,7 +1337,7 @@ var BABYLON;
             };
             GLTFLoader._loadMaterialsAsync = function (runtime, onSuccess, onError) {
                 var materials = runtime.gltf.materials;
-                if (!materials) {
+                if (!materials || materials.length === 0) {
                     onSuccess();
                     return;
                 }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 1 - 1
dist/preview release/loaders/babylon.glTF2FileLoader.min.js


+ 1 - 1
dist/preview release/loaders/babylon.glTFFileLoader.d.ts

@@ -842,7 +842,7 @@ declare module BABYLON.GLTF2 {
          * @param runtime: the GLTF runtime
          * @param accessor: the GLTF accessor
          */
-        static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): any;
+        static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): ArrayBufferView;
         /**
          * Decodes a buffer view into a string
          * @param view: the buffer view

+ 167 - 235
dist/preview release/loaders/babylon.glTFFileLoader.js

@@ -2434,203 +2434,146 @@ var BABYLON;
 (function (BABYLON) {
     var GLTF2;
     (function (GLTF2) {
-        /**
-        * Values
-        */
-        var glTFAnimationPaths = ["translation", "rotation", "scale", "weights"];
-        var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling", "influence"];
-        /**
-        * Utils
-        */
-        var normalizeUVs = function (buffer) {
-            if (!buffer) {
-                return;
-            }
-            for (var i = 0; i < buffer.length / 2; i++) {
-                buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
-            }
-        };
-        var createStringId = function (index) {
+        var getNodeID = function (index) {
             return "node" + index;
         };
-        /**
-        * Returns the animation path (glTF -> Babylon)
-        */
-        var getAnimationPath = function (path) {
-            var index = glTFAnimationPaths.indexOf(path);
-            if (index !== -1) {
-                return babylonAnimationPaths[index];
+        var loadAnimation = function (runtime, animation, animationIndex) {
+            for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
+                var channel = animation.channels[channelIndex];
+                if (!channel) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + "] Channel " + channelIndex + " does not exist");
+                    continue;
+                }
+                var samplerIndex = channel.sampler;
+                if (samplerIndex === undefined) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + samplerIndex + "] Sampler is not defined");
+                    continue;
+                }
+                var sampler = animation.samplers[samplerIndex];
+                if (!sampler) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler " + samplerIndex + " does not exist");
+                    continue;
+                }
+                if (!channel.target) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target does not exist");
+                    continue;
+                }
+                var targetNode = runtime.babylonScene.getNodeByID(getNodeID(channel.target.node));
+                if (!targetNode) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target node " + channel.target.node + " does not exist");
+                    continue;
+                }
+                var targetPath = {
+                    "translation": "position",
+                    "rotation": "rotationQuaternion",
+                    "scale": "scaling",
+                    "weights": "influence"
+                }[channel.target.path];
+                if (!targetPath) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target path " + channel.target.path + " is invalid");
+                    continue;
+                }
+                var inputBuffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.input]);
+                var outputBuffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.output]);
+                var outputBufferOffset = 0;
+                var animationType = {
+                    "position": BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
+                    "rotationQuaternion": BABYLON.Animation.ANIMATIONTYPE_QUATERNION,
+                    "scale": BABYLON.Animation.ANIMATIONTYPE_VECTOR3,
+                    "influence": BABYLON.Animation.ANIMATIONTYPE_FLOAT,
+                }[targetPath];
+                var getNextOutputValue = {
+                    "position": function () {
+                        var value = BABYLON.Vector3.FromArray(outputBuffer, outputBufferOffset);
+                        outputBufferOffset += 3;
+                        return value;
+                    },
+                    "rotationQuaternion": function () {
+                        var value = BABYLON.Quaternion.FromArray(outputBuffer, outputBufferOffset);
+                        outputBufferOffset += 4;
+                        return value;
+                    },
+                    "scale": function () {
+                        var value = BABYLON.Vector3.FromArray(outputBuffer, outputBufferOffset);
+                        outputBufferOffset += 3;
+                        return value;
+                    },
+                    "influence": function () {
+                        var numTargets = targetNode.morphTargetManager.numTargets;
+                        var value = new Array(numTargets);
+                        for (var i = 0; i < numTargets; i++) {
+                            value[i] = outputBuffer[outputBufferOffset++];
+                        }
+                        return value;
+                    },
+                }[targetPath];
+                var getNextKey = {
+                    "LINEAR": function (frameIndex) { return ({
+                        frame: inputBuffer[frameIndex],
+                        value: getNextOutputValue()
+                    }); },
+                    "CUBICSPLINE": function (frameIndex) { return ({
+                        frame: inputBuffer[frameIndex],
+                        inTangent: getNextOutputValue(),
+                        value: getNextOutputValue(),
+                        outTangent: getNextOutputValue()
+                    }); },
+                }[sampler.interpolation];
+                if (!getNextKey) {
+                    BABYLON.Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler interpolation '" + sampler.interpolation + "' is invalid");
+                    continue;
+                }
+                var keys = new Array(inputBuffer.length);
+                for (var frameIndex = 0; frameIndex < inputBuffer.length; frameIndex++) {
+                    keys[frameIndex] = getNextKey(frameIndex);
+                }
+                if (targetPath === "influence") {
+                    var targetMesh = targetNode;
+                    for (var targetIndex = 0; targetIndex < targetMesh.morphTargetManager.numTargets; targetIndex++) {
+                        var morphTarget = targetMesh.morphTargetManager.getTarget(targetIndex);
+                        var animationName = (animation.name || "anim" + animationIndex) + "_" + targetIndex;
+                        var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
+                        babylonAnimation.setKeys(keys.map(function (key) { return ({
+                            frame: key.frame,
+                            inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
+                            value: key.value[targetIndex],
+                            outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
+                        }); }));
+                        morphTarget.animations.push(babylonAnimation);
+                        runtime.babylonScene.beginAnimation(morphTarget, 0, inputBuffer[inputBuffer.length - 1], true);
+                    }
+                }
+                else {
+                    var animationName = animation.name || "anim" + animationIndex;
+                    var babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType);
+                    babylonAnimation.setKeys(keys);
+                    targetNode.animations.push(babylonAnimation);
+                    runtime.babylonScene.beginAnimation(targetNode, 0, inputBuffer[inputBuffer.length - 1], true);
+                }
             }
-            return path;
         };
         /**
         * Loads and creates animations
         */
         var loadAnimations = function (runtime) {
             var animations = runtime.gltf.animations;
-            if (!animations) {
+            if (!animations || animations.length === 0) {
                 return;
             }
             for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
                 var animation = animations[animationIndex];
-                if (!animation || !animation.channels || !animation.samplers) {
+                if (!animation) {
+                    BABYLON.Tools.Warn("Animation " + animationIndex + " not found");
                     continue;
                 }
-                var lastAnimation = null;
-                for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
-                    var channel = animation.channels[channelIndex];
-                    if (!channel) {
-                        continue;
-                    }
-                    var sampler = animation.samplers[channel.sampler];
-                    if (!sampler) {
-                        continue;
-                    }
-                    var inputData = sampler.input;
-                    var outputData = sampler.output;
-                    var bufferInput = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[inputData]);
-                    var bufferOutput = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[outputData]);
-                    var targetID = channel.target.node;
-                    var targetNode = runtime.babylonScene.getNodeByID(createStringId(targetID));
-                    if (targetNode === null) {
-                        BABYLON.Tools.Warn("Creating animation index " + animationIndex + " but cannot find node index " + targetID + " to attach to");
-                        continue;
-                    }
-                    var isBone = targetNode instanceof BABYLON.Bone;
-                    var numTargets = 0;
-                    // Get target path (position, rotation, scaling, or weights)
-                    var targetPath = channel.target.path;
-                    var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
-                    if (targetPathIndex !== -1) {
-                        targetPath = babylonAnimationPaths[targetPathIndex];
-                    }
-                    var isMorph = targetPath === "influence";
-                    // Determine animation type
-                    var animationType = BABYLON.Animation.ANIMATIONTYPE_MATRIX;
-                    if (!isBone) {
-                        if (targetPath === "rotationQuaternion") {
-                            animationType = BABYLON.Animation.ANIMATIONTYPE_QUATERNION;
-                            targetNode.rotationQuaternion = new BABYLON.Quaternion();
-                        }
-                        else if (isMorph) {
-                            animationType = BABYLON.Animation.ANIMATIONTYPE_FLOAT;
-                            numTargets = targetNode.morphTargetManager.numTargets;
-                        }
-                        else {
-                            animationType = BABYLON.Animation.ANIMATIONTYPE_VECTOR3;
-                        }
-                    }
-                    // Create animation and key frames
-                    var babylonAnimation = null;
-                    var keys = [];
-                    var arrayOffset = 0;
-                    var modifyKey = false;
-                    if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
-                        babylonAnimation = lastAnimation;
-                        modifyKey = true;
-                    }
-                    // Each morph animation may have more than one more, so we need a
-                    // multi dimensional array.
-                    if (isMorph) {
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            keys[influence] = [];
-                        }
-                    }
-                    // For each frame
-                    for (var frameIndex = 0; frameIndex < bufferInput.length; frameIndex++) {
-                        var value = null;
-                        if (targetPath === "rotationQuaternion") {
-                            value = BABYLON.Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
-                            arrayOffset += 4;
-                        }
-                        else if (isMorph) {
-                            value = [];
-                            // There is 1 value for each morph target for each frame
-                            for (var influence = 0; influence < numTargets; influence++) {
-                                value.push(bufferOutput[arrayOffset + influence]);
-                            }
-                            arrayOffset += numTargets;
-                        }
-                        else {
-                            value = BABYLON.Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
-                            arrayOffset += 3;
-                        }
-                        if (isBone) {
-                            var bone = targetNode;
-                            var translation = BABYLON.Vector3.Zero();
-                            var rotationQuaternion = new BABYLON.Quaternion();
-                            var scaling = BABYLON.Vector3.Zero();
-                            // Warning on decompose
-                            var mat = bone.getBaseMatrix();
-                            if (modifyKey) {
-                                mat = lastAnimation.getKeys()[frameIndex].value;
-                            }
-                            mat.decompose(scaling, rotationQuaternion, translation);
-                            if (targetPath === "position") {
-                                translation = value;
-                            }
-                            else if (targetPath === "rotationQuaternion") {
-                                rotationQuaternion = value;
-                            }
-                            else {
-                                scaling = value;
-                            }
-                            value = BABYLON.Matrix.Compose(scaling, rotationQuaternion, translation);
-                        }
-                        if (!modifyKey) {
-                            if (isMorph) {
-                                for (var influence = 0; influence < numTargets; influence++) {
-                                    keys[influence].push({
-                                        frame: bufferInput[frameIndex],
-                                        value: value[influence]
-                                    });
-                                }
-                            }
-                            else {
-                                keys.push({
-                                    frame: bufferInput[frameIndex],
-                                    value: value
-                                });
-                            }
-                        }
-                        else {
-                            lastAnimation.getKeys()[frameIndex].value = value;
-                        }
-                    }
-                    // Finish
-                    if (!modifyKey) {
-                        if (isMorph) {
-                            for (var influence = 0; influence < numTargets; influence++) {
-                                var morphTarget = targetNode.morphTargetManager.getTarget(influence);
-                                if (morphTarget.animations === undefined) {
-                                    morphTarget.animations = [];
-                                }
-                                var animationName = (animation.name || "anim" + animationIndex) + "_" + influence;
-                                babylonAnimation = new BABYLON.Animation(animationName, targetPath, 1, animationType, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
-                                babylonAnimation.setKeys(keys[influence]);
-                                morphTarget.animations.push(babylonAnimation);
-                            }
-                        }
-                        else {
-                            var animationName = animation.name || "anim" + animationIndex;
-                            babylonAnimation = new BABYLON.Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, BABYLON.Animation.ANIMATIONLOOPMODE_CYCLE);
-                            babylonAnimation.setKeys(keys);
-                            targetNode.animations.push(babylonAnimation);
-                        }
-                    }
-                    lastAnimation = babylonAnimation;
-                    if (isMorph) {
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            var morph = targetNode.morphTargetManager.getTarget(influence);
-                            runtime.babylonScene.stopAnimation(morph);
-                            runtime.babylonScene.beginAnimation(morph, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                        }
-                    }
-                    else {
-                        runtime.babylonScene.stopAnimation(targetNode);
-                        runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                    }
+                if (!animation.channels || animation.channels.length === 0) {
+                    BABYLON.Tools.Warn("Animation " + animationIndex + " has no channels");
                 }
+                if (!animation.samplers || animation.samplers.length === 0) {
+                    BABYLON.Tools.Warn("Animation " + animationIndex + " has no samplers");
+                    continue;
+                }
+                loadAnimation(runtime, animation, animationIndex);
             }
         };
         /**
@@ -2654,7 +2597,7 @@ var BABYLON;
         */
         var getParentBone = function (runtime, skin, index, newSkeleton) {
             // Try to find
-            var nodeStringID = createStringId(index);
+            var nodeStringID = getNodeID(index);
             for (var i = 0; i < newSkeleton.bones.length; i++) {
                 if (newSkeleton.bones[i].id === nodeStringID) {
                     return newSkeleton.bones[i].getParent();
@@ -2674,8 +2617,8 @@ var BABYLON;
                     }
                     if (childID === index) {
                         var mat = configureBoneTransformation(parent);
-                        var bone = new BABYLON.Bone(parent.name || createStringId(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
-                        bone.id = createStringId(parentID);
+                        var bone = new BABYLON.Bone(parent.name || getNodeID(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
+                        bone.id = getNodeID(parentID);
                         return bone;
                     }
                 }
@@ -2735,8 +2678,8 @@ var BABYLON;
                 }
                 // Create node to root bone
                 var mat = configureBoneTransformation(node);
-                var bone = new BABYLON.Bone(node.name || createStringId(i), newSkeleton, null, mat);
-                bone.id = createStringId(i);
+                var bone = new BABYLON.Bone(node.name || getNodeID(i), newSkeleton, null, mat);
+                bone.id = getNodeID(i);
                 nodesToRoot.push({ bone: bone, node: node, index: i });
             }
             // Parenting
@@ -2789,7 +2732,7 @@ var BABYLON;
                     continue;
                 }
                 var index = jointNode.index;
-                var stringID = createStringId(index);
+                var stringID = getNodeID(index);
                 // Optimize, if the bone already exists...
                 var existingBone = runtime.babylonScene.getBoneByID(stringID);
                 if (existingBone) {
@@ -2839,7 +2782,7 @@ var BABYLON;
                 if (!jointNode) {
                     continue;
                 }
-                var jointNodeStringId = createStringId(jointNode.index);
+                var jointNodeStringId = getNodeID(jointNode.index);
                 for (var j = 0; j < bones.length; j++) {
                     if (bones[j].id === jointNodeStringId) {
                         babylonSkeleton.bones.push(bones[j]);
@@ -2894,7 +2837,7 @@ var BABYLON;
             var verticesCounts = [];
             var indexStarts = [];
             var indexCounts = [];
-            var morphTargetManager = new BABYLON.MorphTargetManager();
+            var morphTargetManager;
             // Positions, normals and UVs
             for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
                 // Temporary vertex data
@@ -2912,37 +2855,28 @@ var BABYLON;
                     accessor = runtime.gltf.accessors[attributes[semantic]];
                     buffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
                     if (semantic === "NORMAL") {
-                        tempVertexData.normals = new Float32Array(buffer.length);
-                        tempVertexData.normals.set(buffer);
+                        tempVertexData.normals = buffer;
                     }
                     else if (semantic === "POSITION") {
-                        tempVertexData.positions = new Float32Array(buffer.length);
-                        tempVertexData.positions.set(buffer);
+                        tempVertexData.positions = buffer;
                         verticesCounts.push(tempVertexData.positions.length);
                     }
                     else if (semantic === "TANGENT") {
-                        tempVertexData.tangents = new Float32Array(buffer.length);
-                        tempVertexData.tangents.set(buffer);
+                        tempVertexData.tangents = buffer;
                     }
                     else if (semantic.indexOf("TEXCOORD_") !== -1) {
                         var channel = Number(semantic.split("_")[1]);
                         var uvKind = BABYLON.VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
-                        var uvs = new Float32Array(buffer.length);
-                        uvs.set(buffer);
-                        normalizeUVs(uvs);
-                        tempVertexData.set(uvs, uvKind);
+                        tempVertexData.set(buffer, uvKind);
                     }
                     else if (semantic === "JOINT") {
-                        tempVertexData.matricesIndices = new Float32Array(buffer.length);
-                        tempVertexData.matricesIndices.set(buffer);
+                        tempVertexData.matricesIndices = buffer;
                     }
                     else if (semantic === "WEIGHT") {
-                        tempVertexData.matricesWeights = new Float32Array(buffer.length);
-                        tempVertexData.matricesWeights.set(buffer);
+                        tempVertexData.matricesWeights = buffer;
                     }
                     else if (semantic === "COLOR_0") {
-                        tempVertexData.colors = new Float32Array(buffer.length);
-                        tempVertexData.colors.set(buffer);
+                        tempVertexData.colors = buffer;
                     }
                     else {
                         BABYLON.Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
@@ -2952,17 +2886,15 @@ var BABYLON;
                 accessor = runtime.gltf.accessors[primitive.indices];
                 if (accessor) {
                     buffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
-                    tempVertexData.indices = new Int32Array(buffer.length);
-                    tempVertexData.indices.set(buffer);
+                    tempVertexData.indices = buffer;
                     indexCounts.push(tempVertexData.indices.length);
                 }
                 else {
                     // Set indices on the fly
-                    var indices = [];
-                    for (var index = 0; index < tempVertexData.positions.length / 3; index++) {
-                        indices.push(index);
+                    tempVertexData.indices = new Uint32Array(tempVertexData.positions.length / 3);
+                    for (var index = 0; index < tempVertexData.indices.length; index++) {
+                        tempVertexData.indices[index] = index;
                     }
-                    tempVertexData.indices = new Int32Array(indices);
                     indexCounts.push(tempVertexData.indices.length);
                 }
                 vertexData.merge(tempVertexData);
@@ -2971,22 +2903,22 @@ var BABYLON;
                 var material = getMaterial(runtime, primitive.material);
                 multiMat.subMaterials.push(material);
                 // Morph Targets
-                if (primitive.targets !== undefined) {
+                if (primitive.targets) {
                     for (var targetsIndex = 0; targetsIndex < primitive.targets.length; targetsIndex++) {
                         var target = primitive.targets[targetsIndex];
                         var weight = 0.0;
-                        if (node.weights !== undefined) {
+                        if (node.weights) {
                             weight = node.weights[targetsIndex];
                         }
-                        else if (mesh.weights !== undefined) {
+                        else if (mesh.weights) {
                             weight = mesh.weights[targetsIndex];
                         }
                         var morph = new BABYLON.MorphTarget("morph" + targetsIndex, weight);
                         for (var semantic in target) {
                             // Link accessor and buffer view
                             accessor = runtime.gltf.accessors[target[semantic]];
-                            buffer = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
-                            if (accessor.name !== undefined) {
+                            var values = GLTF2.GLTFUtils.GetBufferFromAccessor(runtime, accessor);
+                            if (accessor.name) {
                                 morph.name = accessor.name;
                             }
                             // glTF stores morph target information as deltas
@@ -2994,34 +2926,38 @@ var BABYLON;
                             // As a result we have to add the original data to the delta to calculate
                             // the final data.
                             if (semantic === "NORMAL") {
-                                for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                    buffer[bufferIndex] += vertexData.normals[bufferIndex];
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.normals[i];
                                 }
-                                morph.setNormals(buffer);
+                                morph.setNormals(values);
                             }
                             else if (semantic === "POSITION") {
-                                for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                    buffer[bufferIndex] += vertexData.positions[bufferIndex];
+                                for (var i = 0; i < values.length; i++) {
+                                    values[i] += vertexData.positions[i];
                                 }
-                                morph.setPositions(buffer);
+                                morph.setPositions(values);
                             }
                             else if (semantic === "TANGENT") {
                                 // Tangent data for morph targets is stored as xyz delta.
                                 // The vertexData.tangent is stored as xyzw.
                                 // So we need to skip every fourth vertexData.tangent.
-                                for (var bufferIndex = 0, tangentsIndex = 0; bufferIndex < buffer.length; bufferIndex++, tangentsIndex++) {
-                                    buffer[bufferIndex] += vertexData.tangents[tangentsIndex];
-                                    if ((bufferIndex + 1) % 3 == 0) {
-                                        tangentsIndex++;
+                                for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                    values[i] += vertexData.tangents[j];
+                                    if ((i + 1) % 3 == 0) {
+                                        j++;
                                     }
                                 }
-                                morph.setTangents(buffer);
+                                morph.setTangents(values);
                             }
                             else {
                                 BABYLON.Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
                             }
                         }
-                        if (morph.getPositions() !== undefined) {
+                        if (morph.getPositions()) {
+                            if (!morphTargetManager) {
+                                morphTargetManager = new BABYLON.MorphTargetManager();
+                                babylonMesh.morphTargetManager = morphTargetManager;
+                            }
                             morphTargetManager.addTarget(morph);
                         }
                         else {
@@ -3036,10 +2972,6 @@ var BABYLON;
             // Apply geometry
             geometry.setAllVerticesData(vertexData, false);
             babylonMesh.computeWorldMatrix(true);
-            // Set morph target manager after all vertices data has been processed
-            if (morphTargetManager !== undefined && morphTargetManager.numTargets > 0) {
-                babylonMesh.morphTargetManager = morphTargetManager;
-            }
             // Apply submeshes
             babylonMesh.subMeshes = [];
             for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
@@ -3167,7 +3099,7 @@ var BABYLON;
             if (meshIncluded) {
                 newNode = importNode(runtime, node);
                 if (newNode !== null) {
-                    newNode.id = createStringId(index);
+                    newNode.id = getNodeID(index);
                     newNode.parent = parent;
                 }
             }
@@ -3438,7 +3370,7 @@ var BABYLON;
                 var sampler = (texture.sampler === undefined ? {} : runtime.gltf.samplers[texture.sampler]);
                 var noMipMaps = (sampler.minFilter === GLTF2.ETextureMinFilter.NEAREST || sampler.minFilter === GLTF2.ETextureMinFilter.LINEAR);
                 var samplingMode = GLTF2.GLTFUtils.GetTextureFilterMode(sampler.minFilter);
-                var babylonTexture = new BABYLON.Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, function () {
+                var babylonTexture = new BABYLON.Texture(url, runtime.babylonScene, noMipMaps, false, samplingMode, function () {
                     onSuccess(babylonTexture);
                 }, onError);
                 babylonTexture.coordinatesIndex = texCoord;
@@ -3555,7 +3487,7 @@ var BABYLON;
             };
             GLTFLoader._loadMaterialsAsync = function (runtime, onSuccess, onError) {
                 var materials = runtime.gltf.materials;
-                if (!materials) {
+                if (!materials || materials.length === 0) {
                     onSuccess();
                     return;
                 }

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 2
dist/preview release/loaders/babylon.glTFFileLoader.min.js


+ 183 - 270
loaders/src/glTF/2.0/babylon.glTFLoader.ts

@@ -1,242 +1,167 @@
 /// <reference path="../../../../dist/preview release/babylon.d.ts"/>
 
 module BABYLON.GLTF2 {
-    /**
-    * Values
-    */
-    var glTFAnimationPaths = ["translation", "rotation", "scale", "weights"];
-    var babylonAnimationPaths = ["position", "rotationQuaternion", "scaling", "influence"];
-
-    /**
-    * Utils
-    */
-    var normalizeUVs = (buffer: any): void => {
-        if (!buffer) {
-            return;
-        }
-
-        for (var i = 0; i < buffer.length / 2; i++) {
-            buffer[i * 2 + 1] = 1.0 - buffer[i * 2 + 1];
-        }
-    };
-
-    var createStringId = (index: number): string => {
+    var getNodeID = (index: number): string => {
         return "node" + index;
     };
 
-    /**
-    * Returns the animation path (glTF -> Babylon)
-    */
-    var getAnimationPath = (path: string): string => {
-        var index = glTFAnimationPaths.indexOf(path);
-
-        if (index !== -1) {
-            return babylonAnimationPaths[index];
-        }
-
-        return path;
-    };
-
-    /**
-    * Loads and creates animations
-    */
-    var loadAnimations = (runtime: IGLTFRuntime): void => {
-        var animations = runtime.gltf.animations;
-        if (!animations) {
-            return;
-        }
-
-        for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
-            var animation = animations[animationIndex];
-            if (!animation || !animation.channels || !animation.samplers) {
+    var loadAnimation = (runtime: IGLTFRuntime, animation: IGLTFAnimation, animationIndex: number): void => {
+        for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
+            var channel = animation.channels[channelIndex];
+            if (!channel) {
+                Tools.Warn("[Animation " + animationIndex + "] Channel " + channelIndex + " does not exist");
                 continue;
             }
 
-            var lastAnimation: Animation = null;
-
-            for (var channelIndex = 0; channelIndex < animation.channels.length; channelIndex++) {
-                var channel = animation.channels[channelIndex];
-                if (!channel) {
-                    continue;
-                }
-
-                var sampler = animation.samplers[channel.sampler];
-                if (!sampler) {
-                    continue;
-                }
-
-                var inputData = sampler.input;
-                var outputData = sampler.output;
-
-                var bufferInput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[inputData]);
-                var bufferOutput = GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[outputData]);
-
-                var targetID = channel.target.node;
-                var targetNode: any = runtime.babylonScene.getNodeByID(createStringId(targetID));
-
-                if (targetNode === null) {
-                    Tools.Warn("Creating animation index " + animationIndex + " but cannot find node index " + targetID + " to attach to");
-                    continue;
-                }
-
-                var isBone = targetNode instanceof Bone;
-                var numTargets = 0;
-
-                // Get target path (position, rotation, scaling, or weights)
-                var targetPath = channel.target.path;
-                var targetPathIndex = glTFAnimationPaths.indexOf(targetPath);
-
-                if (targetPathIndex !== -1) {
-                    targetPath = babylonAnimationPaths[targetPathIndex];
-                }
-
-                var isMorph = targetPath === "influence";
+            var samplerIndex = channel.sampler;
+            if (samplerIndex === undefined) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + samplerIndex + "] Sampler is not defined");
+                continue;
+            }
 
-                // Determine animation type
-                var animationType = Animation.ANIMATIONTYPE_MATRIX;
+            var sampler = animation.samplers[samplerIndex];
+            if (!sampler) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler " + samplerIndex + " does not exist");
+                continue;
+            }
 
-                if (!isBone) {
-                    if (targetPath === "rotationQuaternion") {
-                        animationType = Animation.ANIMATIONTYPE_QUATERNION;
-                        targetNode.rotationQuaternion = new Quaternion();
-                    }
-                    else if (isMorph) {
-                        animationType = Animation.ANIMATIONTYPE_FLOAT;
-                        numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
-                    }
-                    else {
-                        animationType = Animation.ANIMATIONTYPE_VECTOR3;
-                    }
-                }
+            if (!channel.target) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target does not exist");
+                continue;
+            }
 
-                // Create animation and key frames
-                var babylonAnimation: Animation = null;
-                var keys = [];
-                var arrayOffset = 0;
-                var modifyKey = false;
+            var targetNode = runtime.babylonScene.getNodeByID(getNodeID(channel.target.node));
+            if (!targetNode) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target node " + channel.target.node + " does not exist");
+                continue;
+            }
 
-                if (isBone && lastAnimation && lastAnimation.getKeys().length === bufferInput.length) {
-                    babylonAnimation = lastAnimation;
-                    modifyKey = true;
-                }
+            var targetPath = {
+                "translation": "position",
+                "rotation": "rotationQuaternion",
+                "scale": "scaling",
+                "weights": "influence"
+            }[channel.target.path];
+            if (!targetPath) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Target path " + channel.target.path + " is invalid");
+                continue;
+            }
 
-                // Each morph animation may have more than one more, so we need a
-                // multi dimensional array.
-                if (isMorph) {
-                    for (var influence = 0; influence < numTargets; influence++) {
-                        keys[influence] = [];
-                    }
-                }
+            var inputBuffer = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.input]);
+            var outputBuffer = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, runtime.gltf.accessors[sampler.output]);
+            var outputBufferOffset = 0;
 
-                // For each frame
-                for (var frameIndex = 0; frameIndex < bufferInput.length; frameIndex++) {
-                    var value: any = null;
+            var animationType = {
+                "position": Animation.ANIMATIONTYPE_VECTOR3,
+                "rotationQuaternion": Animation.ANIMATIONTYPE_QUATERNION,
+                "scale": Animation.ANIMATIONTYPE_VECTOR3,
+                "influence": Animation.ANIMATIONTYPE_FLOAT,
+            }[targetPath];
 
-                    if (targetPath === "rotationQuaternion") { // VEC4
-                        value = Quaternion.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2], bufferOutput[arrayOffset + 3]]);
-                        arrayOffset += 4;
-                    }
-                    else if (isMorph) { // FLOAT
-                        value = [];
-                        // There is 1 value for each morph target for each frame
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            value.push(bufferOutput[arrayOffset + influence]);
-                        }
-                        arrayOffset += numTargets;
-                    }
-                    else { // Position and scaling are VEC3
-                        value = Vector3.FromArray([bufferOutput[arrayOffset], bufferOutput[arrayOffset + 1], bufferOutput[arrayOffset + 2]]);
-                        arrayOffset += 3;
+            var getNextOutputValue: () => any = {
+                "position": () => {
+                    var value = Vector3.FromArray(outputBuffer, outputBufferOffset);
+                    outputBufferOffset += 3;
+                    return value;
+                },
+                "rotationQuaternion": () => {
+                    var value = Quaternion.FromArray(outputBuffer, outputBufferOffset);
+                    outputBufferOffset += 4;
+                    return value;
+                },
+                "scale": () => {
+                    var value = Vector3.FromArray(outputBuffer, outputBufferOffset);
+                    outputBufferOffset += 3;
+                    return value;
+                },
+                "influence": () => {
+                    var numTargets = (<Mesh>targetNode).morphTargetManager.numTargets;
+                    var value = new Array(numTargets);
+                    for (var i = 0; i < numTargets; i++) {
+                        value[i] = outputBuffer[outputBufferOffset++];
                     }
+                    return value;
+                },
+            }[targetPath];
+
+            var getNextKey: (frameIndex) => any = {
+                "LINEAR": frameIndex => ({
+                    frame: inputBuffer[frameIndex],
+                    value: getNextOutputValue()
+                }),
+                "CUBICSPLINE": frameIndex => ({
+                    frame: inputBuffer[frameIndex],
+                    inTangent: getNextOutputValue(),
+                    value: getNextOutputValue(),
+                    outTangent: getNextOutputValue()
+                }),
+            }[sampler.interpolation];
+
+            if (!getNextKey) {
+                Tools.Warn("[Animation " + animationIndex + ", Channel + " + channelIndex + "] Sampler interpolation '" + sampler.interpolation + "' is invalid");
+                continue;
+            }
 
-                    if (isBone) {
-                        var bone = <Bone>targetNode;
-                        var translation = Vector3.Zero();
-                        var rotationQuaternion = new Quaternion();
-                        var scaling = Vector3.Zero();
-
-                        // Warning on decompose
-                        var mat = bone.getBaseMatrix();
+            var keys = new Array(inputBuffer.length);
+            for (var frameIndex = 0; frameIndex < inputBuffer.length; frameIndex++) {
+                keys[frameIndex] = getNextKey(frameIndex);
+            }
 
-                        if (modifyKey) {
-                            mat = lastAnimation.getKeys()[frameIndex].value;
-                        }
+            if (targetPath === "influence") {
+                var targetMesh = <Mesh>targetNode;
 
-                        mat.decompose(scaling, rotationQuaternion, translation);
+                for (var targetIndex = 0; targetIndex < targetMesh.morphTargetManager.numTargets; targetIndex++) {
+                    var morphTarget = targetMesh.morphTargetManager.getTarget(targetIndex);
+                    var animationName = (animation.name || "anim" + animationIndex) + "_" + targetIndex;
+                    var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
+                    babylonAnimation.setKeys(keys.map(key => ({
+                        frame: key.frame,
+                        inTangent: key.inTangent ? key.inTangent[targetIndex] : undefined,
+                        value: key.value[targetIndex],
+                        outTangent: key.outTangent ? key.outTangent[targetIndex] : undefined
+                    })));
 
-                        if (targetPath === "position") {
-                            translation = value;
-                        }
-                        else if (targetPath === "rotationQuaternion") {
-                            rotationQuaternion = value;
-                        }
-                        else {
-                            scaling = value;
-                        }
-
-                        value = Matrix.Compose(scaling, rotationQuaternion, translation);
-                    }
-
-                    if (!modifyKey) {
-                        if (isMorph) {
-                            for (var influence = 0; influence < numTargets; influence++) {
-                                keys[influence].push({
-                                    frame: bufferInput[frameIndex],
-                                    value: value[influence]
-                                });
-                            }
-                        }
-                        else {
-                            keys.push({
-                                frame: bufferInput[frameIndex],
-                                value: value
-                            });
-                        }
-                    }
-                    else {
-                        lastAnimation.getKeys()[frameIndex].value = value;
-                    }
+                    morphTarget.animations.push(babylonAnimation);
+                    runtime.babylonScene.beginAnimation(morphTarget, 0, inputBuffer[inputBuffer.length - 1], true);
                 }
+            }
+            else {
+                var animationName = animation.name || "anim" + animationIndex;
+                var babylonAnimation = new Animation(animationName, targetPath, 1, animationType);
+                babylonAnimation.setKeys(keys);
 
-                // Finish
-                if (!modifyKey) {
-                    if (isMorph) {
-                        for (var influence = 0; influence < numTargets; influence++) {
-                            var morphTarget = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
-                            if ((<any>morphTarget).animations === undefined) {
-                                (<any>morphTarget).animations = [];
-                            }
+                targetNode.animations.push(babylonAnimation);
+                runtime.babylonScene.beginAnimation(targetNode, 0, inputBuffer[inputBuffer.length - 1], true);
+            }
+        }
+    }
 
-                            var animationName = (animation.name || "anim" + animationIndex) + "_" + influence;
-                            babylonAnimation = new Animation(animationName, targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
+    /**
+    * Loads and creates animations
+    */
+    var loadAnimations = (runtime: IGLTFRuntime): void => {
+        var animations = runtime.gltf.animations;
+        if (!animations || animations.length === 0) {
+            return;
+        }
 
-                            babylonAnimation.setKeys(keys[influence]);
-                            (<any>morphTarget).animations.push(babylonAnimation);
-                        }
-                    }
-                    else {
-                        var animationName = animation.name || "anim" + animationIndex;
-                        babylonAnimation = new Animation(animationName, isBone ? "_matrix" : targetPath, 1, animationType, Animation.ANIMATIONLOOPMODE_CYCLE);
-                
-                        babylonAnimation.setKeys(keys);
-                        targetNode.animations.push(babylonAnimation);
-                    }
-                }
+        for (var animationIndex = 0; animationIndex < animations.length; animationIndex++) {
+            var animation = animations[animationIndex];
+            if (!animation) {
+                Tools.Warn("Animation " + animationIndex + " not found");
+                continue;
+            }
 
-                lastAnimation = babylonAnimation;
+            if (!animation.channels || animation.channels.length === 0) {
+                Tools.Warn("Animation " + animationIndex + " has no channels");
+            }
 
-                if (isMorph) {
-                    for (var influence = 0; influence < numTargets; influence++) {
-                        var morph = (<Mesh>targetNode).morphTargetManager.getTarget(influence);
-                        runtime.babylonScene.stopAnimation(morph);
-                        runtime.babylonScene.beginAnimation(morph, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                    }
-                }
-                else {
-                    runtime.babylonScene.stopAnimation(targetNode);
-                    runtime.babylonScene.beginAnimation(targetNode, 0, bufferInput[bufferInput.length - 1], true, 1.0);
-                }
+            if (!animation.samplers || animation.samplers.length === 0) {
+                Tools.Warn("Animation " + animationIndex + " has no samplers");
+                continue;
             }
+
+            loadAnimation(runtime, animation, animationIndex);
         }
     };
 
@@ -265,7 +190,7 @@ module BABYLON.GLTF2 {
     */
     var getParentBone = (runtime: IGLTFRuntime, skin: IGLTFSkin, index: number, newSkeleton: Skeleton): Bone => {
         // Try to find
-        var nodeStringID = createStringId(index);
+        var nodeStringID = getNodeID(index);
         for (var i = 0; i < newSkeleton.bones.length; i++) {
             if (newSkeleton.bones[i].id === nodeStringID) {
                 return newSkeleton.bones[i].getParent();
@@ -289,8 +214,8 @@ module BABYLON.GLTF2 {
                 if (childID === index)
                 {
                     var mat = configureBoneTransformation(parent);
-                    var bone = new Bone(parent.name || createStringId(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
-                    bone.id = createStringId(parentID);
+                    var bone = new Bone(parent.name || getNodeID(parentID), newSkeleton, getParentBone(runtime, skin, parentID, newSkeleton), mat);
+                    bone.id = getNodeID(parentID);
                     return bone;
                 }
             }
@@ -361,8 +286,8 @@ module BABYLON.GLTF2 {
 
             // Create node to root bone
             var mat = configureBoneTransformation(node);
-            var bone = new Bone(node.name || createStringId(i), newSkeleton, null, mat);
-            bone.id = createStringId(i);
+            var bone = new Bone(node.name || getNodeID(i), newSkeleton, null, mat);
+            bone.id = getNodeID(i);
             nodesToRoot.push({ bone: bone, node: node, index: i });
         }
 
@@ -428,7 +353,7 @@ module BABYLON.GLTF2 {
             }
 
             var index = jointNode.index;
-            var stringID = createStringId(index);
+            var stringID = getNodeID(index);
 
             // Optimize, if the bone already exists...
             var existingBone = runtime.babylonScene.getBoneByID(stringID);
@@ -493,7 +418,7 @@ module BABYLON.GLTF2 {
                 continue;
             }
 
-            var jointNodeStringId = createStringId(jointNode.index);
+            var jointNodeStringId = getNodeID(jointNode.index);
             for (var j = 0; j < bones.length; j++) {
                 if (bones[j].id === jointNodeStringId) {
                     babylonSkeleton.bones.push(bones[j]);
@@ -564,7 +489,7 @@ module BABYLON.GLTF2 {
         var indexStarts = [];
         var indexCounts = [];
 
-        var morphTargetManager = new BABYLON.MorphTargetManager();
+        var morphTargetManager: MorphTargetManager;
 
         // Positions, normals and UVs
         for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
@@ -578,7 +503,7 @@ module BABYLON.GLTF2 {
 
             var attributes = primitive.attributes;
             var accessor: IGLTFAccessor = null;
-            var buffer: any = null;
+            var buffer: ArrayBufferView = null;
 
             // Set positions, normal and uvs
             for (var semantic in attributes) {
@@ -588,37 +513,28 @@ module BABYLON.GLTF2 {
                 buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
 
                 if (semantic === "NORMAL") {
-                    tempVertexData.normals = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.normals).set(buffer);
+                    tempVertexData.normals = <Float32Array>buffer;
                 }
                 else if (semantic === "POSITION") {
-                    tempVertexData.positions = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.positions).set(buffer);
+                    tempVertexData.positions = <Float32Array>buffer;
                     verticesCounts.push(tempVertexData.positions.length);
                 }
                 else if (semantic === "TANGENT") {
-                    tempVertexData.tangents = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.tangents).set(buffer);
+                    tempVertexData.tangents = <Float32Array>buffer;
                 }
                 else if (semantic.indexOf("TEXCOORD_") !== -1) {
                     var channel = Number(semantic.split("_")[1]);
                     var uvKind = VertexBuffer.UVKind + (channel === 0 ? "" : (channel + 1));
-                    var uvs = new Float32Array(buffer.length);
-                    (<Float32Array>uvs).set(buffer);
-                    normalizeUVs(uvs);
-                    tempVertexData.set(uvs, uvKind);
+                    tempVertexData.set(<Float32Array>buffer, uvKind);
                 }
                 else if (semantic === "JOINT") {
-                    tempVertexData.matricesIndices = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.matricesIndices).set(buffer);
+                    tempVertexData.matricesIndices = <Float32Array>buffer;
                 }
                 else if (semantic === "WEIGHT") {
-                    tempVertexData.matricesWeights = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.matricesWeights).set(buffer);
+                    tempVertexData.matricesWeights = <Float32Array>buffer;
                 }
                 else if (semantic === "COLOR_0") {
-                    tempVertexData.colors = new Float32Array(buffer.length);
-                    (<Float32Array>tempVertexData.colors).set(buffer);
+                    tempVertexData.colors = <Float32Array>buffer;
                 }
                 else {
                     Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
@@ -629,19 +545,16 @@ module BABYLON.GLTF2 {
             accessor = runtime.gltf.accessors[primitive.indices];
             if (accessor) {
                 buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
-
-                tempVertexData.indices = new Int32Array(buffer.length);
-                (<Float32Array>tempVertexData.indices).set(buffer);
+                tempVertexData.indices = <Uint32Array>buffer;
                 indexCounts.push(tempVertexData.indices.length);
             }
             else {
                 // Set indices on the fly
-                var indices: number[] = [];
-                for (var index = 0; index < tempVertexData.positions.length / 3; index++) {
-                    indices.push(index);
+                tempVertexData.indices = new Uint32Array(tempVertexData.positions.length / 3);
+                for (var index = 0; index < tempVertexData.indices.length; index++) {
+                    tempVertexData.indices[index] = index;
                 }
 
-                tempVertexData.indices = new Int32Array(indices);
                 indexCounts.push(tempVertexData.indices.length);
             }
 
@@ -653,26 +566,26 @@ module BABYLON.GLTF2 {
             multiMat.subMaterials.push(material);
 
             // Morph Targets
-            if (primitive.targets !== undefined) {
+            if (primitive.targets) {
                 for (var targetsIndex = 0; targetsIndex < primitive.targets.length; targetsIndex++) {
                     var target = primitive.targets[targetsIndex];
 
                     var weight = 0.0;
-                    if (node.weights !== undefined) {
+                    if (node.weights) {
                         weight = node.weights[targetsIndex];
                     }
-                    else if (mesh.weights !== undefined) {
+                    else if (mesh.weights) {
                         weight = mesh.weights[targetsIndex];
                     }
 
-                    var morph = new BABYLON.MorphTarget("morph" + targetsIndex, weight);
+                    var morph = new MorphTarget("morph" + targetsIndex, weight);
 
                     for (var semantic in target) {
                         // Link accessor and buffer view
                         accessor = runtime.gltf.accessors[target[semantic]];
-                        buffer = GLTFUtils.GetBufferFromAccessor(runtime, accessor);
+                        var values = <Float32Array>GLTFUtils.GetBufferFromAccessor(runtime, accessor);
 
-                        if (accessor.name !== undefined) {
+                        if (accessor.name) {
                             morph.name = accessor.name;
                         }
 
@@ -681,35 +594,40 @@ module BABYLON.GLTF2 {
                         // As a result we have to add the original data to the delta to calculate
                         // the final data.
                         if (semantic === "NORMAL") {
-                            for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                buffer[bufferIndex] += (<Float32Array>vertexData.normals)[bufferIndex];
+                            for (var i = 0; i < values.length; i++) {
+                                values[i] += vertexData.normals[i];
                             }
-                            morph.setNormals(buffer);
+                            morph.setNormals(values);
                         }
                         else if (semantic === "POSITION") {
-                            for (var bufferIndex = 0; bufferIndex < buffer.length; bufferIndex++) {
-                                buffer[bufferIndex] += (<Float32Array>vertexData.positions)[bufferIndex];
+                            for (var i = 0; i < values.length; i++) {
+                                values[i] += vertexData.positions[i];
                             }
-                            morph.setPositions(buffer);
+                            morph.setPositions(values);
                         }
                         else if (semantic === "TANGENT") {
                             // Tangent data for morph targets is stored as xyz delta.
                             // The vertexData.tangent is stored as xyzw.
                             // So we need to skip every fourth vertexData.tangent.
-                            for (var bufferIndex = 0, tangentsIndex = 0; bufferIndex < buffer.length; bufferIndex++, tangentsIndex++) {
-                                buffer[bufferIndex] += (<Float32Array>vertexData.tangents)[tangentsIndex];
-                                if ((bufferIndex + 1) % 3 == 0) {
-                                    tangentsIndex++;
+                            for (var i = 0, j = 0; i < values.length; i++, j++) {
+                                values[i] += vertexData.tangents[j];
+                                if ((i + 1) % 3 == 0) {
+                                    j++;
                                 }
                             }
-                            morph.setTangents(buffer);
+                            morph.setTangents(values);
                         }
                         else {
                             Tools.Warn("Ignoring unrecognized semantic '" + semantic + "'");
                         }
                     }
-                    
-                    if (morph.getPositions() !== undefined) {
+
+                    if (morph.getPositions()) {
+                        if (!morphTargetManager) {
+                            morphTargetManager = new MorphTargetManager();
+                            babylonMesh.morphTargetManager = morphTargetManager;
+                        }
+
                         morphTargetManager.addTarget(morph);
                     }
                     else {
@@ -727,11 +645,6 @@ module BABYLON.GLTF2 {
         geometry.setAllVerticesData(vertexData, false);
         babylonMesh.computeWorldMatrix(true);
 
-        // Set morph target manager after all vertices data has been processed
-        if (morphTargetManager !== undefined && morphTargetManager.numTargets > 0) {
-            babylonMesh.morphTargetManager = morphTargetManager;
-        }
-
         // Apply submeshes
         babylonMesh.subMeshes = [];
         for (var primitiveIndex = 0; primitiveIndex < mesh.primitives.length; primitiveIndex++) {
@@ -889,7 +802,7 @@ module BABYLON.GLTF2 {
             newNode = importNode(runtime, node);
 
             if (newNode !== null) {
-                newNode.id = createStringId(index);
+                newNode.id = getNodeID(index);
                 newNode.parent = parent;
             }
         }
@@ -1214,7 +1127,7 @@ module BABYLON.GLTF2 {
             var noMipMaps = (sampler.minFilter === ETextureMinFilter.NEAREST || sampler.minFilter === ETextureMinFilter.LINEAR);
             var samplingMode = GLTFUtils.GetTextureFilterMode(sampler.minFilter);
 
-            var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, true, samplingMode, () => {
+            var babylonTexture = new Texture(url, runtime.babylonScene, noMipMaps, false, samplingMode, () => {
                 onSuccess(babylonTexture);
             }, onError);
 
@@ -1352,7 +1265,7 @@ module BABYLON.GLTF2 {
 
         private static _loadMaterialsAsync(runtime: IGLTFRuntime, onSuccess: () => void, onError: () => void): void {
             var materials = runtime.gltf.materials;
-            if (!materials) {
+            if (!materials || materials.length === 0) {
                 onSuccess();
                 return;
             }

+ 1 - 1
loaders/src/glTF/2.0/babylon.glTFLoaderUtils.ts

@@ -102,7 +102,7 @@ module BABYLON.GLTF2 {
          * @param runtime: the GLTF runtime
          * @param accessor: the GLTF accessor
          */
-        public static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): any {
+        public static GetBufferFromAccessor(runtime: IGLTFRuntime, accessor: IGLTFAccessor): ArrayBufferView {
             var bufferView = runtime.gltf.bufferViews[accessor.bufferView];
             var byteOffset = accessor.byteOffset || 0;
             var byteLength = accessor.count * GLTFUtils.GetByteStrideFromType(accessor);

+ 33 - 0
src/Bones/babylon.bone.ts

@@ -93,6 +93,39 @@ module BABYLON {
             return this._absoluteTransform;
         }
 
+        // Properties (matches AbstractMesh properties)
+        public get position(): Vector3 {
+            return this.getPosition();
+        }
+
+        public set position(newPosition: Vector3) {
+            this.setPosition(newPosition);
+        }
+
+        public get rotation(): Vector3 {
+            return this.getRotation();
+        }
+
+        public set rotation(newRotation: Vector3) {
+            this.setRotation(newRotation);
+        }
+
+        public get rotationQuaternion() {
+            return this.getRotationQuaternion();
+        }
+
+        public set rotationQuaternion(newRotation: Quaternion) {
+            this.setRotationQuaternion(newRotation);
+        }
+
+        public get scaling(): Vector3 {
+            return this.getScale();
+        }
+
+        public set scaling(newScaling: Vector3) {
+            this.setScale(newScaling.x, newScaling.y, newScaling.z);
+        }
+
         // Methods
         public updateMatrix(matrix: Matrix, updateDifferenceMatrix = true): void {
             this._baseMatrix = matrix.clone();

+ 24 - 25
src/Cameras/babylon.arcRotateCamera.ts

@@ -56,7 +56,7 @@ module BABYLON {
         @serialize()
         public inertialPanningY: number = 0;
 
-        //-- begin properties for backward compatibility for inputs       
+        //-- begin properties for backward compatibility for inputs
         public get angularSensibilityX() {
             var pointers = <ArcRotateCameraPointersInput>this.inputs.attached["pointers"];
             if (pointers)
@@ -168,8 +168,8 @@ module BABYLON {
             if (mousewheel)
                 mousewheel.wheelPrecision = value;
         }
-        
-        //-- end properties for backward compatibility for inputs        
+
+        //-- end properties for backward compatibility for inputs
 
         @serialize()
         public zoomOnFactor = 1;
@@ -185,7 +185,7 @@ module BABYLON {
         public inputs: ArcRotateCameraInputsManager;
 
         public _reset: () => void;
-        
+
         // Panning
         public panningAxis: Vector3 = new Vector3(1, 1, 0);
         private _localDirection: Vector3;
@@ -204,7 +204,7 @@ module BABYLON {
         private _previousRadius: number;
         //due to async collision inspection
         private _collisionTriggered: boolean;
-        
+
         private _targetBoundingCenter: Vector3;
 
         constructor(name: string, alpha: number, beta: number, radius: number, target: Vector3, scene: Scene) {
@@ -222,7 +222,7 @@ module BABYLON {
             this.getViewMatrix();
             this.inputs = new ArcRotateCameraInputsManager(this);
             this.inputs.addKeyboard().addMouseWheel().addPointers();
-        }      
+        }
 
         // Cache
         public _initCache(): void {
@@ -302,7 +302,7 @@ module BABYLON {
             this.inputs.checkInputs();
             // Inertia
             if (this.inertialAlphaOffset !== 0 || this.inertialBetaOffset !== 0 || this.inertialRadiusOffset !== 0) {
-                
+
                 if (this.getScene().useRightHandedSystem) {
                     this.alpha -= this.beta <= 0 ? -this.inertialAlphaOffset : this.inertialAlphaOffset;
                 } else {
@@ -315,11 +315,11 @@ module BABYLON {
                 this.inertialAlphaOffset *= this.inertia;
                 this.inertialBetaOffset *= this.inertia;
                 this.inertialRadiusOffset *= this.inertia;
-                if (Math.abs(this.inertialAlphaOffset) < Epsilon)
+                if (Math.abs(this.inertialAlphaOffset) < this.speed * Epsilon)
                     this.inertialAlphaOffset = 0;
-                if (Math.abs(this.inertialBetaOffset) < Epsilon)
+                if (Math.abs(this.inertialBetaOffset) < this.speed * Epsilon)
                     this.inertialBetaOffset = 0;
-                if (Math.abs(this.inertialRadiusOffset) < Epsilon)
+                if (Math.abs(this.inertialRadiusOffset) < this.speed * Epsilon)
                     this.inertialRadiusOffset = 0;
             }
 
@@ -330,14 +330,6 @@ module BABYLON {
                     this._transformedDirection = Vector3.Zero();
                 }
 
-                this.inertialPanningX *= this.inertia;
-                this.inertialPanningY *= this.inertia;
-
-                if (Math.abs(this.inertialPanningX) < Epsilon)
-                    this.inertialPanningX = 0;
-                if (Math.abs(this.inertialPanningY) < Epsilon)
-                    this.inertialPanningY = 0;
-
                 this._localDirection.copyFromFloats(this.inertialPanningX, this.inertialPanningY, this.inertialPanningY);
                 this._localDirection.multiplyInPlace(this.panningAxis);
                 this._viewMatrix.invertToRef(this._cameraTransformMatrix);
@@ -349,7 +341,15 @@ module BABYLON {
 
                 if (!this._targetHost) {
                     this._target.addInPlace(this._transformedDirection);
-                }                
+                }
+
+                this.inertialPanningX *= this.inertia;
+                this.inertialPanningY *= this.inertia;
+
+                if (Math.abs(this.inertialPanningX) < this.speed * Epsilon)
+                    this.inertialPanningX = 0;
+                if (Math.abs(this.inertialPanningY) < this.speed * Epsilon)
+                    this.inertialPanningY = 0;
             }
 
             // Limits
@@ -420,7 +420,7 @@ module BABYLON {
             this.rebuildAnglesAndRadius();
         }
 
-        public setTarget(target: AbstractMesh | Vector3, toBoundingCenter = false, allowSamePosition = false): void {                        
+        public setTarget(target: AbstractMesh | Vector3, toBoundingCenter = false, allowSamePosition = false): void {
 
             if ((<any>target).getBoundingInfo){
                 if (toBoundingCenter){
@@ -559,7 +559,7 @@ module BABYLON {
                 this.maxZ = distance * 2;
             }
         }
-        
+
         /**
          * @override
          * Override Camera.createRigCamera
@@ -581,7 +581,7 @@ module BABYLON {
             rigCam._cameraRigParams = {};
             return rigCam;
         }
-        
+
         /**
          * @override
          * Override Camera._updateRigCameras
@@ -589,7 +589,7 @@ module BABYLON {
         public _updateRigCameras() {
             var camLeft  = <ArcRotateCamera>this._rigCameras[0];
             var camRight = <ArcRotateCamera>this._rigCameras[1];
-            
+
             camLeft.beta = camRight.beta = this.beta;
             camLeft.radius = camRight.radius = this.radius;
 
@@ -618,5 +618,4 @@ module BABYLON {
             return "ArcRotateCamera";
         }
     }
-} 
-
+}

+ 5 - 5
src/Cameras/babylon.targetCamera.ts

@@ -199,26 +199,26 @@ module BABYLON {
 
             // Inertia
             if (needToMove) {
-                if (Math.abs(this.cameraDirection.x) < Epsilon) {
+                if (Math.abs(this.cameraDirection.x) < this.speed * Epsilon) {
                     this.cameraDirection.x = 0;
                 }
 
-                if (Math.abs(this.cameraDirection.y) < Epsilon) {
+                if (Math.abs(this.cameraDirection.y) < this.speed * Epsilon) {
                     this.cameraDirection.y = 0;
                 }
 
-                if (Math.abs(this.cameraDirection.z) < Epsilon) {
+                if (Math.abs(this.cameraDirection.z) < this.speed * Epsilon) {
                     this.cameraDirection.z = 0;
                 }
 
                 this.cameraDirection.scaleInPlace(this.inertia);
             }
             if (needToRotate) {
-                if (Math.abs(this.cameraRotation.x) < Epsilon) {
+                if (Math.abs(this.cameraRotation.x) < this.speed * Epsilon) {
                     this.cameraRotation.x = 0;
                 }
 
-                if (Math.abs(this.cameraRotation.y) < Epsilon) {
+                if (Math.abs(this.cameraRotation.y) < this.speed * Epsilon) {
                     this.cameraRotation.y = 0;
                 }
                 this.cameraRotation.scaleInPlace(this.inertia);

+ 1 - 1
src/Mesh/babylon.abstractMesh.ts

@@ -116,7 +116,7 @@
         public definedFacingForward = true; // orientation for POV movement & rotation
         public position = new Vector3(0.0, 0.0, 0.0);
         private _rotation = new Vector3(0.0, 0.0, 0.0);
-        public _rotationQuaternion: Quaternion;
+        private _rotationQuaternion: Quaternion;
         private _scaling = new Vector3(1.0, 1.0, 1.0);
         public billboardMode = AbstractMesh.BILLBOARDMODE_NONE;
         public visibility = 1.0;

+ 16 - 16
src/babylon.scene.ts

@@ -3589,26 +3589,26 @@
 
             // Camera
             if (!this.activeCamera) {
-                // Compute position
                 var worldExtends = this.getWorldExtends();
-                var worldCenter = worldExtends.min.add(worldExtends.max.subtract(worldExtends.min).scale(0.5));
-
-                var camera;
+                var worldSize = worldExtends.max.subtract(worldExtends.min);
+                var worldCenter = worldExtends.min.add(worldSize.scale(0.5));
 
+                var camera: TargetCamera;
+                var radius = worldSize.length() * 1.5;
                 if (createArcRotateCamera) {
-                    camera = new ArcRotateCamera("default camera", 0, 0, 10, Vector3.Zero(), this);
-                    camera.setPosition(new Vector3(worldCenter.x, worldCenter.y, worldExtends.min.z - (worldExtends.max.z - worldExtends.min.z)));
-                    camera.lowerRadiusLimit = 0.5;
-                    camera.setTarget(worldCenter);
-                } else {
-                    camera = new FreeCamera("default camera", Vector3.Zero(), this);
-
-                    camera.position = new Vector3(worldCenter.x, worldCenter.y, worldExtends.min.z - (worldExtends.max.z - worldExtends.min.z));
-                    camera.setTarget(worldCenter);
+                    var arcRotateCamera = new ArcRotateCamera("default camera", 4.712, 1.571, radius, worldCenter, this);
+                    arcRotateCamera.lowerRadiusLimit = radius * 0.01;
+                    arcRotateCamera.wheelPrecision = 100 / radius;
+                    camera = arcRotateCamera;
+                }
+                else {
+                    var freeCamera = new FreeCamera("default camera", new Vector3(worldCenter.x, worldCenter.y, this.useRightHandedSystem ? -radius : radius), this);
+                    freeCamera.setTarget(worldCenter);
+                    camera = freeCamera;
                 }
-                camera.minZ = 0.1;
-                var maxDist = worldExtends.max.subtract(worldExtends.min).length();
-                camera.wheelPrecision = 100.0 / maxDist;
+                camera.minZ = radius * 0.01;
+                camera.maxZ = radius * 100;
+                camera.speed = radius * 0.2;
                 this.activeCamera = camera;
             }
         }