mirror of
https://github.com/bkaradzic/bgfx.git
synced 2026-02-19 13:32:59 +01:00
180 lines
5.4 KiB
JavaScript
180 lines
5.4 KiB
JavaScript
THREE.OptMeshLoader = (function ()
|
|
{
|
|
function OptMeshLoader(manager)
|
|
{
|
|
this.manager = (manager !== undefined) ? manager : THREE.DefaultLoadingManager;
|
|
this.materials = Promise.resolve(null);
|
|
}
|
|
|
|
OptMeshLoader.prototype =
|
|
{
|
|
constructor: OptMeshLoader,
|
|
|
|
load: function (url, onLoad, onProgress, onError)
|
|
{
|
|
var scope = this;
|
|
|
|
var loader = new THREE.FileLoader(scope.manager);
|
|
loader.setResponseType('arraybuffer');
|
|
loader.setPath(this.path);
|
|
loader.load(url, function (data)
|
|
{
|
|
scope.decoder.ready.then(function ()
|
|
{
|
|
scope.materials.then(function (materials)
|
|
{
|
|
onLoad(scope.parse(data, materials));
|
|
});
|
|
});
|
|
}, onProgress, onError);
|
|
},
|
|
|
|
setDecoder: function (value)
|
|
{
|
|
this.decoder = value;
|
|
return this;
|
|
|
|
},
|
|
|
|
setPath: function (value)
|
|
{
|
|
this.path = value;
|
|
return this;
|
|
},
|
|
|
|
setMaterials: function (materials)
|
|
{
|
|
this.materials = Promise.resolve(materials);
|
|
return this;
|
|
},
|
|
|
|
setMaterialLib: function (lib)
|
|
{
|
|
var scope = this;
|
|
|
|
this.materials = new Promise(function (resolve, reject)
|
|
{
|
|
var loader = new THREE.MTLLoader();
|
|
loader.setPath(scope.path);
|
|
loader.load(lib, function (materials) { materials.preload(); resolve(materials); }, null, reject);
|
|
});
|
|
|
|
return this;
|
|
},
|
|
|
|
parse: function (data, materials)
|
|
{
|
|
console.time('OptMeshLoader');
|
|
|
|
var array = new Uint8Array(data);
|
|
var view = new DataView(data);
|
|
|
|
var endian = true;
|
|
var magic = view.getUint32(0, endian);
|
|
var objectCount = view.getUint32(4, endian);
|
|
var vertexCount = view.getUint32(8, endian);
|
|
var indexCount = view.getUint32(12, endian);
|
|
var vertexDataSize = view.getUint32(16, endian);
|
|
var indexDataSize = view.getUint32(20, endian);
|
|
var posOffsetX = view.getFloat32(24, endian);
|
|
var posOffsetY = view.getFloat32(28, endian);
|
|
var posOffsetZ = view.getFloat32(32, endian);
|
|
var posScale = view.getFloat32(36, endian);
|
|
var uvOffsetX = view.getFloat32(40, endian);
|
|
var uvOffsetY = view.getFloat32(44, endian);
|
|
var uvScaleX = view.getFloat32(48, endian);
|
|
var uvScaleY = view.getFloat32(52, endian);
|
|
|
|
if (magic != 0x4D54504F)
|
|
throw new Error("Malformed mesh file: unrecognized header");
|
|
|
|
var objectOffset = 64;
|
|
var objectDataOffset = objectOffset + 16 * objectCount;
|
|
|
|
var objectDataSize = 0;
|
|
|
|
for (var i = 0; i < objectCount; ++i)
|
|
objectDataSize += view.getUint32(objectOffset + 16 * i + 8, endian);
|
|
|
|
var vertexDataOffset = objectDataOffset + objectDataSize;
|
|
var indexDataOffset = vertexDataOffset + vertexDataSize;
|
|
|
|
var endOffset = indexDataOffset + indexDataSize;
|
|
|
|
if (endOffset != data.byteLength)
|
|
throw new Error("Malformed mesh file: unexpected input size");
|
|
|
|
var vertexSize = 16;
|
|
var indexSize = 4;
|
|
|
|
var vertexBuffer = new ArrayBuffer(vertexCount * vertexSize);
|
|
var vertexBufferU8 = new Uint8Array(vertexBuffer);
|
|
this.decoder.decodeVertexBuffer(vertexBufferU8, vertexCount, vertexSize, array.subarray(vertexDataOffset, vertexDataOffset + vertexDataSize));
|
|
|
|
var indexBuffer = new ArrayBuffer(indexCount * indexSize);
|
|
var indexBufferU8 = new Uint8Array(indexBuffer);
|
|
this.decoder.decodeIndexBuffer(indexBufferU8, indexCount, indexSize, array.subarray(indexDataOffset, indexDataOffset + indexDataSize));
|
|
|
|
var geometry = new THREE.BufferGeometry();
|
|
|
|
geometry.addAttribute('position', new THREE.InterleavedBufferAttribute(new THREE.InterleavedBuffer(new Uint16Array(vertexBuffer), 8), 3, 0, false));
|
|
geometry.addAttribute('normal', new THREE.InterleavedBufferAttribute(new THREE.InterleavedBuffer(new Int8Array(vertexBuffer), 16), 3, 8, true));
|
|
geometry.addAttribute('uv', new THREE.InterleavedBufferAttribute(new THREE.InterleavedBuffer(new Uint16Array(vertexBuffer), 8), 2, 6, false));
|
|
geometry.setIndex(new THREE.BufferAttribute(new Uint32Array(indexBuffer), 1, false));
|
|
|
|
var objectDataOffsetAcc = objectDataOffset;
|
|
|
|
var objectMaterials = [];
|
|
var objectMaterialsLookup = {};
|
|
|
|
for (var i = 0; i < objectCount; i++)
|
|
{
|
|
var objectIndexOffset = view.getUint32(objectOffset + 16 * i + 0, endian);
|
|
var objectIndexCount = view.getUint32(objectOffset + 16 * i + 4, endian);
|
|
var objectMaterialLength = view.getUint32(objectOffset + 16 * i + 8, endian);
|
|
|
|
var objectMaterialName = String.fromCharCode.apply(null, array.subarray(objectDataOffsetAcc, objectDataOffsetAcc + objectMaterialLength));
|
|
var objectMaterialIndex = objectMaterialsLookup[objectMaterialName];
|
|
|
|
if (objectMaterialIndex == undefined)
|
|
{
|
|
var objectMaterial = null;
|
|
|
|
if (materials !== null)
|
|
objectMaterial = materials.create(objectMaterialName);
|
|
|
|
if (!objectMaterial)
|
|
objectMaterial = new THREE.MeshPhongMaterial();
|
|
|
|
if (objectMaterial.map)
|
|
{
|
|
objectMaterial.map.offset.set(uvOffsetX, uvOffsetY);
|
|
objectMaterial.map.repeat.set(uvScaleX, uvScaleY);
|
|
}
|
|
|
|
objectMaterialIndex = objectMaterials.length;
|
|
objectMaterialsLookup[objectMaterialName] = objectMaterialIndex;
|
|
objectMaterials.push(objectMaterial);
|
|
}
|
|
|
|
geometry.addGroup(objectIndexOffset, objectIndexCount, objectMaterialIndex);
|
|
|
|
objectDataOffsetAcc += objectMaterialLength;
|
|
}
|
|
|
|
var mesh = new THREE.Mesh(geometry, objectMaterials);
|
|
mesh.position.set(posOffsetX, posOffsetY, posOffsetZ);
|
|
mesh.scale.set(posScale, posScale, posScale);
|
|
|
|
var container = new THREE.Group();
|
|
container.add(mesh);
|
|
|
|
console.timeEnd('OptMeshLoader');
|
|
|
|
return container;
|
|
}
|
|
};
|
|
|
|
return OptMeshLoader;
|
|
})();
|