// Private Methods private void Read(MDChunk model, MDNode node, BinaryReader reader) { _subMeshPointerTableOffset = reader.ReadUInt32(); if (_subMeshPointerTableOffset == 0) { return; } reader.BaseStream.Seek((uint)model.offset + MDChunk.DATA_START_ADDRESS + _subMeshPointerTableOffset, SeekOrigin.Begin); _numSubmeshes = reader.ReadUInt16(); _numUnknown = reader.ReadUInt16(); _subMeshPointerArray = new uint[_numSubmeshes]; if (_numSubmeshes == 0 && _numUnknown == 0) { return; } for (int i = 0; i < _numSubmeshes; i++) { _subMeshPointerArray[i] = reader.ReadUInt32(); } _subMeshes = new IMDSubMesh[_numSubmeshes]; for (int i = 0; i < _numSubmeshes; i++) { reader.BaseStream.Seek((uint)model.offset + MDChunk.DATA_START_ADDRESS + _subMeshPointerArray[i], SeekOrigin.Begin); _subMeshes[i] = MDSubMeshFactory.Get(model, node, reader); } }
// Internal Methods internal void ReadMeshes(MDChunk model, BinaryReader reader) { if (_meshOffset != 0) { reader.BaseStream.Seek((uint)model.offset + MDChunk.DATA_START_ADDRESS + _meshOffset, SeekOrigin.Begin); _mesh = new MDMesh(model, this, reader); } }
// Methods public static IMDSubMesh Get(MDChunk model, MDNode node, BinaryReader reader) { IntPtr ptr = (IntPtr)reader.BaseStream.Position; uint type = reader.ReadUInt32(); switch (type) { case 1: return(new MDSubMeshType1(model, node, ptr, reader)); case 2: return(new MDSubMeshType2(model, node, ptr, reader)); default: return(null); } }
// Private Methods private void Read(MDChunk model, BinaryReader reader) { _flag1 = reader.ReadUInt32(); _flag2 = reader.ReadUInt32(); _index = reader.ReadInt32(); _parentIndex = reader.ReadInt32(); _rotation = reader.ReadVector3(); reader.BaseStream.Position += 4; _position = reader.ReadVector3(); reader.BaseStream.Position += 4; _scale = reader.ReadVector3(); reader.BaseStream.Position += 4; _meshBoundingBoxOffset = reader.ReadUInt32(); _meshOffset = reader.ReadUInt32(); _unk1 = reader.ReadUInt32(); _unk2 = reader.ReadUInt32(); _localMatrix = Matrix4.CreateRotationX(_rotation.X) * Matrix4.CreateRotationY(_rotation.Y) * Matrix4.CreateRotationZ(_rotation.Z); _localMatrix *= Matrix4.CreateScale(_scale); _localMatrix *= Matrix4.CreateTranslation(_position); _worldMatrix = _localMatrix; if (_parentIndex != -1) { Parent = model.Nodes[_parentIndex]; _worldMatrix *= Parent.WorldMatrix; } if (model.NodeNameSection != null) { _name = Array.Find(model.NodeNameSection.Names, n => n.ID == _index).Name; } if (_meshBoundingBoxOffset != 0) { reader.BaseStream.Seek((uint)model.offset + MDChunk.DATA_START_ADDRESS + _meshBoundingBoxOffset, SeekOrigin.Begin); _bbox = new MDBoundingBox(); _bbox.Min = reader.ReadVector3(); _bbox.Max = reader.ReadVector3(); } }
// Methods internal void InternalRead(MDChunk model, BinaryReader reader) { _batchSize = reader.ReadUInt16(); _materialID = reader.ReadUInt16(); _batchOffset = reader.ReadInt32(); reader.BaseStream.Seek((uint)model.offset + MDChunk.DATA_START_ADDRESS + _batchOffset, SeekOrigin.Begin); _vifPackets = VIFCodeEvaluator.EvaluateBlock(reader, _batchSize); _batches = MDSubMeshVifBatch.ParseBatches(_vifPackets, UsedNodeCount); foreach (MDSubMeshVifBatch batch in _batches) { batch.TransformedPositions = new Vector3[batch.VertexCount]; batch.TransformedNormals = new Vector3[batch.VertexCount]; for (int i = 0; i < batch.VertexCount; i++) { batch.TransformedPositions[i] = Vector3.Transform(batch.Positions[i], UsedNodes[batch.UsedNodeArrayIndex].WorldMatrix); batch.TransformedNormals[i] = Vector3.TransformNormal(batch.Normals[i], UsedNodes[batch.UsedNodeArrayIndex].WorldMatrix); } } }
// Constructors internal MDNode(MDChunk model, BinaryReader reader) { _ptr = (IntPtr)reader.BaseStream.Position; Read(model, reader); }
// Constructors internal MDSubMeshType2(MDChunk model, MDNode node, IntPtr ptr, BinaryReader reader) { _node = node; InternalRead(model, reader); _material = model.Materials[_materialID]; }
// Constructors internal MDMesh(MDChunk model, MDNode node, BinaryReader reader) { Read(model, node, reader); }
// Methods internal void InternalRead(MDChunk model, BinaryReader reader) { _batchSize = reader.ReadUInt16(); _materialID = reader.ReadUInt16(); _batchOffset = reader.ReadInt32(); _numUsedNodes = reader.ReadInt32(); _usedNodeIndices = reader.ReadUInt16Array(_numUsedNodes); _usedNodes = new MDNode[_numUsedNodes]; for (int i = 0; i < _numUsedNodes; i++) { _usedNodes[i] = model.Nodes[_usedNodeIndices[i]]; } reader.BaseStream.Seek((int)model.offset + MDChunk.DATA_START_ADDRESS + _batchOffset, SeekOrigin.Begin); _vifPackets = VIFCodeEvaluator.EvaluateBlock(reader, _batchSize); _batches = MDSubMeshVifBatch.ParseBatches(_vifPackets, _numUsedNodes); foreach (MDSubMeshVifBatch batch in _batches) { batch.TransformedPositions = new Vector3[batch.VertexCount]; batch.TransformedNormals = new Vector3[batch.VertexCount]; for (int i = 0; i < batch.VertexCount; i++) { if (batch.Weights[i] != 0) { batch.TransformedPositions[i] = Vector3.Transform(batch.Positions[i], UsedNodes[batch.UsedNodeArrayIndex].WorldMatrix * batch.Weights[i]); } else { batch.TransformedPositions[i] = Vector3.Zero; } if (batch.Weights[i] != 0) { batch.TransformedNormals[i] = Vector3.TransformNormal(batch.Normals[i], UsedNodes[batch.UsedNodeArrayIndex].WorldMatrix * batch.Weights[i]); } else { batch.TransformedNormals[i] = Vector3.Zero; } } } List<MDSubMeshVifBatch> fixedBatches = new List<MDSubMeshVifBatch>(); for (int i = 0; i < _batches.Count; i+=(int)_numUsedNodes) { Vector3[] pos = new Vector3[_batches[i].VertexCount]; Vector3[] nrm = new Vector3[_batches[i].VertexCount]; for (int k = 0; k < _batches[i].VertexCount; k++) { for (int j = 0; j < _numUsedNodes; j++) { pos[k] += _batches[i + j].TransformedPositions[k]; nrm[k] += _batches[i + j].TransformedNormals[k]; } } for (int k = 0; k < _batches[i].VertexCount; k++) { nrm[k].Normalize(); } /* SubMeshVifBatch finalBatch = _batches[(int)_numUsedNodes - 1]; finalBatch.TransformedPositions = pos; finalBatch.TransformedNormals = pos; finalBatch.NodeIndices = fixedBatches.Add(finalBatch); */ for (int j = 0; j < _numUsedNodes; j++) { _batches[i + j].TransformedPositions = pos; _batches[i + j].TransformedNormals = nrm; _batches[i + j].Colors = _batches[(int)_numUsedNodes - 1].Colors; _batches[i + j].TextureCoords = _batches[(int)_numUsedNodes - 1].TextureCoords; } } }
// Methods internal void InternalRead(MDChunk model, BinaryReader reader) { _batchSize = reader.ReadUInt16(); _materialID = reader.ReadUInt16(); _batchOffset = reader.ReadInt32(); _numUsedNodes = reader.ReadInt32(); _usedNodeIndices = reader.ReadUInt16Array(_numUsedNodes); _usedNodes = new MDNode[_numUsedNodes]; for (int i = 0; i < _numUsedNodes; i++) { _usedNodes[i] = model.Nodes[_usedNodeIndices[i]]; } reader.BaseStream.Seek((int)model.offset + MDChunk.DATA_START_ADDRESS + _batchOffset, SeekOrigin.Begin); _vifPackets = VIFCodeEvaluator.EvaluateBlock(reader, _batchSize); _batches = MDSubMeshVifBatch.ParseBatches(_vifPackets, _numUsedNodes); foreach (MDSubMeshVifBatch batch in _batches) { batch.TransformedPositions = new Vector3[batch.VertexCount]; batch.TransformedNormals = new Vector3[batch.VertexCount]; for (int i = 0; i < batch.VertexCount; i++) { if (batch.Weights[i] != 0) { batch.TransformedPositions[i] = Vector3.Transform(batch.Positions[i], UsedNodes[batch.UsedNodeArrayIndex].WorldMatrix * batch.Weights[i]); } else { batch.TransformedPositions[i] = Vector3.Zero; } if (batch.Weights[i] != 0) { batch.TransformedNormals[i] = Vector3.TransformNormal(batch.Normals[i], UsedNodes[batch.UsedNodeArrayIndex].WorldMatrix * batch.Weights[i]); } else { batch.TransformedNormals[i] = Vector3.Zero; } } } List <MDSubMeshVifBatch> fixedBatches = new List <MDSubMeshVifBatch>(); for (int i = 0; i < _batches.Count; i += (int)_numUsedNodes) { Vector3[] pos = new Vector3[_batches[i].VertexCount]; Vector3[] nrm = new Vector3[_batches[i].VertexCount]; for (int k = 0; k < _batches[i].VertexCount; k++) { for (int j = 0; j < _numUsedNodes; j++) { pos[k] += _batches[i + j].TransformedPositions[k]; nrm[k] += _batches[i + j].TransformedNormals[k]; } } for (int k = 0; k < _batches[i].VertexCount; k++) { nrm[k].Normalize(); } /* * SubMeshVifBatch finalBatch = _batches[(int)_numUsedNodes - 1]; * finalBatch.TransformedPositions = pos; * finalBatch.TransformedNormals = pos; * finalBatch.NodeIndices = * fixedBatches.Add(finalBatch); */ for (int j = 0; j < _numUsedNodes; j++) { _batches[i + j].TransformedPositions = pos; _batches[i + j].TransformedNormals = nrm; _batches[i + j].Colors = _batches[(int)_numUsedNodes - 1].Colors; _batches[i + j].TextureCoords = _batches[(int)_numUsedNodes - 1].TextureCoords; } } }