public RenderObjectREM(remParser parser, remMesh mesh) { HighlightSubmesh = new HashSet<int>(); highlightMaterial = new Material(); highlightMaterial.Ambient = new Color4(1, 1, 1, 1); highlightMaterial.Diffuse = new Color4(1, 0, 1, 0); this.device = Gui.Renderer.Device; if (Textures.Count + parser.MATC.Count > Textures.Capacity) { Textures.Capacity += parser.MATC.Count; } Materials = new Material[parser.MATC.Count]; rootFrame = CreateHierarchy(parser, mesh, device, out meshFrames); AnimationController = new AnimationController(numFrames, 30, 30, 1); Frame.RegisterNamedMatrices(rootFrame, AnimationController); for (int i = 0; i < meshFrames.Count; i++) { if (i == 0) { Bounds = meshFrames[i].Bounds; } else { Bounds = BoundingBox.Merge(Bounds, meshFrames[i].Bounds); } } }
public static remMesh CreateMesh(WorkspaceMesh mesh, out string[] materialNames, out int[] indices, out bool[] worldCoords, out bool[] replaceSubmeshesOption) { int numUncheckedSubmeshes = 0; foreach (ImportedSubmesh submesh in mesh.SubmeshList) { if (!mesh.isSubmeshEnabled(submesh)) numUncheckedSubmeshes++; } int numSubmeshes = mesh.SubmeshList.Count - numUncheckedSubmeshes; materialNames = new string[numSubmeshes]; indices = new int[numSubmeshes]; worldCoords = new bool[numSubmeshes]; replaceSubmeshesOption = new bool[numSubmeshes]; remMesh newMesh = new remMesh(numSubmeshes); newMesh.name = new remId(mesh.Name); List<remVertex> newVertices = new List<remVertex>(); List<int> newFaces = new List<int>(); List<int> newFaceMarks = new List<int>(); for (int i = 0, submeshIdx = 0; i < numSubmeshes; i++, submeshIdx++) { while (!mesh.isSubmeshEnabled(mesh.SubmeshList[submeshIdx])) submeshIdx++; ImportedSubmesh submesh = mesh.SubmeshList[submeshIdx]; newMesh.AddMaterial(new remId(submesh.Material)); materialNames[i] = submesh.Material; indices[i] = submesh.Index; worldCoords[i] = submesh.WorldCoords; replaceSubmeshesOption[i] = mesh.isSubmeshReplacingOriginal(submesh); List<ImportedFace> faceList = submesh.FaceList; newFaces.Capacity += faceList.Count * 3; int[] faceMarks = new int[faceList.Count]; for (int j = 0; j < faceList.Count; j++) { ImportedFace face = faceList[j]; for (int k = 0; k < 3; k++) { newFaces.Add(face.VertexIndices[k] + newVertices.Count); } faceMarks[j] = i; } newFaceMarks.AddRange(faceMarks); List<ImportedVertex> vertexList = submesh.VertexList; newVertices.Capacity += vertexList.Count; for (int j = 0; j < vertexList.Count; j++) { ImportedVertex vert = vertexList[j]; remVertex newVertex = new remVertex(); if (submesh.WorldCoords) { newVertex.Position = vert.Position; newVertex.Normal = vert.Normal; } else { newVertex.Position = new Vector3(vert.Position.X, -vert.Position.Z, vert.Position.Y); newVertex.Normal = new Vector3(vert.Normal.X, -vert.Normal.Z, vert.Normal.Y); } newVertex.UV = new Vector2(vert.UV[0], vert.UV[1]); newVertices.Add(newVertex); } } newMesh.vertices = newVertices.ToArray(); newMesh.faces = newFaces.ToArray(); newMesh.faceMarks = newFaceMarks.ToArray(); return newMesh; }
public static void RemoveSubmesh(remParser parser, remMesh mesh, int submeshIdx) { List<int> newFaces = new List<int>(mesh.numFaces * 3); List<int> newFaceMarks = new List<int>(mesh.numFaces); bool[] usedVertices = new bool[mesh.numVertices]; for (int i = 0; i < mesh.faceMarks.Length; i++) { if (mesh.faceMarks[i] != submeshIdx) { newFaceMarks.Add(mesh.faceMarks[i] < submeshIdx ? mesh.faceMarks[i] : mesh.faceMarks[i] - 1); for (int j = i * 3; j < i * 3 + 3; j++) { int vertIdx = mesh.faces[j]; newFaces.Add(vertIdx); usedVertices[vertIdx] = true; } } } int[] vertIdxMap = new int[mesh.numVertices]; List<remVertex> vertList = new List<remVertex>(mesh.numVertices); int numNewVerts = 0; for (int i = 0; i < mesh.numVertices; i++) { if (usedVertices[i]) { vertIdxMap[i] = numNewVerts++; vertList.Add(mesh.vertices[i]); } } mesh.vertices = vertList.ToArray(); for (int i = 0; i < newFaces.Count; i++) { newFaces[i] = vertIdxMap[newFaces[i]]; } mesh.faces = newFaces.ToArray(); mesh.faceMarks = newFaceMarks.ToArray(); mesh.materials.RemoveAt(submeshIdx); remSkin skin = rem.FindSkin(mesh.name, parser.SKIC); if (skin != null) { for (int i = 0; i < skin.Count; i++) { remBoneWeights bw = skin[i]; Dictionary<int, float> newBoneWeights = new Dictionary<int,float>(); for (int j = 0; j < bw.numVertIdxWts; j++) { int oldVertIdx = bw.vertexIndices[j]; if (usedVertices[oldVertIdx]) { newBoneWeights.Add(vertIdxMap[oldVertIdx], bw.vertexWeights[j]); } } if (newBoneWeights.Count > 0) { bw.vertexIndices = new int[newBoneWeights.Count]; bw.vertexWeights = new float[newBoneWeights.Count]; newBoneWeights.Keys.CopyTo(bw.vertexIndices, 0); newBoneWeights.Values.CopyTo(bw.vertexWeights, 0); } else { skin.RemoveChild(i); i--; } } } }
public static void RemoveMesh(remParser parser, remMesh mesh) { parser.MESC.RemoveChild(mesh); mesh.frame = null; remSkin skin = FindSkin(mesh.name, parser.SKIC); if (skin != null) { parser.SKIC.RemoveChild(skin); } }
private AnimationFrame CreateHierarchy(remParser parser, remMesh mesh, Device device, out List<AnimationFrame> meshFrames) { meshFrames = new List<AnimationFrame>(1); HashSet<string> extractFrames = rem.SearchHierarchy(parser, mesh); #if !DONT_MIRROR Matrix orignalMatrix = parser.BONC.rootFrame.matrix; parser.BONC.rootFrame.matrix *= Matrix.Scaling(1f, 1f, -1f); #endif AnimationFrame rootFrame = CreateFrame(parser.BONC.rootFrame, parser, extractFrames, mesh, device, Matrix.Identity, meshFrames); SetupBoneMatrices(rootFrame, rootFrame); #if !DONT_MIRROR parser.BONC.rootFrame.matrix = orignalMatrix; #endif return rootFrame; }
private AnimationFrame CreateFrame(remBone frame, remParser parser, HashSet<string> extractFrames, remMesh mesh, Device device, Matrix combinedParent, List<AnimationFrame> meshFrames) { AnimationFrame animationFrame = new AnimationFrame(); animationFrame.Name = frame.name.ToString(); animationFrame.TransformationMatrix = frame.matrix; animationFrame.OriginalTransform = animationFrame.TransformationMatrix; animationFrame.CombinedTransform = combinedParent * animationFrame.TransformationMatrix; if (frame.name == mesh.frame) { ExtendedMaterial[] materials = new ExtendedMaterial[mesh.numMats]; List<List<remVertex>> submeshVertLists = new List<List<remVertex>>(mesh.numMats); List<List<ushort>> submeshFaceLists = new List<List<ushort>>(mesh.numMats); List<int[]> submeshVertIndices = new List<int[]>(mesh.numMats); SplitMesh(mesh, submeshVertLists, submeshFaceLists, submeshVertIndices); remSkin boneList = rem.FindSkin(mesh.name, parser.SKIC); bool skinned = boneList != null; int numBones = skinned ? boneList.Count : 0; List<string> boneNamesList = new List<string>(numBones); List<Matrix> boneOffsetsList = new List<Matrix>(numBones); for (int boneIdx = 0; boneIdx < numBones; boneIdx++) { boneNamesList.Add(boneList[boneIdx].bone.ToString()); boneOffsetsList.Add(boneList[boneIdx].matrix); } List<string> boneFrameParentNames = new List<string>(numBones); List<Matrix> boneFrameParentMatrices = new List<Matrix>(numBones); for (int boneIdx = 0; boneIdx < numBones; boneIdx++) { remBone boneFrame = rem.FindFrame(boneList[boneIdx].bone, parser.BONC.rootFrame); if (boneFrame == null) { continue; } remBone boneFrameParent = boneFrame.Parent; if (!boneNamesList.Contains(boneFrameParent.name) && !boneFrameParentNames.Contains(boneFrameParent.name)) { boneFrameParentNames.Add(boneFrameParent.name); Matrix incompleteMeshFrameCorrection = Matrix.Invert(frame.matrix); boneFrameParentMatrices.Add(incompleteMeshFrameCorrection * Matrix.Invert(boneFrame.matrix) * boneList[boneIdx].matrix); } } boneNamesList.AddRange(boneFrameParentNames); string[] boneNames = boneNamesList.ToArray(); boneOffsetsList.AddRange(boneFrameParentMatrices); Matrix[] boneOffsets = boneOffsetsList.ToArray(); AnimationMeshContainer[] meshContainers = new AnimationMeshContainer[submeshFaceLists.Count]; Vector3 min = new Vector3(Single.MaxValue); Vector3 max = new Vector3(Single.MinValue); for (int i = 0; i < submeshFaceLists.Count; i++) { List<ushort> faceList = submeshFaceLists[i]; List<remVertex> vertexList = submeshVertLists[i]; Mesh animationMesh = new Mesh(device, faceList.Count, vertexList.Count, MeshFlags.Managed, PositionBlendWeightsIndexedNormalTexturedColoured.Format); using (DataStream indexStream = animationMesh.LockIndexBuffer(LockFlags.None)) { for (int j = 0; j < faceList.Count; j++) { indexStream.Write(faceList[j]); } animationMesh.UnlockIndexBuffer(); } byte[][] vertexBoneIndices = null; float[][] vertexWeights = ConvertVertexWeights(vertexList, submeshVertIndices[i], boneList, out vertexBoneIndices); FillVertexBuffer(animationMesh, vertexList, vertexWeights, vertexBoneIndices, -1); var normalLines = new PositionBlendWeightsIndexedColored[vertexList.Count * 2]; for (int j = 0; j < vertexList.Count; j++) { remVertex vertex = vertexList[j]; Vector3 position = vertex.Position; Vector3 normal = vertex.Normal; float[] boneWeights = vertexWeights[j]; normalLines[j * 2] = new PositionBlendWeightsIndexedColored(position, boneWeights, vertexBoneIndices[j], Color.Coral.ToArgb()); normalLines[(j * 2) + 1] = new PositionBlendWeightsIndexedColored(position + normal, boneWeights, vertexBoneIndices[j], Color.Blue.ToArgb()); #if !DONT_MIRROR position.Z *= -1f; #endif min = Vector3.Minimize(min, position); max = Vector3.Maximize(max, position); } AnimationMeshContainer meshContainer = new AnimationMeshContainer(); meshContainer.Name = animationFrame.Name; meshContainer.MeshData = new MeshData(animationMesh); meshContainer.NormalLines = normalLines; meshContainer.BoneNames = boneNames; meshContainer.BoneOffsets = boneOffsets; meshContainers[i] = meshContainer; remMaterial mat = rem.FindMaterial(mesh.materials[i], parser.MATC); if (mat != null) { Material material3D = new Material(); material3D.Ambient = new Color4(mat.ambient); material3D.Diffuse = new Color4(mat.diffuse); material3D.Emissive = new Color4(mat.emissive); material3D.Specular = new Color4(mat.specular); material3D.Power = mat.specularPower; int matIdx = parser.MATC.IndexOf(mat); Materials[matIdx] = material3D; meshContainer.MaterialIndex = matIdx; int texIdx = 0; if (mat.texture != null && !TextureDic.TryGetValue(mat.texture.ToString(), out texIdx)) { ImportedTexture importedTex = null; if (!ImportedTextures.TryGetValue(mat.texture.ToString(), out importedTex)) { importedTex = rem.ImportedTexture(mat.texture, parser.RemPath, true); if (importedTex == null) { Report.ReportLog("Export textures of TEXH.FPK!"); continue; } ImportedTextures.Add(mat.texture.ToString(), importedTex); } Texture memTex = Texture.FromMemory(device, importedTex.Data); texIdx = TextureDic.Count; TextureDic.Add(mat.texture.ToString(), texIdx); Textures.Add(memTex); } meshContainer.TextureIndex = texIdx; } } for (int i = 0; i < (meshContainers.Length - 1); i++) { meshContainers[i].NextMeshContainer = meshContainers[i + 1]; } min = Vector3.TransformCoordinate(min, animationFrame.CombinedTransform); max = Vector3.TransformCoordinate(max, animationFrame.CombinedTransform); animationFrame.Bounds = new BoundingBox(min, max); animationFrame.MeshContainer = meshContainers[0]; meshFrames.Add(animationFrame); } for (int i = 0; i < frame.Count; i++) { remBone child = frame[i]; if (extractFrames.Contains(child.name.ToString())) { AnimationFrame childAnimationFrame = CreateFrame(child, parser, extractFrames, mesh, device, animationFrame.CombinedTransform, meshFrames); childAnimationFrame.Parent = animationFrame; animationFrame.AppendChild(childAnimationFrame); } } numFrames++; return animationFrame; }
private static void SplitMesh(remMesh mesh, List<List<remVertex>> submeshVertLists, List<List<ushort>> submeshFaceLists, List<int[]> submeshVertIndices) { for (int i = 0; i < mesh.numFaces; i++) { while (mesh.faceMarks[i] >= submeshFaceLists.Count) { List<ushort> newFaceList = new List<ushort>(mesh.numFaces); submeshFaceLists.Add(newFaceList); List<remVertex> newVertList = new List<remVertex>(mesh.numVertices); submeshVertLists.Add(newVertList); int[] newVertIndices = new int[mesh.numVertices]; for (int j = 0; j < mesh.numVertices; j++) newVertIndices[j] = -1; submeshVertIndices.Add(newVertIndices); } int submesh = mesh.faceMarks[i]; for (int j = 0; j < 3; j++) { int vertIdx = mesh.faces[i * 3 + j]; if (submeshVertIndices[submesh][vertIdx] < 0) { submeshVertIndices[submesh][vertIdx] = submeshVertLists[submesh].Count; submeshVertLists[submesh].Add(mesh.vertices[vertIdx]); } submeshFaceLists[submesh].Add((ushort)submeshVertIndices[submesh][vertIdx]); } } }
public void HighlightBone(remParser parser, remMesh remMesh, int boneIdx, bool show) { List<List<remVertex>> submeshVertLists = new List<List<remVertex>>(remMesh.numMats); List<List<ushort>> submeshFaceLists = new List<List<ushort>>(remMesh.numMats); List<int[]> submeshVertIndices = new List<int[]>(remMesh.numMats); SplitMesh(remMesh, submeshVertLists, submeshFaceLists, submeshVertIndices); remSkin boneList = rem.FindSkin(remMesh.name, parser.SKIC); int submeshIdx = 0; for (AnimationMeshContainer mesh = (AnimationMeshContainer)meshFrames[0].MeshContainer; mesh != null; mesh = (AnimationMeshContainer)mesh.NextMeshContainer, submeshIdx++) { if (mesh.MeshData != null && mesh.MeshData.Mesh != null) { List<remVertex> vertexList = submeshVertLists[submeshIdx]; byte[][] vertexBoneIndices = null; float[][] vertexWeights = ConvertVertexWeights(vertexList, submeshVertIndices[submeshIdx], boneList, out vertexBoneIndices); FillVertexBuffer(mesh.MeshData.Mesh, vertexList, vertexWeights, vertexBoneIndices, show ? boneIdx : -1); } if (mesh.BoneLines != null) { for (int j = 0; j < BoneObjSize; j++) { mesh.BoneLines[boneIdx * BoneObjSize + j].Color = show ? Color.Crimson.ToArgb(): Color.CornflowerBlue.ToArgb(); } } } }
private static remMESCsection ReadMeshes(string sectionName, int sectionLength, int numMeshes, byte[] sectionBuffer) { remMESCsection meshSec = new remMESCsection(numMeshes); int secBufIdx = 0; for (int subSection = 0; subSection < numMeshes; subSection++) { byte[] type = new byte[4] { sectionBuffer[secBufIdx+0], sectionBuffer[secBufIdx+1], sectionBuffer[secBufIdx+2], sectionBuffer[secBufIdx+3] }; int length = BitConverter.ToInt32(sectionBuffer, secBufIdx+4); remMesh mesh = new remMesh(5); Trace.Assert(TypeCheck(remMesh.ClassType, type)); mesh.frame = GetIdentifier(sectionBuffer, secBufIdx+8); int numMats = BitConverter.ToInt32(sectionBuffer, secBufIdx+8+256); mesh.name = GetIdentifier(sectionBuffer, secBufIdx+8+256+4); int numFaces = BitConverter.ToInt32(sectionBuffer, secBufIdx+8+256+4+256); int numVertices = BitConverter.ToInt32(sectionBuffer, secBufIdx+8+256+4+256 + 4); for (int i = 0; i < mesh.unknown.Length; i++) mesh.unknown[i] = BitConverter.ToInt32(sectionBuffer, secBufIdx+8+256+4+256+8 + i*4); for (int i = 0; i < numMats; i++) { remId mat = GetIdentifier(sectionBuffer, secBufIdx+8+256+4+256 + 4*4 + i*256); mesh.AddMaterial(mat); } mesh.vertices = new remVertex[numVertices]; int vertBufIdx = secBufIdx+8+256+4+256 + 4*4 + mesh.numMats*256; for (int i = 0; i < numVertices; i++) { remVertex vertex = new remVertex(); vertex.Position = new Vector3(); vertex.Position[0] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 0); vertex.Position[1] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 4); vertex.Position[2] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 8); vertex.UV = new Vector2(); vertex.UV[0] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 12); vertex.UV[1] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 16); vertex.Normal = new Vector3(); vertex.Normal[0] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 20); vertex.Normal[1] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 24); vertex.Normal[2] = BitConverter.ToSingle(sectionBuffer, vertBufIdx + 28); vertex.RGBA = new Color4(BitConverter.ToInt32(sectionBuffer, vertBufIdx + 32)); mesh.vertices[i] = vertex; vertBufIdx += 36; } mesh.faces = new int[numFaces * 3]; int faceBufIdx = vertBufIdx; for (int i = 0; i < numFaces; i++) { mesh.faces[i*3+0] = BitConverter.ToInt32(sectionBuffer, faceBufIdx + 0); mesh.faces[i*3+1] = BitConverter.ToInt32(sectionBuffer, faceBufIdx + 4); mesh.faces[i*3+2] = BitConverter.ToInt32(sectionBuffer, faceBufIdx + 8); faceBufIdx += 12; } mesh.faceMarks = new int[numFaces]; int faceExtraIdx = faceBufIdx; for (int i = 0; i < numFaces; i++) { mesh.faceMarks[i] = BitConverter.ToInt32(sectionBuffer, faceExtraIdx); faceExtraIdx += 4; } meshSec.AddChild(mesh); secBufIdx += length; } if (secBufIdx != sectionLength) Report.ReportLog("Warning! MESC section has wrong length."); return meshSec; }