Files
bgfx/3rdparty/meshoptimizer/tools/OptMeshLoader.js
2019-04-13 11:52:26 +02:00

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;
})();