361 lines
11 KiB
JavaScript
361 lines
11 KiB
JavaScript
import { Loader, FileLoader, BufferGeometry, Vector3, Float32BufferAttribute, AnimationClip } from "three";
|
|
const _normalData = [
|
|
[-0.525731, 0, 0.850651],
|
|
[-0.442863, 0.238856, 0.864188],
|
|
[-0.295242, 0, 0.955423],
|
|
[-0.309017, 0.5, 0.809017],
|
|
[-0.16246, 0.262866, 0.951056],
|
|
[0, 0, 1],
|
|
[0, 0.850651, 0.525731],
|
|
[-0.147621, 0.716567, 0.681718],
|
|
[0.147621, 0.716567, 0.681718],
|
|
[0, 0.525731, 0.850651],
|
|
[0.309017, 0.5, 0.809017],
|
|
[0.525731, 0, 0.850651],
|
|
[0.295242, 0, 0.955423],
|
|
[0.442863, 0.238856, 0.864188],
|
|
[0.16246, 0.262866, 0.951056],
|
|
[-0.681718, 0.147621, 0.716567],
|
|
[-0.809017, 0.309017, 0.5],
|
|
[-0.587785, 0.425325, 0.688191],
|
|
[-0.850651, 0.525731, 0],
|
|
[-0.864188, 0.442863, 0.238856],
|
|
[-0.716567, 0.681718, 0.147621],
|
|
[-0.688191, 0.587785, 0.425325],
|
|
[-0.5, 0.809017, 0.309017],
|
|
[-0.238856, 0.864188, 0.442863],
|
|
[-0.425325, 0.688191, 0.587785],
|
|
[-0.716567, 0.681718, -0.147621],
|
|
[-0.5, 0.809017, -0.309017],
|
|
[-0.525731, 0.850651, 0],
|
|
[0, 0.850651, -0.525731],
|
|
[-0.238856, 0.864188, -0.442863],
|
|
[0, 0.955423, -0.295242],
|
|
[-0.262866, 0.951056, -0.16246],
|
|
[0, 1, 0],
|
|
[0, 0.955423, 0.295242],
|
|
[-0.262866, 0.951056, 0.16246],
|
|
[0.238856, 0.864188, 0.442863],
|
|
[0.262866, 0.951056, 0.16246],
|
|
[0.5, 0.809017, 0.309017],
|
|
[0.238856, 0.864188, -0.442863],
|
|
[0.262866, 0.951056, -0.16246],
|
|
[0.5, 0.809017, -0.309017],
|
|
[0.850651, 0.525731, 0],
|
|
[0.716567, 0.681718, 0.147621],
|
|
[0.716567, 0.681718, -0.147621],
|
|
[0.525731, 0.850651, 0],
|
|
[0.425325, 0.688191, 0.587785],
|
|
[0.864188, 0.442863, 0.238856],
|
|
[0.688191, 0.587785, 0.425325],
|
|
[0.809017, 0.309017, 0.5],
|
|
[0.681718, 0.147621, 0.716567],
|
|
[0.587785, 0.425325, 0.688191],
|
|
[0.955423, 0.295242, 0],
|
|
[1, 0, 0],
|
|
[0.951056, 0.16246, 0.262866],
|
|
[0.850651, -0.525731, 0],
|
|
[0.955423, -0.295242, 0],
|
|
[0.864188, -0.442863, 0.238856],
|
|
[0.951056, -0.16246, 0.262866],
|
|
[0.809017, -0.309017, 0.5],
|
|
[0.681718, -0.147621, 0.716567],
|
|
[0.850651, 0, 0.525731],
|
|
[0.864188, 0.442863, -0.238856],
|
|
[0.809017, 0.309017, -0.5],
|
|
[0.951056, 0.16246, -0.262866],
|
|
[0.525731, 0, -0.850651],
|
|
[0.681718, 0.147621, -0.716567],
|
|
[0.681718, -0.147621, -0.716567],
|
|
[0.850651, 0, -0.525731],
|
|
[0.809017, -0.309017, -0.5],
|
|
[0.864188, -0.442863, -0.238856],
|
|
[0.951056, -0.16246, -0.262866],
|
|
[0.147621, 0.716567, -0.681718],
|
|
[0.309017, 0.5, -0.809017],
|
|
[0.425325, 0.688191, -0.587785],
|
|
[0.442863, 0.238856, -0.864188],
|
|
[0.587785, 0.425325, -0.688191],
|
|
[0.688191, 0.587785, -0.425325],
|
|
[-0.147621, 0.716567, -0.681718],
|
|
[-0.309017, 0.5, -0.809017],
|
|
[0, 0.525731, -0.850651],
|
|
[-0.525731, 0, -0.850651],
|
|
[-0.442863, 0.238856, -0.864188],
|
|
[-0.295242, 0, -0.955423],
|
|
[-0.16246, 0.262866, -0.951056],
|
|
[0, 0, -1],
|
|
[0.295242, 0, -0.955423],
|
|
[0.16246, 0.262866, -0.951056],
|
|
[-0.442863, -0.238856, -0.864188],
|
|
[-0.309017, -0.5, -0.809017],
|
|
[-0.16246, -0.262866, -0.951056],
|
|
[0, -0.850651, -0.525731],
|
|
[-0.147621, -0.716567, -0.681718],
|
|
[0.147621, -0.716567, -0.681718],
|
|
[0, -0.525731, -0.850651],
|
|
[0.309017, -0.5, -0.809017],
|
|
[0.442863, -0.238856, -0.864188],
|
|
[0.16246, -0.262866, -0.951056],
|
|
[0.238856, -0.864188, -0.442863],
|
|
[0.5, -0.809017, -0.309017],
|
|
[0.425325, -0.688191, -0.587785],
|
|
[0.716567, -0.681718, -0.147621],
|
|
[0.688191, -0.587785, -0.425325],
|
|
[0.587785, -0.425325, -0.688191],
|
|
[0, -0.955423, -0.295242],
|
|
[0, -1, 0],
|
|
[0.262866, -0.951056, -0.16246],
|
|
[0, -0.850651, 0.525731],
|
|
[0, -0.955423, 0.295242],
|
|
[0.238856, -0.864188, 0.442863],
|
|
[0.262866, -0.951056, 0.16246],
|
|
[0.5, -0.809017, 0.309017],
|
|
[0.716567, -0.681718, 0.147621],
|
|
[0.525731, -0.850651, 0],
|
|
[-0.238856, -0.864188, -0.442863],
|
|
[-0.5, -0.809017, -0.309017],
|
|
[-0.262866, -0.951056, -0.16246],
|
|
[-0.850651, -0.525731, 0],
|
|
[-0.716567, -0.681718, -0.147621],
|
|
[-0.716567, -0.681718, 0.147621],
|
|
[-0.525731, -0.850651, 0],
|
|
[-0.5, -0.809017, 0.309017],
|
|
[-0.238856, -0.864188, 0.442863],
|
|
[-0.262866, -0.951056, 0.16246],
|
|
[-0.864188, -0.442863, 0.238856],
|
|
[-0.809017, -0.309017, 0.5],
|
|
[-0.688191, -0.587785, 0.425325],
|
|
[-0.681718, -0.147621, 0.716567],
|
|
[-0.442863, -0.238856, 0.864188],
|
|
[-0.587785, -0.425325, 0.688191],
|
|
[-0.309017, -0.5, 0.809017],
|
|
[-0.147621, -0.716567, 0.681718],
|
|
[-0.425325, -0.688191, 0.587785],
|
|
[-0.16246, -0.262866, 0.951056],
|
|
[0.442863, -0.238856, 0.864188],
|
|
[0.16246, -0.262866, 0.951056],
|
|
[0.309017, -0.5, 0.809017],
|
|
[0.147621, -0.716567, 0.681718],
|
|
[0, -0.525731, 0.850651],
|
|
[0.425325, -0.688191, 0.587785],
|
|
[0.587785, -0.425325, 0.688191],
|
|
[0.688191, -0.587785, 0.425325],
|
|
[-0.955423, 0.295242, 0],
|
|
[-0.951056, 0.16246, 0.262866],
|
|
[-1, 0, 0],
|
|
[-0.850651, 0, 0.525731],
|
|
[-0.955423, -0.295242, 0],
|
|
[-0.951056, -0.16246, 0.262866],
|
|
[-0.864188, 0.442863, -0.238856],
|
|
[-0.951056, 0.16246, -0.262866],
|
|
[-0.809017, 0.309017, -0.5],
|
|
[-0.864188, -0.442863, -0.238856],
|
|
[-0.951056, -0.16246, -0.262866],
|
|
[-0.809017, -0.309017, -0.5],
|
|
[-0.681718, 0.147621, -0.716567],
|
|
[-0.681718, -0.147621, -0.716567],
|
|
[-0.850651, 0, -0.525731],
|
|
[-0.688191, 0.587785, -0.425325],
|
|
[-0.587785, 0.425325, -0.688191],
|
|
[-0.425325, 0.688191, -0.587785],
|
|
[-0.425325, -0.688191, -0.587785],
|
|
[-0.587785, -0.425325, -0.688191],
|
|
[-0.688191, -0.587785, -0.425325]
|
|
];
|
|
class MD2Loader extends Loader {
|
|
constructor(manager) {
|
|
super(manager);
|
|
}
|
|
load(url, onLoad, onProgress, onError) {
|
|
const scope = this;
|
|
const loader = new FileLoader(scope.manager);
|
|
loader.setPath(scope.path);
|
|
loader.setResponseType("arraybuffer");
|
|
loader.setRequestHeader(scope.requestHeader);
|
|
loader.setWithCredentials(scope.withCredentials);
|
|
loader.load(
|
|
url,
|
|
function(buffer) {
|
|
try {
|
|
onLoad(scope.parse(buffer));
|
|
} catch (e) {
|
|
if (onError) {
|
|
onError(e);
|
|
} else {
|
|
console.error(e);
|
|
}
|
|
scope.manager.itemError(url);
|
|
}
|
|
},
|
|
onProgress,
|
|
onError
|
|
);
|
|
}
|
|
parse(buffer) {
|
|
const data = new DataView(buffer);
|
|
const header = {};
|
|
const headerNames = [
|
|
"ident",
|
|
"version",
|
|
"skinwidth",
|
|
"skinheight",
|
|
"framesize",
|
|
"num_skins",
|
|
"num_vertices",
|
|
"num_st",
|
|
"num_tris",
|
|
"num_glcmds",
|
|
"num_frames",
|
|
"offset_skins",
|
|
"offset_st",
|
|
"offset_tris",
|
|
"offset_frames",
|
|
"offset_glcmds",
|
|
"offset_end"
|
|
];
|
|
for (let i = 0; i < headerNames.length; i++) {
|
|
header[headerNames[i]] = data.getInt32(i * 4, true);
|
|
}
|
|
if (header.ident !== 844121161 || header.version !== 8) {
|
|
console.error("Not a valid MD2 file");
|
|
return;
|
|
}
|
|
if (header.offset_end !== data.byteLength) {
|
|
console.error("Corrupted MD2 file");
|
|
return;
|
|
}
|
|
const geometry = new BufferGeometry();
|
|
const uvsTemp = [];
|
|
let offset = header.offset_st;
|
|
for (let i = 0, l = header.num_st; i < l; i++) {
|
|
const u = data.getInt16(offset + 0, true);
|
|
const v = data.getInt16(offset + 2, true);
|
|
uvsTemp.push(u / header.skinwidth, 1 - v / header.skinheight);
|
|
offset += 4;
|
|
}
|
|
offset = header.offset_tris;
|
|
const vertexIndices = [];
|
|
const uvIndices = [];
|
|
for (let i = 0, l = header.num_tris; i < l; i++) {
|
|
vertexIndices.push(
|
|
data.getUint16(offset + 0, true),
|
|
data.getUint16(offset + 2, true),
|
|
data.getUint16(offset + 4, true)
|
|
);
|
|
uvIndices.push(
|
|
data.getUint16(offset + 6, true),
|
|
data.getUint16(offset + 8, true),
|
|
data.getUint16(offset + 10, true)
|
|
);
|
|
offset += 12;
|
|
}
|
|
const translation = new Vector3();
|
|
const scale = new Vector3();
|
|
const string = [];
|
|
const frames = [];
|
|
offset = header.offset_frames;
|
|
for (let i = 0, l = header.num_frames; i < l; i++) {
|
|
scale.set(data.getFloat32(offset + 0, true), data.getFloat32(offset + 4, true), data.getFloat32(offset + 8, true));
|
|
translation.set(
|
|
data.getFloat32(offset + 12, true),
|
|
data.getFloat32(offset + 16, true),
|
|
data.getFloat32(offset + 20, true)
|
|
);
|
|
offset += 24;
|
|
for (let j = 0; j < 16; j++) {
|
|
const character = data.getUint8(offset + j, true);
|
|
if (character === 0)
|
|
break;
|
|
string[j] = character;
|
|
}
|
|
const frame = {
|
|
name: String.fromCharCode.apply(null, string),
|
|
vertices: [],
|
|
normals: []
|
|
};
|
|
offset += 16;
|
|
for (let j = 0; j < header.num_vertices; j++) {
|
|
let x = data.getUint8(offset++, true);
|
|
let y = data.getUint8(offset++, true);
|
|
let z = data.getUint8(offset++, true);
|
|
const n = _normalData[data.getUint8(offset++, true)];
|
|
x = x * scale.x + translation.x;
|
|
y = y * scale.y + translation.y;
|
|
z = z * scale.z + translation.z;
|
|
frame.vertices.push(x, z, y);
|
|
frame.normals.push(n[0], n[2], n[1]);
|
|
}
|
|
frames.push(frame);
|
|
}
|
|
const positions = [];
|
|
const normals = [];
|
|
const uvs = [];
|
|
const verticesTemp = frames[0].vertices;
|
|
const normalsTemp = frames[0].normals;
|
|
for (let i = 0, l = vertexIndices.length; i < l; i++) {
|
|
const vertexIndex = vertexIndices[i];
|
|
let stride = vertexIndex * 3;
|
|
const x = verticesTemp[stride];
|
|
const y = verticesTemp[stride + 1];
|
|
const z = verticesTemp[stride + 2];
|
|
positions.push(x, y, z);
|
|
const nx = normalsTemp[stride];
|
|
const ny = normalsTemp[stride + 1];
|
|
const nz = normalsTemp[stride + 2];
|
|
normals.push(nx, ny, nz);
|
|
const uvIndex = uvIndices[i];
|
|
stride = uvIndex * 2;
|
|
const u = uvsTemp[stride];
|
|
const v = uvsTemp[stride + 1];
|
|
uvs.push(u, v);
|
|
}
|
|
geometry.setAttribute("position", new Float32BufferAttribute(positions, 3));
|
|
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
|
|
geometry.setAttribute("uv", new Float32BufferAttribute(uvs, 2));
|
|
const morphPositions = [];
|
|
const morphNormals = [];
|
|
for (let i = 0, l = frames.length; i < l; i++) {
|
|
const frame = frames[i];
|
|
const attributeName = frame.name;
|
|
if (frame.vertices.length > 0) {
|
|
const positions2 = [];
|
|
for (let j = 0, jl = vertexIndices.length; j < jl; j++) {
|
|
const vertexIndex = vertexIndices[j];
|
|
const stride = vertexIndex * 3;
|
|
const x = frame.vertices[stride];
|
|
const y = frame.vertices[stride + 1];
|
|
const z = frame.vertices[stride + 2];
|
|
positions2.push(x, y, z);
|
|
}
|
|
const positionAttribute = new Float32BufferAttribute(positions2, 3);
|
|
positionAttribute.name = attributeName;
|
|
morphPositions.push(positionAttribute);
|
|
}
|
|
if (frame.normals.length > 0) {
|
|
const normals2 = [];
|
|
for (let j = 0, jl = vertexIndices.length; j < jl; j++) {
|
|
const vertexIndex = vertexIndices[j];
|
|
const stride = vertexIndex * 3;
|
|
const nx = frame.normals[stride];
|
|
const ny = frame.normals[stride + 1];
|
|
const nz = frame.normals[stride + 2];
|
|
normals2.push(nx, ny, nz);
|
|
}
|
|
const normalAttribute = new Float32BufferAttribute(normals2, 3);
|
|
normalAttribute.name = attributeName;
|
|
morphNormals.push(normalAttribute);
|
|
}
|
|
}
|
|
geometry.morphAttributes.position = morphPositions;
|
|
geometry.morphAttributes.normal = morphNormals;
|
|
geometry.morphTargetsRelative = false;
|
|
geometry.animations = AnimationClip.CreateClipsFromMorphTargetSequences(frames, 10);
|
|
return geometry;
|
|
}
|
|
}
|
|
export {
|
|
MD2Loader
|
|
};
|
|
//# sourceMappingURL=MD2Loader.js.map
|