|
@@ -31,6 +31,16 @@ import { IGLTFLoader, GLTFFileLoader, GLTFLoaderState, IGLTFLoaderData, GLTFLoad
|
|
import { IAnimationKey, AnimationKeyInterpolation } from 'babylonjs/Animations/animationKey';
|
|
import { IAnimationKey, AnimationKeyInterpolation } from 'babylonjs/Animations/animationKey';
|
|
import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
|
|
import { IAnimatable } from 'babylonjs/Animations/animatable.interface';
|
|
|
|
|
|
|
|
+interface TypedArrayLike extends ArrayBufferView {
|
|
|
|
+ readonly length: number;
|
|
|
|
+ [n: number]: number;
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+interface TypedArrayConstructor {
|
|
|
|
+ new(length: number): TypedArrayLike;
|
|
|
|
+ new(buffer: ArrayBufferLike, byteOffset: number, length?: number): TypedArrayLike;
|
|
|
|
+}
|
|
|
|
+
|
|
interface IFileRequestInfo extends IFileRequest {
|
|
interface IFileRequestInfo extends IFileRequest {
|
|
_lengthComputable?: boolean;
|
|
_lengthComputable?: boolean;
|
|
_loaded?: number;
|
|
_loaded?: number;
|
|
@@ -1403,32 +1413,9 @@ export class GLTFLoader implements IGLTFLoader {
|
|
return bufferView._data;
|
|
return bufferView._data;
|
|
}
|
|
}
|
|
|
|
|
|
- private _loadIndicesAccessorAsync(context: string, accessor: IAccessor): Promise<IndicesArray> {
|
|
|
|
- if (accessor.type !== AccessorType.SCALAR) {
|
|
|
|
- throw new Error(`${context}/type: Invalid value ${accessor.type}`);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (accessor.componentType !== AccessorComponentType.UNSIGNED_BYTE &&
|
|
|
|
- accessor.componentType !== AccessorComponentType.UNSIGNED_SHORT &&
|
|
|
|
- accessor.componentType !== AccessorComponentType.UNSIGNED_INT) {
|
|
|
|
- throw new Error(`${context}/componentType: Invalid value ${accessor.componentType}`);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- if (accessor._data) {
|
|
|
|
- return accessor._data as Promise<IndicesArray>;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
- accessor._data = this.loadBufferViewAsync(`/bufferViews/${bufferView.index}`, bufferView).then((data) => {
|
|
|
|
- return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, accessor.count);
|
|
|
|
- });
|
|
|
|
-
|
|
|
|
- return accessor._data as Promise<IndicesArray>;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private _loadFloatAccessorAsync(context: string, accessor: IAccessor): Promise<Float32Array> {
|
|
|
|
|
|
+ private _loadAccessorAsync(context: string, accessor: IAccessor, constructor: TypedArrayConstructor): Promise<ArrayBufferView> {
|
|
if (accessor._data) {
|
|
if (accessor._data) {
|
|
- return accessor._data as Promise<Float32Array>;
|
|
|
|
|
|
+ return accessor._data;
|
|
}
|
|
}
|
|
|
|
|
|
const numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
|
|
const numComponents = GLTFLoader._GetNumComponents(context, accessor.type);
|
|
@@ -1436,7 +1423,7 @@ export class GLTFLoader implements IGLTFLoader {
|
|
const length = numComponents * accessor.count;
|
|
const length = numComponents * accessor.count;
|
|
|
|
|
|
if (accessor.bufferView == undefined) {
|
|
if (accessor.bufferView == undefined) {
|
|
- accessor._data = Promise.resolve(new Float32Array(length));
|
|
|
|
|
|
+ accessor._data = Promise.resolve(new constructor(length));
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
|
|
const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
|
|
@@ -1445,19 +1432,19 @@ export class GLTFLoader implements IGLTFLoader {
|
|
return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, length);
|
|
return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, length);
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
- const floatData = new Float32Array(length);
|
|
|
|
- VertexBuffer.ForEach(data, accessor.byteOffset || 0, bufferView.byteStride || byteStride, numComponents, accessor.componentType, floatData.length, accessor.normalized || false, (value, index) => {
|
|
|
|
- floatData[index] = value;
|
|
|
|
|
|
+ const typedArray = new constructor(length);
|
|
|
|
+ VertexBuffer.ForEach(data, accessor.byteOffset || 0, bufferView.byteStride || byteStride, numComponents, accessor.componentType, typedArray.length, accessor.normalized || false, (value, index) => {
|
|
|
|
+ typedArray[index] = value;
|
|
});
|
|
});
|
|
- return floatData;
|
|
|
|
|
|
+ return typedArray;
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
if (accessor.sparse) {
|
|
if (accessor.sparse) {
|
|
const sparse = accessor.sparse;
|
|
const sparse = accessor.sparse;
|
|
- accessor._data = accessor._data.then((view: ArrayBufferView) => {
|
|
|
|
- const data = view as Float32Array;
|
|
|
|
|
|
+ accessor._data = accessor._data.then((data) => {
|
|
|
|
+ const typedArray = data as TypedArrayLike;
|
|
const indicesBufferView = ArrayItem.Get(`${context}/sparse/indices/bufferView`, this._gltf.bufferViews, sparse.indices.bufferView);
|
|
const indicesBufferView = ArrayItem.Get(`${context}/sparse/indices/bufferView`, this._gltf.bufferViews, sparse.indices.bufferView);
|
|
const valuesBufferView = ArrayItem.Get(`${context}/sparse/values/bufferView`, this._gltf.bufferViews, sparse.values.bufferView);
|
|
const valuesBufferView = ArrayItem.Get(`${context}/sparse/values/bufferView`, this._gltf.bufferViews, sparse.values.bufferView);
|
|
return Promise.all([
|
|
return Promise.all([
|
|
@@ -1467,14 +1454,14 @@ export class GLTFLoader implements IGLTFLoader {
|
|
const indices = GLTFLoader._GetTypedArray(`${context}/sparse/indices`, sparse.indices.componentType, indicesData, sparse.indices.byteOffset, sparse.count) as IndicesArray;
|
|
const indices = GLTFLoader._GetTypedArray(`${context}/sparse/indices`, sparse.indices.componentType, indicesData, sparse.indices.byteOffset, sparse.count) as IndicesArray;
|
|
|
|
|
|
const sparseLength = numComponents * sparse.count;
|
|
const sparseLength = numComponents * sparse.count;
|
|
- let values: Float32Array;
|
|
|
|
|
|
+ let values: TypedArrayLike;
|
|
|
|
|
|
if (accessor.componentType === AccessorComponentType.FLOAT && !accessor.normalized) {
|
|
if (accessor.componentType === AccessorComponentType.FLOAT && !accessor.normalized) {
|
|
- values = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength) as Float32Array;
|
|
|
|
|
|
+ values = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength);
|
|
}
|
|
}
|
|
else {
|
|
else {
|
|
const sparseData = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength);
|
|
const sparseData = GLTFLoader._GetTypedArray(`${context}/sparse/values`, accessor.componentType, valuesData, sparse.values.byteOffset, sparseLength);
|
|
- values = new Float32Array(sparseLength);
|
|
|
|
|
|
+ values = new constructor(sparseLength);
|
|
VertexBuffer.ForEach(sparseData, 0, byteStride, numComponents, accessor.componentType, values.length, accessor.normalized || false, (value, index) => {
|
|
VertexBuffer.ForEach(sparseData, 0, byteStride, numComponents, accessor.componentType, values.length, accessor.normalized || false, (value, index) => {
|
|
values[index] = value;
|
|
values[index] = value;
|
|
});
|
|
});
|
|
@@ -1484,16 +1471,49 @@ export class GLTFLoader implements IGLTFLoader {
|
|
for (let indicesIndex = 0; indicesIndex < indices.length; indicesIndex++) {
|
|
for (let indicesIndex = 0; indicesIndex < indices.length; indicesIndex++) {
|
|
let dataIndex = indices[indicesIndex] * numComponents;
|
|
let dataIndex = indices[indicesIndex] * numComponents;
|
|
for (let componentIndex = 0; componentIndex < numComponents; componentIndex++) {
|
|
for (let componentIndex = 0; componentIndex < numComponents; componentIndex++) {
|
|
- data[dataIndex++] = values[valuesIndex++];
|
|
|
|
|
|
+ typedArray[dataIndex++] = values[valuesIndex++];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- return data;
|
|
|
|
|
|
+ return typedArray;
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
- return accessor._data as Promise<Float32Array>;
|
|
|
|
|
|
+ return accessor._data;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private _loadFloatAccessorAsync(context: string, accessor: IAccessor): Promise<Float32Array> {
|
|
|
|
+ return this._loadAccessorAsync(context, accessor, Float32Array) as Promise<Float32Array>;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ private _loadIndicesAccessorAsync(context: string, accessor: IAccessor): Promise<IndicesArray> {
|
|
|
|
+ if (accessor.type !== AccessorType.SCALAR) {
|
|
|
|
+ throw new Error(`${context}/type: Invalid value ${accessor.type}`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (accessor.componentType !== AccessorComponentType.UNSIGNED_BYTE &&
|
|
|
|
+ accessor.componentType !== AccessorComponentType.UNSIGNED_SHORT &&
|
|
|
|
+ accessor.componentType !== AccessorComponentType.UNSIGNED_INT) {
|
|
|
|
+ throw new Error(`${context}/componentType: Invalid value ${accessor.componentType}`);
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (accessor._data) {
|
|
|
|
+ return accessor._data as Promise<IndicesArray>;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if (accessor.sparse) {
|
|
|
|
+ const constructor = GLTFLoader._GetTypedArrayConstructor(`${context}/componentType`, accessor.componentType);
|
|
|
|
+ accessor._data = this._loadAccessorAsync(context, accessor, constructor);
|
|
|
|
+ }
|
|
|
|
+ else {
|
|
|
|
+ const bufferView = ArrayItem.Get(`${context}/bufferView`, this._gltf.bufferViews, accessor.bufferView);
|
|
|
|
+ accessor._data = this.loadBufferViewAsync(`/bufferViews/${bufferView.index}`, bufferView).then((data) => {
|
|
|
|
+ return GLTFLoader._GetTypedArray(context, accessor.componentType, data, accessor.byteOffset, accessor.count);
|
|
|
|
+ });
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return accessor._data as Promise<IndicesArray>;
|
|
}
|
|
}
|
|
|
|
|
|
private _loadVertexBufferViewAsync(bufferView: IBufferView, kind: string): Promise<Buffer> {
|
|
private _loadVertexBufferViewAsync(bufferView: IBufferView, kind: string): Promise<Buffer> {
|
|
@@ -2040,20 +2060,26 @@ export class GLTFLoader implements IGLTFLoader {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- private static _GetTypedArray(context: string, componentType: AccessorComponentType, bufferView: ArrayBufferView, byteOffset: number | undefined, length: number): ArrayBufferView {
|
|
|
|
|
|
+ private static _GetTypedArrayConstructor(context: string, componentType: AccessorComponentType): TypedArrayConstructor {
|
|
|
|
+ switch (componentType) {
|
|
|
|
+ case AccessorComponentType.BYTE: return Int8Array;
|
|
|
|
+ case AccessorComponentType.UNSIGNED_BYTE: return Uint8Array;
|
|
|
|
+ case AccessorComponentType.SHORT: return Int16Array;
|
|
|
|
+ case AccessorComponentType.UNSIGNED_SHORT: return Uint16Array;
|
|
|
|
+ case AccessorComponentType.UNSIGNED_INT: return Uint32Array;
|
|
|
|
+ case AccessorComponentType.FLOAT: return Float32Array;
|
|
|
|
+ default: throw new Error(`${context}: Invalid component type ${componentType}`);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+ private static _GetTypedArray(context: string, componentType: AccessorComponentType, bufferView: ArrayBufferView, byteOffset: number | undefined, length: number): TypedArrayLike {
|
|
const buffer = bufferView.buffer;
|
|
const buffer = bufferView.buffer;
|
|
byteOffset = bufferView.byteOffset + (byteOffset || 0);
|
|
byteOffset = bufferView.byteOffset + (byteOffset || 0);
|
|
|
|
|
|
|
|
+ const constructor = GLTFLoader._GetTypedArrayConstructor(`${context}/componentType`, componentType);
|
|
|
|
+
|
|
try {
|
|
try {
|
|
- switch (componentType) {
|
|
|
|
- case AccessorComponentType.BYTE: return new Int8Array(buffer, byteOffset, length);
|
|
|
|
- case AccessorComponentType.UNSIGNED_BYTE: return new Uint8Array(buffer, byteOffset, length);
|
|
|
|
- case AccessorComponentType.SHORT: return new Int16Array(buffer, byteOffset, length);
|
|
|
|
- case AccessorComponentType.UNSIGNED_SHORT: return new Uint16Array(buffer, byteOffset, length);
|
|
|
|
- case AccessorComponentType.UNSIGNED_INT: return new Uint32Array(buffer, byteOffset, length);
|
|
|
|
- case AccessorComponentType.FLOAT: return new Float32Array(buffer, byteOffset, length);
|
|
|
|
- default: throw new Error(`Invalid component type ${componentType}`);
|
|
|
|
- }
|
|
|
|
|
|
+ return new constructor(buffer, byteOffset, length);
|
|
}
|
|
}
|
|
catch (e) {
|
|
catch (e) {
|
|
throw new Error(`${context}: ${e}`);
|
|
throw new Error(`${context}: ${e}`);
|