FoamMesh LoadMesh(BinaryReader Reader, DPMMesh Msh) { FoamVertex3[] Verts = new FoamVertex3[Msh.num_verts]; FoamBoneInfo[] Info = new FoamBoneInfo[Verts.Length]; ushort[] Inds = new ushort[Msh.num_tris * 3]; Reader.Seek(Msh.ofs_verts); for (int i = 0; i < Verts.Length; i++) { DPMVertex V = Reader.ReadStructReverse <DPMVertex>(); for (int j = 0; j < V.numbones; j++) { DPMBoneVert BoneVert = Reader.ReadStructReverse <DPMBoneVert>(); } } return(new FoamMesh(Verts, Inds, Info, Msh.GetShaderName(), 0)); }
static void UpdateModel(FoamModel Model, int FrameIndex) { if (Model.Animations == null) { return; } //Matrix4x4 ParentRotMat = Matrix4x4.CreateFromYawPitchRoll(0, -Pi / 2, 0); foreach (var Msh in Model.Meshes) { List <Vertex3> Verts = new List <Vertex3>(); if (Msh.BoneInformation == null) { continue; } foreach (var Index in Msh.Indices) { FoamVertex3 Vert = Msh.Vertices[Index]; FoamBoneInfo Info = Msh.BoneInformation[Index]; FoamBone Bone1 = Model.Bones[Info.Bone1]; // TODO: Weights Matrix4x4 BindWorld = Bone1.BindMatrix; Matrix4x4 WorldTrans = Model.CalcWorldTransform(0, FrameIndex, Info.Bone1); Vector3 Pos = Vector3.Transform(Vert.Position, BindWorld * WorldTrans); // TODO: Flip? Verts.Add(new Vertex3(Pos, Vert.UV)); } Mesh *RayMesh = ((Model)Msh.Userdata).meshes; Raylib.UnloadMesh(*RayMesh); *RayMesh = Raylib.GenMeshRaw(Verts.ToArray()); } }
public FoamModel Load(Stream S, string IQMFile) { int NumFrames = 0; ushort[] FrameData = null; Vector3[] Position = null; Vector2[] Texcoord = null; Vector3[] Normal = null; Vector4[] Tangent = null; IQMBlendIndices[] BlendIndexes = null; IQMBlendWeights[] BlendWeights = null; FoamColor[] Color = null; byte[] Text = null; byte[] Comment = null; IQMTriangle[] Triangles = null; IQMMesh[] Meshes = null; IQMJoint[] Joints = null; IQMPose[] Poses = null; IQMAnim[] Anims = null; FoamVertex3[] FoamVertices = null; FoamBoneInfo[] FoamBoneInfo = null; using (BinaryReader Reader = new BinaryReader(S, Encoding.UTF8, true)) { IQMHeader Header = Reader.ReadStruct <IQMHeader>(); NumFrames = (int)Header.num_frames; if (Header.GetMagic() != "INTERQUAKEMODEL") { throw new Exception("Invalid magic in IQM file"); } if (Header.Version != 2) { throw new Exception("Only IQM version 2 supported"); } // Text if (Header.ofs_text != 0) { Reader.Seek(Header.ofs_text); //Text = Encoding.ASCII.GetString(Reader.ReadBytes((int)Header.num_text)).Split(new char[] { (char)0 }); Text = Reader.ReadBytes((int)Header.num_text); } // Comments if (Header.ofs_comment != 0) { Reader.Seek(Header.ofs_comment); Comment = Reader.ReadBytes((int)Header.num_comment); } // Vertex arrays Reader.Seek(Header.ofs_vertexarrays); IQMVertexArray[] VertArrays = new IQMVertexArray[Header.num_vertexarrays]; for (int i = 0; i < VertArrays.Length; i++) { VertArrays[i] = Reader.ReadStruct <IQMVertexArray>(); } for (int i = 0; i < VertArrays.Length; i++) { ref IQMVertexArray VA = ref VertArrays[i]; Reader.Seek(VA.offset); switch (VA.type) { case IQMVertexArrayType.IQM_POSITION: if (VA.format != IQMVertexArrayFormat.IQM_FLOAT && VA.size != 3) { throw new NotImplementedException(); } Position = Reader.ReadStructArray <Vector3>((uint)(Header.num_vertexes * Marshal.SizeOf <Vector3>())); break; case IQMVertexArrayType.IQM_TEXCOORD: if (VA.format != IQMVertexArrayFormat.IQM_FLOAT && VA.size != 2) { throw new NotImplementedException(); } Texcoord = Reader.ReadStructArray <Vector2>((uint)(Header.num_vertexes * Marshal.SizeOf <Vector2>())); break; case IQMVertexArrayType.IQM_NORMAL: if (VA.format != IQMVertexArrayFormat.IQM_FLOAT && VA.size != 3) { throw new NotImplementedException(); } Normal = Reader.ReadStructArray <Vector3>((uint)(Header.num_vertexes * Marshal.SizeOf <Vector3>())); break; case IQMVertexArrayType.IQM_TANGENT: if (VA.format != IQMVertexArrayFormat.IQM_FLOAT && VA.size != 4) { throw new NotImplementedException(); } Tangent = Reader.ReadStructArray <Vector4>((uint)(Header.num_vertexes * Marshal.SizeOf <Vector4>())); break; case IQMVertexArrayType.IQM_BLENDINDEXES: if (VA.format != IQMVertexArrayFormat.IQM_UBYTE && VA.size != 4) { throw new NotImplementedException(); } BlendIndexes = Reader.ReadStructArray <IQMBlendIndices>((uint)(Header.num_vertexes * Marshal.SizeOf <IQMBlendIndices>())); break; case IQMVertexArrayType.IQM_BLENDWEIGHTS: if (VA.format != IQMVertexArrayFormat.IQM_UBYTE && VA.size != 4) { throw new NotImplementedException(); } BlendWeights = Reader.ReadStructArray <IQMBlendWeights>((uint)(Header.num_vertexes * Marshal.SizeOf <IQMBlendWeights>())); break; case IQMVertexArrayType.IQM_COLOR: if (VA.format != IQMVertexArrayFormat.IQM_UBYTE && VA.size != 4) { throw new NotImplementedException(); } Color = Reader.ReadStructArray <FoamColor>((uint)(Header.num_vertexes * Marshal.SizeOf <FoamColor>())); break; case IQMVertexArrayType.IQM_CUSTOM: default: throw new NotImplementedException(); } } // Triangles Reader.Seek(Header.ofs_triangles); Triangles = Reader.ReadStructArray <IQMTriangle>((uint)(Header.num_triangles * sizeof(IQMTriangle))); // Meshes Reader.Seek(Header.ofs_meshes); Meshes = Reader.ReadStructArray <IQMMesh>((uint)(Header.num_meshes * sizeof(IQMMesh))); // Joints Reader.Seek(Header.ofs_joints); Joints = Reader.ReadStructArray <IQMJoint>((uint)(Header.num_joints * sizeof(IQMJoint))); // Poses Reader.Seek(Header.ofs_poses); Poses = Reader.ReadStructArray <IQMPose>((uint)(Header.num_poses * sizeof(IQMPose))); // Anims Reader.Seek(Header.ofs_anims); Anims = Reader.ReadStructArray <IQMAnim>((uint)(Header.num_anims * sizeof(IQMAnim))); // Frames Reader.Seek(Header.ofs_frames); FrameData = Reader.ReadStructArray <ushort>((uint)(CountFrameDataLength(NumFrames, Poses) * sizeof(ushort))); // Foam vertices FoamVertices = new FoamVertex3[Header.num_vertexes]; for (int i = 0; i < FoamVertices.Length; i++) { FoamVertices[i] = BuildVertex(i, Tangent, Normal, Position, Texcoord, Color); } // Foam bone info FoamBoneInfo = new FoamBoneInfo[FoamVertices.Length]; for (int i = 0; i < FoamBoneInfo.Length; i++) { FoamBoneInfo Info = new FoamBoneInfo(); if (BlendIndexes != null && BlendWeights != null) { IQMBlendIndices BInd = BlendIndexes[i]; IQMBlendWeights BWgt = BlendWeights[i]; Info.Bone1 = BInd.BlendIndex1; Info.Bone2 = BInd.BlendIndex2; Info.Bone3 = BInd.BlendIndex3; Info.Bone4 = BInd.BlendIndex4; const float WeightDividend = 255.0f; Info.Weight1 = BWgt.BlendWeight1 / WeightDividend; Info.Weight2 = BWgt.BlendWeight2 / WeightDividend; Info.Weight3 = BWgt.BlendWeight3 / WeightDividend; Info.Weight4 = BWgt.BlendWeight4 / WeightDividend; } FoamBoneInfo[i] = Info; } }
static FoamModel Load(string FileName, int MD3Frame = 0) { string Ext = Path.GetExtension(FileName).ToLower(); using (AssimpContext Importer = new AssimpContext()) { Importer.SetConfig(new MD3HandleMultiPartConfig(false)); //Importer.SetConfig(new MD5NoAnimationAutoLoadConfig(true)); Importer.SetConfig(new VertexBoneWeightLimitConfig(4)); Importer.SetConfig(new MD3KeyFrameImportConfig(MD3Frame)); PostProcessSteps ProcessSteps = PostProcessSteps.Triangulate; ProcessSteps |= PostProcessSteps.SplitLargeMeshes; ProcessSteps |= PostProcessSteps.OptimizeMeshes; ProcessSteps |= PostProcessSteps.LimitBoneWeights; ProcessSteps |= PostProcessSteps.JoinIdenticalVertices; ProcessSteps |= PostProcessSteps.ImproveCacheLocality; ProcessSteps |= PostProcessSteps.GenerateNormals; ProcessSteps |= PostProcessSteps.GenerateUVCoords; //if (Ext != ".md3") ProcessSteps |= PostProcessPreset.ConvertToLeftHanded; Scene Sc = Importer.ImportFile(FileName, ProcessSteps); List <FoamMaterial> MaterialList = new List <FoamMaterial>(); foreach (var Mat in Sc.Materials) { FoamMaterial FoamMat = new FoamMaterial(Mat.Name); AddTextureIfExists(Mat.HasTextureDiffuse, ref FoamMat, Mat.TextureDiffuse, FoamTextureType.Diffuse); AddTextureIfExists(Mat.HasTextureEmissive, ref FoamMat, Mat.TextureEmissive, FoamTextureType.Glow); AddTextureIfExists(Mat.HasTextureNormal, ref FoamMat, Mat.TextureNormal, FoamTextureType.Normal); AddTextureIfExists(Mat.HasTextureSpecular, ref FoamMat, Mat.TextureSpecular, FoamTextureType.Specular); AddTextureIfExists(Mat.HasTextureReflection, ref FoamMat, Mat.TextureReflection, FoamTextureType.Reflection); AddTextureIfExists(Mat.HasTextureHeight, ref FoamMat, Mat.TextureHeight, FoamTextureType.Height); AddTextureIfExists(Mat.HasTextureLightMap, ref FoamMat, Mat.TextureLightMap, FoamTextureType.LightMap); AddTextureIfExists(Mat.HasTextureDisplacement, ref FoamMat, Mat.TextureDisplacement, FoamTextureType.Displacement); AddTextureIfExists(Mat.HasTextureAmbient, ref FoamMat, Mat.TextureAmbient, FoamTextureType.Ambient); AddTextureIfExists(Mat.HasTextureOpacity, ref FoamMat, Mat.TextureOpacity, FoamTextureType.Opacity); MaterialList.Add(FoamMat); } FoamBone[] Bones = new FoamBone[0]; List <FoamMesh> MeshList = new List <FoamMesh>(); foreach (var Msh in Sc.Meshes) { Vector3D[] Verts = Msh.Vertices.ToArray(); Vector3D[] UVs1 = Msh.TextureCoordinateChannels[0].ToArray(); Vector3D[] UVs2 = Msh.TextureCoordinateChannels[1].ToArray(); Vector3D[] Normals = Msh.Normals.ToArray(); Vector3D[] Tangents = Msh.Tangents.ToArray(); Color4D[] Colors = Msh.VertexColorChannels[0].ToArray(); string MeshName = Msh.Name; int MaterialIndex = Msh.MaterialIndex; FoamVertex3[] FoamVertices = new FoamVertex3[Verts.Length]; for (int i = 0; i < FoamVertices.Length; i++) { Vector2 UV1 = UVs1.Length != 0 ? new Vector2(UVs1[i].X, UVs1[i].Y) : Vector2.Zero; Vector2 UV2 = UVs2.Length != 0 ? new Vector2(UVs2[i].X, UVs2[i].Y) : Vector2.Zero; Vector3 Normal = Normals.Length != 0 ? new Vector3(Normals[i].X, Normals[i].Y, Normals[i].Z) : Vector3.Zero; Vector3 Tangent = Tangents.Length != 0 ? new Vector3(Tangents[i].X, Tangents[i].Y, Tangents[i].Z) : Vector3.Zero; FoamColor Color = Colors.Length != 0 ? new FoamColor(Colors[i].R, Colors[i].G, Colors[i].B, Colors[i].A) : FoamColor.White; FoamVertex3 V = new FoamVertex3(new Vector3(Verts[i].X, Verts[i].Y, Verts[i].Z), UV1, UV2, Normal, Tangent, Color); FoamVertices[i] = V; } bool CalculateTangents = Tangents.Length == 0 && UVs1.Length != 0; //bool CalculateNormals = Normals.Length == 0; List <ushort> FoamIndices = new List <ushort>(); foreach (var F in Msh.Faces) { ushort IndexA = (ushort)F.Indices[0]; ushort IndexB = (ushort)F.Indices[1]; ushort IndexC = (ushort)F.Indices[2]; if (CalculateTangents) { FoamVertex3 V0 = FoamVertices[IndexA]; FoamVertex3 V1 = FoamVertices[IndexB]; FoamVertex3 V2 = FoamVertices[IndexC]; Vector3 DeltaPos1 = V1.Position - V0.Position; Vector3 DeltaPos2 = V2.Position - V0.Position; //if (CalculateTangents) { Vector2 DeltaUV1 = V1.UV - V0.UV; Vector2 DeltaUV2 = V2.UV - V0.UV; Vector3 Tangent = (DeltaPos1 * DeltaUV2.Y - DeltaPos2 * DeltaUV1.Y) * (1.0f / (DeltaUV1.X * DeltaUV2.Y - DeltaUV1.Y * DeltaUV2.X)); FoamVertices[IndexA].Tangent = FoamVertices[IndexB].Tangent = FoamVertices[IndexC].Tangent = Tangent; /*} * * if (CalculateNormals) * FoamVertices[IndexA].Normal = FoamVertices[IndexB].Normal = FoamVertices[IndexC].Normal = Vector3.Normalize(Vector3.Cross(DeltaPos1, DeltaPos2));*/ } FoamIndices.AddRange(F.Indices.Select(I => (ushort)I)); } FoamBoneInfo[] BoneInfo = null; if (Msh.BoneCount != 0) { BoneInfo = new FoamBoneInfo[FoamVertices.Length]; Bone[] OrigBones = Msh.Bones.ToArray(); // Convert bones for (int i = 0; i < OrigBones.Length; i++) { if (!ContainsBoneNamed(Bones, OrigBones[i].Name)) { Utils.Append(ref Bones, new FoamBone(OrigBones[i].Name, -1, ConvertMatrix(OrigBones[i].OffsetMatrix))); } } // Convert vertex bone information for (int i = 0; i < FoamVertices.Length; i++) { BoneInfo[i] = FindWeightsFor(OrigBones, Bones, i); } } MeshList.Add(new FoamMesh(FoamVertices, FoamIndices?.ToArray() ?? null, BoneInfo, MeshName, MaterialIndex)); } if (Bones.Length > 0) { Node[] NodeHierarchy = Flatten(Sc.RootNode); //Node SceneRootNode = Sc.RootNode; Node RootNode = FindRoot(FindNode(NodeHierarchy, Bones[0].Name), Bones); Utils.Prepend(ref Bones, new FoamBone(RootNode.Name, -1, ConvertMatrix(RootNode.Transform))); /*Node RootNodeTest = RootNode; * while (RootNodeTest.Parent != null) { * Bones[0].BindMatrix = Bones[0].BindMatrix * ConvertMatrix(RootNodeTest.Transform); * RootNodeTest = RootNodeTest.Parent; * }*/ /*while (RootNode.Parent != null) { * Utils.Prepend(ref Bones, new FoamBone(RootNode.Name, -1, NumMatrix4x4.Identity)); * RootNode = RootNode.Parent; * }*/ for (int i = 0; i < Bones.Length; i++) { Node BoneNode = FindNode(NodeHierarchy, Bones[i].Name); int BoneParentIndex = FindBoneIndex(Bones, BoneNode.Parent.Name); if (BoneNode != RootNode) { if (BoneParentIndex == -1) { throw new Exception("Could not find a bone"); } } Bones[i].ParentBoneIndex = BoneParentIndex; } } else { Bones = null; } // Animations FoamAnimation[] Animations = null; foreach (var Anim in Sc.Animations) { string[] BoneNames = Anim.NodeAnimationChannels.Select(C => C.NodeName).ToArray(); int FrameCount = Anim.NodeAnimationChannels[0].PositionKeyCount; FoamAnimationFrame[] Frames = new FoamAnimationFrame[FrameCount]; for (int i = 0; i < FrameCount; i++) { Frames[i] = ReadFrame(Anim.NodeAnimationChannels, BoneNames, i); } FoamAnimation Animation = new FoamAnimation(Anim.Name, Frames, BoneNames, (float)Anim.DurationInTicks, (float)Anim.TicksPerSecond); Utils.Append(ref Animations, Animation); } return(new FoamModel(Path.GetFileNameWithoutExtension(FileName), FoamFlags.Model, MeshList.ToArray(), Bones, Animations, MaterialList.ToArray())); } }
static Vertex3 ToVert3(FoamVertex3 V) { return(new Vertex3(V.Position, new Vector2(V.UV2.X, 1.0f - V.UV2.Y))); }
static void GenAtlas(string OutDir, FoamModel LevelModel, out MeshAtlasMap AtlasMap) { const bool GenerateNewUVs = true; const float TextureScale = 2; //const float VertexScale = 1.0f / 100; const float VertexScale = 1.0f; const int BounceCount = 2; FoamMesh[] Meshes = LevelModel.Meshes; List <FoamMesh> VertexMeshMap = new List <FoamMesh>(); List <FoamVertex3> ModelVerts = new List <FoamVertex3>(); //ushort[] NewInds = null; int W; int H; { foreach (var Mesh in Meshes) { IEnumerable <FoamVertex3> MeshVerts = Mesh.GetFlatVertices(); foreach (var V in MeshVerts) { VertexMeshMap.Add(Mesh); ModelVerts.Add(V); } Mesh.Indices = new ushort[] { }; Mesh.Vertices = new FoamVertex3[] { }; } if (GenerateNewUVs) { AtlasStruct * _Atlas = XAtlas.Create(); XAtlas_MeshDecl MeshDecl = new XAtlas_MeshDecl(ModelVerts.Select(V => V.Position).ToArray()); XAtlas.AddMesh(_Atlas, ref MeshDecl); XAtlas.Generate(_Atlas, ChartOptions.CreateOptions(), null, PackOptions.CreatePackOptions()); XAtlasMesh *XMsh = &_Atlas->meshes[0]; /*NewInds = null; * for (int i = 0; i < XMsh->indexCount; i++) * Utils.Append(ref NewInds, (ushort)XMsh->indexArray[i]);*/ W = (int)(_Atlas->width * TextureScale); H = (int)(_Atlas->height * TextureScale); AtlasMap = new MeshAtlasMap(W, H); FoamVertex3[] OldModelVerts = ModelVerts.ToArray(); ModelVerts.Clear(); FoamMesh[] OldVertexMeshMap = VertexMeshMap.ToArray(); VertexMeshMap.Clear(); Vector2 AtlasSize = new Vector2((int)_Atlas->width, (int)_Atlas->height); for (int i = 0; i < XMsh->vertexCount; i++) { XAtlasVertex *XVert = &XMsh->vertexArray[i]; FoamVertex3 OldVert = OldModelVerts[(int)XVert->xref]; FoamMesh OldMesh = OldVertexMeshMap[(int)XVert->xref]; //OldVert.UV = (XVert->UV) / AtlasSize; OldVert.UV2 = (XVert->UV) / AtlasSize; //OldVert.UV.X = (int)OldVert.UV.X; //OldVert.UV.Y = (int)OldVert.UV.Y; ModelVerts.Add(OldVert); VertexMeshMap.Add(OldMesh); } } else { /*for (int i = 0; i < ModelVerts.Count; i++) * Utils.Append(ref NewInds, (ushort)i);*/ AtlasMap = new MeshAtlasMap(512, 512); } } Vector3[] RL_Pos = new Vector3[ModelVerts.Count]; Vector2[] RL_UV = new Vector2[ModelVerts.Count]; // Calculate normals for (int i = 0; i < ModelVerts.Count; i += 3) { FoamVertex3 VA = ModelVerts[i + 0]; FoamVertex3 VB = ModelVerts[i + 1]; FoamVertex3 VC = ModelVerts[i + 2]; Vector3 CB = VC.Position - VB.Position; Vector3 AB = VA.Position - VB.Position; Vector3 Normal = Vector3.Normalize(Vector3.Cross(CB, AB)); VA.Normal = Normal; VB.Normal = Normal; VC.Normal = Normal; ModelVerts[i + 0] = VA; ModelVerts[i + 1] = VB; ModelVerts[i + 2] = VC; RL_Pos[i + 0] = VA.Position * VertexScale; RL_Pos[i + 1] = VB.Position * VertexScale; RL_Pos[i + 2] = VC.Position * VertexScale; RL_UV[i + 0] = VA.UV2; RL_UV[i + 1] = VB.UV2; RL_UV[i + 2] = VC.UV2; } Vector2 PixelsSize = new Vector2(W, H); Vector4[] Pixels = new Vector4[W * H]; ApplyEmissive(Pixels, W, H, ModelVerts, VertexMeshMap, LevelModel); //int TriIdx = 6; //Vector4 TriClr = new Vector4(50.0f / 255, 100.0f / 255, 200.0f / 255, 1); //DrawTriangle(Pixels, W, H, TriClr, ModelVerts[TriIdx * 3 + 0].UV2 * PixelsSize, ModelVerts[TriIdx * 3 + 1].UV2 * PixelsSize, ModelVerts[TriIdx * 3 + 2].UV2 * PixelsSize); Lightmapper.GenerateLightmap(ref Pixels, W, H, RL_Pos, RL_UV, BounceCount); ApplyEmissive(Pixels, W, H, ModelVerts, VertexMeshMap, LevelModel); //DrawTriangle(Pixels, W, H, TriClr, ModelVerts[TriIdx * 3 + 0].UV2 * PixelsSize, ModelVerts[TriIdx * 3 + 1].UV2 * PixelsSize, ModelVerts[TriIdx * 3 + 2].UV2 * PixelsSize); for (int i = 0; i < Pixels.Length; i++) { int X = i % W; int Y = (i - X) / W; Vector4 Clr = Pixels[i]; Clr = Utils.Clamp(Clr, Vector4.Zero, Vector4.One); AtlasMap.Atlas.SetPixel(X, Y, new FastColor((byte)(Clr.X * 255), (byte)(Clr.Y * 255), (byte)(Clr.Z * 255), 255)); } for (int i = 0; i < VertexMeshMap.Count; i++) { FoamMesh CurMesh = VertexMeshMap[i]; //Utils.Append(ref CurMesh.Indices, (ushort)(NewInds[i])); Utils.Append(ref CurMesh.Vertices, ModelVerts[i]); } for (int i = 0; i < Meshes.Length; i++) { int VertCount = Meshes[i].Vertices.Length; Meshes[i].Indices = new ushort[VertCount]; for (int j = 0; j < VertCount; j++) { Meshes[i].Indices[j] = (ushort)j; } } //Msh.Vertices = Verts.ToArray(); //Msh.Indices = NewInds.ToArray(); }