public void BuildModel(int modelIndex) { _srModel = _srFile.Models[modelIndex]; String modelName = _objectName + "-" + modelIndex.ToString(); #region Materials ProgressStage = "Model " + modelIndex.ToString() + " - Creating Materials"; Thread.Sleep(500); for (int materialIndex = 0; materialIndex < _srModel.MaterialCount; materialIndex++) { Material material = new Material(); Color colorDiffuse = Color.FromArgb((int)unchecked (_srModel.Materials[materialIndex].colour)); material.Diffuse = colorDiffuse; material.TextureFileName = GetTextureName(_srModel, materialIndex); Materials.Add(material); progressLevel += _srModel.IndexCount / _srModel.Groups.Length; } #endregion #region Groups for (int groupIndex = 0; groupIndex < _srModel.Groups.Length; groupIndex++) { ProgressStage = "Model " + modelIndex.ToString() + " - Creating Group " + groupIndex.ToString(); Thread.Sleep(100); Tree srGroup = _srModel.Groups[groupIndex]; String groupName = String.Format("{0}-{1}-group-{2}", _objectName, modelIndex, groupIndex); if (srGroup != null && srGroup.mesh != null && srGroup.mesh.indexCount > 0 && srGroup.mesh.polygonCount > 0) { Node group = new Node(); SRMeshParser meshParser = new SRMeshParser(_objectName, _srFile); meshParser.BuildMesh(modelIndex, groupIndex, 0); foreach (SubMesh subMesh in meshParser.SubMeshes) { // If the mesh parser knew the total submeshes for the model, // then this could be done inside BuildMesh. subMesh.MeshIndex = Meshes.Count; group.SubMeshIndices.Add(SubMeshes.Count); SubMeshes.Add(subMesh); } Meshes.Add(meshParser.Mesh); group.Name = groupName; Groups.Add(group); } } #endregion ModelName = modelName; if (_srFile.Asset == CDC.Asset.Unit) { Model = new Unit(this); } else { Model = new Physical(this); } }
public void BuildModel(RenderResource resource, int modelIndex, CDC.Objects.ExportOptions options) { _srModel = _srFile.Models[modelIndex]; String modelName = _objectName + "-" + modelIndex.ToString(); #region Materials for (int materialIndex = 0; materialIndex < _srModel.MaterialCount; materialIndex++) { Material material = new Material(); material.Visible = _srModel.Materials[materialIndex].visible; // Breaks early SR1 builds. //material.BlendMode = _srModel.Materials[materialIndex].blendMode; //int sortPush = unchecked((sbyte)_srModel.Materials[materialIndex].sortPush); //sortPush = 128 - sortPush; //material.DepthBias = (1.0f / 100000.0f) * sortPush; // Maybe use a hack for warpgates WARPGATE_DrawWarpGateRim indicates tree 3 should have lower priority. Color colorDiffuse = Color.FromArgb((int)unchecked (_srModel.Materials[materialIndex].colour)); material.Diffuse = colorDiffuse; material.TextureFileName = CDC.Objects.Models.SRModel.GetTextureName(_srModel, materialIndex, options); Materials.Add(material); } #endregion #region Groups for (int groupIndex = 0; groupIndex < _srModel.Groups.Length; groupIndex++) { Tree srGroup = _srModel.Groups[groupIndex]; String groupName = String.Format("{0}-{1}-group-{2}", _objectName, modelIndex, groupIndex); if (srGroup != null && srGroup.mesh != null && srGroup.mesh.indexCount > 0 && srGroup.mesh.polygonCount > 0) { ModelNode group = new ModelNode(); SRMeshParser meshParser = new SRMeshParser(_objectName, _srFile); meshParser.BuildMesh(resource, modelIndex, groupIndex, 0); foreach (SubMesh subMesh in meshParser.SubMeshes) { // If the mesh parser knew the total submeshes for the model, // then this could be done inside BuildMesh. subMesh.MeshIndex = Meshes.Count; group.SubMeshIndices.Add(SubMeshes.Count); SubMeshes.Add(subMesh); } Meshes.Add(meshParser.Mesh); group.Name = groupName; Groups.Add(group); } } #endregion ModelName = modelName; Model = new Model(this); }
public void MergeSubMeshes() { var submesh = new ObjSubMesh(this); submesh.PositionFaces = SubMeshes.SelectMany(i => i.PositionFaces).ToList(); submesh.NormalFaces = SubMeshes.SelectMany(i => i.NormalFaces).ToList(); submesh.TexCoordFaces = SubMeshes.SelectMany(i => i.TexCoordFaces).ToList(); SubMeshes.Clear(); SubMeshes.Add(submesh); }
internal void Read(EndianBinaryReader reader, MeshSection section = null) { uint signature = reader.ReadUInt32(); reader.SeekCurrent(4); int subMeshCount, materialCount; long subMeshesOffset, materialsOffset; // X stores submesh/material count before the bounding sphere if (section?.Format == BinaryFormat.X) { subMeshCount = reader.ReadInt32(); materialCount = reader.ReadInt32(); BoundingSphere = reader.ReadBoundingSphere(); subMeshesOffset = reader.ReadOffset(); materialsOffset = reader.ReadOffset(); } else { BoundingSphere = reader.ReadBoundingSphere(); subMeshCount = reader.ReadInt32(); subMeshesOffset = reader.ReadOffset(); materialCount = reader.ReadInt32(); materialsOffset = reader.ReadOffset(); } SubMeshes.Capacity = subMeshCount; for (int i = 0; i < subMeshCount; i++) { reader.ReadAtOffset(subMeshesOffset + i * SubMesh.GetByteSize(section?.Format ?? BinaryFormat.DT), () => { var submesh = new SubMesh(); submesh.Read(reader, section); SubMeshes.Add(submesh); }); } Materials.Capacity = materialCount; for (int i = 0; i < materialCount; i++) { reader.ReadAtOffset(materialsOffset + i * Material.BYTE_SIZE, () => { var material = new Material(); material.Read(reader); Materials.Add(material); }); } }
public ushort CreateFreshSubMesh(ushort vertsToReserve, ushort trisToReserve) { // create custom List<> implementation with NativeArray that supports growth without assignment! SubMesh subMesh = new SubMesh((ushort)Verts.Count, (ushort)Tris.Count, vertsToReserve, trisToReserve); lastVert += vertsToReserve; lastTri += trisToReserve; SubMeshes.Add(subMesh); for (int i = 0; i < vertsToReserve; i++) { Verts.Add(Vector3.zero); // this is multiple assignment! BAD! Normals.Add(Vector3.up); TextureUVs.Add(Vector2.zero); SubmaterialUVs.Add(Vector2.zero); } for (int i = 0; i < trisToReserve; i++) { Tris.Add(0); // more evil multiple assignment! } return((ushort)(SubMeshes.Count + SubMeshBaseIdx - 1)); }
public void BuildModel(RenderResource resource) { Material materialA = new Material(); materialA.Visible = true; Color colorDiffuseA = Color.FromArgb(unchecked ((int)0xFF0000FF)); materialA.Diffuse = colorDiffuseA; materialA.TextureFileName = ""; Materials.Add(materialA); Material materialB = new Material(); materialB.Visible = true; Color colorDiffuseB = Color.FromArgb(unchecked ((int)0xFF00FF00)); materialB.Diffuse = colorDiffuseB; materialB.TextureFileName = ""; Materials.Add(materialB); ModelNode group = new ModelNode(); group.Name = "group"; MeshParser meshParser = new MeshParser(ModelName); meshParser.BuildMesh(resource); foreach (SubMesh subMesh in meshParser.SubMeshes) { // If the mesh parser knew the total submeshes for the model, // then this could be done inside BuildMesh. subMesh.MeshIndex = Meshes.Count; group.SubMeshIndices.Add(SubMeshes.Count); SubMeshes.Add(subMesh); } Meshes.Add(meshParser.Mesh); Groups.Add(group); Model = new Model(this); }
public void Push(SkinnedMeshRenderer renderer) { var mesh = renderer.sharedMesh; if (mesh == null) { Debug.LogWarningFormat("{0} has no mesh", renderer.name); return; } Renderers.Add(renderer); var indexOffset = Positions.Count; var boneIndexOffset = Bones.Count; Positions.AddRange(mesh.vertices); Normals.AddRange(mesh.normals); UV.AddRange(mesh.uv); Tangents.AddRange(mesh.tangents); if (mesh.vertexCount == mesh.boneWeights.Length) { BoneWeights.AddRange(mesh.boneWeights.Select(x => AddBoneIndexOffset(x, boneIndexOffset)).ToArray()); } else { BoneWeights.AddRange(Enumerable.Range(0, mesh.vertexCount).Select(x => new BoneWeight()).ToArray()); } BindPoses.AddRange(mesh.bindposes); Bones.AddRange(renderer.bones); for (int i = 0; i < mesh.subMeshCount; ++i) { var indices = mesh.GetIndices(i).Select(x => x + indexOffset); var mat = renderer.sharedMaterials[i]; var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat)); if (sameMaterialSubMeshIndex >= 0) { SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices); } else { SubMeshes.Add(new SubMesh { Indices = indices.ToList(), Material = mat, }); } } for (int i = 0; i < mesh.blendShapeCount; ++i) { var positions = (Vector3[])mesh.vertices.Clone(); var normals = (Vector3[])mesh.normals.Clone(); var tangents = mesh.tangents.Select(x => (Vector3)x).ToArray(); mesh.GetBlendShapeFrameVertices(i, 0, positions, normals, tangents); BlendShapes.Add(new BlendShape { VertexOffset = indexOffset, FrameWeight = mesh.GetBlendShapeFrameWeight(i, 0), Name = mesh.GetBlendShapeName(i), Positions = positions, Normals = normals, Tangents = tangents, }); } }
public void Push(MeshRenderer renderer) { var meshFilter = renderer.GetComponent <MeshFilter>(); if (meshFilter == null) { Debug.LogWarningFormat("{0} has no mesh filter", renderer.name); return; } var mesh = meshFilter.sharedMesh; if (mesh == null) { Debug.LogWarningFormat("{0} has no mesh", renderer.name); return; } Result.SourceMeshRenderers.Add(renderer); Result.MeshMap.Sources.Add(mesh); var indexOffset = Positions.Count; var boneIndexOffset = Bones.Count; Positions.AddRange(mesh.vertices .Select(x => renderer.transform.TransformPoint(x)) ); Normals.AddRange(mesh.normals .Select(x => renderer.transform.TransformVector(x)) ); UV.AddRange(mesh.uv); Tangents.AddRange(mesh.tangents .Select(t => { var v = renderer.transform.TransformVector(t.x, t.y, t.z); return(new Vector4(v.x, v.y, v.z, t.w)); }) ); var self = renderer.transform; var bone = self.parent; if (bone == null) { Debug.LogWarningFormat("{0} is root gameobject.", self.name); return; } var bindpose = bone.worldToLocalMatrix; BoneWeights.AddRange(Enumerable.Range(0, mesh.vertices.Length) .Select(x => new BoneWeight() { boneIndex0 = Bones.Count, weight0 = 1, }) ); BindPoses.Add(bindpose); Bones.Add(bone); for (int i = 0; i < mesh.subMeshCount && i < renderer.sharedMaterials.Length; ++i) { var indices = mesh.GetIndices(i).Select(x => x + indexOffset); var mat = renderer.sharedMaterials[i]; var sameMaterialSubMeshIndex = SubMeshes.FindIndex(x => ReferenceEquals(x.Material, mat)); if (sameMaterialSubMeshIndex >= 0) { SubMeshes[sameMaterialSubMeshIndex].Indices.AddRange(indices); } else { SubMeshes.Add(new SubMesh { Indices = indices.ToList(), Material = mat, }); } } }
public void BuildMesh(RenderResource resource) { float v = 1.2f; float h = 1.0f; BasicVertex[] vertices = { new BasicVertex { X = 0, Y = v, Z = 0 }, new BasicVertex { X = -h, Y = 0, Z = h }, new BasicVertex { X = -h, Y = 0, Z = -h }, new BasicVertex { X = h, Y = 0, Z = -h }, new BasicVertex { X = h, Y = 0, Z = h }, new BasicVertex { X = 0, Y = -v, Z = 0 } }; _vertexList.AddRange(vertices); int[] indices = { 0, 1, 2, 5, 3, 2, 0, 3, 4, 5, 1, 4, 5, 2, 1, 0, 2, 3, 5, 4, 3, 0, 4, 1 }; _indexList.AddRange(indices); Technique = "DefaultRender"; Mesh = new MeshPCT(resource, this); SubMesh subMeshA = new SubMesh { Name = MeshName + "-0", MaterialIndex = 0, indexCount = 12, startIndexLocation = 0, baseVertexLocation = 0 }; SubMeshes.Add(subMeshA); SubMesh subMeshB = new SubMesh { Name = MeshName + "-1", MaterialIndex = 1, indexCount = 12, startIndexLocation = 12, baseVertexLocation = 0 }; SubMeshes.Add(subMeshB); }
internal void Read(EndianBinaryReader reader, ObjectSection section = null) { reader.SeekCurrent(4); // Unused flags BoundingSphere = reader.ReadBoundingSphere(); int subMeshCount = reader.ReadInt32(); long subMeshesOffset = reader.ReadOffset(); var vertexFormat = ( VertexFormatAttributes )reader.ReadUInt32(); int vertexSize = reader.ReadInt32(); int vertexCount = reader.ReadInt32(); var attributeOffsets = reader.ReadOffsets(20); Flags = ( MeshFlags )reader.ReadInt32(); uint attributeFlags = reader.ReadUInt32(); reader.SkipNulls(6 * sizeof(uint)); Name = reader.ReadString(StringBinaryFormat.FixedLength, 64); reader.ReadAtOffset(subMeshesOffset, () => { SubMeshes.Capacity = subMeshCount; for (int i = 0; i < subMeshCount; i++) { var subMesh = new SubMesh(); subMesh.Read(reader, section); SubMeshes.Add(subMesh); } }); // Modern Format if ((vertexFormat & VertexFormatAttributes.UsesModernStorage) != 0) { ReadVertexAttributesModern(); } else { ReadVertexAttributesClassic(); } void ReadVertexAttributesClassic() { Vector4[] boneWeights = null; Vector4[] boneIndices = null; for (int i = 0; i < attributeOffsets.Length; i++) { var attribute = ( VertexFormatAttributes )(1 << i); reader.ReadAtOffsetIf((vertexFormat & attribute) != 0, attributeOffsets[i], () => { switch (attribute) { case VertexFormatAttributes.Position: Positions = reader.ReadVector3s(vertexCount); break; case VertexFormatAttributes.Normal: Normals = reader.ReadVector3s(vertexCount); break; case VertexFormatAttributes.Tangent: Tangents = reader.ReadVector4s(vertexCount); break; case VertexFormatAttributes.TexCoord0: TexCoords0 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.TexCoord1: TexCoords1 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.TexCoord2: TexCoords2 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.TexCoord3: TexCoords3 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttributes.Color0: Colors0 = reader.ReadColors(vertexCount); break; case VertexFormatAttributes.Color1: Colors1 = reader.ReadColors(vertexCount); break; case VertexFormatAttributes.BoneWeight: boneWeights = reader.ReadVector4s(vertexCount); break; case VertexFormatAttributes.BoneIndex: boneIndices = reader.ReadVector4s(vertexCount); break; default: Console.WriteLine("Unhandled vertex format element: {0}", attribute); break; } }); } if (boneWeights == null || boneIndices == null) { return; } BoneWeights = new BoneWeight[vertexCount]; for (int i = 0; i < vertexCount; i++) { var weight4 = boneWeights[i]; var index4 = Vector4.Divide(boneIndices[i], 3); var boneWeight = new BoneWeight { Weight1 = weight4.X, Weight2 = weight4.Y, Weight3 = weight4.Z, Weight4 = weight4.W, Index1 = ( int )index4.X, Index2 = ( int )index4.Y, Index3 = ( int )index4.Z, Index4 = ( int )index4.W }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } } void ReadVertexAttributesModern() { Positions = new Vector3[vertexCount]; Normals = new Vector3[vertexCount]; Tangents = new Vector4[vertexCount]; TexCoords0 = new Vector2[vertexCount]; TexCoords1 = new Vector2[vertexCount]; if (attributeFlags == 10) { TexCoords2 = new Vector2[vertexCount]; TexCoords3 = new Vector2[vertexCount]; } else if (attributeFlags == 6) { TexCoords2 = new Vector2[vertexCount]; } Colors0 = new Color[vertexCount]; if (attributeFlags == 4) { BoneWeights = new BoneWeight[vertexCount]; } bool hasTangents = false; EndianBinaryReader vertexReader; long baseOffset; if (section != null) { vertexReader = section.VertexData.Reader; baseOffset = section.VertexData.DataOffset; } else { vertexReader = reader; baseOffset = reader.BaseOffset; } long current = reader.Position; for (int i = 0; i < vertexCount; i++) { vertexReader.SeekBegin(baseOffset + attributeOffsets[13] + vertexSize * i); Positions[i] = vertexReader.ReadVector3(); Normals[i] = vertexReader.ReadVector3(VectorBinaryFormat.Int16); vertexReader.SeekCurrent(2); Tangents[i] = vertexReader.ReadVector4(VectorBinaryFormat.Int16); TexCoords0[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); TexCoords1[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); if (attributeFlags == 10) { TexCoords2[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); TexCoords3[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); } else if (attributeFlags == 6) { TexCoords2[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); } Colors0[i] = vertexReader.ReadColor(VectorBinaryFormat.Half); if (attributeFlags == 4) { var boneWeight = new BoneWeight { Weight1 = vertexReader.ReadUInt16() / 32767f, Weight2 = vertexReader.ReadUInt16() / 32767f, Weight3 = vertexReader.ReadUInt16() / 32767f, Weight4 = vertexReader.ReadUInt16() / 32767f, Index1 = vertexReader.ReadByte() / 3, Index2 = vertexReader.ReadByte() / 3, Index3 = vertexReader.ReadByte() / 3, Index4 = vertexReader.ReadByte() / 3 }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } // Normalize normal because precision Normals[i] = Vector3.Normalize(Normals[i]); // Checks to get rid of useless data after reading if (Tangents[i] != Vector4.Zero) { hasTangents = true; } } if (!hasTangents) { Tangents = null; } reader.SeekBegin(current); } if (Tangents == null) { return; } for (int i = 0; i < Tangents.Length; i++) { int direction = Math.Sign(Tangents[i].W); var tangent = Vector3.Normalize(new Vector3(Tangents[i].X, Tangents[i].Y, Tangents[i].Z)); Tangents[i] = new Vector4(tangent, direction); } }
internal void Read(EndianBinaryReader reader, ObjectSection section = null) { reader.SeekCurrent(4); BoundingSphere = reader.ReadBoundingSphere(); int subMeshCount = reader.ReadInt32(); long subMeshesOffset = reader.ReadOffset(); var attributes = ( VertexFormatAttribute )reader.ReadUInt32(); int stride = reader.ReadInt32(); int vertexCount = reader.ReadInt32(); var elemItems = reader.ReadUInt32s(section?.Format == BinaryFormat.X ? 49 : 28); Name = reader.ReadString(StringBinaryFormat.FixedLength, 64); SubMeshes.Capacity = subMeshCount; for (int i = 0; i < subMeshCount; i++) { reader.ReadAtOffset(subMeshesOffset + i * SubMesh.GetByteSize(section?.Format ?? BinaryFormat.DT), () => { var subMesh = new SubMesh(); subMesh.Read(reader, section); SubMeshes.Add(subMesh); }); } // Modern Format if (section != null) { ReadVertexAttributesModern(); } else { ReadVertexAttributesClassic(); } void ReadVertexAttributesClassic() { Vector4[] boneWeights = null; Vector4[] boneIndices = null; for (int i = 0; i < 28; i++) { var attribute = ( VertexFormatAttribute )(1 << i); reader.ReadAtOffsetIf((attributes & attribute) != 0, elemItems[i], () => { switch (attribute) { case VertexFormatAttribute.Vertex: Vertices = reader.ReadVector3s(vertexCount); break; case VertexFormatAttribute.Normal: Normals = reader.ReadVector3s(vertexCount); break; case VertexFormatAttribute.Tangent: Tangents = reader.ReadVector4s(vertexCount); break; case VertexFormatAttribute.UVChannel1: UVChannel1 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttribute.UVChannel2: UVChannel2 = reader.ReadVector2s(vertexCount); break; case VertexFormatAttribute.Color: Colors = reader.ReadColors(vertexCount); break; case VertexFormatAttribute.BoneWeight: boneWeights = reader.ReadVector4s(vertexCount); break; case VertexFormatAttribute.BoneIndex: boneIndices = reader.ReadVector4s(vertexCount); break; default: Console.WriteLine("Unhandled vertex format element: {0}", attribute); break; } }); } if (boneWeights != null && boneIndices != null) { BoneWeights = new BoneWeight[vertexCount]; for (int i = 0; i < vertexCount; i++) { var weight4 = boneWeights[i]; var index4 = Vector4.Divide(boneIndices[i], 3); var boneWeight = new BoneWeight { Weight1 = weight4.X, Weight2 = weight4.Y, Weight3 = weight4.Z, Weight4 = weight4.W, Index1 = ( int )index4.X, Index2 = ( int )index4.Y, Index3 = ( int )index4.Z, Index4 = ( int )index4.W }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } } } void ReadVertexAttributesModern() { uint dataOffset = elemItems[section.Format == BinaryFormat.X ? 27 : 13]; uint attributeFlags = elemItems[section.Format == BinaryFormat.X ? 42 : 21]; if (attributeFlags == 2 || attributeFlags == 4) { Vertices = new Vector3[vertexCount]; Normals = new Vector3[vertexCount]; Tangents = new Vector4[vertexCount]; UVChannel1 = new Vector2[vertexCount]; UVChannel2 = new Vector2[vertexCount]; Colors = new Color[vertexCount]; if (attributeFlags == 4) { BoneWeights = new BoneWeight[vertexCount]; } bool hasTangents = false; bool hasUVChannel2 = false; bool hasColors = false; var vertexReader = section.VertexData.Reader; for (int i = 0; i < vertexCount; i++) { vertexReader.SeekBegin(section.VertexData.DataOffset + dataOffset + stride * i); Vertices[i] = vertexReader.ReadVector3(); Normals[i] = vertexReader.ReadVector3(VectorBinaryFormat.Int16); vertexReader.SeekCurrent(2); Tangents[i] = vertexReader.ReadVector4(VectorBinaryFormat.Int16); UVChannel1[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); UVChannel2[i] = vertexReader.ReadVector2(VectorBinaryFormat.Half); Colors[i] = vertexReader.ReadColor(VectorBinaryFormat.Half); if (attributeFlags == 4) { var boneWeight = new BoneWeight { Weight1 = vertexReader.ReadUInt16() / 32767f, Weight2 = vertexReader.ReadUInt16() / 32767f, Weight3 = vertexReader.ReadUInt16() / 32767f, Weight4 = vertexReader.ReadUInt16() / 32767f, Index1 = vertexReader.ReadByte() / 3, Index2 = vertexReader.ReadByte() / 3, Index3 = vertexReader.ReadByte() / 3, Index4 = vertexReader.ReadByte() / 3 }; boneWeight.Validate(); BoneWeights[i] = boneWeight; } // Normalize normal because precision Normals[i] = Vector3.Normalize(Normals[i]); // Checks to get rid of useless data after reading if (Tangents[i] != Vector4.Zero) { hasTangents = true; } if (UVChannel1[i] != UVChannel2[i]) { hasUVChannel2 = true; } if (!Colors[i].Equals(Color.White)) { hasColors = true; } } if (!hasTangents) { Tangents = null; } if (!hasUVChannel2) { UVChannel2 = null; } if (!hasColors) { Colors = null; } } if (Tangents != null) { for (int i = 0; i < Tangents.Length; i++) { int direction = Math.Sign(Tangents[i].W); var tangent = Vector3.Normalize(new Vector3(Tangents[i].X, Tangents[i].Y, Tangents[i].Z)); Tangents[i] = new Vector4(tangent, direction); } } } }
/// <summary> /// Returns the submesh for this face based on material info. /// </summary> /// <param name='f'>The face to find a submesh for.</param> public KeyValuePair <IntermediateMaterial, List <int> > FindOrCreateSubMesh(Face f) { ExternalReference externalRef = null; if (Header.Parent != null) { externalRef = Header.Parent as ExternalReference; } // Fetch palettes MaterialPalette mp = null; if (f.MaterialIndex != -1) { if (externalRef != null) { externalRef.Header.MaterialPalettes.TryGetValue(f.MaterialIndex, out mp); } if (mp == null) { Header.MaterialPalettes.TryGetValue(f.MaterialIndex, out mp); } if (mp == null) { Log.WriteError("Could not find material palette: " + f.MaterialIndex); } } TexturePalette mainTex = null; if (f.TexturePattern != -1) { if (externalRef != null) { externalRef.Header.TexturePalettes.TryGetValue(f.TexturePattern, out mainTex); } if (mainTex == null) { Header.TexturePalettes.TryGetValue(f.TexturePattern, out mainTex); } if (mainTex == null) { Log.WriteError("Could not find texture pattern: " + f.TexturePattern); } } TexturePalette detailTex = null; if (f.DetailTexturePattern != -1) { if (externalRef != null) { externalRef.Header.TexturePalettes.TryGetValue(f.DetailTexturePattern, out detailTex); } if (mainTex == null) { Header.TexturePalettes.TryGetValue(f.DetailTexturePattern, out detailTex); } if (mainTex == null) { Log.WriteError("Could not find detail texture pattern: " + f.DetailTexturePattern); } } // Check locally foreach (KeyValuePair <IntermediateMaterial, List <int> > mesh in SubMeshes) { if (mesh.Key.Equals(mp, mainTex, detailTex, f.Transparency, f.LightMode)) { return(mesh); } } // Create a new submesh IntermediateMaterial im = Header.MaterialBank.FindOrCreateMaterial(f); KeyValuePair <IntermediateMaterial, List <int> > newMesh = new KeyValuePair <IntermediateMaterial, List <int> >(im, new List <int>()); SubMeshes.Add(newMesh); return(newMesh); }