683 lines
19 KiB
JavaScript
683 lines
19 KiB
JavaScript
OV.CHUNK3DS =
|
|
{
|
|
MAIN3DS : 0x4D4D,
|
|
EDIT3DS : 0x3D3D,
|
|
EDIT_MATERIAL : 0xAFFF,
|
|
MAT_NAME : 0xA000,
|
|
MAT_AMBIENT : 0xA010,
|
|
MAT_DIFFUSE : 0xA020,
|
|
MAT_SPECULAR : 0xA030,
|
|
MAT_SHININESS : 0xA040,
|
|
MAT_SHININESS_STRENGTH : 0xA041,
|
|
MAT_TRANSPARENCY : 0xA050,
|
|
MAT_COLOR_F : 0x0010,
|
|
MAT_COLOR : 0x0011,
|
|
MAT_LIN_COLOR : 0x0012,
|
|
MAT_LIN_COLOR_F : 0x0013,
|
|
MAT_TEXMAP : 0xA200,
|
|
MAT_TEXMAP_NAME : 0xA300,
|
|
MAT_TEXMAP_UOFFSET : 0xA358,
|
|
MAT_TEXMAP_VOFFSET : 0xA35A,
|
|
MAT_TEXMAP_USCALE : 0xA354,
|
|
MAT_TEXMAP_VSCALE : 0xA356,
|
|
MAT_TEXMAP_ROTATION : 0xA35C,
|
|
PERCENTAGE : 0x0030,
|
|
PERCENTAGE_F : 0x0031,
|
|
EDIT_OBJECT : 0x4000,
|
|
OBJ_TRIMESH : 0x4100,
|
|
OBJ_LIGHT : 0x4600,
|
|
OBJ_CAMERA : 0x4700,
|
|
TRI_VERTEX : 0x4110,
|
|
TRI_TEXVERTEX : 0x4140,
|
|
TRI_FACE : 0x4120,
|
|
TRI_TRANSFORMATION : 0x4160,
|
|
TRI_MATERIAL : 0x4130,
|
|
TRI_SMOOTH : 0x4150,
|
|
KF3DS : 0xB000,
|
|
OBJECT_NODE : 0xB002,
|
|
OBJECT_HIERARCHY : 0xB010,
|
|
OBJECT_INSTANCE_NAME : 0xB011,
|
|
OBJECT_PIVOT : 0xB013,
|
|
OBJECT_POSITION : 0xB020,
|
|
OBJECT_ROTATION : 0xB021,
|
|
OBJECT_SCALE : 0xB022,
|
|
OBJECT_ID : 0xB030
|
|
};
|
|
|
|
OV.Importer3ds = class extends OV.ImporterBase
|
|
{
|
|
constructor ()
|
|
{
|
|
super ();
|
|
|
|
this.materialNameToIndex = null;
|
|
this.meshNameToIndex = null;
|
|
|
|
this.meshTransformations = null;
|
|
this.defaultMaterialIndex = null;
|
|
}
|
|
|
|
ResetState ()
|
|
{
|
|
this.materialNameToIndex = {};
|
|
this.meshNameToIndex = {};
|
|
|
|
this.meshTransformations = [];
|
|
this.defaultMaterialIndex = null;
|
|
}
|
|
|
|
CanImportExtension (extension)
|
|
{
|
|
return extension === '3ds';
|
|
}
|
|
|
|
GetKnownFileFormats ()
|
|
{
|
|
return {
|
|
'3ds' : OV.FileFormat.Binary
|
|
};
|
|
}
|
|
|
|
GetUpDirection ()
|
|
{
|
|
return OV.Direction.Z;
|
|
}
|
|
|
|
ImportContent (fileContent)
|
|
{
|
|
this.ProcessBinary (fileContent);
|
|
}
|
|
|
|
ProcessBinary (fileContent)
|
|
{
|
|
let obj = this;
|
|
let reader = new OV.BinaryReader (fileContent, true);
|
|
let endByte = reader.GetByteLength ();
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.MAIN3DS) {
|
|
obj.ReadMainChunk (reader, chunkLength);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
}
|
|
|
|
ReadMainChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.EDIT3DS) {
|
|
obj.ReadEditorChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.KF3DS) {
|
|
obj.ReadKeyFrameChunk (reader, chunkLength);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
}
|
|
|
|
ReadEditorChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.EDIT_MATERIAL) {
|
|
obj.ReadMaterialChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.EDIT_OBJECT) {
|
|
obj.ReadObjectChunk (reader, chunkLength);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
}
|
|
|
|
ReadMaterialChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let material = new OV.Material ();
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
let shininess = null;
|
|
let shininessStrength = null;
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.MAT_NAME) {
|
|
material.name = obj.ReadName (reader);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_AMBIENT) {
|
|
material.ambient = obj.ReadColorChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_DIFFUSE) {
|
|
material.diffuse = obj.ReadColorChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_SPECULAR) {
|
|
material.specular = obj.ReadColorChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_SHININESS) {
|
|
shininess = obj.ReadPercentageChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_SHININESS_STRENGTH) {
|
|
shininessStrength = obj.ReadPercentageChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TRANSPARENCY) {
|
|
material.opacity = 1.0 - obj.ReadPercentageChunk (reader, chunkLength);
|
|
material.transparent = OV.IsLower (material.opacity, 1.0);
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP) {
|
|
material.diffuseMap = obj.ReadTextureMapChunk (reader, chunkLength);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
|
|
if (shininess !== null || shininessStrength !== null) {
|
|
material.shininess = shininess * shininessStrength;
|
|
}
|
|
let materialIndex = this.model.AddMaterial (material);
|
|
this.materialNameToIndex[material.name] = materialIndex;
|
|
}
|
|
|
|
ReadTextureMapChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let texture = new OV.TextureMap ();
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_NAME) {
|
|
let textureName = obj.ReadName (reader);
|
|
let textureBuffer = obj.GetTextureBuffer (textureName);
|
|
texture.name = textureName;
|
|
if (textureBuffer !== null) {
|
|
texture.url = textureBuffer.url;
|
|
texture.buffer = textureBuffer.buffer;
|
|
}
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_UOFFSET) {
|
|
texture.offset.x = reader.ReadFloat32 ();
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_VOFFSET) {
|
|
texture.offset.y = reader.ReadFloat32 ();
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_USCALE) {
|
|
texture.scale.x = reader.ReadFloat32 ();
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_VSCALE) {
|
|
texture.scale.y = reader.ReadFloat32 ();
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_TEXMAP_ROTATION) {
|
|
texture.rotation = reader.ReadFloat32 () * OV.DegRad;
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
return texture;
|
|
}
|
|
|
|
ReadColorChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let color = new OV.Color (0, 0, 0);
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
let hasLinColor = false;
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.MAT_COLOR) {
|
|
if (!hasLinColor) {
|
|
color.r = reader.ReadUnsignedCharacter8 ();
|
|
color.g = reader.ReadUnsignedCharacter8 ();
|
|
color.b = reader.ReadUnsignedCharacter8 ();
|
|
}
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_LIN_COLOR) {
|
|
color.r = reader.ReadUnsignedCharacter8 ();
|
|
color.g = reader.ReadUnsignedCharacter8 ();
|
|
color.b = reader.ReadUnsignedCharacter8 ();
|
|
hasLinColor = true;
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_COLOR_F) {
|
|
if (!hasLinColor) {
|
|
color.r = parseInt (reader.ReadFloat32 () * 255.0, 10);
|
|
color.g = parseInt (reader.ReadFloat32 () * 255.0, 10);
|
|
color.b = parseInt (reader.ReadFloat32 () * 255.0, 10);
|
|
}
|
|
} else if (chunkId === OV.CHUNK3DS.MAT_LIN_COLOR_F) {
|
|
color.r = parseInt (reader.ReadFloat32 () * 255.0, 10);
|
|
color.g = parseInt (reader.ReadFloat32 () * 255.0, 10);
|
|
color.b = parseInt (reader.ReadFloat32 () * 255.0, 10);
|
|
hasLinColor = true;
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
return color;
|
|
}
|
|
|
|
ReadPercentageChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let percentage = 0.0;
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.PERCENTAGE) {
|
|
percentage = reader.ReadUnsignedInteger16 () / 100.0;
|
|
} else if (chunkId === OV.CHUNK3DS.PERCENTAGE_F) {
|
|
percentage = reader.ReadFloat32 ();
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
return percentage;
|
|
}
|
|
|
|
ReadObjectChunk (reader, length)
|
|
{
|
|
let obj = this;
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
let objectName = this.ReadName (reader);
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.OBJ_TRIMESH) {
|
|
obj.ReadMeshChunk (reader, chunkLength, objectName);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJ_LIGHT) {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJ_CAMERA) {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
}
|
|
|
|
ReadMeshChunk (reader, length, objectName)
|
|
{
|
|
let obj = this;
|
|
|
|
let mesh = new OV.Mesh ();
|
|
mesh.SetName (objectName);
|
|
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
let transformation = null;
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.TRI_VERTEX) {
|
|
obj.ReadVerticesChunk (mesh, reader);
|
|
} else if (chunkId === OV.CHUNK3DS.TRI_TEXVERTEX) {
|
|
obj.ReadTextureVerticesChunk (mesh, reader);
|
|
} else if (chunkId === OV.CHUNK3DS.TRI_FACE) {
|
|
obj.ReadFacesChunk (mesh, reader, chunkLength);
|
|
} else if (chunkId === OV.CHUNK3DS.TRI_TRANSFORMATION) {
|
|
transformation = obj.ReadTransformationChunk (reader);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
|
|
if (mesh.VertexCount () === mesh.TextureUVCount ()) {
|
|
for (let i = 0; i < mesh.TriangleCount (); i++) {
|
|
let triangle = mesh.GetTriangle (i);
|
|
triangle.SetTextureUVs (
|
|
triangle.v0,
|
|
triangle.v1,
|
|
triangle.v2
|
|
);
|
|
}
|
|
}
|
|
|
|
let meshIndex = this.model.AddMesh (mesh);
|
|
this.meshNameToIndex[mesh.GetName ()] = meshIndex;
|
|
this.meshTransformations.push (new OV.Matrix (transformation));
|
|
}
|
|
|
|
ReadVerticesChunk (mesh, reader)
|
|
{
|
|
let vertexCount = reader.ReadUnsignedInteger16 ();
|
|
for (let i = 0; i < vertexCount; i++) {
|
|
let x = reader.ReadFloat32 ();
|
|
let y = reader.ReadFloat32 ();
|
|
let z = reader.ReadFloat32 ();
|
|
mesh.AddVertex (new OV.Coord3D (x, y, z));
|
|
}
|
|
}
|
|
|
|
ReadTextureVerticesChunk (mesh, reader)
|
|
{
|
|
let texVertexCount = reader.ReadUnsignedInteger16 ();
|
|
for (let i = 0; i < texVertexCount; i++) {
|
|
let x = reader.ReadFloat32 ();
|
|
let y = reader.ReadFloat32 ();
|
|
mesh.AddTextureUV (new OV.Coord2D (x, y));
|
|
}
|
|
}
|
|
|
|
ReadFacesChunk (mesh, reader, length)
|
|
{
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
let faceCount = reader.ReadUnsignedInteger16 ();
|
|
for (let i = 0; i < faceCount; i++) {
|
|
let v0 = reader.ReadUnsignedInteger16 ();
|
|
let v1 = reader.ReadUnsignedInteger16 ();
|
|
let v2 = reader.ReadUnsignedInteger16 ();
|
|
reader.ReadUnsignedInteger16 (); // flags
|
|
mesh.AddTriangle (new OV.Triangle (v0, v1, v2));
|
|
}
|
|
|
|
let obj = this;
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.TRI_MATERIAL) {
|
|
obj.ReadFaceMaterialsChunk (mesh, reader);
|
|
} else if (chunkId === OV.CHUNK3DS.TRI_SMOOTH) {
|
|
obj.ReadFaceSmoothingGroupsChunk (mesh, faceCount, reader);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
}
|
|
|
|
ReadFaceMaterialsChunk (mesh, reader)
|
|
{
|
|
let materialName = this.ReadName (reader);
|
|
let materialIndex = this.materialNameToIndex[materialName];
|
|
let faceCount = reader.ReadUnsignedInteger16 ();
|
|
for (let i = 0; i < faceCount; i++) {
|
|
let faceIndex = reader.ReadUnsignedInteger16 ();
|
|
let triangle = mesh.GetTriangle (faceIndex);
|
|
if (materialIndex !== undefined) {
|
|
triangle.mat = materialIndex;
|
|
}
|
|
}
|
|
}
|
|
|
|
ReadFaceSmoothingGroupsChunk (mesh, faceCount, reader)
|
|
{
|
|
for (let i = 0; i < faceCount; i++) {
|
|
let smoothingGroup = reader.ReadUnsignedInteger32 ();
|
|
let triangle = mesh.GetTriangle (i);
|
|
triangle.curve = smoothingGroup;
|
|
}
|
|
}
|
|
|
|
ReadTransformationChunk (reader)
|
|
{
|
|
let matrix = [];
|
|
for (let i = 0; i < 4; i++) {
|
|
for (let j = 0; j < 3; j++) {
|
|
matrix.push (reader.ReadFloat32 ());
|
|
}
|
|
if (i < 3) {
|
|
matrix.push (0);
|
|
} else {
|
|
matrix.push (1);
|
|
}
|
|
}
|
|
return matrix;
|
|
}
|
|
|
|
ReadKeyFrameChunk (reader, length)
|
|
{
|
|
let nodeHierarchy = {
|
|
nodes : [],
|
|
idToIndex : {},
|
|
meshIndexToNodes : {}
|
|
};
|
|
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
let obj = this;
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.OBJECT_NODE) {
|
|
obj.ReadObjectNodeChunk (nodeHierarchy, reader, chunkLength);
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
|
|
this.ApplyModelTransformations (nodeHierarchy);
|
|
}
|
|
|
|
ApplyModelTransformations (nodeHierarchy)
|
|
{
|
|
function GetNodeTransformation (nodeHierarchy, node)
|
|
{
|
|
function GetNodePosition (node)
|
|
{
|
|
if (node.positions.length === 0) {
|
|
return [0.0, 0.0, 0.0];
|
|
}
|
|
return node.positions[0];
|
|
}
|
|
|
|
function GetNodeRotation (node)
|
|
{
|
|
function GetQuaternionFromAxisAndAngle (rotation)
|
|
{
|
|
let result = [0.0, 0.0, 0.0, 1.0];
|
|
let length = Math.sqrt (rotation[0] * rotation[0] + rotation[1] * rotation[1] + rotation[2] * rotation[2]);
|
|
if (length > 0.0) {
|
|
let omega = rotation[3] * -0.5;
|
|
let si = Math.sin (omega) / length;
|
|
result = [si * rotation[0], si * rotation[1], si * rotation[2], Math.cos (omega)];
|
|
}
|
|
return result;
|
|
}
|
|
|
|
if (node.rotations.length === 0) {
|
|
return [0.0, 0.0, 0.0, 1.0];
|
|
}
|
|
|
|
let rotation = node.rotations[0];
|
|
return GetQuaternionFromAxisAndAngle (rotation);
|
|
}
|
|
|
|
function GetNodeScale (node)
|
|
{
|
|
if (node.scales.length === 0) {
|
|
return [1.0, 1.0, 1.0];
|
|
}
|
|
return node.scales[0];
|
|
}
|
|
|
|
if (node.matrix !== null) {
|
|
return node.matrix;
|
|
}
|
|
|
|
let matrix = new OV.Matrix ();
|
|
matrix.ComposeTRS (
|
|
GetNodePosition (node),
|
|
GetNodeRotation (node),
|
|
GetNodeScale (node)
|
|
);
|
|
|
|
if (node.userId !== 65535) {
|
|
let parentIndex = nodeHierarchy.idToIndex[node.userId];
|
|
if (parentIndex !== undefined) {
|
|
let parentNode = nodeHierarchy.nodes[parentIndex];
|
|
let parentMatrix = GetNodeTransformation (nodeHierarchy, parentNode);
|
|
matrix = matrix.MultiplyMatrix (parentMatrix);
|
|
}
|
|
}
|
|
|
|
node.matrix = matrix;
|
|
return matrix;
|
|
}
|
|
|
|
function ApplyMeshTransformation (model, currentMeshIndex, meshMatrix, nodeHierarchy, node)
|
|
{
|
|
function GetNodePivotPoint (node)
|
|
{
|
|
if (node === null) {
|
|
return [0.0, 0.0, 0.0];
|
|
}
|
|
return node.pivot;
|
|
}
|
|
|
|
if (!meshMatrix.IsValid ()) {
|
|
return;
|
|
}
|
|
|
|
let nodeMatrix = meshMatrix;
|
|
if (node !== null) {
|
|
nodeMatrix = GetNodeTransformation (nodeHierarchy, node);
|
|
}
|
|
|
|
let determinant = meshMatrix.Determinant ();
|
|
if (OV.IsNegative (determinant)) {
|
|
// Mirror by x coordinates
|
|
let scaleMatrix = new OV.Matrix ().CreateScale (-1.0, 1.0, 1.0);
|
|
meshMatrix = scaleMatrix.MultiplyMatrix (meshMatrix);
|
|
}
|
|
|
|
let invMeshMatrix = meshMatrix.Invert ();
|
|
if (invMeshMatrix === null) {
|
|
return;
|
|
}
|
|
|
|
let pivotPoint = GetNodePivotPoint (node);
|
|
let pivotMatrix = new OV.Matrix ().CreateTranslation (-pivotPoint[0], -pivotPoint[1], -pivotPoint[2]);
|
|
|
|
let matrix = nodeMatrix.Clone ();
|
|
matrix = pivotMatrix.MultiplyMatrix (matrix);
|
|
matrix = invMeshMatrix.MultiplyMatrix (matrix);
|
|
|
|
let transformation = new OV.Transformation (matrix);
|
|
let mesh = model.GetMesh (currentMeshIndex);
|
|
OV.TransformMesh (mesh, transformation);
|
|
}
|
|
|
|
function AddDuplicatedMesh (model, meshIndex, toIndex)
|
|
{
|
|
let mesh = model.GetMesh (meshIndex);
|
|
let clonedMesh = OV.CloneMesh (mesh);
|
|
let clonedMeshIndex = model.AddMeshToIndex (clonedMesh, toIndex);
|
|
return clonedMeshIndex;
|
|
}
|
|
|
|
let newToOldMeshIndexOffset = 0;
|
|
for (let meshIndex = 0; meshIndex < this.model.MeshCount (); meshIndex++) {
|
|
let currentMeshIndex = meshIndex;
|
|
let originalMeshIndex = currentMeshIndex - newToOldMeshIndexOffset;
|
|
let meshTransformation = this.meshTransformations[originalMeshIndex];
|
|
let meshNodes = nodeHierarchy.meshIndexToNodes[originalMeshIndex];
|
|
if (meshNodes === undefined) {
|
|
ApplyMeshTransformation (this.model, currentMeshIndex, meshTransformation, nodeHierarchy, null);
|
|
} else {
|
|
for (let nodeIndex = 0; nodeIndex < meshNodes.length; nodeIndex++) {
|
|
let currentNode = meshNodes[nodeIndex];
|
|
let transformedMeshIndex = currentMeshIndex;
|
|
if (nodeIndex > 0) {
|
|
transformedMeshIndex = AddDuplicatedMesh (this.model, currentMeshIndex, currentMeshIndex + nodeIndex);
|
|
newToOldMeshIndexOffset += 1;
|
|
meshIndex += 1;
|
|
}
|
|
ApplyMeshTransformation (this.model, transformedMeshIndex, meshTransformation, nodeHierarchy, currentNode);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ReadObjectNodeChunk (nodeHierarchy, reader, length)
|
|
{
|
|
function ReadTrackVector (obj, reader, type)
|
|
{
|
|
let result = [];
|
|
reader.Skip (10);
|
|
|
|
let keyNum = reader.ReadInteger32 ();
|
|
for (let i = 0; i < keyNum; i++) {
|
|
reader.ReadInteger32 ();
|
|
let flags = reader.ReadUnsignedInteger16 ();
|
|
if (flags !== 0) {
|
|
reader.ReadFloat32 ();
|
|
}
|
|
|
|
let current = null;
|
|
if (type === OV.CHUNK3DS.OBJECT_ROTATION) {
|
|
let tmp = reader.ReadFloat32 ();
|
|
current = obj.ReadVector (reader);
|
|
current[3] = tmp;
|
|
} else {
|
|
current = obj.ReadVector (reader);
|
|
}
|
|
result.push (current);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
let objectNode = {
|
|
name : '',
|
|
instanceName : '',
|
|
nodeId : -1,
|
|
flags : -1,
|
|
userId : -1,
|
|
pivot : [0.0, 0.0, 0.0],
|
|
positions : [],
|
|
rotations : [],
|
|
scales : [],
|
|
matrix : null
|
|
};
|
|
|
|
let obj = this;
|
|
let endByte = this.GetChunkEnd (reader, length);
|
|
this.ReadChunks (reader, endByte, function (chunkId, chunkLength) {
|
|
if (chunkId === OV.CHUNK3DS.OBJECT_HIERARCHY) {
|
|
objectNode.name = obj.ReadName (reader);
|
|
objectNode.flags = reader.ReadUnsignedInteger32 ();
|
|
objectNode.userId = reader.ReadUnsignedInteger16 ();
|
|
} else if (chunkId === OV.CHUNK3DS.OBJECT_INSTANCE_NAME) {
|
|
objectNode.instanceName = obj.ReadName (reader);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJECT_PIVOT) {
|
|
objectNode.pivot = obj.ReadVector (reader);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJECT_POSITION) {
|
|
objectNode.positions = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_POSITION);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJECT_ROTATION) {
|
|
objectNode.rotations = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_ROTATION);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJECT_SCALE) {
|
|
objectNode.scales = ReadTrackVector (obj, reader, OV.CHUNK3DS.OBJECT_SCALE);
|
|
} else if (chunkId === OV.CHUNK3DS.OBJECT_ID) {
|
|
objectNode.nodeId = reader.ReadUnsignedInteger16 ();
|
|
} else {
|
|
obj.SkipChunk (reader, chunkLength);
|
|
}
|
|
});
|
|
|
|
let nodeIndex = nodeHierarchy.nodes.length;
|
|
nodeHierarchy.nodes.push (objectNode);
|
|
nodeHierarchy.idToIndex[objectNode.nodeId] = nodeIndex;
|
|
|
|
let meshIndex = this.meshNameToIndex[objectNode.name];
|
|
if (meshIndex !== undefined) {
|
|
let meshNodes = nodeHierarchy.meshIndexToNodes[meshIndex];
|
|
if (meshNodes === undefined) {
|
|
nodeHierarchy.meshIndexToNodes[meshIndex] = [];
|
|
}
|
|
nodeHierarchy.meshIndexToNodes[meshIndex].push (objectNode);
|
|
}
|
|
}
|
|
|
|
ReadName (reader)
|
|
{
|
|
let name = '';
|
|
let char = 0;
|
|
let count = 0;
|
|
while (count < 64) {
|
|
char = reader.ReadCharacter8 ();
|
|
if (char === 0) {
|
|
break;
|
|
}
|
|
name = name + String.fromCharCode (char);
|
|
count = count + 1;
|
|
}
|
|
return name;
|
|
}
|
|
|
|
ReadVector (reader)
|
|
{
|
|
let result = [
|
|
reader.ReadFloat32 (),
|
|
reader.ReadFloat32 (),
|
|
reader.ReadFloat32 ()
|
|
];
|
|
return result;
|
|
}
|
|
|
|
ReadChunks (reader, endByte, onChunk)
|
|
{
|
|
while (reader.GetPosition () <= endByte - 6) {
|
|
let chunkId = reader.ReadUnsignedInteger16 ();
|
|
let chunkLength = reader.ReadUnsignedInteger32 ();
|
|
onChunk (chunkId, chunkLength);
|
|
}
|
|
}
|
|
|
|
GetChunkEnd (reader, length)
|
|
{
|
|
return reader.GetPosition () + length - 6;
|
|
}
|
|
|
|
SkipChunk (reader, length)
|
|
{
|
|
reader.Skip (length - 6);
|
|
}
|
|
};
|