elation-engine 0.9.113 → 0.9.115
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/css/systems/render.css +5 -1
- package/package.json +1 -1
- package/scripts/assets.js +103 -20
- package/scripts/assetworker.js +18 -1
- package/scripts/external/holoplay.js +1494 -0
- package/scripts/external/octree.js +0 -0
- package/scripts/external/three/CSS3DRenderer.js +46 -43
- package/scripts/external/three/CubemapToEquirectangular.js +1 -1
- package/scripts/external/three/three-extras.js +1553 -392
- package/scripts/external/three/three-icosa.js +2575 -0
- package/scripts/external/three/three-loaders.js +925 -133
- package/scripts/external/three/three-postprocessing.js +3 -3
- package/scripts/external/three/three-r116dev.js +50930 -0
- package/scripts/external/three/three-spotlighttextures.js +50953 -0
- package/scripts/external/three/three-vrm.js +2 -2
- package/scripts/external/three/three-working.js +35968 -0
- package/scripts/external/three/three.js +38532 -24087
- package/scripts/external/three-mesh-bvh.js +5370 -0
- package/scripts/external/three-old/BVHLoader.js +406 -0
- package/scripts/external/three-old/ColladaLoader.js +5519 -0
- package/scripts/external/three-old/ColladaLoader2.js +1694 -0
- package/scripts/external/three-old/CubemapToEquirectangular.js +188 -0
- package/scripts/external/three-old/DDSLoader.js +269 -0
- package/scripts/external/three-old/FBXLoader-mine.js +5063 -0
- package/scripts/external/three-old/FBXLoader.js +5112 -0
- package/scripts/external/three-old/FlyControls.js +295 -0
- package/scripts/external/three-old/GLTF2Loader.js +2950 -0
- package/scripts/external/three-old/GLTFLoader.js +2213 -0
- package/scripts/external/three-old/JSONLoader.js +435 -0
- package/scripts/external/three-old/MTLLoader.js +533 -0
- package/scripts/external/three-old/OBJLoader-experimental.js +874 -0
- package/scripts/external/three-old/OBJLoader-working.js +727 -0
- package/scripts/external/three-old/OBJLoader.js +723 -0
- package/scripts/external/three-old/OBJMTLLoader.js +440 -0
- package/scripts/external/three-old/OrbitControls.js +592 -0
- package/scripts/external/three-old/PLYLoader.js +517 -0
- package/scripts/external/three-old/TransformControls.js +1100 -0
- package/scripts/external/three-old/VRMLLoader.js +1021 -0
- package/scripts/external/three-old/glTFLoader-combined.js +2513 -0
- package/scripts/external/three-old/nodethree.js +44018 -0
- package/scripts/external/three-old/render/BleachBypassShader.js +64 -0
- package/scripts/external/three-old/render/BloomPass.js +116 -0
- package/scripts/external/three-old/render/CSS3DRenderer.js +310 -0
- package/scripts/external/three-old/render/ClearPass.js +44 -0
- package/scripts/external/three-old/render/ConvolutionShader.js +101 -0
- package/scripts/external/three-old/render/CopyShader.js +46 -0
- package/scripts/external/three-old/render/EffectComposer.js +211 -0
- package/scripts/external/three-old/render/FXAAShader.js +88 -0
- package/scripts/external/three-old/render/FilmPass.js +60 -0
- package/scripts/external/three-old/render/FilmShader.js +104 -0
- package/scripts/external/three-old/render/ManualMSAARenderPass.js +168 -0
- package/scripts/external/three-old/render/MaskPass.js +97 -0
- package/scripts/external/three-old/render/OculusRenderPass.js +84 -0
- package/scripts/external/three-old/render/OculusRiftEffect.js +240 -0
- package/scripts/external/three-old/render/PortalRenderPass.js +166 -0
- package/scripts/external/three-old/render/RecordingPass.js +208 -0
- package/scripts/external/three-old/render/RenderPass.js +57 -0
- package/scripts/external/three-old/render/SSAOShader.js +259 -0
- package/scripts/external/three-old/render/SepiaShader.js +54 -0
- package/scripts/external/three-old/render/ShaderPass.js +66 -0
- package/scripts/external/three-old/render/VREffect.js +482 -0
- package/scripts/external/three-old/shimthree.js +23 -0
- package/scripts/external/three-old/stats.js +6 -0
- package/scripts/external/three-old/three-88dev.js +45004 -0
- package/scripts/external/three-old/three-backgroundoptimization.js +44432 -0
- package/scripts/external/three-old/three-updates.js +44735 -0
- package/scripts/external/three-old/three-working.js +44719 -0
- package/scripts/external/three-old/three.js +44431 -0
- package/scripts/external/three-old/threex.rendererstats.js +66 -0
- package/scripts/external/three-old/tween.js +13 -0
- package/scripts/external/webvr-polyfill-new.js +3497 -0
- package/scripts/external/webvr-polyfill-newest.js +3491 -0
- package/scripts/external/webvr-polyfill-old.js +6337 -0
- package/scripts/geometries.js +2 -2
- package/scripts/math.js +6 -6
- package/scripts/systems/admin.js +1 -1
- package/scripts/systems/controls.js +6 -4
- package/scripts/systems/physics.js +10 -10
- package/scripts/systems/render.js +58 -20
- package/scripts/systems/render2.js +38 -0
- package/scripts/things/camera.js +6 -1
- package/scripts/things/generic-trackedvectors.js +1875 -0
- package/scripts/things/generic.js +3 -4
- package/scripts/things/label2d.js +1 -1
- package/scripts/things/leapmotion.js +6 -6
- package/scripts/things/menu.js +1 -1
- package/scripts/things/player-bak.js +638 -0
- package/scripts/things/player.js +28 -10
- package/scripts/things/skysphere.js +1 -1
- package/scripts/things/terrain.js +1 -1
- package/scripts/things/text.js +1 -1
|
@@ -0,0 +1,2513 @@
|
|
|
1
|
+
// Copyright (c) 2013 Fabrice Robinet
|
|
2
|
+
// All rights reserved.
|
|
3
|
+
//
|
|
4
|
+
// Redistribution and use in source and binary forms, with or without
|
|
5
|
+
// modification, are permitted provided that the following conditions are met:
|
|
6
|
+
//
|
|
7
|
+
// * Redistributions of source code must retain the above copyright
|
|
8
|
+
// notice, this list of conditions and the following disclaimer.
|
|
9
|
+
// * Redistributions in binary form must reproduce the above copyright
|
|
10
|
+
// notice, this list of conditions and the following disclaimer in the
|
|
11
|
+
// documentation and/or other materials provided with the distribution.
|
|
12
|
+
//
|
|
13
|
+
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
14
|
+
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
15
|
+
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
16
|
+
// ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
|
|
17
|
+
// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|
18
|
+
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|
19
|
+
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|
20
|
+
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
21
|
+
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
22
|
+
// THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
23
|
+
|
|
24
|
+
/*
|
|
25
|
+
The Abstract Loader has two modes:
|
|
26
|
+
#1: [static] load all the JSON at once [as of now]
|
|
27
|
+
#2: [stream] stream and parse JSON progressively [not yet supported]
|
|
28
|
+
|
|
29
|
+
Whatever is the mechanism used to parse the JSON (#1 or #2),
|
|
30
|
+
The loader starts by resolving the paths to binaries and referenced json files (by replace the value of the path property with an absolute path if it was relative).
|
|
31
|
+
|
|
32
|
+
In case #1: it is guaranteed to call the concrete loader implementation methods in a order that solves the dependencies between the entries.
|
|
33
|
+
only the nodes requires an extra pass to set up the hirerarchy.
|
|
34
|
+
In case #2: the concrete implementation will have to solve the dependencies. no order is guaranteed.
|
|
35
|
+
|
|
36
|
+
When case #1 is used the followed dependency order is:
|
|
37
|
+
|
|
38
|
+
scenes -> nodes -> meshes -> materials -> techniques -> shaders
|
|
39
|
+
-> buffers
|
|
40
|
+
-> cameras
|
|
41
|
+
-> lights
|
|
42
|
+
|
|
43
|
+
The readers starts with the leafs, i.e:
|
|
44
|
+
shaders, techniques, materials, meshes, buffers, cameras, lights, nodes, scenes
|
|
45
|
+
|
|
46
|
+
For each called handle method called the client should return true if the next handle can be call right after returning,
|
|
47
|
+
or false if a callback on client side will notify the loader that the next handle method can be called.
|
|
48
|
+
|
|
49
|
+
*/
|
|
50
|
+
var global = window;
|
|
51
|
+
(function (root, factory) {
|
|
52
|
+
if (typeof exports === 'object') {
|
|
53
|
+
// Node. Does not work with strict CommonJS, but
|
|
54
|
+
// only CommonJS-like enviroments that support module.exports,
|
|
55
|
+
// like Node.
|
|
56
|
+
factory(module.exports);
|
|
57
|
+
} else if (typeof define === 'function' && define.amd) {
|
|
58
|
+
// AMD. Register as an anonymous module.
|
|
59
|
+
define([], function () {
|
|
60
|
+
return factory(root);
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
// Browser globals
|
|
64
|
+
factory(root);
|
|
65
|
+
}
|
|
66
|
+
}(this, function (root) {
|
|
67
|
+
"use strict";
|
|
68
|
+
|
|
69
|
+
var categoriesDepsOrder = ["buffers", "bufferViews", "images", "videos", "samplers", "textures", "shaders", "programs", "techniques", "materials", "accessors", "meshes", "cameras", "lights", "skins", "nodes", "scenes", "animations"];
|
|
70
|
+
|
|
71
|
+
var glTFParser = Object.create(Object.prototype, {
|
|
72
|
+
|
|
73
|
+
_rootDescription: { value: null, writable: true },
|
|
74
|
+
|
|
75
|
+
rootDescription: {
|
|
76
|
+
set: function(value) {
|
|
77
|
+
this._rootDescription = value;
|
|
78
|
+
},
|
|
79
|
+
get: function() {
|
|
80
|
+
return this._rootDescription;
|
|
81
|
+
}
|
|
82
|
+
},
|
|
83
|
+
|
|
84
|
+
baseURL: { value: null, writable: true },
|
|
85
|
+
|
|
86
|
+
//detect absolute path following the same protocol than window.location
|
|
87
|
+
_isAbsolutePath: {
|
|
88
|
+
value: function(path) {
|
|
89
|
+
var isAbsolutePathRegExp = new RegExp("^"+window.location.protocol, "i");
|
|
90
|
+
|
|
91
|
+
return path.match(isAbsolutePathRegExp) ? true : false;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
|
|
95
|
+
resolvePathIfNeeded: {
|
|
96
|
+
value: function(path) {
|
|
97
|
+
if (this._isAbsolutePath(path)) {
|
|
98
|
+
return path;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return this.baseURL + path;
|
|
102
|
+
}
|
|
103
|
+
},
|
|
104
|
+
|
|
105
|
+
_resolvePathsForCategories: {
|
|
106
|
+
value: function(categories) {
|
|
107
|
+
categories.forEach( function(category) {
|
|
108
|
+
var descriptions = this.json[category];
|
|
109
|
+
if (descriptions) {
|
|
110
|
+
var descriptionKeys = Object.keys(descriptions);
|
|
111
|
+
descriptionKeys.forEach( function(descriptionKey) {
|
|
112
|
+
var description = descriptions[descriptionKey];
|
|
113
|
+
description.path = this.resolvePathIfNeeded(description.path);
|
|
114
|
+
}, this);
|
|
115
|
+
}
|
|
116
|
+
}, this);
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
|
|
120
|
+
_json: {
|
|
121
|
+
value: null,
|
|
122
|
+
writable: true
|
|
123
|
+
},
|
|
124
|
+
|
|
125
|
+
json: {
|
|
126
|
+
enumerable: true,
|
|
127
|
+
get: function() {
|
|
128
|
+
return this._json;
|
|
129
|
+
},
|
|
130
|
+
set: function(value) {
|
|
131
|
+
if (this._json !== value) {
|
|
132
|
+
this._json = value;
|
|
133
|
+
this._resolvePathsForCategories(["buffers", "shaders", "images", "videos"]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
|
|
138
|
+
_path: {
|
|
139
|
+
value: null,
|
|
140
|
+
writable: true
|
|
141
|
+
},
|
|
142
|
+
|
|
143
|
+
getEntryDescription: {
|
|
144
|
+
value: function (entryID, entryType) {
|
|
145
|
+
var entries = null;
|
|
146
|
+
|
|
147
|
+
var category = entryType;
|
|
148
|
+
entries = this.rootDescription[category];
|
|
149
|
+
if (!entries) {
|
|
150
|
+
console.log("ERROR:CANNOT find expected category named:"+category);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
return entries ? entries[entryID] : null;
|
|
155
|
+
}
|
|
156
|
+
},
|
|
157
|
+
|
|
158
|
+
_stepToNextCategory: {
|
|
159
|
+
value: function() {
|
|
160
|
+
this._state.categoryIndex = this.getNextCategoryIndex(this._state.categoryIndex + 1);
|
|
161
|
+
if (this._state.categoryIndex !== -1) {
|
|
162
|
+
this._state.categoryState.index = 0;
|
|
163
|
+
return true;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return false;
|
|
167
|
+
}
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
_stepToNextDescription: {
|
|
171
|
+
enumerable: false,
|
|
172
|
+
value: function() {
|
|
173
|
+
var categoryState = this._state.categoryState;
|
|
174
|
+
var keys = categoryState.keys;
|
|
175
|
+
if (!keys) {
|
|
176
|
+
console.log("INCONSISTENCY ERROR");
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
categoryState.index++;
|
|
181
|
+
categoryState.keys = null;
|
|
182
|
+
if (categoryState.index >= keys.length) {
|
|
183
|
+
return this._stepToNextCategory();
|
|
184
|
+
}
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
},
|
|
188
|
+
|
|
189
|
+
hasCategory: {
|
|
190
|
+
value: function(category) {
|
|
191
|
+
return this.rootDescription[category] ? true : false;
|
|
192
|
+
}
|
|
193
|
+
},
|
|
194
|
+
|
|
195
|
+
_handleState: {
|
|
196
|
+
value: function() {
|
|
197
|
+
|
|
198
|
+
var methodForType = {
|
|
199
|
+
"buffers" : this.handleBuffer,
|
|
200
|
+
"bufferViews" : this.handleBufferView,
|
|
201
|
+
"shaders" : this.handleShader,
|
|
202
|
+
"programs" : this.handleProgram,
|
|
203
|
+
"techniques" : this.handleTechnique,
|
|
204
|
+
"materials" : this.handleMaterial,
|
|
205
|
+
"meshes" : this.handleMesh,
|
|
206
|
+
"cameras" : this.handleCamera,
|
|
207
|
+
"lights" : this.handleLight,
|
|
208
|
+
"nodes" : this.handleNode,
|
|
209
|
+
"scenes" : this.handleScene,
|
|
210
|
+
"images" : this.handleImage,
|
|
211
|
+
"animations" : this.handleAnimation,
|
|
212
|
+
"accessors" : this.handleAccessor,
|
|
213
|
+
"skins" : this.handleSkin,
|
|
214
|
+
"samplers" : this.handleSampler,
|
|
215
|
+
"textures" : this.handleTexture,
|
|
216
|
+
"videos" : this.handleVideo
|
|
217
|
+
|
|
218
|
+
};
|
|
219
|
+
|
|
220
|
+
var success = true;
|
|
221
|
+
while (this._state.categoryIndex !== -1) {
|
|
222
|
+
var category = categoriesDepsOrder[this._state.categoryIndex];
|
|
223
|
+
var categoryState = this._state.categoryState;
|
|
224
|
+
var keys = categoryState.keys;
|
|
225
|
+
if (!keys) {
|
|
226
|
+
categoryState.keys = keys = Object.keys(this.rootDescription[category]);
|
|
227
|
+
if (keys) {
|
|
228
|
+
if (keys.length == 0) {
|
|
229
|
+
this._stepToNextDescription();
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
var type = category;
|
|
236
|
+
var entryID = keys[categoryState.index];
|
|
237
|
+
var description = this.getEntryDescription(entryID, type);
|
|
238
|
+
if (!description) {
|
|
239
|
+
if (this.handleError) {
|
|
240
|
+
this.handleError("INCONSISTENCY ERROR: no description found for entry "+entryID);
|
|
241
|
+
success = false;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
} else {
|
|
245
|
+
|
|
246
|
+
if (methodForType[type]) {
|
|
247
|
+
if (methodForType[type].call(this, entryID, description, this._state.userInfo) === false) {
|
|
248
|
+
success = false;
|
|
249
|
+
break;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
this._stepToNextDescription();
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (this.handleLoadCompleted) {
|
|
258
|
+
this.handleLoadCompleted(success);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
|
|
264
|
+
_loadJSONIfNeeded: {
|
|
265
|
+
enumerable: true,
|
|
266
|
+
value: function(callback) {
|
|
267
|
+
var self = this;
|
|
268
|
+
//FIXME: handle error
|
|
269
|
+
if (!this._json) {
|
|
270
|
+
var jsonPath = this._path;
|
|
271
|
+
var i = jsonPath.lastIndexOf("/");
|
|
272
|
+
this.baseURL = (i !== 0) ? jsonPath.substring(0, i + 1) : '';
|
|
273
|
+
var jsonfile = new XMLHttpRequest();
|
|
274
|
+
jsonfile.open("GET", jsonPath, true);
|
|
275
|
+
jsonfile.addEventListener( 'load', function ( event ) {
|
|
276
|
+
self.json = JSON.parse(jsonfile.responseText);
|
|
277
|
+
if (callback) {
|
|
278
|
+
callback(self.json);
|
|
279
|
+
}
|
|
280
|
+
}, false );
|
|
281
|
+
jsonfile.send(null);
|
|
282
|
+
} else {
|
|
283
|
+
if (callback) {
|
|
284
|
+
callback(this.json);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
},
|
|
289
|
+
|
|
290
|
+
/* load JSON and assign it as description to the reader */
|
|
291
|
+
_buildLoader: {
|
|
292
|
+
value: function(callback) {
|
|
293
|
+
var self = this;
|
|
294
|
+
function JSONReady(json) {
|
|
295
|
+
self.rootDescription = json;
|
|
296
|
+
if (callback)
|
|
297
|
+
callback(this);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
this._loadJSONIfNeeded(JSONReady);
|
|
301
|
+
}
|
|
302
|
+
},
|
|
303
|
+
|
|
304
|
+
_state: { value: null, writable: true },
|
|
305
|
+
|
|
306
|
+
_getEntryType: {
|
|
307
|
+
value: function(entryID) {
|
|
308
|
+
var rootKeys = categoriesDepsOrder;
|
|
309
|
+
for (var i = 0 ; i < rootKeys.length ; i++) {
|
|
310
|
+
var rootValues = this.rootDescription[rootKeys[i]];
|
|
311
|
+
if (rootValues) {
|
|
312
|
+
return rootKeys[i];
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
|
|
319
|
+
getNextCategoryIndex: {
|
|
320
|
+
value: function(currentIndex) {
|
|
321
|
+
for (var i = currentIndex ; i < categoriesDepsOrder.length ; i++) {
|
|
322
|
+
if (this.hasCategory(categoriesDepsOrder[i])) {
|
|
323
|
+
return i;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
return -1;
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
|
|
331
|
+
load: {
|
|
332
|
+
enumerable: true,
|
|
333
|
+
value: function(userInfo, options) {
|
|
334
|
+
var self = this;
|
|
335
|
+
this._buildLoader(function loaderReady(reader) {
|
|
336
|
+
var startCategory = self.getNextCategoryIndex.call(self,0);
|
|
337
|
+
if (startCategory !== -1) {
|
|
338
|
+
self._state = { "userInfo" : userInfo,
|
|
339
|
+
"options" : options,
|
|
340
|
+
"categoryIndex" : startCategory,
|
|
341
|
+
"categoryState" : { "index" : "0" } };
|
|
342
|
+
self._handleState();
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
},
|
|
347
|
+
|
|
348
|
+
initWithPath: {
|
|
349
|
+
value: function(path) {
|
|
350
|
+
this._path = path;
|
|
351
|
+
this._json = null;
|
|
352
|
+
return this;
|
|
353
|
+
}
|
|
354
|
+
},
|
|
355
|
+
|
|
356
|
+
//this is meant to be global and common for all instances
|
|
357
|
+
_knownURLs: { writable: true, value: {} },
|
|
358
|
+
|
|
359
|
+
//to be invoked by subclass, so that ids can be ensured to not overlap
|
|
360
|
+
loaderContext: {
|
|
361
|
+
value: function() {
|
|
362
|
+
if (typeof this._knownURLs[this._path] === "undefined") {
|
|
363
|
+
this._knownURLs[this._path] = Object.keys(this._knownURLs).length;
|
|
364
|
+
}
|
|
365
|
+
return "__" + this._knownURLs[this._path];
|
|
366
|
+
}
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
initWithJSON: {
|
|
370
|
+
value: function(json, baseURL) {
|
|
371
|
+
this.json = json;
|
|
372
|
+
this.baseURL = baseURL;
|
|
373
|
+
if (!baseURL) {
|
|
374
|
+
console.log("WARNING: no base URL passed to Reader:initWithJSON");
|
|
375
|
+
}
|
|
376
|
+
return this;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
if(root) {
|
|
383
|
+
root.glTFParser = glTFParser;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
return glTFParser;
|
|
387
|
+
|
|
388
|
+
}));
|
|
389
|
+
/**
|
|
390
|
+
* @author Tony Parisi / http://www.tonyparisi.com/
|
|
391
|
+
*/
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
THREE.glTFLoader = function (showStatus) {
|
|
395
|
+
this.useBufferGeometry = (THREE.glTFLoader.useBufferGeometry !== undefined ) ?
|
|
396
|
+
THREE.glTFLoader.useBufferGeometry : true;
|
|
397
|
+
this.meshesRequested = 0;
|
|
398
|
+
this.meshesLoaded = 0;
|
|
399
|
+
this.pendingMeshes = [];
|
|
400
|
+
this.animationsRequested = 0;
|
|
401
|
+
this.animationsLoaded = 0;
|
|
402
|
+
this.animations = [];
|
|
403
|
+
this.shadersRequested = 0;
|
|
404
|
+
this.shadersLoaded = 0;
|
|
405
|
+
this.shaders = {};
|
|
406
|
+
THREE.Loader.call( this, showStatus );
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
THREE.glTFLoader.prototype = new THREE.Loader();
|
|
410
|
+
THREE.glTFLoader.prototype.constructor = THREE.glTFLoader;
|
|
411
|
+
|
|
412
|
+
THREE.glTFLoader.prototype.load = function( url, callback ) {
|
|
413
|
+
|
|
414
|
+
var theLoader = this;
|
|
415
|
+
// Utilities
|
|
416
|
+
|
|
417
|
+
function RgbArraytoHex(colorArray) {
|
|
418
|
+
if(!colorArray) return 0xFFFFFFFF;
|
|
419
|
+
var r = Math.floor(colorArray[0] * 255),
|
|
420
|
+
g = Math.floor(colorArray[1] * 255),
|
|
421
|
+
b = Math.floor(colorArray[2] * 255),
|
|
422
|
+
a = 255;
|
|
423
|
+
|
|
424
|
+
var color = (a << 24) + (r << 16) + (g << 8) + b;
|
|
425
|
+
|
|
426
|
+
return color;
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function convertAxisAngleToQuaternion(rotations, count)
|
|
430
|
+
{
|
|
431
|
+
var q = new THREE.Quaternion;
|
|
432
|
+
var axis = new THREE.Vector3;
|
|
433
|
+
var euler = new THREE.Vector3;
|
|
434
|
+
|
|
435
|
+
var i;
|
|
436
|
+
for (i = 0; i < count; i++) {
|
|
437
|
+
axis.set(rotations[i * 4], rotations[i * 4 + 1],
|
|
438
|
+
rotations[i * 4 + 2]).normalize();
|
|
439
|
+
var angle = rotations[i * 4 + 3];
|
|
440
|
+
q.setFromAxisAngle(axis, angle);
|
|
441
|
+
rotations[i * 4] = q.x;
|
|
442
|
+
rotations[i * 4 + 1] = q.y;
|
|
443
|
+
rotations[i * 4 + 2] = q.z;
|
|
444
|
+
rotations[i * 4 + 3] = q.w;
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function componentsPerElementForGLType(glType) {
|
|
449
|
+
switch (glType) {
|
|
450
|
+
case WebGLRenderingContext.FLOAT :
|
|
451
|
+
case WebGLRenderingContext.UNSIGNED_BYTE :
|
|
452
|
+
case WebGLRenderingContext.UNSIGNED_SHORT :
|
|
453
|
+
return 1;
|
|
454
|
+
case WebGLRenderingContext.FLOAT_VEC2 :
|
|
455
|
+
return 2;
|
|
456
|
+
case WebGLRenderingContext.FLOAT_VEC3 :
|
|
457
|
+
return 3;
|
|
458
|
+
case WebGLRenderingContext.FLOAT_VEC4 :
|
|
459
|
+
return 4;
|
|
460
|
+
case WebGLRenderingContext.FLOAT_MAT4 :
|
|
461
|
+
return 16;
|
|
462
|
+
default:
|
|
463
|
+
return null;
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
|
|
468
|
+
function LoadTexture(src) {
|
|
469
|
+
if(!src) { return null; }
|
|
470
|
+
return THREE.ImageUtils.loadTexture(src);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Geometry processing
|
|
474
|
+
|
|
475
|
+
var ClassicGeometry = function() {
|
|
476
|
+
|
|
477
|
+
if (theLoader.useBufferGeometry) {
|
|
478
|
+
this.geometry = new THREE.BufferGeometry;
|
|
479
|
+
}
|
|
480
|
+
else {
|
|
481
|
+
this.geometry = new THREE.Geometry;
|
|
482
|
+
}
|
|
483
|
+
this.totalAttributes = 0;
|
|
484
|
+
this.loadedAttributes = 0;
|
|
485
|
+
this.indicesLoaded = false;
|
|
486
|
+
this.finished = false;
|
|
487
|
+
|
|
488
|
+
this.onload = null;
|
|
489
|
+
|
|
490
|
+
this.uvs = null;
|
|
491
|
+
this.indexArray = null;
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
ClassicGeometry.prototype.constructor = ClassicGeometry;
|
|
495
|
+
|
|
496
|
+
ClassicGeometry.prototype.buildArrayGeometry = function() {
|
|
497
|
+
|
|
498
|
+
// Build indexed mesh
|
|
499
|
+
var geometry = this.geometry;
|
|
500
|
+
var normals = geometry.normals;
|
|
501
|
+
var indexArray = this.indexArray;
|
|
502
|
+
var uvs = this.uvs;
|
|
503
|
+
var a, b, c;
|
|
504
|
+
var i, l;
|
|
505
|
+
var faceNormals = null;
|
|
506
|
+
var faceTexcoords = null;
|
|
507
|
+
|
|
508
|
+
for(i = 0, l = this.indexArray.length; i < l; i += 3) {
|
|
509
|
+
a = indexArray[i];
|
|
510
|
+
b = indexArray[i+1];
|
|
511
|
+
c = indexArray[i+2];
|
|
512
|
+
if(normals) {
|
|
513
|
+
faceNormals = [normals[a], normals[b], normals[c]];
|
|
514
|
+
}
|
|
515
|
+
geometry.faces.push( new THREE.Face3( a, b, c, faceNormals, null, null ) );
|
|
516
|
+
if(uvs) {
|
|
517
|
+
geometry.faceVertexUvs[0].push([ uvs[a], uvs[b], uvs[c] ]);
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Allow Three.js to calculate some values for us
|
|
522
|
+
geometry.computeBoundingBox();
|
|
523
|
+
geometry.computeBoundingSphere();
|
|
524
|
+
geometry.computeFaceNormals();
|
|
525
|
+
if(!normals) {
|
|
526
|
+
geometry.computeVertexNormals();
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
ClassicGeometry.prototype.buildBufferGeometry = function() {
|
|
532
|
+
// Build indexed mesh
|
|
533
|
+
var geometry = this.geometry;
|
|
534
|
+
geometry.attributes.index = {
|
|
535
|
+
itemSize: 1,
|
|
536
|
+
array : this.indexArray
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
var offset = {
|
|
540
|
+
start: 0,
|
|
541
|
+
index: 0,
|
|
542
|
+
count: this.indexArray.length
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
geometry.offsets.push( offset );
|
|
546
|
+
|
|
547
|
+
geometry.computeBoundingSphere();
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
ClassicGeometry.prototype.checkFinished = function() {
|
|
551
|
+
if(this.indexArray && this.loadedAttributes === this.totalAttributes) {
|
|
552
|
+
|
|
553
|
+
if (theLoader.useBufferGeometry) {
|
|
554
|
+
this.buildBufferGeometry();
|
|
555
|
+
}
|
|
556
|
+
else {
|
|
557
|
+
this.buildArrayGeometry();
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
this.finished = true;
|
|
561
|
+
|
|
562
|
+
if(this.onload) {
|
|
563
|
+
this.onload();
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
};
|
|
567
|
+
|
|
568
|
+
// Delegate for processing index buffers
|
|
569
|
+
var IndicesDelegate = function() {};
|
|
570
|
+
|
|
571
|
+
IndicesDelegate.prototype.handleError = function(errorCode, info) {
|
|
572
|
+
// FIXME: report error
|
|
573
|
+
console.log("ERROR(IndicesDelegate):"+errorCode+":"+info);
|
|
574
|
+
};
|
|
575
|
+
|
|
576
|
+
IndicesDelegate.prototype.convert = function(resource, ctx) {
|
|
577
|
+
return new Uint16Array(resource, 0, ctx.indices.count);
|
|
578
|
+
};
|
|
579
|
+
|
|
580
|
+
IndicesDelegate.prototype.resourceAvailable = function(glResource, ctx) {
|
|
581
|
+
var geometry = ctx.geometry;
|
|
582
|
+
geometry.indexArray = glResource;
|
|
583
|
+
geometry.checkFinished();
|
|
584
|
+
return true;
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
var indicesDelegate = new IndicesDelegate();
|
|
588
|
+
|
|
589
|
+
var IndicesContext = function(indices, geometry) {
|
|
590
|
+
this.indices = indices;
|
|
591
|
+
this.geometry = geometry;
|
|
592
|
+
};
|
|
593
|
+
|
|
594
|
+
// Delegate for processing vertex attribute buffers
|
|
595
|
+
var VertexAttributeDelegate = function() {};
|
|
596
|
+
|
|
597
|
+
VertexAttributeDelegate.prototype.handleError = function(errorCode, info) {
|
|
598
|
+
// FIXME: report error
|
|
599
|
+
console.log("ERROR(VertexAttributeDelegate):"+errorCode+":"+info);
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
VertexAttributeDelegate.prototype.convert = function(resource, ctx) {
|
|
603
|
+
return resource;
|
|
604
|
+
};
|
|
605
|
+
|
|
606
|
+
|
|
607
|
+
|
|
608
|
+
VertexAttributeDelegate.prototype.arrayResourceAvailable = function(glResource, ctx) {
|
|
609
|
+
var geom = ctx.geometry;
|
|
610
|
+
var attribute = ctx.attribute;
|
|
611
|
+
var semantic = ctx.semantic;
|
|
612
|
+
var floatArray;
|
|
613
|
+
var i, l;
|
|
614
|
+
//FIXME: Float32 is assumed here, but should be checked.
|
|
615
|
+
|
|
616
|
+
if(semantic == "POSITION") {
|
|
617
|
+
// TODO: Should be easy to take strides into account here
|
|
618
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
|
|
619
|
+
for(i = 0, l = floatArray.length; i < l; i += 3) {
|
|
620
|
+
geom.geometry.vertices.push( new THREE.Vector3( floatArray[i], floatArray[i+1], floatArray[i+2] ) );
|
|
621
|
+
}
|
|
622
|
+
} else if(semantic == "NORMAL") {
|
|
623
|
+
geom.geometry.normals = [];
|
|
624
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
|
|
625
|
+
for(i = 0, l = floatArray.length; i < l; i += 3) {
|
|
626
|
+
geom.geometry.normals.push( new THREE.Vector3( floatArray[i], floatArray[i+1], floatArray[i+2] ) );
|
|
627
|
+
}
|
|
628
|
+
} else if ((semantic == "TEXCOORD_0") || (semantic == "TEXCOORD" )) {
|
|
629
|
+
geom.uvs = [];
|
|
630
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
|
|
631
|
+
for(i = 0, l = floatArray.length; i < l; i += 2) {
|
|
632
|
+
geom.uvs.push( new THREE.Vector2( floatArray[i], 1.0 - floatArray[i+1] ) );
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
else if (semantic == "WEIGHT") {
|
|
636
|
+
nComponents = componentsPerElementForGLType(attribute.type);
|
|
637
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
|
|
638
|
+
for(i = 0, l = floatArray.length; i < l; i += 4) {
|
|
639
|
+
geom.geometry.skinWeights.push( new THREE.Vector4( floatArray[i], floatArray[i+1], floatArray[i+2], floatArray[i+3] ) );
|
|
640
|
+
}
|
|
641
|
+
}
|
|
642
|
+
else if (semantic == "JOINT") {
|
|
643
|
+
nComponents = componentsPerElementForGLType(attribute.type);
|
|
644
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
|
|
645
|
+
for(i = 0, l = floatArray.length; i < l; i += 4) {
|
|
646
|
+
geom.geometry.skinIndices.push( new THREE.Vector4( floatArray[i], floatArray[i+1], floatArray[i+2], floatArray[i+3] ) );
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
VertexAttributeDelegate.prototype.bufferResourceAvailable = function(glResource, ctx) {
|
|
652
|
+
var geom = ctx.geometry;
|
|
653
|
+
var attribute = ctx.attribute;
|
|
654
|
+
var semantic = ctx.semantic;
|
|
655
|
+
var floatArray;
|
|
656
|
+
var i, l;
|
|
657
|
+
var nComponents;
|
|
658
|
+
//FIXME: Float32 is assumed here, but should be checked.
|
|
659
|
+
|
|
660
|
+
if(semantic == "POSITION") {
|
|
661
|
+
// TODO: Should be easy to take strides into account here
|
|
662
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
|
|
663
|
+
geom.geometry.attributes.position = {
|
|
664
|
+
itemSize: 3,
|
|
665
|
+
array : floatArray
|
|
666
|
+
};
|
|
667
|
+
} else if(semantic == "NORMAL") {
|
|
668
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * componentsPerElementForGLType(attribute.type));
|
|
669
|
+
geom.geometry.attributes.normal = {
|
|
670
|
+
itemSize: 3,
|
|
671
|
+
array : floatArray
|
|
672
|
+
};
|
|
673
|
+
} else if ((semantic == "TEXCOORD_0") || (semantic == "TEXCOORD" )) {
|
|
674
|
+
|
|
675
|
+
nComponents = componentsPerElementForGLType(attribute.type);
|
|
676
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
|
|
677
|
+
// N.B.: flip Y value... should we just set texture.flipY everywhere?
|
|
678
|
+
for (i = 0; i < floatArray.length / 2; i++) {
|
|
679
|
+
floatArray[i*2+1] = 1.0 - floatArray[i*2+1];
|
|
680
|
+
}
|
|
681
|
+
geom.geometry.attributes.uv = {
|
|
682
|
+
itemSize: nComponents,
|
|
683
|
+
array : floatArray
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
else if (semantic == "WEIGHT") {
|
|
687
|
+
nComponents = componentsPerElementForGLType(attribute.type);
|
|
688
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
|
|
689
|
+
geom.geometry.attributes.skinWeight = {
|
|
690
|
+
itemSize: nComponents,
|
|
691
|
+
array : floatArray
|
|
692
|
+
};
|
|
693
|
+
}
|
|
694
|
+
else if (semantic == "JOINT") {
|
|
695
|
+
nComponents = componentsPerElementForGLType(attribute.type);
|
|
696
|
+
floatArray = new Float32Array(glResource, 0, attribute.count * nComponents);
|
|
697
|
+
geom.geometry.attributes.skinIndex = {
|
|
698
|
+
itemSize: nComponents,
|
|
699
|
+
array : floatArray
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
VertexAttributeDelegate.prototype.resourceAvailable = function(glResource, ctx) {
|
|
705
|
+
if (theLoader.useBufferGeometry) {
|
|
706
|
+
this.bufferResourceAvailable(glResource, ctx);
|
|
707
|
+
}
|
|
708
|
+
else {
|
|
709
|
+
this.arrayResourceAvailable(glResource, ctx);
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
var geom = ctx.geometry;
|
|
713
|
+
geom.loadedAttributes++;
|
|
714
|
+
geom.checkFinished();
|
|
715
|
+
return true;
|
|
716
|
+
};
|
|
717
|
+
|
|
718
|
+
var vertexAttributeDelegate = new VertexAttributeDelegate();
|
|
719
|
+
|
|
720
|
+
var VertexAttributeContext = function(attribute, semantic, geometry) {
|
|
721
|
+
this.attribute = attribute;
|
|
722
|
+
this.semantic = semantic;
|
|
723
|
+
this.geometry = geometry;
|
|
724
|
+
};
|
|
725
|
+
|
|
726
|
+
var Mesh = function() {
|
|
727
|
+
this.primitives = [];
|
|
728
|
+
this.materialsPending = [];
|
|
729
|
+
this.loadedGeometry = 0;
|
|
730
|
+
this.onCompleteCallbacks = [];
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
Mesh.prototype.addPrimitive = function(geometry, material) {
|
|
734
|
+
|
|
735
|
+
var self = this;
|
|
736
|
+
geometry.onload = function() {
|
|
737
|
+
self.loadedGeometry++;
|
|
738
|
+
self.checkComplete();
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
this.primitives.push({
|
|
742
|
+
geometry: geometry,
|
|
743
|
+
material: material,
|
|
744
|
+
mesh: null
|
|
745
|
+
});
|
|
746
|
+
};
|
|
747
|
+
|
|
748
|
+
Mesh.prototype.onComplete = function(callback) {
|
|
749
|
+
this.onCompleteCallbacks.push(callback);
|
|
750
|
+
this.checkComplete();
|
|
751
|
+
};
|
|
752
|
+
|
|
753
|
+
Mesh.prototype.checkComplete = function() {
|
|
754
|
+
var self = this;
|
|
755
|
+
if(this.onCompleteCallbacks.length && this.primitives.length == this.loadedGeometry) {
|
|
756
|
+
this.onCompleteCallbacks.forEach(function(callback) {
|
|
757
|
+
callback(self);
|
|
758
|
+
});
|
|
759
|
+
this.onCompleteCallbacks = [];
|
|
760
|
+
}
|
|
761
|
+
};
|
|
762
|
+
|
|
763
|
+
Mesh.prototype.attachToNode = function(threeNode) {
|
|
764
|
+
// Assumes that the geometry is complete
|
|
765
|
+
this.primitives.forEach(function(primitive) {
|
|
766
|
+
/*if(!primitive.mesh) {
|
|
767
|
+
primitive.mesh = new THREE.Mesh(primitive.geometry, primitive.material);
|
|
768
|
+
}*/
|
|
769
|
+
var material = primitive.material;
|
|
770
|
+
if (!(material instanceof THREE.Material)) {
|
|
771
|
+
material = theLoader.createShaderMaterial(material);
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
var threeMesh = new THREE.Mesh(primitive.geometry.geometry, material);
|
|
775
|
+
threeMesh.castShadow = true;
|
|
776
|
+
threeNode.add(threeMesh);
|
|
777
|
+
});
|
|
778
|
+
};
|
|
779
|
+
|
|
780
|
+
// Delayed-loaded material
|
|
781
|
+
var Material = function(params) {
|
|
782
|
+
this.params = params;
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
// Delegate for processing animation parameter buffers
|
|
786
|
+
var AnimationParameterDelegate = function() {};
|
|
787
|
+
|
|
788
|
+
AnimationParameterDelegate.prototype.handleError = function(errorCode, info) {
|
|
789
|
+
// FIXME: report error
|
|
790
|
+
console.log("ERROR(AnimationParameterDelegate):"+errorCode+":"+info);
|
|
791
|
+
};
|
|
792
|
+
|
|
793
|
+
AnimationParameterDelegate.prototype.convert = function(resource, ctx) {
|
|
794
|
+
var parameter = ctx.parameter;
|
|
795
|
+
|
|
796
|
+
var glResource = null;
|
|
797
|
+
switch (parameter.type) {
|
|
798
|
+
case WebGLRenderingContext.FLOAT :
|
|
799
|
+
case WebGLRenderingContext.FLOAT_VEC2 :
|
|
800
|
+
case WebGLRenderingContext.FLOAT_VEC3 :
|
|
801
|
+
case WebGLRenderingContext.FLOAT_VEC4 :
|
|
802
|
+
glResource = new Float32Array(resource, 0, parameter.count * componentsPerElementForGLType(parameter.type));
|
|
803
|
+
break;
|
|
804
|
+
default:
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
return glResource;
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
AnimationParameterDelegate.prototype.resourceAvailable = function(glResource, ctx) {
|
|
812
|
+
var animation = ctx.animation;
|
|
813
|
+
var parameter = ctx.parameter;
|
|
814
|
+
parameter.data = glResource;
|
|
815
|
+
animation.handleParameterLoaded(parameter);
|
|
816
|
+
return true;
|
|
817
|
+
};
|
|
818
|
+
|
|
819
|
+
var animationParameterDelegate = new AnimationParameterDelegate();
|
|
820
|
+
|
|
821
|
+
var AnimationParameterContext = function(parameter, animation) {
|
|
822
|
+
this.parameter = parameter;
|
|
823
|
+
this.animation = animation;
|
|
824
|
+
};
|
|
825
|
+
|
|
826
|
+
// Animations
|
|
827
|
+
var Animation = function() {
|
|
828
|
+
|
|
829
|
+
// create Three.js keyframe here
|
|
830
|
+
this.totalParameters = 0;
|
|
831
|
+
this.loadedParameters = 0;
|
|
832
|
+
this.parameters = {};
|
|
833
|
+
this.finishedLoading = false;
|
|
834
|
+
this.onload = null;
|
|
835
|
+
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
Animation.prototype.constructor = Animation;
|
|
839
|
+
|
|
840
|
+
Animation.prototype.handleParameterLoaded = function(parameter) {
|
|
841
|
+
this.parameters[parameter.name] = parameter;
|
|
842
|
+
this.loadedParameters++;
|
|
843
|
+
this.checkFinished();
|
|
844
|
+
};
|
|
845
|
+
|
|
846
|
+
Animation.prototype.checkFinished = function() {
|
|
847
|
+
if(this.loadedParameters === this.totalParameters) {
|
|
848
|
+
// Build animation
|
|
849
|
+
this.finishedLoading = true;
|
|
850
|
+
|
|
851
|
+
if (this.onload) {
|
|
852
|
+
this.onload();
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
};
|
|
856
|
+
|
|
857
|
+
// Delegate for processing inverse bind matrices buffer
|
|
858
|
+
var InverseBindMatricesDelegate = function() {};
|
|
859
|
+
|
|
860
|
+
InverseBindMatricesDelegate.prototype.handleError = function(errorCode, info) {
|
|
861
|
+
// FIXME: report error
|
|
862
|
+
console.log("ERROR(InverseBindMatricesDelegate):"+errorCode+":"+info);
|
|
863
|
+
};
|
|
864
|
+
|
|
865
|
+
InverseBindMatricesDelegate.prototype.convert = function(resource, ctx) {
|
|
866
|
+
var parameter = ctx.parameter;
|
|
867
|
+
|
|
868
|
+
var glResource = null;
|
|
869
|
+
switch (parameter.type) {
|
|
870
|
+
case WebGLRenderingContext.FLOAT_MAT4 :
|
|
871
|
+
glResource = new Float32Array(resource, 0, parameter.count * componentsPerElementForGLType(parameter.type));
|
|
872
|
+
break;
|
|
873
|
+
default:
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
return glResource;
|
|
878
|
+
};
|
|
879
|
+
|
|
880
|
+
InverseBindMatricesDelegate.prototype.resourceAvailable = function(glResource, ctx) {
|
|
881
|
+
var skin = ctx.skin;
|
|
882
|
+
skin.inverseBindMatrices = glResource;
|
|
883
|
+
return true;
|
|
884
|
+
};
|
|
885
|
+
|
|
886
|
+
var inverseBindMatricesDelegate = new InverseBindMatricesDelegate();
|
|
887
|
+
|
|
888
|
+
var InverseBindMatricesContext = function(param, skin) {
|
|
889
|
+
this.parameter = param;
|
|
890
|
+
this.skin = skin;
|
|
891
|
+
};
|
|
892
|
+
|
|
893
|
+
// Delegate for processing shaders from external files
|
|
894
|
+
var ShaderDelegate = function() {};
|
|
895
|
+
|
|
896
|
+
ShaderDelegate.prototype.handleError = function(errorCode, info) {
|
|
897
|
+
// FIXME: report error
|
|
898
|
+
console.log("ERROR(ShaderDelegate):"+errorCode+":"+info);
|
|
899
|
+
};
|
|
900
|
+
|
|
901
|
+
ShaderDelegate.prototype.convert = function(resource, ctx) {
|
|
902
|
+
return resource;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
ShaderDelegate.prototype.resourceAvailable = function(data, ctx) {
|
|
906
|
+
theLoader.shadersLoaded++;
|
|
907
|
+
theLoader.shaders[ctx.id] = data;
|
|
908
|
+
return true;
|
|
909
|
+
};
|
|
910
|
+
|
|
911
|
+
var shaderDelegate = new ShaderDelegate();
|
|
912
|
+
|
|
913
|
+
var ShaderContext = function(id, path) {
|
|
914
|
+
this.id = id;
|
|
915
|
+
this.path = path;
|
|
916
|
+
};
|
|
917
|
+
|
|
918
|
+
// Resource management
|
|
919
|
+
|
|
920
|
+
var ResourceEntry = function(entryID, object, description) {
|
|
921
|
+
this.entryID = entryID;
|
|
922
|
+
this.object = object;
|
|
923
|
+
this.description = description;
|
|
924
|
+
};
|
|
925
|
+
|
|
926
|
+
var Resources = function() {
|
|
927
|
+
this._entries = {};
|
|
928
|
+
};
|
|
929
|
+
|
|
930
|
+
Resources.prototype.setEntry = function(entryID, object, description) {
|
|
931
|
+
if (!entryID) {
|
|
932
|
+
console.error("No EntryID provided, cannot store", description);
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (this._entries[entryID]) {
|
|
937
|
+
console.warn("entry["+entryID+"] is being overwritten");
|
|
938
|
+
}
|
|
939
|
+
|
|
940
|
+
this._entries[entryID] = new ResourceEntry(entryID, object, description );
|
|
941
|
+
};
|
|
942
|
+
|
|
943
|
+
Resources.prototype.getEntry = function(entryID) {
|
|
944
|
+
return this._entries[entryID];
|
|
945
|
+
};
|
|
946
|
+
|
|
947
|
+
Resources.prototype.clearEntries = function() {
|
|
948
|
+
this._entries = {};
|
|
949
|
+
};
|
|
950
|
+
|
|
951
|
+
LoadDelegate = function() {
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
LoadDelegate.prototype.loadCompleted = function(callback, obj) {
|
|
955
|
+
callback.call(Window, obj);
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
// Loader
|
|
959
|
+
|
|
960
|
+
var ThreeGLTFLoader = Object.create(glTFParser, {
|
|
961
|
+
|
|
962
|
+
load: {
|
|
963
|
+
enumerable: true,
|
|
964
|
+
value: function(userInfo, options) {
|
|
965
|
+
this.resources = new Resources();
|
|
966
|
+
this.cameras = [];
|
|
967
|
+
this.lights = [];
|
|
968
|
+
this.animations = [];
|
|
969
|
+
this.joints = {};
|
|
970
|
+
this.skeltons = {};
|
|
971
|
+
THREE.GLTFLoaderUtils.init();
|
|
972
|
+
glTFParser.load.call(this, userInfo, options);
|
|
973
|
+
}
|
|
974
|
+
},
|
|
975
|
+
|
|
976
|
+
cameras: {
|
|
977
|
+
enumerable: true,
|
|
978
|
+
writable: true,
|
|
979
|
+
value : []
|
|
980
|
+
},
|
|
981
|
+
|
|
982
|
+
lights: {
|
|
983
|
+
enumerable: true,
|
|
984
|
+
writable: true,
|
|
985
|
+
value : []
|
|
986
|
+
},
|
|
987
|
+
|
|
988
|
+
animations: {
|
|
989
|
+
enumerable: true,
|
|
990
|
+
writable: true,
|
|
991
|
+
value : []
|
|
992
|
+
},
|
|
993
|
+
|
|
994
|
+
// Implement WebGLTFLoader handlers
|
|
995
|
+
|
|
996
|
+
handleBuffer: {
|
|
997
|
+
value: function(entryID, description, userInfo) {
|
|
998
|
+
this.resources.setEntry(entryID, null, description);
|
|
999
|
+
description.type = "ArrayBuffer";
|
|
1000
|
+
return true;
|
|
1001
|
+
}
|
|
1002
|
+
},
|
|
1003
|
+
|
|
1004
|
+
handleBufferView: {
|
|
1005
|
+
value: function(entryID, description, userInfo) {
|
|
1006
|
+
this.resources.setEntry(entryID, null, description);
|
|
1007
|
+
|
|
1008
|
+
var buffer = this.resources.getEntry(description.buffer);
|
|
1009
|
+
description.type = "ArrayBufferView";
|
|
1010
|
+
|
|
1011
|
+
var bufferViewEntry = this.resources.getEntry(entryID);
|
|
1012
|
+
bufferViewEntry.buffer = buffer;
|
|
1013
|
+
return true;
|
|
1014
|
+
}
|
|
1015
|
+
},
|
|
1016
|
+
|
|
1017
|
+
handleShader: {
|
|
1018
|
+
value: function(entryID, description, userInfo) {
|
|
1019
|
+
this.resources.setEntry(entryID, null, description);
|
|
1020
|
+
var shaderRequest = {
|
|
1021
|
+
id : entryID,
|
|
1022
|
+
path : description.path,
|
|
1023
|
+
};
|
|
1024
|
+
|
|
1025
|
+
var shaderContext = new ShaderContext(entryID, description.path);
|
|
1026
|
+
|
|
1027
|
+
theLoader.shadersRequested++;
|
|
1028
|
+
THREE.GLTFLoaderUtils.getFile(shaderRequest, shaderDelegate, shaderContext);
|
|
1029
|
+
|
|
1030
|
+
return true;
|
|
1031
|
+
}
|
|
1032
|
+
},
|
|
1033
|
+
|
|
1034
|
+
handleProgram: {
|
|
1035
|
+
value: function(entryID, description, userInfo) {
|
|
1036
|
+
this.resources.setEntry(entryID, null, description);
|
|
1037
|
+
return true;
|
|
1038
|
+
}
|
|
1039
|
+
},
|
|
1040
|
+
|
|
1041
|
+
handleTechnique: {
|
|
1042
|
+
value: function(entryID, description, userInfo) {
|
|
1043
|
+
this.resources.setEntry(entryID, null, description);
|
|
1044
|
+
return true;
|
|
1045
|
+
}
|
|
1046
|
+
},
|
|
1047
|
+
|
|
1048
|
+
createShaderMaterial : {
|
|
1049
|
+
value: function(material) {
|
|
1050
|
+
|
|
1051
|
+
var fragmentShader = theLoader.shaders[material.params.fragmentShader];
|
|
1052
|
+
if (!fragmentShader) {
|
|
1053
|
+
console.log("ERROR: Missing fragment shader definition:", material.params.fragmentShader);
|
|
1054
|
+
return new THREE.MeshPhongMaterial;
|
|
1055
|
+
}
|
|
1056
|
+
|
|
1057
|
+
var vertexShader = theLoader.shaders[material.params.vertexShader];
|
|
1058
|
+
if (!fragmentShader) {
|
|
1059
|
+
console.log("ERROR: Missing vertex shader definition:", material.params.vertexShader);
|
|
1060
|
+
return new THREE.MeshPhongMaterial;
|
|
1061
|
+
}
|
|
1062
|
+
|
|
1063
|
+
var uniforms = {};
|
|
1064
|
+
var shaderMaterial = new THREE.ShaderMaterial( {
|
|
1065
|
+
|
|
1066
|
+
fragmentShader: fragmentShader,
|
|
1067
|
+
vertexShader: vertexShader,
|
|
1068
|
+
uniforms: uniforms,
|
|
1069
|
+
|
|
1070
|
+
} );
|
|
1071
|
+
|
|
1072
|
+
return new THREE.MeshPhongMaterial(material.params);
|
|
1073
|
+
}
|
|
1074
|
+
},
|
|
1075
|
+
|
|
1076
|
+
createShaderParams : {
|
|
1077
|
+
value: function(materialId, values, params, instanceProgram) {
|
|
1078
|
+
var program = this.resources.getEntry(instanceProgram.program);
|
|
1079
|
+
|
|
1080
|
+
if (program) {
|
|
1081
|
+
params.fragmentShader = program.description.fragmentShader;
|
|
1082
|
+
params.vertexShader = program.description.vertexShader;
|
|
1083
|
+
params.attributes = instanceProgram.attributes;
|
|
1084
|
+
params.uniforms = instanceProgram.uniforms;
|
|
1085
|
+
}
|
|
1086
|
+
}
|
|
1087
|
+
},
|
|
1088
|
+
|
|
1089
|
+
threeJSMaterialType : {
|
|
1090
|
+
value: function(materialId, technique, values, params) {
|
|
1091
|
+
|
|
1092
|
+
var materialType = THREE.MeshPhongMaterial;
|
|
1093
|
+
var defaultPass = null;
|
|
1094
|
+
if (technique && technique.description && technique.description.passes)
|
|
1095
|
+
defaultPass = technique.description.passes.defaultPass;
|
|
1096
|
+
|
|
1097
|
+
if (defaultPass) {
|
|
1098
|
+
if (defaultPass.details && defaultPass.details.commonProfile) {
|
|
1099
|
+
var profile = technique.description.passes.defaultPass.details.commonProfile;
|
|
1100
|
+
if (profile)
|
|
1101
|
+
{
|
|
1102
|
+
switch (profile.lightingModel)
|
|
1103
|
+
{
|
|
1104
|
+
case 'Blinn' :
|
|
1105
|
+
case 'Phong' :
|
|
1106
|
+
materialType = THREE.MeshPhongMaterial;
|
|
1107
|
+
break;
|
|
1108
|
+
|
|
1109
|
+
case 'Lambert' :
|
|
1110
|
+
materialType = THREE.MeshLambertMaterial;
|
|
1111
|
+
break;
|
|
1112
|
+
|
|
1113
|
+
default :
|
|
1114
|
+
materialType = THREE.MeshBasicMaterial;
|
|
1115
|
+
break;
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
if (profile.extras && profile.extras.doubleSided)
|
|
1119
|
+
{
|
|
1120
|
+
params.side = THREE.DoubleSide;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
else if (defaultPass.instanceProgram) {
|
|
1125
|
+
|
|
1126
|
+
var instanceProgram = defaultPass.instanceProgram;
|
|
1127
|
+
|
|
1128
|
+
this.createShaderParams(materialId, values, params, instanceProgram);
|
|
1129
|
+
|
|
1130
|
+
var loadshaders = true;
|
|
1131
|
+
|
|
1132
|
+
if (loadshaders) {
|
|
1133
|
+
materialType = Material;
|
|
1134
|
+
}
|
|
1135
|
+
}
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
var texturePath = null;
|
|
1139
|
+
var textureParams = null;
|
|
1140
|
+
var diffuse = values.diffuse;
|
|
1141
|
+
if (diffuse)
|
|
1142
|
+
{
|
|
1143
|
+
var texture = diffuse;
|
|
1144
|
+
if (texture) {
|
|
1145
|
+
var textureEntry = this.resources.getEntry(texture);
|
|
1146
|
+
if (textureEntry) {
|
|
1147
|
+
{
|
|
1148
|
+
var imageEntry = this.resources.getEntry(textureEntry.description.source);
|
|
1149
|
+
if (imageEntry) {
|
|
1150
|
+
texturePath = imageEntry.description.path;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
var samplerEntry = this.resources.getEntry(textureEntry.description.sampler);
|
|
1154
|
+
if (samplerEntry) {
|
|
1155
|
+
textureParams = samplerEntry.description;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
var texture = LoadTexture(texturePath);
|
|
1163
|
+
if (texture && textureParams) {
|
|
1164
|
+
|
|
1165
|
+
if (textureParams.wrapS == WebGLRenderingContext.REPEAT)
|
|
1166
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
1167
|
+
|
|
1168
|
+
if (textureParams.wrapT == WebGLRenderingContext.REPEAT)
|
|
1169
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
1170
|
+
|
|
1171
|
+
if (textureParams.magFilter == WebGLRenderingContext.LINEAR)
|
|
1172
|
+
texture.magFilter = THREE.LinearFilter;
|
|
1173
|
+
|
|
1174
|
+
// if (textureParams.minFilter == "LINEAR")
|
|
1175
|
+
// texture.minFilter = THREE.LinearFilter;
|
|
1176
|
+
|
|
1177
|
+
params.map = texture;
|
|
1178
|
+
}
|
|
1179
|
+
|
|
1180
|
+
var envMapPath = null;
|
|
1181
|
+
var envMapParams = null;
|
|
1182
|
+
var reflective = values.reflective;
|
|
1183
|
+
if (reflective)
|
|
1184
|
+
{
|
|
1185
|
+
var texture = reflective;
|
|
1186
|
+
if (texture) {
|
|
1187
|
+
var textureEntry = this.resources.getEntry(texture);
|
|
1188
|
+
if (textureEntry) {
|
|
1189
|
+
{
|
|
1190
|
+
var imageEntry = this.resources.getEntry(textureEntry.description.source);
|
|
1191
|
+
if (imageEntry) {
|
|
1192
|
+
envMapPath = imageEntry.description.path;
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
var samplerEntry = this.resources.getEntry(textureEntry.description.sampler);
|
|
1196
|
+
if (samplerEntry) {
|
|
1197
|
+
envMapParams = samplerEntry.description;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1203
|
+
|
|
1204
|
+
var texture = LoadTexture(envMapPath);
|
|
1205
|
+
if (texture && envMapParams) {
|
|
1206
|
+
|
|
1207
|
+
if (envMapParams.wrapS == WebGLRenderingContext.REPEAT)
|
|
1208
|
+
texture.wrapS = THREE.RepeatWrapping;
|
|
1209
|
+
|
|
1210
|
+
if (envMapParams.wrapT == WebGLRenderingContext.REPEAT)
|
|
1211
|
+
texture.wrapT = THREE.RepeatWrapping;
|
|
1212
|
+
|
|
1213
|
+
if (envMapParams.magFilter == WebGLRenderingContext.LINEAR)
|
|
1214
|
+
texture.magFilter = THREE.LinearFilter;
|
|
1215
|
+
|
|
1216
|
+
// if (envMapParams.minFilter == WebGLRenderingContext.LINEAR)
|
|
1217
|
+
// texture.minFilter = THREE.LinearFilter;
|
|
1218
|
+
|
|
1219
|
+
params.envMap = texture;
|
|
1220
|
+
}
|
|
1221
|
+
|
|
1222
|
+
var shininess = values.shininesss || values.shininess; // N.B.: typo in converter!
|
|
1223
|
+
if (shininess)
|
|
1224
|
+
{
|
|
1225
|
+
shininess = shininess;
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
var diffuseColor = !texturePath ? diffuse : null;
|
|
1229
|
+
var opacity = 1.0;
|
|
1230
|
+
if (values.hasOwnProperty("transparency"))
|
|
1231
|
+
{
|
|
1232
|
+
var USE_A_ONE = true; // for now, hack because file format isn't telling us
|
|
1233
|
+
opacity = USE_A_ONE ? values.transparency : (1.0 - values.transparency);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
// if (diffuseColor) diffuseColor = [0, 1, 0];
|
|
1237
|
+
|
|
1238
|
+
params.color = RgbArraytoHex(diffuseColor);
|
|
1239
|
+
params.opacity = opacity;
|
|
1240
|
+
params.transparent = opacity < 1.0;
|
|
1241
|
+
// hack hack hack
|
|
1242
|
+
if (texturePath && texturePath.toLowerCase().indexOf(".png") != -1)
|
|
1243
|
+
params.transparent = true;
|
|
1244
|
+
|
|
1245
|
+
if (!(shininess === undefined))
|
|
1246
|
+
{
|
|
1247
|
+
params.shininess = shininess;
|
|
1248
|
+
}
|
|
1249
|
+
|
|
1250
|
+
if (!(values.ambient === undefined) && !(typeof(values.ambient) == 'string'))
|
|
1251
|
+
{
|
|
1252
|
+
params.ambient = RgbArraytoHex(values.ambient);
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
if (!(values.emission === undefined))
|
|
1256
|
+
{
|
|
1257
|
+
params.emissive = RgbArraytoHex(values.emission);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
if (!(values.specular === undefined))
|
|
1261
|
+
{
|
|
1262
|
+
params.specular = RgbArraytoHex(values.specular);
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
return materialType;
|
|
1266
|
+
|
|
1267
|
+
}
|
|
1268
|
+
},
|
|
1269
|
+
|
|
1270
|
+
handleMaterial: {
|
|
1271
|
+
value: function(entryID, description, userInfo) {
|
|
1272
|
+
//this should be rewritten using the meta datas that actually create the shader.
|
|
1273
|
+
//here we will infer what needs to be pass to Three.js by looking inside the technique parameters.
|
|
1274
|
+
var technique = this.resources.getEntry(description.instanceTechnique.technique);
|
|
1275
|
+
var materialParams = {};
|
|
1276
|
+
var values = description.instanceTechnique.values;
|
|
1277
|
+
|
|
1278
|
+
var materialType = this.threeJSMaterialType(entryID, technique, values, materialParams);
|
|
1279
|
+
|
|
1280
|
+
var material = new materialType(materialParams);
|
|
1281
|
+
|
|
1282
|
+
this.resources.setEntry(entryID, material, description);
|
|
1283
|
+
|
|
1284
|
+
return true;
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
|
|
1288
|
+
handleMesh: {
|
|
1289
|
+
value: function(entryID, description, userInfo) {
|
|
1290
|
+
var mesh = new Mesh();
|
|
1291
|
+
this.resources.setEntry(entryID, mesh, description);
|
|
1292
|
+
var primitivesDescription = description.primitives;
|
|
1293
|
+
if (!primitivesDescription) {
|
|
1294
|
+
//FIXME: not implemented in delegate
|
|
1295
|
+
console.log("MISSING_PRIMITIVES for mesh:"+ entryID);
|
|
1296
|
+
return false;
|
|
1297
|
+
}
|
|
1298
|
+
|
|
1299
|
+
for (var i = 0 ; i < primitivesDescription.length ; i++) {
|
|
1300
|
+
var primitiveDescription = primitivesDescription[i];
|
|
1301
|
+
|
|
1302
|
+
if (primitiveDescription.primitive === WebGLRenderingContext.TRIANGLES) {
|
|
1303
|
+
|
|
1304
|
+
var geometry = new ClassicGeometry();
|
|
1305
|
+
var materialEntry = this.resources.getEntry(primitiveDescription.material);
|
|
1306
|
+
|
|
1307
|
+
mesh.addPrimitive(geometry, materialEntry.object);
|
|
1308
|
+
|
|
1309
|
+
var indices = this.resources.getEntry(primitiveDescription.indices);
|
|
1310
|
+
var bufferEntry = this.resources.getEntry(indices.description.bufferView);
|
|
1311
|
+
var indicesObject = {
|
|
1312
|
+
bufferView : bufferEntry,
|
|
1313
|
+
byteOffset : indices.description.byteOffset,
|
|
1314
|
+
count : indices.description.count,
|
|
1315
|
+
id : indices.entryID,
|
|
1316
|
+
type : indices.description.type
|
|
1317
|
+
};
|
|
1318
|
+
|
|
1319
|
+
var indicesContext = new IndicesContext(indicesObject, geometry);
|
|
1320
|
+
var alreadyProcessedIndices = THREE.GLTFLoaderUtils.getBuffer(indicesObject, indicesDelegate, indicesContext);
|
|
1321
|
+
/*if(alreadyProcessedIndices) {
|
|
1322
|
+
indicesDelegate.resourceAvailable(alreadyProcessedIndices, indicesContext);
|
|
1323
|
+
}*/
|
|
1324
|
+
|
|
1325
|
+
// Load Vertex Attributes
|
|
1326
|
+
var allAttributes = Object.keys(primitiveDescription.attributes);
|
|
1327
|
+
allAttributes.forEach( function(semantic) {
|
|
1328
|
+
geometry.totalAttributes++;
|
|
1329
|
+
|
|
1330
|
+
var attribute;
|
|
1331
|
+
var attributeID = primitiveDescription.attributes[semantic];
|
|
1332
|
+
var attributeEntry = this.resources.getEntry(attributeID);
|
|
1333
|
+
if (!attributeEntry) {
|
|
1334
|
+
//let's just use an anonymous object for the attribute
|
|
1335
|
+
attribute = description.attributes[attributeID];
|
|
1336
|
+
attribute.id = attributeID;
|
|
1337
|
+
this.resources.setEntry(attributeID, attribute, attribute);
|
|
1338
|
+
|
|
1339
|
+
var bufferEntry = this.resources.getEntry(attribute.bufferView);
|
|
1340
|
+
attributeEntry = this.resources.getEntry(attributeID);
|
|
1341
|
+
|
|
1342
|
+
} else {
|
|
1343
|
+
attribute = attributeEntry.object;
|
|
1344
|
+
attribute.id = attributeID;
|
|
1345
|
+
var bufferEntry = this.resources.getEntry(attribute.bufferView);
|
|
1346
|
+
}
|
|
1347
|
+
|
|
1348
|
+
var attributeObject = {
|
|
1349
|
+
bufferView : bufferEntry,
|
|
1350
|
+
byteOffset : attribute.byteOffset,
|
|
1351
|
+
byteStride : attribute.byteStride,
|
|
1352
|
+
count : attribute.count,
|
|
1353
|
+
max : attribute.max,
|
|
1354
|
+
min : attribute.min,
|
|
1355
|
+
type : attribute.type,
|
|
1356
|
+
id : attributeID
|
|
1357
|
+
};
|
|
1358
|
+
|
|
1359
|
+
var attribContext = new VertexAttributeContext(attributeObject, semantic, geometry);
|
|
1360
|
+
|
|
1361
|
+
var alreadyProcessedAttribute = THREE.GLTFLoaderUtils.getBuffer(attributeObject, vertexAttributeDelegate, attribContext);
|
|
1362
|
+
/*if(alreadyProcessedAttribute) {
|
|
1363
|
+
vertexAttributeDelegate.resourceAvailable(alreadyProcessedAttribute, attribContext);
|
|
1364
|
+
}*/
|
|
1365
|
+
}, this);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
return true;
|
|
1369
|
+
}
|
|
1370
|
+
},
|
|
1371
|
+
|
|
1372
|
+
handleCamera: {
|
|
1373
|
+
value: function(entryID, description, userInfo) {
|
|
1374
|
+
var camera;
|
|
1375
|
+
if (description.type == "perspective")
|
|
1376
|
+
{
|
|
1377
|
+
var znear = description.perspective.znear;
|
|
1378
|
+
var zfar = description.perspective.zfar;
|
|
1379
|
+
var yfov = description.perspective.yfov;
|
|
1380
|
+
var xfov = description.perspective.xfov;
|
|
1381
|
+
var aspect_ratio = description.perspective.aspect_ratio;
|
|
1382
|
+
|
|
1383
|
+
if (!aspect_ratio)
|
|
1384
|
+
aspect_ratio = 1;
|
|
1385
|
+
|
|
1386
|
+
if (yfov === undefined)
|
|
1387
|
+
{
|
|
1388
|
+
if (xfov)
|
|
1389
|
+
{
|
|
1390
|
+
// According to COLLADA spec...
|
|
1391
|
+
// aspect_ratio = xfov / yfov
|
|
1392
|
+
yfov = xfov / aspect_ratio;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1395
|
+
}
|
|
1396
|
+
|
|
1397
|
+
if (yfov)
|
|
1398
|
+
{
|
|
1399
|
+
camera = new THREE.PerspectiveCamera(yfov, aspect_ratio, znear, zfar);
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
else
|
|
1403
|
+
{
|
|
1404
|
+
camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, znear, zfar );
|
|
1405
|
+
}
|
|
1406
|
+
|
|
1407
|
+
if (camera)
|
|
1408
|
+
{
|
|
1409
|
+
this.resources.setEntry(entryID, camera, description);
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
return true;
|
|
1413
|
+
}
|
|
1414
|
+
},
|
|
1415
|
+
|
|
1416
|
+
handleLight: {
|
|
1417
|
+
value: function(entryID, description, userInfo) {
|
|
1418
|
+
|
|
1419
|
+
var light = null;
|
|
1420
|
+
var type = description.type;
|
|
1421
|
+
console.log('HANDLELIGHT', type, description[type]);
|
|
1422
|
+
if (type && description[type])
|
|
1423
|
+
{
|
|
1424
|
+
var lparams = description[type];
|
|
1425
|
+
var color = RgbArraytoHex(lparams.color);
|
|
1426
|
+
|
|
1427
|
+
switch (type) {
|
|
1428
|
+
case "directional" :
|
|
1429
|
+
light = new THREE.DirectionalLight(color);
|
|
1430
|
+
light.position.set(0, 0, 1);
|
|
1431
|
+
break;
|
|
1432
|
+
|
|
1433
|
+
case "point" :
|
|
1434
|
+
light = new THREE.PointLight(color);
|
|
1435
|
+
break;
|
|
1436
|
+
|
|
1437
|
+
case "spot" :
|
|
1438
|
+
light = new THREE.SpotLight(color);
|
|
1439
|
+
light.position.set(0, 0, 1);
|
|
1440
|
+
light.castShadow = true;
|
|
1441
|
+
light.shadowCameraVisible = true;
|
|
1442
|
+
light.shadowCameraNear = .5;
|
|
1443
|
+
light.shadowCameraFar = 100;
|
|
1444
|
+
light.shadowCameraFov = 120;
|
|
1445
|
+
light.shadowCameraWidth = 2048;
|
|
1446
|
+
light.shadowCameraHeight = 2048;
|
|
1447
|
+
break;
|
|
1448
|
+
|
|
1449
|
+
case "ambient" :
|
|
1450
|
+
light = new THREE.AmbientLight(color);
|
|
1451
|
+
break;
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
|
|
1455
|
+
console.log('do light!', light);
|
|
1456
|
+
if (light)
|
|
1457
|
+
{
|
|
1458
|
+
this.resources.setEntry(entryID, light, description);
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
return true;
|
|
1462
|
+
}
|
|
1463
|
+
},
|
|
1464
|
+
|
|
1465
|
+
addPendingMesh: {
|
|
1466
|
+
value: function(mesh, threeNode) {
|
|
1467
|
+
theLoader.pendingMeshes.push({
|
|
1468
|
+
mesh: mesh,
|
|
1469
|
+
node: threeNode
|
|
1470
|
+
});
|
|
1471
|
+
}
|
|
1472
|
+
},
|
|
1473
|
+
|
|
1474
|
+
handleNode: {
|
|
1475
|
+
value: function(entryID, description, userInfo) {
|
|
1476
|
+
|
|
1477
|
+
var threeNode = null;
|
|
1478
|
+
if (description.jointId) {
|
|
1479
|
+
threeNode = new THREE.Bone();
|
|
1480
|
+
threeNode.jointId = description.jointId;
|
|
1481
|
+
this.joints[description.jointId] = entryID;
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
threeNode = new THREE.Object3D();
|
|
1485
|
+
}
|
|
1486
|
+
|
|
1487
|
+
threeNode.name = description.name;
|
|
1488
|
+
|
|
1489
|
+
this.resources.setEntry(entryID, threeNode, description);
|
|
1490
|
+
|
|
1491
|
+
var m = description.matrix;
|
|
1492
|
+
if(m) {
|
|
1493
|
+
threeNode.applyMatrix(new THREE.Matrix4(
|
|
1494
|
+
m[0], m[4], m[8], m[12],
|
|
1495
|
+
m[1], m[5], m[9], m[13],
|
|
1496
|
+
m[2], m[6], m[10], m[14],
|
|
1497
|
+
m[3], m[7], m[11], m[15]
|
|
1498
|
+
));
|
|
1499
|
+
threeNode.matrixAutoUpdate = false;
|
|
1500
|
+
threeNode.matrixWorldNeedsUpdate = true;
|
|
1501
|
+
}
|
|
1502
|
+
else {
|
|
1503
|
+
var t = description.translation;
|
|
1504
|
+
var r = description.rotation;
|
|
1505
|
+
var s = description.scale;
|
|
1506
|
+
|
|
1507
|
+
var position = t ? new THREE.Vector3(t[0], t[1], t[2]) :
|
|
1508
|
+
new THREE.Vector3;
|
|
1509
|
+
if (r) {
|
|
1510
|
+
convertAxisAngleToQuaternion(r, 1);
|
|
1511
|
+
}
|
|
1512
|
+
var rotation = r ? new THREE.Quaternion(r[0], r[1], r[2], r[3]) :
|
|
1513
|
+
new THREE.Quaternion;
|
|
1514
|
+
var scale = s ? new THREE.Vector3(s[0], s[1], s[2]) :
|
|
1515
|
+
new THREE.Vector3;
|
|
1516
|
+
|
|
1517
|
+
var matrix = new THREE.Matrix4;
|
|
1518
|
+
matrix.compose(position, rotation, scale);
|
|
1519
|
+
threeNode.matrixAutoUpdate = false;
|
|
1520
|
+
threeNode.matrixWorldNeedsUpdate = true;
|
|
1521
|
+
threeNode.applyMatrix(matrix);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
var self = this;
|
|
1525
|
+
|
|
1526
|
+
// Iterate through all node meshes and attach the appropriate objects
|
|
1527
|
+
//FIXME: decision needs to be made between these 2 ways, probably meshes will be discarded.
|
|
1528
|
+
var meshEntry;
|
|
1529
|
+
if (description.mesh) {
|
|
1530
|
+
meshEntry = this.resources.getEntry(description.mesh);
|
|
1531
|
+
theLoader.meshesRequested++;
|
|
1532
|
+
meshEntry.object.onComplete(function(mesh) {
|
|
1533
|
+
self.addPendingMesh(mesh, threeNode);
|
|
1534
|
+
theLoader.meshesLoaded++;
|
|
1535
|
+
theLoader.checkComplete();
|
|
1536
|
+
});
|
|
1537
|
+
}
|
|
1538
|
+
|
|
1539
|
+
if (description.meshes) {
|
|
1540
|
+
description.meshes.forEach( function(meshID) {
|
|
1541
|
+
meshEntry = this.resources.getEntry(meshID);
|
|
1542
|
+
theLoader.meshesRequested++;
|
|
1543
|
+
meshEntry.object.onComplete(function(mesh) {
|
|
1544
|
+
self.addPendingMesh(mesh, threeNode);
|
|
1545
|
+
theLoader.meshesLoaded++;
|
|
1546
|
+
theLoader.checkComplete();
|
|
1547
|
+
});
|
|
1548
|
+
}, this);
|
|
1549
|
+
}
|
|
1550
|
+
|
|
1551
|
+
if (description.instanceSkin) {
|
|
1552
|
+
|
|
1553
|
+
var skinEntry = this.resources.getEntry(description.instanceSkin.skin);
|
|
1554
|
+
|
|
1555
|
+
if (skinEntry) {
|
|
1556
|
+
|
|
1557
|
+
var skin = skinEntry.object;
|
|
1558
|
+
description.instanceSkin.skin = skin;
|
|
1559
|
+
threeNode.instanceSkin = description.instanceSkin;
|
|
1560
|
+
|
|
1561
|
+
var sources = description.instanceSkin.sources;
|
|
1562
|
+
skin.meshes = [];
|
|
1563
|
+
sources.forEach( function(meshID) {
|
|
1564
|
+
meshEntry = this.resources.getEntry(meshID);
|
|
1565
|
+
theLoader.meshesRequested++;
|
|
1566
|
+
meshEntry.object.onComplete(function(mesh) {
|
|
1567
|
+
|
|
1568
|
+
skin.meshes.push(mesh);
|
|
1569
|
+
theLoader.meshesLoaded++;
|
|
1570
|
+
theLoader.checkComplete();
|
|
1571
|
+
});
|
|
1572
|
+
}, this);
|
|
1573
|
+
|
|
1574
|
+
}
|
|
1575
|
+
}
|
|
1576
|
+
|
|
1577
|
+
if (description.camera) {
|
|
1578
|
+
var cameraEntry = this.resources.getEntry(description.camera);
|
|
1579
|
+
if (cameraEntry) {
|
|
1580
|
+
threeNode.add(cameraEntry.object);
|
|
1581
|
+
this.cameras.push(cameraEntry.object);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
if (description.light) {
|
|
1586
|
+
var lightEntry = this.resources.getEntry(description.light);
|
|
1587
|
+
if (lightEntry) {
|
|
1588
|
+
threeNode.add(lightEntry.object);
|
|
1589
|
+
this.lights.push(lightEntry.object);
|
|
1590
|
+
}
|
|
1591
|
+
}
|
|
1592
|
+
|
|
1593
|
+
return true;
|
|
1594
|
+
}
|
|
1595
|
+
},
|
|
1596
|
+
|
|
1597
|
+
buildNodeHirerachy: {
|
|
1598
|
+
value: function(nodeEntryId, parentThreeNode) {
|
|
1599
|
+
var nodeEntry = this.resources.getEntry(nodeEntryId);
|
|
1600
|
+
var threeNode = nodeEntry.object;
|
|
1601
|
+
parentThreeNode.add(threeNode);
|
|
1602
|
+
|
|
1603
|
+
var children = nodeEntry.description.children;
|
|
1604
|
+
if (children) {
|
|
1605
|
+
children.forEach( function(childID) {
|
|
1606
|
+
this.buildNodeHirerachy(childID, threeNode);
|
|
1607
|
+
}, this);
|
|
1608
|
+
}
|
|
1609
|
+
|
|
1610
|
+
return threeNode;
|
|
1611
|
+
}
|
|
1612
|
+
},
|
|
1613
|
+
|
|
1614
|
+
buildSkin: {
|
|
1615
|
+
value: function(node) {
|
|
1616
|
+
|
|
1617
|
+
var skin = node.instanceSkin.skin;
|
|
1618
|
+
if (skin) {
|
|
1619
|
+
node.instanceSkin.skeletons.forEach(function(skeleton) {
|
|
1620
|
+
var nodeEntry = this.resources.getEntry(skeleton);
|
|
1621
|
+
if (nodeEntry) {
|
|
1622
|
+
|
|
1623
|
+
var rootSkeleton = nodeEntry.object;
|
|
1624
|
+
|
|
1625
|
+
var dobones = true;
|
|
1626
|
+
|
|
1627
|
+
var i, len = skin.meshes.length;
|
|
1628
|
+
for (i = 0; i < len; i++) {
|
|
1629
|
+
var mesh = skin.meshes[i];
|
|
1630
|
+
var threeMesh = null;
|
|
1631
|
+
mesh.primitives.forEach(function(primitive) {
|
|
1632
|
+
|
|
1633
|
+
var material = primitive.material;
|
|
1634
|
+
if (!(material instanceof THREE.Material)) {
|
|
1635
|
+
material = this.createShaderMaterial(material);
|
|
1636
|
+
}
|
|
1637
|
+
|
|
1638
|
+
threeMesh = new THREE.SkinnedMesh(primitive.geometry.geometry, material, false);
|
|
1639
|
+
threeMesh.add(rootSkeleton);
|
|
1640
|
+
|
|
1641
|
+
var geometry = primitive.geometry.geometry;
|
|
1642
|
+
var j;
|
|
1643
|
+
if (geometry.vertices) {
|
|
1644
|
+
for ( j = 0; j < geometry.vertices.length; j ++ ) {
|
|
1645
|
+
geometry.vertices[j].applyMatrix4( skin.bindShapeMatrix );
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1648
|
+
else if (geometry.attributes.position) {
|
|
1649
|
+
var a = geometry.attributes.position.array;
|
|
1650
|
+
var v = new THREE.Vector3;
|
|
1651
|
+
for ( j = 0; j < a.length / 3; j++ ) {
|
|
1652
|
+
v.set(a[j * 3], a[j * 3 + 1], a[j * 3 + 2]);
|
|
1653
|
+
v.applyMatrix4( skin.bindShapeMatrix );
|
|
1654
|
+
a[j * 3] = v.x;
|
|
1655
|
+
a[j * 3 + 1] = v.y;
|
|
1656
|
+
a[j * 3 + 2] = v.z;
|
|
1657
|
+
}
|
|
1658
|
+
}
|
|
1659
|
+
|
|
1660
|
+
if (threeMesh && dobones) {
|
|
1661
|
+
|
|
1662
|
+
material.skinning = true;
|
|
1663
|
+
|
|
1664
|
+
threeMesh.boneInverses = [];
|
|
1665
|
+
var jointsIds = skin.jointsIds;
|
|
1666
|
+
var joints = [];
|
|
1667
|
+
var i, len = jointsIds.length;
|
|
1668
|
+
for (i = 0; i < len; i++) {
|
|
1669
|
+
var jointId = jointsIds[i];
|
|
1670
|
+
var nodeForJoint = this.joints[jointId];
|
|
1671
|
+
var joint = this.resources.getEntry(nodeForJoint).object;
|
|
1672
|
+
if (joint) {
|
|
1673
|
+
|
|
1674
|
+
joint.skin = threeMesh;
|
|
1675
|
+
joints.push(joint);
|
|
1676
|
+
threeMesh.bones.push(joint);
|
|
1677
|
+
|
|
1678
|
+
var m = skin.inverseBindMatrices;
|
|
1679
|
+
var mat = new THREE.Matrix4(
|
|
1680
|
+
m[i * 16 + 0], m[i * 16 + 4], m[i * 16 + 8], m[i * 16 + 12],
|
|
1681
|
+
m[i * 16 + 1], m[i * 16 + 5], m[i * 16 + 9], m[i * 16 + 13],
|
|
1682
|
+
m[i * 16 + 2], m[i * 16 + 6], m[i * 16 + 10], m[i * 16 + 14],
|
|
1683
|
+
m[i * 16 + 3], m[i * 16 + 7], m[i * 16 + 11], m[i * 16 + 15]
|
|
1684
|
+
);
|
|
1685
|
+
threeMesh.boneInverses.push(mat);
|
|
1686
|
+
threeMesh.pose();
|
|
1687
|
+
|
|
1688
|
+
} else {
|
|
1689
|
+
console.log("WARNING: jointId:"+jointId+" cannot be found in skeleton:"+skeleton);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
if (threeMesh) {
|
|
1695
|
+
threeMesh.castShadow = true;
|
|
1696
|
+
node.add(threeMesh);
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
}, this);
|
|
1700
|
+
}
|
|
1701
|
+
|
|
1702
|
+
}
|
|
1703
|
+
|
|
1704
|
+
|
|
1705
|
+
}, this);
|
|
1706
|
+
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1709
|
+
},
|
|
1710
|
+
|
|
1711
|
+
buildSkins: {
|
|
1712
|
+
value: function(node) {
|
|
1713
|
+
|
|
1714
|
+
if (node.instanceSkin)
|
|
1715
|
+
this.buildSkin(node);
|
|
1716
|
+
|
|
1717
|
+
var children = node.children;
|
|
1718
|
+
if (children) {
|
|
1719
|
+
children.forEach( function(child) {
|
|
1720
|
+
this.buildSkins(child);
|
|
1721
|
+
}, this);
|
|
1722
|
+
}
|
|
1723
|
+
}
|
|
1724
|
+
},
|
|
1725
|
+
|
|
1726
|
+
createMeshAnimations : {
|
|
1727
|
+
value : function(root) {
|
|
1728
|
+
this.buildSkins(root);
|
|
1729
|
+
}
|
|
1730
|
+
},
|
|
1731
|
+
|
|
1732
|
+
handleScene: {
|
|
1733
|
+
value: function(entryID, description, userInfo) {
|
|
1734
|
+
|
|
1735
|
+
if (!description.nodes) {
|
|
1736
|
+
console.log("ERROR: invalid file required nodes property is missing from scene");
|
|
1737
|
+
return false;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
description.nodes.forEach( function(nodeUID) {
|
|
1741
|
+
this.buildNodeHirerachy(nodeUID, userInfo.rootObj);
|
|
1742
|
+
}, this);
|
|
1743
|
+
|
|
1744
|
+
if (this.delegate) {
|
|
1745
|
+
this.delegate.loadCompleted(userInfo.callback, userInfo.rootObj);
|
|
1746
|
+
}
|
|
1747
|
+
|
|
1748
|
+
return true;
|
|
1749
|
+
}
|
|
1750
|
+
},
|
|
1751
|
+
|
|
1752
|
+
handleImage: {
|
|
1753
|
+
value: function(entryID, description, userInfo) {
|
|
1754
|
+
this.resources.setEntry(entryID, null, description);
|
|
1755
|
+
return true;
|
|
1756
|
+
}
|
|
1757
|
+
},
|
|
1758
|
+
|
|
1759
|
+
addNodeAnimationChannel : {
|
|
1760
|
+
value : function(name, channel, interp) {
|
|
1761
|
+
if (!this.nodeAnimationChannels)
|
|
1762
|
+
this.nodeAnimationChannels = {};
|
|
1763
|
+
|
|
1764
|
+
if (!this.nodeAnimationChannels[name]) {
|
|
1765
|
+
this.nodeAnimationChannels[name] = [];
|
|
1766
|
+
}
|
|
1767
|
+
|
|
1768
|
+
this.nodeAnimationChannels[name].push(interp);
|
|
1769
|
+
},
|
|
1770
|
+
},
|
|
1771
|
+
|
|
1772
|
+
createAnimations : {
|
|
1773
|
+
value : function() {
|
|
1774
|
+
for (var name in this.nodeAnimationChannels) {
|
|
1775
|
+
var nodeAnimationChannels = this.nodeAnimationChannels[name];
|
|
1776
|
+
var i, len = nodeAnimationChannels.length;
|
|
1777
|
+
//console.log(" animation channels for node " + name);
|
|
1778
|
+
//for (i = 0; i < len; i++) {
|
|
1779
|
+
// console.log(nodeAnimationChannels[i]);
|
|
1780
|
+
//}
|
|
1781
|
+
var anim = new THREE.glTFAnimation(nodeAnimationChannels);
|
|
1782
|
+
anim.name = "animation_" + name;
|
|
1783
|
+
this.animations.push(anim);
|
|
1784
|
+
}
|
|
1785
|
+
}
|
|
1786
|
+
},
|
|
1787
|
+
|
|
1788
|
+
buildAnimation: {
|
|
1789
|
+
value : function(animation) {
|
|
1790
|
+
|
|
1791
|
+
var interps = [];
|
|
1792
|
+
var i, len = animation.channels.length;
|
|
1793
|
+
for (i = 0; i < len; i++) {
|
|
1794
|
+
|
|
1795
|
+
var channel = animation.channels[i];
|
|
1796
|
+
var sampler = animation.samplers[channel.sampler];
|
|
1797
|
+
if (sampler) {
|
|
1798
|
+
|
|
1799
|
+
var input = animation.parameters[sampler.input];
|
|
1800
|
+
if (input && input.data) {
|
|
1801
|
+
|
|
1802
|
+
var output = animation.parameters[sampler.output];
|
|
1803
|
+
if (output && output.data) {
|
|
1804
|
+
|
|
1805
|
+
var target = channel.target;
|
|
1806
|
+
var node = this.resources.getEntry(target.id);
|
|
1807
|
+
if (node) {
|
|
1808
|
+
|
|
1809
|
+
var path = target.path;
|
|
1810
|
+
|
|
1811
|
+
if (path == "rotation")
|
|
1812
|
+
{
|
|
1813
|
+
convertAxisAngleToQuaternion(output.data, output.count);
|
|
1814
|
+
}
|
|
1815
|
+
|
|
1816
|
+
var interp = {
|
|
1817
|
+
keys : input.data,
|
|
1818
|
+
values : output.data,
|
|
1819
|
+
count : input.count,
|
|
1820
|
+
target : node.object,
|
|
1821
|
+
path : path,
|
|
1822
|
+
type : sampler.interpolation
|
|
1823
|
+
};
|
|
1824
|
+
|
|
1825
|
+
this.addNodeAnimationChannel(target.id, channel, interp);
|
|
1826
|
+
interps.push(interp);
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
}
|
|
1833
|
+
},
|
|
1834
|
+
|
|
1835
|
+
handleAnimation: {
|
|
1836
|
+
value: function(entryID, description, userInfo) {
|
|
1837
|
+
|
|
1838
|
+
var self = this;
|
|
1839
|
+
theLoader.animationsRequested++;
|
|
1840
|
+
var animation = new Animation();
|
|
1841
|
+
animation.name = entryID;
|
|
1842
|
+
animation.onload = function() {
|
|
1843
|
+
// self.buildAnimation(animation);
|
|
1844
|
+
theLoader.animationsLoaded++;
|
|
1845
|
+
theLoader.animations.push(animation);
|
|
1846
|
+
theLoader.checkComplete();
|
|
1847
|
+
};
|
|
1848
|
+
|
|
1849
|
+
animation.channels = description.channels;
|
|
1850
|
+
animation.samplers = description.samplers;
|
|
1851
|
+
this.resources.setEntry(entryID, animation, description);
|
|
1852
|
+
var parameters = description.parameters;
|
|
1853
|
+
if (!parameters) {
|
|
1854
|
+
//FIXME: not implemented in delegate
|
|
1855
|
+
console.log("MISSING_PARAMETERS for animation:"+ entryID);
|
|
1856
|
+
return false;
|
|
1857
|
+
}
|
|
1858
|
+
|
|
1859
|
+
// Load parameter buffers
|
|
1860
|
+
var params = Object.keys(parameters);
|
|
1861
|
+
params.forEach( function(param) {
|
|
1862
|
+
|
|
1863
|
+
animation.totalParameters++;
|
|
1864
|
+
var parameter = parameters[param];
|
|
1865
|
+
var accessor = this.resources.getEntry(parameter);
|
|
1866
|
+
if (!accessor)
|
|
1867
|
+
debugger;
|
|
1868
|
+
accessor = accessor.object;
|
|
1869
|
+
var bufferView = this.resources.getEntry(accessor.bufferView);
|
|
1870
|
+
var paramObject = {
|
|
1871
|
+
bufferView : bufferView,
|
|
1872
|
+
byteOffset : accessor.byteOffset,
|
|
1873
|
+
count : accessor.count,
|
|
1874
|
+
type : accessor.type,
|
|
1875
|
+
id : accessor.bufferView,
|
|
1876
|
+
name : param
|
|
1877
|
+
};
|
|
1878
|
+
|
|
1879
|
+
var paramContext = new AnimationParameterContext(paramObject, animation);
|
|
1880
|
+
|
|
1881
|
+
var alreadyProcessedAttribute = THREE.GLTFLoaderUtils.getBuffer(paramObject, animationParameterDelegate, paramContext);
|
|
1882
|
+
/*if(alreadyProcessedAttribute) {
|
|
1883
|
+
vertexAttributeDelegate.resourceAvailable(alreadyProcessedAttribute, attribContext);
|
|
1884
|
+
}*/
|
|
1885
|
+
}, this);
|
|
1886
|
+
|
|
1887
|
+
return true;
|
|
1888
|
+
}
|
|
1889
|
+
},
|
|
1890
|
+
|
|
1891
|
+
handleAccessor: {
|
|
1892
|
+
value: function(entryID, description, userInfo) {
|
|
1893
|
+
// Save attribute entry
|
|
1894
|
+
this.resources.setEntry(entryID, description, description);
|
|
1895
|
+
return true;
|
|
1896
|
+
}
|
|
1897
|
+
},
|
|
1898
|
+
|
|
1899
|
+
handleSkin: {
|
|
1900
|
+
value: function(entryID, description, userInfo) {
|
|
1901
|
+
// Save skin entry
|
|
1902
|
+
|
|
1903
|
+
var skin = {
|
|
1904
|
+
};
|
|
1905
|
+
|
|
1906
|
+
var m = description.bindShapeMatrix;
|
|
1907
|
+
skin.bindShapeMatrix = new THREE.Matrix4(
|
|
1908
|
+
m[0], m[4], m[8], m[12],
|
|
1909
|
+
m[1], m[5], m[9], m[13],
|
|
1910
|
+
m[2], m[6], m[10], m[14],
|
|
1911
|
+
m[3], m[7], m[11], m[15]
|
|
1912
|
+
);
|
|
1913
|
+
|
|
1914
|
+
skin.jointsIds = description.joints;
|
|
1915
|
+
var inverseBindMatricesDescription = description.inverseBindMatrices;
|
|
1916
|
+
skin.inverseBindMatricesDescription = inverseBindMatricesDescription;
|
|
1917
|
+
skin.inverseBindMatricesDescription.id = entryID + "_inverseBindMatrices";
|
|
1918
|
+
|
|
1919
|
+
var bufferEntry = this.resources.getEntry(inverseBindMatricesDescription.bufferView);
|
|
1920
|
+
|
|
1921
|
+
var paramObject = {
|
|
1922
|
+
bufferView : bufferEntry,
|
|
1923
|
+
byteOffset : inverseBindMatricesDescription.byteOffset,
|
|
1924
|
+
count : inverseBindMatricesDescription.count,
|
|
1925
|
+
type : inverseBindMatricesDescription.type,
|
|
1926
|
+
id : inverseBindMatricesDescription.bufferView,
|
|
1927
|
+
name : skin.inverseBindMatricesDescription.id
|
|
1928
|
+
};
|
|
1929
|
+
|
|
1930
|
+
var context = new InverseBindMatricesContext(paramObject, skin);
|
|
1931
|
+
|
|
1932
|
+
var alreadyProcessedAttribute = THREE.GLTFLoaderUtils.getBuffer(paramObject, inverseBindMatricesDelegate, context);
|
|
1933
|
+
|
|
1934
|
+
var bufferView = this.resources.getEntry(skin.inverseBindMatricesDescription.bufferView);
|
|
1935
|
+
skin.inverseBindMatricesDescription.bufferView =
|
|
1936
|
+
bufferView.object;
|
|
1937
|
+
this.resources.setEntry(entryID, skin, description);
|
|
1938
|
+
return true;
|
|
1939
|
+
}
|
|
1940
|
+
},
|
|
1941
|
+
|
|
1942
|
+
handleSampler: {
|
|
1943
|
+
value: function(entryID, description, userInfo) {
|
|
1944
|
+
// Save attribute entry
|
|
1945
|
+
this.resources.setEntry(entryID, description, description);
|
|
1946
|
+
return true;
|
|
1947
|
+
}
|
|
1948
|
+
},
|
|
1949
|
+
|
|
1950
|
+
handleTexture: {
|
|
1951
|
+
value: function(entryID, description, userInfo) {
|
|
1952
|
+
// Save attribute entry
|
|
1953
|
+
this.resources.setEntry(entryID, null, description);
|
|
1954
|
+
return true;
|
|
1955
|
+
}
|
|
1956
|
+
},
|
|
1957
|
+
|
|
1958
|
+
handleError: {
|
|
1959
|
+
value: function(msg) {
|
|
1960
|
+
|
|
1961
|
+
throw new Error(msg);
|
|
1962
|
+
return true;
|
|
1963
|
+
}
|
|
1964
|
+
},
|
|
1965
|
+
|
|
1966
|
+
_delegate: {
|
|
1967
|
+
value: new LoadDelegate,
|
|
1968
|
+
writable: true
|
|
1969
|
+
},
|
|
1970
|
+
|
|
1971
|
+
delegate: {
|
|
1972
|
+
enumerable: true,
|
|
1973
|
+
get: function() {
|
|
1974
|
+
return this._delegate;
|
|
1975
|
+
},
|
|
1976
|
+
set: function(value) {
|
|
1977
|
+
this._delegate = value;
|
|
1978
|
+
}
|
|
1979
|
+
}
|
|
1980
|
+
});
|
|
1981
|
+
|
|
1982
|
+
|
|
1983
|
+
// Loader
|
|
1984
|
+
|
|
1985
|
+
var Context = function(rootObj, callback) {
|
|
1986
|
+
this.rootObj = rootObj;
|
|
1987
|
+
this.callback = callback;
|
|
1988
|
+
};
|
|
1989
|
+
|
|
1990
|
+
var rootObj = new THREE.Object3D();
|
|
1991
|
+
|
|
1992
|
+
var self = this;
|
|
1993
|
+
|
|
1994
|
+
var loader = Object.create(ThreeGLTFLoader);
|
|
1995
|
+
loader.initWithPath(url);
|
|
1996
|
+
loader.load(new Context(rootObj,
|
|
1997
|
+
function(obj) {
|
|
1998
|
+
}),
|
|
1999
|
+
null);
|
|
2000
|
+
|
|
2001
|
+
this.loader = loader;
|
|
2002
|
+
this.callback = callback;
|
|
2003
|
+
this.rootObj = rootObj;
|
|
2004
|
+
return rootObj;
|
|
2005
|
+
}
|
|
2006
|
+
|
|
2007
|
+
THREE.glTFLoader.prototype.callLoadedCallback = function() {
|
|
2008
|
+
var result = {
|
|
2009
|
+
scene : this.rootObj,
|
|
2010
|
+
cameras : this.loader.cameras,
|
|
2011
|
+
animations : this.loader.animations,
|
|
2012
|
+
};
|
|
2013
|
+
|
|
2014
|
+
this.callback(result);
|
|
2015
|
+
}
|
|
2016
|
+
|
|
2017
|
+
THREE.glTFLoader.prototype.checkComplete = function() {
|
|
2018
|
+
if (this.meshesLoaded == this.meshesRequested
|
|
2019
|
+
&& this.shadersLoaded == this.shadersRequested
|
|
2020
|
+
&& this.animationsLoaded == this.animationsRequested)
|
|
2021
|
+
{
|
|
2022
|
+
|
|
2023
|
+
for (var i = 0; i < this.pendingMeshes.length; i++) {
|
|
2024
|
+
var pending = this.pendingMeshes[i];
|
|
2025
|
+
pending.mesh.attachToNode(pending.node);
|
|
2026
|
+
}
|
|
2027
|
+
|
|
2028
|
+
for (var i = 0; i < this.animationsLoaded; i++) {
|
|
2029
|
+
var animation = this.animations[i];
|
|
2030
|
+
this.loader.buildAnimation(animation);
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
this.loader.createAnimations();
|
|
2034
|
+
this.loader.createMeshAnimations(this.rootObj);
|
|
2035
|
+
|
|
2036
|
+
this.callLoadedCallback();
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
|
|
2041
|
+
|
|
2042
|
+
/**
|
|
2043
|
+
* @author Tony Parisi / http://www.tonyparisi.com/
|
|
2044
|
+
*/
|
|
2045
|
+
|
|
2046
|
+
THREE.GLTFLoaderUtils = Object.create(Object, {
|
|
2047
|
+
|
|
2048
|
+
// errors
|
|
2049
|
+
MISSING_DESCRIPTION: { value: "MISSING_DESCRIPTION" },
|
|
2050
|
+
INVALID_PATH: { value: "INVALID_PATH" },
|
|
2051
|
+
INVALID_TYPE: { value: "INVALID_TYPE" },
|
|
2052
|
+
XMLHTTPREQUEST_STATUS_ERROR: { value: "XMLHTTPREQUEST_STATUS_ERROR" },
|
|
2053
|
+
NOT_FOUND: { value: "NOT_FOUND" },
|
|
2054
|
+
// misc constants
|
|
2055
|
+
ARRAY_BUFFER: { value: "ArrayBuffer" },
|
|
2056
|
+
|
|
2057
|
+
_streams : { value:{}, writable: true },
|
|
2058
|
+
|
|
2059
|
+
_streamsStatus: { value: {}, writable: true },
|
|
2060
|
+
|
|
2061
|
+
_resources: { value: {}, writable: true },
|
|
2062
|
+
|
|
2063
|
+
_resourcesStatus: { value: {}, writable: true },
|
|
2064
|
+
|
|
2065
|
+
// initialization
|
|
2066
|
+
init: {
|
|
2067
|
+
value: function() {
|
|
2068
|
+
this._streams = {};
|
|
2069
|
+
this._streamsStatus = {};
|
|
2070
|
+
this._resources = {};
|
|
2071
|
+
this._resourcesStatus = {};
|
|
2072
|
+
}
|
|
2073
|
+
},
|
|
2074
|
+
|
|
2075
|
+
//manage entries
|
|
2076
|
+
_containsResource: {
|
|
2077
|
+
enumerable: false,
|
|
2078
|
+
value: function(resourceID) {
|
|
2079
|
+
return this._resources[resourceID] ? true : false;
|
|
2080
|
+
}
|
|
2081
|
+
},
|
|
2082
|
+
|
|
2083
|
+
_storeResource: {
|
|
2084
|
+
enumerable: false,
|
|
2085
|
+
value: function(resourceID, resource) {
|
|
2086
|
+
if (!resourceID) {
|
|
2087
|
+
console.log("ERROR: entry does not contain id, cannot store");
|
|
2088
|
+
return;
|
|
2089
|
+
}
|
|
2090
|
+
|
|
2091
|
+
if (this._containsResource[resourceID]) {
|
|
2092
|
+
console.log("WARNING: resource:"+resourceID+" is already stored, overriding");
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
this._resources[resourceID] = resource;
|
|
2096
|
+
}
|
|
2097
|
+
},
|
|
2098
|
+
|
|
2099
|
+
_getResource: {
|
|
2100
|
+
enumerable: false,
|
|
2101
|
+
value: function(resourceID) {
|
|
2102
|
+
return this._resources[resourceID];
|
|
2103
|
+
}
|
|
2104
|
+
},
|
|
2105
|
+
|
|
2106
|
+
_loadStream: {
|
|
2107
|
+
value: function(path, type, delegate) {
|
|
2108
|
+
var self = this;
|
|
2109
|
+
|
|
2110
|
+
if (!type) {
|
|
2111
|
+
delegate.handleError(THREE.GLTFLoaderUtils.INVALID_TYPE, null);
|
|
2112
|
+
return;
|
|
2113
|
+
}
|
|
2114
|
+
|
|
2115
|
+
if (!path) {
|
|
2116
|
+
delegate.handleError(THREE.GLTFLoaderUtils.INVALID_PATH);
|
|
2117
|
+
return;
|
|
2118
|
+
}
|
|
2119
|
+
|
|
2120
|
+
var xhr = new XMLHttpRequest();
|
|
2121
|
+
xhr.open('GET', path, true);
|
|
2122
|
+
xhr.responseType = (type === this.ARRAY_BUFFER) ? "arraybuffer" : "text";
|
|
2123
|
+
|
|
2124
|
+
//if this is not specified, 1 "big blob" scenes fails to load.
|
|
2125
|
+
xhr.setRequestHeader("If-Modified-Since", "Sat, 01 Jan 1970 00:00:00 GMT");
|
|
2126
|
+
xhr.addEventListener( 'load', function ( event ) {
|
|
2127
|
+
delegate.streamAvailable(path, xhr.response);
|
|
2128
|
+
}, false );
|
|
2129
|
+
xhr.addEventListener( 'error', function ( event ) {
|
|
2130
|
+
delegate.handleError(THREE.GLTFLoaderUtils.XMLHTTPREQUEST_STATUS_ERROR, xhr.status);
|
|
2131
|
+
}, false );
|
|
2132
|
+
xhr.send(null);
|
|
2133
|
+
return xhr;
|
|
2134
|
+
}
|
|
2135
|
+
},
|
|
2136
|
+
|
|
2137
|
+
send: { value: 0, writable: true },
|
|
2138
|
+
requested: { value: 0, writable: true },
|
|
2139
|
+
|
|
2140
|
+
_handleRequest: {
|
|
2141
|
+
value: function(request) {
|
|
2142
|
+
var resourceStatus = this._resourcesStatus[request.id];
|
|
2143
|
+
if (resourceStatus)
|
|
2144
|
+
{
|
|
2145
|
+
this._resourcesStatus[request.id]++;
|
|
2146
|
+
}
|
|
2147
|
+
else
|
|
2148
|
+
{
|
|
2149
|
+
this._resourcesStatus[request.id] = 1;
|
|
2150
|
+
}
|
|
2151
|
+
|
|
2152
|
+
var streamStatus = this._streamsStatus[request.path];
|
|
2153
|
+
if (streamStatus && streamStatus.status === "loading" )
|
|
2154
|
+
{
|
|
2155
|
+
streamStatus.requests.push(request);
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
|
|
2159
|
+
this._streamsStatus[request.path] = { status : "loading", requests : [request] };
|
|
2160
|
+
|
|
2161
|
+
var self = this;
|
|
2162
|
+
var processResourceDelegate = {};
|
|
2163
|
+
|
|
2164
|
+
processResourceDelegate.streamAvailable = function(path, res_) {
|
|
2165
|
+
var streamStatus = self._streamsStatus[path];
|
|
2166
|
+
var requests = streamStatus.requests;
|
|
2167
|
+
requests.forEach( function(req_) {
|
|
2168
|
+
var subArray = res_.slice(req_.range[0], req_.range[1]);
|
|
2169
|
+
var convertedResource = req_.delegate.convert(subArray, req_.ctx);
|
|
2170
|
+
self._storeResource(req_.id, convertedResource);
|
|
2171
|
+
req_.delegate.resourceAvailable(convertedResource, req_.ctx);
|
|
2172
|
+
--self._resourcesStatus[req_.id];
|
|
2173
|
+
|
|
2174
|
+
}, this);
|
|
2175
|
+
|
|
2176
|
+
delete self._streamsStatus[path];
|
|
2177
|
+
|
|
2178
|
+
};
|
|
2179
|
+
|
|
2180
|
+
processResourceDelegate.handleError = function(errorCode, info) {
|
|
2181
|
+
request.delegate.handleError(errorCode, info);
|
|
2182
|
+
}
|
|
2183
|
+
|
|
2184
|
+
return this._loadStream(request.path, request.type, processResourceDelegate);
|
|
2185
|
+
}
|
|
2186
|
+
},
|
|
2187
|
+
|
|
2188
|
+
|
|
2189
|
+
_elementSizeForGLType: {
|
|
2190
|
+
value: function(glType) {
|
|
2191
|
+
switch (glType) {
|
|
2192
|
+
case WebGLRenderingContext.FLOAT :
|
|
2193
|
+
return Float32Array.BYTES_PER_ELEMENT;
|
|
2194
|
+
case WebGLRenderingContext.UNSIGNED_BYTE :
|
|
2195
|
+
return Uint8Array.BYTES_PER_ELEMENT;
|
|
2196
|
+
case WebGLRenderingContext.UNSIGNED_SHORT :
|
|
2197
|
+
return Uint16Array.BYTES_PER_ELEMENT;
|
|
2198
|
+
case WebGLRenderingContext.FLOAT_VEC2 :
|
|
2199
|
+
return Float32Array.BYTES_PER_ELEMENT * 2;
|
|
2200
|
+
case WebGLRenderingContext.FLOAT_VEC3 :
|
|
2201
|
+
return Float32Array.BYTES_PER_ELEMENT * 3;
|
|
2202
|
+
case WebGLRenderingContext.FLOAT_VEC4 :
|
|
2203
|
+
return Float32Array.BYTES_PER_ELEMENT * 4;
|
|
2204
|
+
case WebGLRenderingContext.FLOAT_MAT3 :
|
|
2205
|
+
return Float32Array.BYTES_PER_ELEMENT * 9;
|
|
2206
|
+
case WebGLRenderingContext.FLOAT_MAT4 :
|
|
2207
|
+
return Float32Array.BYTES_PER_ELEMENT * 16;
|
|
2208
|
+
default:
|
|
2209
|
+
return null;
|
|
2210
|
+
}
|
|
2211
|
+
}
|
|
2212
|
+
},
|
|
2213
|
+
|
|
2214
|
+
_handleWrappedBufferViewResourceLoading: {
|
|
2215
|
+
value: function(wrappedBufferView, delegate, ctx) {
|
|
2216
|
+
var bufferView = wrappedBufferView.bufferView;
|
|
2217
|
+
var buffer = bufferView.buffer;
|
|
2218
|
+
var byteOffset = wrappedBufferView.byteOffset + bufferView.description.byteOffset;
|
|
2219
|
+
var range = [byteOffset , (this._elementSizeForGLType(wrappedBufferView.type) * wrappedBufferView.count) + byteOffset];
|
|
2220
|
+
|
|
2221
|
+
return this._handleRequest({ "id" : wrappedBufferView.id,
|
|
2222
|
+
"range" : range,
|
|
2223
|
+
"type" : buffer.description.type,
|
|
2224
|
+
"path" : buffer.description.path,
|
|
2225
|
+
"delegate" : delegate,
|
|
2226
|
+
"ctx" : ctx }, null);
|
|
2227
|
+
}
|
|
2228
|
+
},
|
|
2229
|
+
|
|
2230
|
+
getBuffer: {
|
|
2231
|
+
|
|
2232
|
+
value: function(wrappedBufferView, delegate, ctx) {
|
|
2233
|
+
|
|
2234
|
+
var savedBuffer = this._getResource(wrappedBufferView.id);
|
|
2235
|
+
if (savedBuffer) {
|
|
2236
|
+
return savedBuffer;
|
|
2237
|
+
} else {
|
|
2238
|
+
this._handleWrappedBufferViewResourceLoading(wrappedBufferView, delegate, ctx);
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
return null;
|
|
2242
|
+
}
|
|
2243
|
+
},
|
|
2244
|
+
|
|
2245
|
+
getFile: {
|
|
2246
|
+
|
|
2247
|
+
value: function(request, delegate, ctx) {
|
|
2248
|
+
|
|
2249
|
+
request.delegate = delegate;
|
|
2250
|
+
request.ctx = ctx;
|
|
2251
|
+
|
|
2252
|
+
return this._handleRequest({ "id" : request.id,
|
|
2253
|
+
"path" : request.path,
|
|
2254
|
+
"range" : [0],
|
|
2255
|
+
"type" : "text",
|
|
2256
|
+
"delegate" : delegate,
|
|
2257
|
+
"ctx" : ctx }, null);
|
|
2258
|
+
|
|
2259
|
+
return null;
|
|
2260
|
+
}
|
|
2261
|
+
},
|
|
2262
|
+
});
|
|
2263
|
+
/**
|
|
2264
|
+
* @author Tony Parisi / http://www.tonyparisi.com/
|
|
2265
|
+
*/
|
|
2266
|
+
|
|
2267
|
+
THREE.glTFAnimator = ( function () {
|
|
2268
|
+
|
|
2269
|
+
var animators = [];
|
|
2270
|
+
|
|
2271
|
+
return {
|
|
2272
|
+
add : function(animator)
|
|
2273
|
+
{
|
|
2274
|
+
animators.push(animator);
|
|
2275
|
+
},
|
|
2276
|
+
|
|
2277
|
+
remove: function(animator)
|
|
2278
|
+
{
|
|
2279
|
+
|
|
2280
|
+
var i = animators.indexOf(animator);
|
|
2281
|
+
|
|
2282
|
+
if ( i !== -1 ) {
|
|
2283
|
+
animators.splice( i, 1 );
|
|
2284
|
+
}
|
|
2285
|
+
},
|
|
2286
|
+
|
|
2287
|
+
update : function()
|
|
2288
|
+
{
|
|
2289
|
+
for (i = 0; i < animators.length; i++)
|
|
2290
|
+
{
|
|
2291
|
+
animators[i].update();
|
|
2292
|
+
}
|
|
2293
|
+
},
|
|
2294
|
+
};
|
|
2295
|
+
})();
|
|
2296
|
+
|
|
2297
|
+
// Construction/initialization
|
|
2298
|
+
THREE.glTFAnimation = function(interps)
|
|
2299
|
+
{
|
|
2300
|
+
this.running = false;
|
|
2301
|
+
this.loop = false;
|
|
2302
|
+
this.duration = 0;
|
|
2303
|
+
this.startTime = 0;
|
|
2304
|
+
this.interps = [];
|
|
2305
|
+
|
|
2306
|
+
if (interps)
|
|
2307
|
+
{
|
|
2308
|
+
this.createInterpolators(interps);
|
|
2309
|
+
}
|
|
2310
|
+
}
|
|
2311
|
+
|
|
2312
|
+
THREE.glTFAnimation.prototype.createInterpolators = function(interps)
|
|
2313
|
+
{
|
|
2314
|
+
var i, len = interps.length;
|
|
2315
|
+
for (i = 0; i < len; i++)
|
|
2316
|
+
{
|
|
2317
|
+
var interp = new THREE.glTFInterpolator(interps[i]);
|
|
2318
|
+
this.interps.push(interp);
|
|
2319
|
+
this.duration = Math.max(this.duration, interp.duration);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
|
|
2323
|
+
// Start/stop
|
|
2324
|
+
THREE.glTFAnimation.prototype.play = function()
|
|
2325
|
+
{
|
|
2326
|
+
if (this.running)
|
|
2327
|
+
return;
|
|
2328
|
+
|
|
2329
|
+
this.startTime = Date.now();
|
|
2330
|
+
this.running = true;
|
|
2331
|
+
THREE.glTFAnimator.add(this);
|
|
2332
|
+
}
|
|
2333
|
+
|
|
2334
|
+
THREE.glTFAnimation.prototype.stop = function()
|
|
2335
|
+
{
|
|
2336
|
+
this.running = false;
|
|
2337
|
+
THREE.glTFAnimator.remove(this);
|
|
2338
|
+
}
|
|
2339
|
+
|
|
2340
|
+
// Update - drive key frame evaluation
|
|
2341
|
+
THREE.glTFAnimation.prototype.update = function()
|
|
2342
|
+
{
|
|
2343
|
+
if (!this.running)
|
|
2344
|
+
return;
|
|
2345
|
+
|
|
2346
|
+
var now = Date.now();
|
|
2347
|
+
var deltat = (now - this.startTime) / 1000;
|
|
2348
|
+
var t = deltat % this.duration;
|
|
2349
|
+
var nCycles = Math.floor(deltat / this.duration);
|
|
2350
|
+
|
|
2351
|
+
if (nCycles >= 1 && !this.loop)
|
|
2352
|
+
{
|
|
2353
|
+
this.running = false;
|
|
2354
|
+
var i, len = this.interps.length;
|
|
2355
|
+
for (i = 0; i < len; i++)
|
|
2356
|
+
{
|
|
2357
|
+
this.interps[i].interp(this.duration);
|
|
2358
|
+
}
|
|
2359
|
+
this.stop();
|
|
2360
|
+
return;
|
|
2361
|
+
}
|
|
2362
|
+
else
|
|
2363
|
+
{
|
|
2364
|
+
var i, len = this.interps.length;
|
|
2365
|
+
for (i = 0; i < len; i++)
|
|
2366
|
+
{
|
|
2367
|
+
this.interps[i].interp(t);
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
//Interpolator class
|
|
2373
|
+
//Construction/initialization
|
|
2374
|
+
THREE.glTFInterpolator = function(param)
|
|
2375
|
+
{
|
|
2376
|
+
this.keys = param.keys;
|
|
2377
|
+
this.values = param.values;
|
|
2378
|
+
this.count = param.count;
|
|
2379
|
+
this.type = param.type;
|
|
2380
|
+
this.path = param.path;
|
|
2381
|
+
this.isRot = false;
|
|
2382
|
+
|
|
2383
|
+
var node = param.target;
|
|
2384
|
+
node.updateMatrix();
|
|
2385
|
+
node.matrixAutoUpdate = true;
|
|
2386
|
+
this.targetNode = node;
|
|
2387
|
+
|
|
2388
|
+
switch (param.path) {
|
|
2389
|
+
case "translation" :
|
|
2390
|
+
this.target = node.position;
|
|
2391
|
+
this.originalValue = node.position.clone();
|
|
2392
|
+
break;
|
|
2393
|
+
case "rotation" :
|
|
2394
|
+
this.target = node.quaternion;
|
|
2395
|
+
this.originalValue = node.quaternion.clone();
|
|
2396
|
+
this.isRot = true;
|
|
2397
|
+
break;
|
|
2398
|
+
case "scale" :
|
|
2399
|
+
this.target = node.scale;
|
|
2400
|
+
this.originalValue = node.scale.clone();
|
|
2401
|
+
break;
|
|
2402
|
+
}
|
|
2403
|
+
|
|
2404
|
+
this.duration = this.keys[this.count - 1];
|
|
2405
|
+
|
|
2406
|
+
this.vec1 = new THREE.Vector3;
|
|
2407
|
+
this.vec2 = new THREE.Vector3;
|
|
2408
|
+
this.vec3 = new THREE.Vector3;
|
|
2409
|
+
this.quat1 = new THREE.Quaternion;
|
|
2410
|
+
this.quat2 = new THREE.Quaternion;
|
|
2411
|
+
this.quat3 = new THREE.Quaternion;
|
|
2412
|
+
}
|
|
2413
|
+
|
|
2414
|
+
//Interpolation and tweening methods
|
|
2415
|
+
THREE.glTFInterpolator.prototype.interp = function(t)
|
|
2416
|
+
{
|
|
2417
|
+
var i, j;
|
|
2418
|
+
if (t == this.keys[0])
|
|
2419
|
+
{
|
|
2420
|
+
if (this.isRot) {
|
|
2421
|
+
this.quat3.set(this.values[0], this.values[1], this.values[2], this.values[3]);
|
|
2422
|
+
}
|
|
2423
|
+
else {
|
|
2424
|
+
this.vec3.set(this.values[0], this.values[1], this.values[2]);
|
|
2425
|
+
}
|
|
2426
|
+
}
|
|
2427
|
+
else if (t < this.keys[0])
|
|
2428
|
+
{
|
|
2429
|
+
if (this.isRot) {
|
|
2430
|
+
this.quat1.set(this.originalValue.x,
|
|
2431
|
+
this.originalValue.y,
|
|
2432
|
+
this.originalValue.z,
|
|
2433
|
+
this.originalValue.w);
|
|
2434
|
+
this.quat2.set(this.values[0],
|
|
2435
|
+
this.values[1],
|
|
2436
|
+
this.values[2],
|
|
2437
|
+
this.values[3]);
|
|
2438
|
+
THREE.Quaternion.slerp(this.quat1, this.quat2, this.quat3, t / this.keys[0]);
|
|
2439
|
+
}
|
|
2440
|
+
else {
|
|
2441
|
+
this.vec3.set(this.originalValue.x,
|
|
2442
|
+
this.originalValue.y,
|
|
2443
|
+
this.originalValue.z);
|
|
2444
|
+
this.vec2.set(this.values[0],
|
|
2445
|
+
this.values[1],
|
|
2446
|
+
this.values[2]);
|
|
2447
|
+
|
|
2448
|
+
this.vec3.lerp(this.vec2, t / this.keys[0]);
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
else if (t >= this.keys[this.count - 1])
|
|
2452
|
+
{
|
|
2453
|
+
if (this.isRot) {
|
|
2454
|
+
this.quat3.set(this.values[(this.count - 1) * 4],
|
|
2455
|
+
this.values[(this.count - 1) * 4 + 1],
|
|
2456
|
+
this.values[(this.count - 1) * 4 + 2],
|
|
2457
|
+
this.values[(this.count - 1) * 4 + 3]);
|
|
2458
|
+
}
|
|
2459
|
+
else {
|
|
2460
|
+
this.vec3.set(this.values[(this.count - 1) * 3],
|
|
2461
|
+
this.values[(this.count - 1) * 3 + 1],
|
|
2462
|
+
this.values[(this.count - 1) * 3 + 2]);
|
|
2463
|
+
}
|
|
2464
|
+
}
|
|
2465
|
+
else
|
|
2466
|
+
{
|
|
2467
|
+
for (i = 0; i < this.count - 1; i++)
|
|
2468
|
+
{
|
|
2469
|
+
var key1 = this.keys[i];
|
|
2470
|
+
var key2 = this.keys[i + 1];
|
|
2471
|
+
|
|
2472
|
+
if (t >= key1 && t <= key2)
|
|
2473
|
+
{
|
|
2474
|
+
if (this.isRot) {
|
|
2475
|
+
this.quat1.set(this.values[i * 4],
|
|
2476
|
+
this.values[i * 4 + 1],
|
|
2477
|
+
this.values[i * 4 + 2],
|
|
2478
|
+
this.values[i * 4 + 3]);
|
|
2479
|
+
this.quat2.set(this.values[(i + 1) * 4],
|
|
2480
|
+
this.values[(i + 1) * 4 + 1],
|
|
2481
|
+
this.values[(i + 1) * 4 + 2],
|
|
2482
|
+
this.values[(i + 1) * 4 + 3]);
|
|
2483
|
+
THREE.Quaternion.slerp(this.quat1, this.quat2, this.quat3, (t - key1) / (key2 - key1));
|
|
2484
|
+
}
|
|
2485
|
+
else {
|
|
2486
|
+
this.vec3.set(this.values[i * 3],
|
|
2487
|
+
this.values[i * 3 + 1],
|
|
2488
|
+
this.values[i * 3 + 2]);
|
|
2489
|
+
this.vec2.set(this.values[(i + 1) * 3],
|
|
2490
|
+
this.values[(i + 1) * 3 + 1],
|
|
2491
|
+
this.values[(i + 1) * 3 + 2]);
|
|
2492
|
+
|
|
2493
|
+
this.vec3.lerp(this.vec2, (t - key1) / (key2 - key1));
|
|
2494
|
+
}
|
|
2495
|
+
}
|
|
2496
|
+
}
|
|
2497
|
+
}
|
|
2498
|
+
|
|
2499
|
+
if (this.target)
|
|
2500
|
+
{
|
|
2501
|
+
this.copyValue(this.target);
|
|
2502
|
+
}
|
|
2503
|
+
}
|
|
2504
|
+
|
|
2505
|
+
THREE.glTFInterpolator.prototype.copyValue = function(target) {
|
|
2506
|
+
|
|
2507
|
+
if (this.isRot) {
|
|
2508
|
+
target.copy(this.quat3);
|
|
2509
|
+
}
|
|
2510
|
+
else {
|
|
2511
|
+
target.copy(this.vec3);
|
|
2512
|
+
}
|
|
2513
|
+
}
|