public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, H3DDict <H3DBone> Skeleton = null) { H3D Output = default(H3D); BinaryReader Reader = new BinaryReader(Input); if (Input.Length <= Header.Entries[0].Address) { return(null); } Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin); uint MagicNum = Reader.ReadUInt32(); switch (MagicNum) { case GFModelConstant: GFModelPack MdlPack = new GFModelPack(); //High Poly Pokémon model Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin); MdlPack.Models.Add(new GFModel(Reader, "PM_HighPoly")); //Low Poly Pokémon model Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin); MdlPack.Models.Add(new GFModel(Reader, "PM_LowPoly")); //Pokémon Shader package Input.Seek(Header.Entries[2].Address, SeekOrigin.Begin); GFPackage.Header PSHeader = GFPackage.GetPackageHeader(Input); foreach (GFPackage.Entry Entry in PSHeader.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); MdlPack.Shaders.Add(new GFShader(Reader)); } //More shaders Input.Seek(Header.Entries[3].Address, SeekOrigin.Begin); if (GFPackage.IsValidPackage(Input)) { GFPackage.Header PCHeader = GFPackage.GetPackageHeader(Input); foreach (GFPackage.Entry Entry in PCHeader.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); MdlPack.Shaders.Add(new GFShader(Reader)); } } Output = MdlPack.ToH3D(); break; case GFTextureConstant: Output = new H3D(); foreach (GFPackage.Entry Entry in Header.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); Output.Textures.Add(new GFTexture(Reader).ToH3DTexture()); } break; case GFMotionConstant: Output = new H3D(); if (Skeleton == null) { break; } for (int Index = 0; Index < Header.Entries.Length; Index++) { Input.Seek(Header.Entries[Index].Address, SeekOrigin.Begin); if (Input.Position + 4 > Input.Length) { break; } if (Reader.ReadUInt32() != GFMotionConstant) { continue; } Input.Seek(-4, SeekOrigin.Current); GFMotion Mot = new GFMotion(Reader, Index); H3DAnimation SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton); H3DMaterialAnim MatAnim = Mot.ToH3DMaterialAnimation(); H3DAnimation VisAnim = Mot.ToH3DVisibilityAnimation(); if (SklAnim != null) { SklAnim.Name = $"Motion_{Mot.Index}"; Output.SkeletalAnimations.Add(SklAnim); } if (MatAnim != null) { MatAnim.Name = $"Motion_{Mot.Index}"; Output.MaterialAnimations.Add(MatAnim); } if (VisAnim != null) { VisAnim.Name = $"Motion_{Mot.Index}"; Output.VisibilityAnimations.Add(VisAnim); } } break; case BCHConstant: Output = new H3D(); foreach (GFPackage.Entry Entry in Header.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); MagicNum = Reader.ReadUInt32(); if (MagicNum != BCHConstant) { continue; } Input.Seek(-4, SeekOrigin.Current); byte[] Buffer = Reader.ReadBytes(Entry.Length); Output.Merge(H3D.Open(Buffer)); } break; } return(Output); }
public static H3D IdentifyAndOpen(string FileName, H3DDict <H3DBone> Skeleton = null) { //Formats that can by identified by extensions string FilePath = Path.GetDirectoryName(FileName); switch (Path.GetExtension(FileName).ToLower()) { case ".txt": H3D AllFiles = new H3D(); string[] files = File.ReadAllLines(FileName); string Parent = FilePath; foreach (string File in files) { AllFiles.Merge(IdentifyAndOpen(Path.Combine(Parent, File))); } return(AllFiles); case ".gmp": H3D OutputH3D = new H3D(); GF1MotionPack MotPack = new GF1MotionPack(new BinaryReader(new FileStream(FileName, FileMode.Open))); foreach (GF1Motion Mot in MotPack) { H3DAnimation SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton); SklAnim.Name = $"Motion_{Mot.Index}"; OutputH3D.SkeletalAnimations.Add(SklAnim); } return(OutputH3D); case ".smd": return(new SMD(FileName).ToH3D(FilePath)); case ".obj": return(new OBJ(FileName).ToH3D(FilePath)); case ".mtl": return(new OBJ(FileName).ToH3D(FilePath)); case ".cmif": return(new CMIFFile(new FileStream(FileName, FileMode.Open)).ToH3D()); case ".png": H3D Out = new H3D(); Out.Textures.Add(new H3DTexture(FileName, true)); return(Out); case ".gfbmdl": H3DModel model = new GFModel(new BinaryReader(new FileStream(FileName, FileMode.Open)), Path.GetFileNameWithoutExtension(FileName)).ToH3DModel(); H3D Scene = new H3D(); Scene.Models.Add(model); return(Scene); case ".mbn": using (FileStream Input = new FileStream(FileName, FileMode.Open)) { H3D BaseScene = H3D.Open(File.ReadAllBytes(FileName.Replace(".mbn", ".bch"))); MBn ModelBinary = new MBn(new BinaryReader(Input), BaseScene); return(ModelBinary.ToH3D()); } } //Formats that can only be indetified by "magic numbers" H3D Output = null; using (FileStream FS = new FileStream(FileName, FileMode.Open)) { if (FS.Length > 4) { BinaryReader Reader = new BinaryReader(FS); uint MagicNum = Reader.ReadUInt32(); FS.Seek(-4, SeekOrigin.Current); string Magic = Encoding.ASCII.GetString(Reader.ReadBytes(4)); FS.Seek(0, SeekOrigin.Begin); if (Magic.StartsWith("BCH")) { return(H3D.Open(Reader.ReadBytes((int)FS.Length))); } else if (Magic.StartsWith("MOD")) { return(LoadMTModel(Reader, FileName, Path.GetDirectoryName(FileName))); } else if (Magic.StartsWith("TEX")) { return(new MTTexture(Reader, Path.GetFileNameWithoutExtension(FileName)).ToH3D()); } else if (Magic.StartsWith("MFX")) { MTShader = new MTShaderEffects(Reader); } else if (Magic.StartsWith("CGFX")) { return(Gfx.Open(FS)); } else if (Magic.StartsWith("CMIF")) { return(new CMIFFile(new FileStream(FileName, FileMode.Open)).ToH3D()); } else { if (GFPackage.IsValidPackage(FS)) { GFPackage.Header PackHeader = GFPackage.GetPackageHeader(FS); switch (PackHeader.Magic) { case "AL": Output = GFAreaLOD.OpenAsH3D(FS, PackHeader, 1); break; case "AD": Output = GFPackedTexture.OpenAsH3D(FS, PackHeader, 1); break; //case "BG": Output = GFL2OverWorld.OpenAsH3D(FS, PackHeader, Skeleton); break; case "BS": Output = GFBtlSklAnim.OpenAsH3D(FS, PackHeader, Skeleton); break; case "CM": Output = GFCharaModel.OpenAsH3D(FS, PackHeader); break; case "GR": Output = GFOWMapModel.OpenAsH3D(FS, PackHeader); break; case "MM": Output = GFOWCharaModel.OpenAsH3D(FS, PackHeader); break; case "PC": Output = GFPkmnModel.OpenAsH3D(FS, PackHeader, Skeleton); break; case "LL": default: case "PT": Output = GFPackedTexture.OpenAsH3D(FS, PackHeader, 0); break; case "PK": case "PB": Output = GFPkmnSklAnim.OpenAsH3D(FS, PackHeader, Skeleton); break; } } else { switch (MagicNum) { case 0x15122117: Output = new H3D(); Output.Models.Add(new GFModel(Reader, "Model").ToH3DModel()); break; case 0x15041213: Output = new H3D(); Output.Textures.Add(new GFTexture(Reader).ToH3DTexture()); break; case 0x00010000: Output = new GFModelPack(Reader).ToH3D(); break; case 0x00060000: if (Skeleton != null) { Output = new H3D(); GFMotion Motion = new GFMotion(Reader, 0); H3DAnimation SklAnim = Motion.ToH3DSkeletalAnimation(Skeleton); H3DMaterialAnim MatAnim = Motion.ToH3DMaterialAnimation(); H3DAnimation VisAnim = Motion.ToH3DVisibilityAnimation(); if (SklAnim != null) { Output.SkeletalAnimations.Add(SklAnim); } if (MatAnim != null) { Output.MaterialAnimations.Add(MatAnim); } if (VisAnim != null) { Output.VisibilityAnimations.Add(VisAnim); } } break; } } } } } return(Output); }
public static H3D IdentifyByMagic(Stream Stream, H3DDict <H3DBone> Skeleton, string FileName) { H3D Output = null; if (Stream.Length > 4) { BinaryReader Reader = new BinaryReader(Stream); uint MagicNum = Reader.ReadUInt32(); Stream.Seek(-4, SeekOrigin.Current); string Magic = Encoding.ASCII.GetString(Reader.ReadBytes(4)); Stream.Seek(0, SeekOrigin.Begin); if (Magic.StartsWith("BCH")) { return(H3D.Open(Reader.ReadBytes((int)Stream.Length))); } else if (Magic.StartsWith("MOD") && FileName != null) { return(LoadMTModel(Reader, FileName, Path.GetDirectoryName(FileName))); } else if (Magic.StartsWith("TEX") && FileName != null) { return(new MTTexture(Reader, Path.GetFileNameWithoutExtension(FileName)).ToH3D()); } else if (Magic.StartsWith("MFX")) { MTShader = new MTShaderEffects(Reader); } else if (Magic.StartsWith("CGFX")) { return(Gfx.Open(Stream)); } else if (Magic.StartsWith("CMIF")) { return(new CMIFFile(Stream).ToH3D()); } else { switch (MagicNum) { case GFModel.MagicNum: GFModel Model = new GFModel(Reader, "Model"); Output = Model.ToH3D(); Output.SourceData.Add(Model); break; case GFTexture.MagicNum: //Can be GFShader or GFTexture Reader.BaseStream.Seek(0x8, SeekOrigin.Current); string GFMagicStr = StringUtils.ReadPaddedString(Reader, 8); if (GFMagicStr == GFTexture.MagicStr) { Reader.BaseStream.Seek(-0x10, SeekOrigin.Current); Output = new H3D(); Output.Textures.Add(new GFTexture(Reader).ToH3DTexture()); } else { Reader.BaseStream.Seek(0x8, SeekOrigin.Current); GFMagicStr = StringUtils.ReadPaddedString(Reader, 8); if (GFMagicStr == GFShader.MagicStr) { Reader.BaseStream.Seek(-0x18, SeekOrigin.Current); Output = new H3D(); Output.SourceData.Add(new GFShader(Reader)); } } break; case GFModelPack.MagicNum: if (GFModelPack.IsModelPack(Reader)) { Output = new GFModelPack(Reader).ToH3D(); } break; case GFMotion.MagicNum: if (Skeleton != null) { Output = new H3D(); GFMotion Motion = new GFMotion(Reader, 0); H3DAnimation SklAnim = Motion.ToH3DSkeletalAnimation(Skeleton); H3DMaterialAnim MatAnim = Motion.ToH3DMaterialAnimation(); H3DAnimation VisAnim = Motion.ToH3DVisibilityAnimation(); if (SklAnim != null) { Output.SkeletalAnimations.Add(SklAnim); } if (MatAnim != null) { Output.MaterialAnimations.Add(MatAnim); } if (VisAnim != null) { Output.VisibilityAnimations.Add(VisAnim); } } break; } if (GFMotionPack.IsGFL2MotionPack(Reader)) { GFMotionPack Pack = new GFMotionPack(Reader); Output = Pack.ToH3D(Skeleton); } if (GF1MotionPack.IsGFL1MotionPack(Reader)) { Output = new GF1MotionPack(Reader).ToH3D(Skeleton); } } } return(Output); }
public static H3D OpenAsH3D(Stream Input, GFPackage.Header Header, int FileIndex, int AnimCount, H3DDict <H3DBone> Skeleton = null) { int fileIndex = FileIndex; H3D Output = default(H3D); BinaryReader Reader = new BinaryReader(Input); try { Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin); uint MagicNum = Reader.ReadUInt32(); switch (MagicNum) { case GFModelConstant: GFModelPack MdlPack = new GFModelPack(); //High Poly Pokémon model Input.Seek(Header.Entries[0].Address, SeekOrigin.Begin); MdlPack.Models.Add(new GFModel(Reader, "PM_HighPoly")); //Low Poly Pokémon model Input.Seek(Header.Entries[1].Address, SeekOrigin.Begin); MdlPack.Models.Add(new GFModel(Reader, "PM_LowPoly")); //Pokémon Shader package Input.Seek(Header.Entries[2].Address, SeekOrigin.Begin); GFPackage.Header PSHeader = GFPackage.GetPackageHeader(Input); foreach (GFPackage.Entry Entry in PSHeader.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); MdlPack.Shaders.Add(new GFShader(Reader)); } //More shaders Input.Seek(Header.Entries[3].Address, SeekOrigin.Begin); if (GFPackage.IsValidPackage(Input)) { GFPackage.Header PCHeader = GFPackage.GetPackageHeader(Input); foreach (GFPackage.Entry Entry in PCHeader.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); MdlPack.Shaders.Add(new GFShader(Reader)); } } Output = MdlPack.ToH3D(); break; case GFTextureConstant: Output = new H3D(); foreach (GFPackage.Entry Entry in Header.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); Output.Textures.Add(new GFTexture(Reader).ToH3DTexture()); } break; case GFMotionConstant: Output = new H3D(); if (Skeleton == null) { break; } HashSet <uint> sklAdresses = new HashSet <uint>(); HashSet <uint> materialAdresses = new HashSet <uint>(); HashSet <uint> visibilityAdresses = new HashSet <uint>(); for (int Index = 0; Index < Header.Entries.Length; Index++) { Input.Seek(Header.Entries[Index].Address, SeekOrigin.Begin); if (Input.Position + 4 > Input.Length) { break; } if (Reader.ReadUInt32() != GFMotionConstant) { continue; } Input.Seek(-4, SeekOrigin.Current); GFMotion Mot = new GFMotion(Reader, Index); H3DAnimation SklAnim = Mot.ToH3DSkeletalAnimation(Skeleton); H3DMaterialAnim MatAnim = Mot.ToH3DMaterialAnimation(); H3DAnimation VisAnim = Mot.ToH3DVisibilityAnimation(); if (SklAnim != null) { // SklAnim.Name = $"Motion_{Mot.Index}"; // Output.SkeletalAnimations.Add(SklAnim); if (!sklAdresses.Contains(Header.Entries[Index].Address)) { Output.SkeletalAnimations.Add(SklAnim); sklAdresses.Add(Header.Entries[Index].Address); Console.WriteLine("skeletal " + Header.Entries[Index].Address); } } if (MatAnim != null) { //MatAnim.Name = $"Motion_{Mot.Index}"; if (!materialAdresses.Contains(Header.Entries[Index].Address)) { Output.MaterialAnimations.Add(MatAnim); materialAdresses.Add(Header.Entries[Index].Address); Console.WriteLine("material " + Header.Entries[Index].Address); } } if (VisAnim != null) { //VisAnim.Name = $"Motion_{Mot.Index}"; Output.VisibilityAnimations.Add(VisAnim); if (!visibilityAdresses.Contains(Header.Entries[Index].Address)) { Output.VisibilityAnimations.Add(VisAnim); visibilityAdresses.Add(Header.Entries[Index].Address); Console.WriteLine("visibility " + Header.Entries[Index].Address); } } } // Console.WriteLine(Output.SkeletalAnimations.Count); // Console.WriteLine(AnimCount); while (Output.SkeletalAnimations.Count > AnimCount) { Output.SkeletalAnimations.Remove(Output.SkeletalAnimations.Count - 1); } // if (fileIndex == 4) // { // // } //todo здесь проверку // if (Output.SkeletalAnimations.Any()) // { // Output.SkeletalAnimations.Remove(Output.SkeletalAnimations.Count-1); // } break; case BCHConstant: Output = new H3D(); foreach (GFPackage.Entry Entry in Header.Entries) { Input.Seek(Entry.Address, SeekOrigin.Begin); MagicNum = Reader.ReadUInt32(); if (MagicNum != BCHConstant) { continue; } Input.Seek(-4, SeekOrigin.Current); byte[] Buffer = Reader.ReadBytes(Entry.Length); Output.Merge(H3D.Open(Buffer)); } break; } return(Output); } catch (EndOfStreamException e) { return(new H3D()); throw; } }
public static H3D IdentifyAndOpen(string fileName, H3DDict <H3DBone> skeleton = null) { //Formats that can by identified by extensions var filePath = Path.GetDirectoryName(fileName); switch (Path.GetExtension(fileName).ToLower()) { case ".smd": return(new SMD(fileName).ToH3D(filePath)); case ".obj": return(new OBJ(fileName).ToH3D(filePath)); case ".mbn": using (var input = new FileStream(fileName, FileMode.Open)) { var baseScene = H3D.Open(File.ReadAllBytes(fileName.Replace(".mbn", ".bch"))); var modelBinary = new MBn(new BinaryReader(input), baseScene); return(modelBinary.ToH3D()); } } //Formats that can only be indetified by "magic numbers" var output = default(H3D); using (var fs = new FileStream(fileName, FileMode.Open)) { if (fs.Length > 4) { var reader = new BinaryReader(fs); var magicNum = reader.ReadUInt32(); fs.Seek(-4, SeekOrigin.Current); var magic = Encoding.ASCII.GetString(reader.ReadBytes(4)); fs.Seek(0, SeekOrigin.Begin); if (magic.StartsWith("BCH")) { return(H3D.Open(reader.ReadBytes((int)fs.Length))); } else if (magic.StartsWith("MOD")) { return(LoadMTModel(reader, fileName, Path.GetDirectoryName(fileName))); } else if (magic.StartsWith("TEX")) { return(new MTTexture(reader, Path.GetFileNameWithoutExtension(fileName)).ToH3D()); } else if (magic.StartsWith("MFX")) { _mtShader = new MTShaderEffects(reader); } else if (magic.StartsWith("CGFX")) { return(Gfx.Open(fs)); } else { if (GFPackage.IsValidPackage(fs)) { var packHeader = GFPackage.GetPackageHeader(fs); switch (packHeader.Magic) { case "AD": output = GFPackedTexture.OpenAsH3D(fs, packHeader, 1); break; case "BG": output = GFL2OverWorld.OpenAsH3D(fs, packHeader, skeleton); break; case "BS": output = GFBtlSklAnim.OpenAsH3D(fs, packHeader, skeleton); break; case "CM": output = GFCharaModel.OpenAsH3D(fs, packHeader); break; case "GR": output = GFOWMapModel.OpenAsH3D(fs, packHeader); break; case "MM": output = GFOWCharaModel.OpenAsH3D(fs, packHeader); break; case "PC": output = GFPkmnModel.OpenAsH3D(fs, packHeader, skeleton); break; case "PT": output = GFPackedTexture.OpenAsH3D(fs, packHeader, 0); break; case "PK": case "PB": output = GFPkmnSklAnim.OpenAsH3D(fs, packHeader, skeleton); break; } } else { switch (magicNum) { case 0x15122117: output = new H3D(); output.Models.Add(new GFModel(reader, "Model").ToH3DModel()); break; case 0x15041213: output = new H3D(); output.Textures.Add(new GFTexture(reader).ToH3DTexture()); break; case 0x00010000: output = new GFModelPack(reader).ToH3D(); break; case 0x00060000: if (skeleton != null) { output = new H3D(); var motion = new GFMotion(reader, 0); var sklAnim = motion.ToH3DSkeletalAnimation(skeleton); var matAnim = motion.ToH3DMaterialAnimation(); var visAnim = motion.ToH3DVisibilityAnimation(); if (sklAnim != null) { output.SkeletalAnimations.Add(sklAnim); } if (matAnim != null) { output.MaterialAnimations.Add(matAnim); } if (visAnim != null) { output.VisibilityAnimations.Add(visAnim); } } break; } } } } } return(output); }
public DAE(H3D Scene, int MdlIndex, int[] AnimIndices = null) { if (MdlIndex != -1) { library_visual_scenes = new List <DAEVisualScene>(); H3DModel Mdl = Scene.Models[MdlIndex]; DAEVisualScene VN = new DAEVisualScene(); VN.name = $"{Mdl.Name}_{MdlIndex.ToString("D2")}"; VN.id = $"{VN.name}_id"; //Materials if (Mdl.Materials.Count > 0) { library_materials = new List <DAEMaterial>(); library_effects = new List <DAEEffect>(); } foreach (H3DMaterial Mtl in Mdl.Materials) { string MtlName = $"{MdlIndex.ToString("D2")}_{Mtl.Name}"; DAEEffect Effect = new DAEEffect(); Effect.name = $"{Mtl.Name}_eff"; Effect.id = $"{Effect.name}_id"; DAEEffectParam ImgSurface = new DAEEffectParam(); DAEEffectParam ImgSampler = new DAEEffectParam(); ImgSurface.surface = new DAEEffectParamSurfaceElement(); ImgSampler.sampler2D = new DAEEffectParamSampler2DElement(); ImgSurface.sid = $"{Mtl.Name}_surf"; ImgSurface.surface.type = "2D"; ImgSurface.surface.init_from = Mtl.Texture0Name; ImgSurface.surface.format = "PNG"; ImgSampler.sid = $"{Mtl.Name}_samp"; ImgSampler.sampler2D.source = ImgSurface.sid; ImgSampler.sampler2D.wrap_s = Mtl.TextureMappers[0].WrapU.ToDAEWrap(); ImgSampler.sampler2D.wrap_t = Mtl.TextureMappers[0].WrapV.ToDAEWrap(); ImgSampler.sampler2D.minfilter = Mtl.TextureMappers[0].MinFilter.ToDAEFilter(); ImgSampler.sampler2D.magfilter = Mtl.TextureMappers[0].MagFilter.ToDAEFilter(); ImgSampler.sampler2D.mipfilter = DAEFilter.LINEAR; Effect.profile_COMMON.newparam.Add(ImgSurface); Effect.profile_COMMON.newparam.Add(ImgSampler); Effect.profile_COMMON.technique.sid = $"{Mtl.Name}_tech"; Effect.profile_COMMON.technique.phong.diffuse.texture.texture = ImgSampler.sid; library_effects.Add(Effect); DAEMaterial Material = new DAEMaterial(); Material.name = $"{Mtl.Name}_mat"; Material.id = $"{Material.name}_id"; Material.instance_effect.url = $"#{Effect.id}"; library_materials.Add(Material); } //Skeleton nodes string RootBoneId = string.Empty; if ((Mdl.Skeleton?.Count ?? 0) > 0) { Queue <Tuple <H3DBone, DAENode> > ChildBones = new Queue <Tuple <H3DBone, DAENode> >(); DAENode RootNode = new DAENode(); ChildBones.Enqueue(Tuple.Create(Mdl.Skeleton[0], RootNode)); RootBoneId = $"#{Mdl.Skeleton[0].Name}_bone_id"; while (ChildBones.Count > 0) { Tuple <H3DBone, DAENode> Bone_Node = ChildBones.Dequeue(); H3DBone Bone = Bone_Node.Item1; Bone_Node.Item2.id = $"{Bone.Name}_bone_id"; Bone_Node.Item2.name = Bone.Name; Bone_Node.Item2.sid = Bone.Name; Bone_Node.Item2.type = DAENodeType.JOINT; Bone_Node.Item2.SetBoneEuler(Bone.Translation, Bone.Rotation, Bone.Scale); foreach (H3DBone B in Mdl.Skeleton) { if (B.ParentIndex == -1) { continue; } H3DBone ParentBone = Mdl.Skeleton[B.ParentIndex]; if (ParentBone == Bone) { DAENode Node = new DAENode(); ChildBones.Enqueue(Tuple.Create(B, Node)); if (Bone_Node.Item2.Nodes == null) { Bone_Node.Item2.Nodes = new List <DAENode>(); } Bone_Node.Item2.Nodes.Add(Node); } } } VN.node.Add(RootNode); } //Mesh if (Mdl.Meshes.Count > 0) { library_geometries = new List <DAEGeometry>(); } for (int MeshIndex = 0; MeshIndex < Mdl.Meshes.Count; MeshIndex++) { if (Mdl.Meshes[MeshIndex].Type == H3DMeshType.Silhouette) { continue; } H3DMesh Mesh = Mdl.Meshes[MeshIndex]; PICAVertex[] Vertices = MeshTransform.GetWorldSpaceVertices(Mdl.Skeleton, Mesh); string MtlName = $"Mdl_{MdlIndex}_Mtl_{Mdl.Materials[Mesh.MaterialIndex].Name}"; string MtlTgt = library_materials[Mesh.MaterialIndex].id; for (int SMIndex = 0; SMIndex < Mesh.SubMeshes.Count; SMIndex++) { H3DSubMesh SM = Mesh.SubMeshes[SMIndex]; string ShortName = string.Empty; if (Mdl.MeshNodesTree != null && Mesh.NodeIndex < Mdl.MeshNodesTree.Count) { ShortName = Mdl.MeshNodesTree.Find(Mesh.NodeIndex); } string MeshName = $"{ShortName}_{MeshIndex}_{SMIndex}"; DAEGeometry Geometry = new DAEGeometry(); Geometry.name = MeshName; Geometry.id = $"{Geometry.name}_geo_id"; //Geometry string VertsId = $"{MeshName}_vtx_id"; Geometry.mesh.vertices.id = VertsId; Geometry.mesh.triangles.material = MtlName; Geometry.mesh.triangles.AddInput("VERTEX", $"#{VertsId}"); Geometry.mesh.triangles.Set_p(SM.Indices); foreach (PICAAttribute Attr in Mesh.Attributes) { if (Attr.Name >= PICAAttributeName.BoneIndex) { continue; } string[] Values = new string[Vertices.Length]; for (int Index = 0; Index < Vertices.Length; Index++) { PICAVertex v = Vertices[Index]; switch (Attr.Name) { case PICAAttributeName.Position: Values[Index] = DAEUtils.Vector3Str(v.Position); break; case PICAAttributeName.Normal: Values[Index] = DAEUtils.Vector3Str(v.Normal); break; case PICAAttributeName.Tangent: Values[Index] = DAEUtils.Vector3Str(v.Tangent); break; case PICAAttributeName.Color: Values[Index] = DAEUtils.Vector4Str(v.Color); break; case PICAAttributeName.TexCoord0: Values[Index] = DAEUtils.Vector2Str(v.TexCoord0); break; case PICAAttributeName.TexCoord1: Values[Index] = DAEUtils.Vector2Str(v.TexCoord1); break; case PICAAttributeName.TexCoord2: Values[Index] = DAEUtils.Vector2Str(v.TexCoord2); break; } } int Elements = 0; switch (Attr.Name) { case PICAAttributeName.Position: Elements = 3; break; case PICAAttributeName.Normal: Elements = 3; break; case PICAAttributeName.Tangent: Elements = 3; break; case PICAAttributeName.Color: Elements = 4; break; case PICAAttributeName.TexCoord0: Elements = 2; break; case PICAAttributeName.TexCoord1: Elements = 2; break; case PICAAttributeName.TexCoord2: Elements = 2; break; } DAESource Source = new DAESource(); Source.name = $"{MeshName}_{Attr.Name}"; Source.id = $"{Source.name}_id"; Source.float_array = new DAEArray() { id = $"{Source.name}_array_id", count = (uint)(Vertices.Length * Elements), data = string.Join(" ", Values) }; DAEAccessor Accessor = new DAEAccessor() { source = $"#{Source.float_array.id}", count = (uint)Vertices.Length, stride = (uint)Elements }; switch (Elements) { case 2: Accessor.AddParams("float", "S", "T"); break; case 3: Accessor.AddParams("float", "X", "Y", "Z"); break; case 4: Accessor.AddParams("float", "R", "G", "B", "A"); break; } Source.technique_common.accessor = Accessor; Geometry.mesh.source.Add(Source); if (Attr.Name < PICAAttributeName.Color) { string Semantic = string.Empty; switch (Attr.Name) { case PICAAttributeName.Position: Semantic = "POSITION"; break; case PICAAttributeName.Normal: Semantic = "NORMAL"; break; case PICAAttributeName.Tangent: Semantic = "TANGENT"; break; } Geometry.mesh.vertices.AddInput(Semantic, $"#{Source.id}"); } else if (Attr.Name == PICAAttributeName.Color) { Geometry.mesh.triangles.AddInput("COLOR", $"#{Source.id}", 0); } else { Geometry.mesh.triangles.AddInput("TEXCOORD", $"#{Source.id}", 0, (uint)Attr.Name - 4); } } //Attributes Loop library_geometries.Add(Geometry); //Controller bool HasController = SM.BoneIndicesCount > 0 && (Mdl.Skeleton?.Count ?? 0) > 0; DAEController Controller = new DAEController(); if (HasController) { if (library_controllers == null) { library_controllers = new List <DAEController>(); } Controller.name = $"{MeshName}_ctrl"; Controller.id = $"{Controller.name}_id"; Controller.skin.source = $"#{Geometry.id}"; Controller.skin.vertex_weights.count = (uint)Vertices.Length; string[] BoneNames = new string[Mdl.Skeleton.Count]; string[] BindPoses = new string[Mdl.Skeleton.Count]; for (int Index = 0; Index < Mdl.Skeleton.Count; Index++) { BoneNames[Index] = Mdl.Skeleton[Index].Name; BindPoses[Index] = DAEUtils.MatrixStr(Mdl.Skeleton[Index].InverseTransform); } //4 is the max number of bones per vertex int[] v = new int[Vertices.Length * 4 * 2]; int[] vcount = new int[Vertices.Length]; Dictionary <string, int> Weights = new Dictionary <string, int>(); int vi = 0, vci = 0; if (SM.Skinning == H3DSubMeshSkinning.Smooth) { foreach (PICAVertex Vertex in Vertices) { int Count = 0; for (int Index = 0; Index < 4; Index++) { int BIndex = Vertex.Indices[Index]; float Weight = Vertex.Weights[Index]; if (Weight == 0) { break; } if (BIndex < SM.BoneIndices.Length && BIndex > -1) { BIndex = SM.BoneIndices[BIndex]; } else { BIndex = 0; } string WStr = Weight.ToString(CultureInfo.InvariantCulture); v[vi++] = BIndex; if (Weights.ContainsKey(WStr)) { v[vi++] = Weights[WStr]; } else { v[vi++] = Weights.Count; Weights.Add(WStr, Weights.Count); } Count++; } vcount[vci++] = Count; } } else { foreach (PICAVertex Vertex in Vertices) { int BIndex = Vertex.Indices[0]; if (BIndex < SM.BoneIndices.Length && BIndex > -1) { BIndex = SM.BoneIndices[BIndex]; } else { BIndex = 0; } v[vi++] = BIndex; v[vi++] = 0; vcount[vci++] = 1; } Weights.Add("1", 0); } Array.Resize(ref v, vi); Controller.skin.src.Add(new DAESource($"{Controller.name}_names", 1, BoneNames, "JOINT", "Name")); Controller.skin.src.Add(new DAESource($"{Controller.name}_poses", 16, BindPoses, "TRANSFORM", "float4x4")); Controller.skin.src.Add(new DAESource($"{Controller.name}_weights", 1, Weights.Keys.ToArray(), "WEIGHT", "float")); Controller.skin.joints.AddInput("JOINT", $"#{Controller.skin.src[0].id}"); Controller.skin.joints.AddInput("INV_BIND_MATRIX", $"#{Controller.skin.src[1].id}"); Controller.skin.vertex_weights.AddInput("JOINT", $"#{Controller.skin.src[0].id}", 0); Controller.skin.vertex_weights.AddInput("WEIGHT", $"#{Controller.skin.src[2].id}", 1); Controller.skin.vertex_weights.vcount = string.Join(" ", vcount); Controller.skin.vertex_weights.v = string.Join(" ", v); library_controllers.Add(Controller); } //Mesh node DAENode Node = new DAENode(); Node.name = $"{MeshName}_node"; Node.id = $"{Node.name}_id"; Node.matrix = DAEMatrix.Identity; DAENodeInstance NodeInstance = new DAENodeInstance(); NodeInstance.url = $"#{(HasController ? Controller.id : Geometry.id)}"; NodeInstance.bind_material.technique_common.instance_material.symbol = MtlName; NodeInstance.bind_material.technique_common.instance_material.target = $"#{MtlTgt}"; if (HasController) { NodeInstance.skeleton = $"#{VN.node[0].id}"; Node.instance_controller = NodeInstance; } else { Node.instance_geometry = NodeInstance; } VN.node.Add(Node); } //SubMesh Loop } //Mesh Loop library_visual_scenes.Add(VN); if (library_visual_scenes.Count > 0) { scene.instance_visual_scene.url = $"#{library_visual_scenes[0].id}"; } if (Scene.Textures.Count > 0) { library_images = new List <DAEImage>(); } foreach (H3DTexture Tex in Scene.Textures) { string dir = "normal-textures"; if (Tex.Name.Contains("tga_1")) { dir = "shiny-textures"; } string fileName = Tex.Name.Replace(".tga_1", ".tga"); library_images.Add(new DAEImage() { id = Tex.Name, init_from = $"./{dir}/{fileName}.png" }); } } //MdlIndex != -1 if (!object.Equals(AnimIndices, null) && AnimIndices.Length > 0) { this.motionGlossary = new Dictionary <string, int[]>(); library_animations = new List <DAEAnimation>(); string[] AnimElemNames = { "translate", "rotateX", "rotateY", "rotateZ", "scale" }; H3DDict <H3DBone> Skeleton = Scene.Models[0].Skeleton; int TotalFrameCount = 0; int FrameOffset = 0; Dictionary <string, AnimMergeCache> Combined = new Dictionary <string, AnimMergeCache>(); foreach (int AnimIndex in AnimIndices) { TotalFrameCount += (int)Scene.SkeletalAnimations[AnimIndex].FramesCount + 1; } for (int a = 0; a < AnimIndices.Length; ++a) { int AnimIndex = AnimIndices[a]; H3DAnimation SklAnim = Scene.SkeletalAnimations[AnimIndex]; int ThisAnimFrames = (int)SklAnim.FramesCount + 1; motionGlossary.Add(GFMotion.GetMotionName(SklAnim.Name), new int[] { FrameOffset, FrameOffset + ThisAnimFrames - 1 }); foreach (H3DAnimationElement Elem in SklAnim.Elements) { if (Elem.PrimitiveType != H3DPrimitiveType.Transform && Elem.PrimitiveType != H3DPrimitiveType.QuatTransform) { continue; } H3DBone SklBone = Skeleton.FirstOrDefault(x => x.Name == Elem.Name); H3DBone Parent = null; if (SklBone != null && SklBone.ParentIndex != -1) { Parent = Skeleton[SklBone.ParentIndex]; } for (int i = 0; i < 5; i++) { string[] AnimTimes = new string[ThisAnimFrames]; string[] AnimPoses = new string[ThisAnimFrames]; string[] AnimLerps = new string[ThisAnimFrames]; bool IsRotation = i > 0 && i < 4; //1, 2, 3 bool Skip = Elem.PrimitiveType != H3DPrimitiveType.Transform && Elem.PrimitiveType != H3DPrimitiveType.QuatTransform; if (!Skip) { if (Elem.Content is H3DAnimTransform Transform) { switch (i) { case 0: Skip = !Transform.TranslationExists; break; case 1: Skip = !Transform.RotationX.Exists; break; case 2: Skip = !Transform.RotationY.Exists; break; case 3: Skip = !Transform.RotationZ.Exists; break; case 4: Skip = !Transform.ScaleExists; break; } } else if (Elem.Content is H3DAnimQuatTransform QuatTransform) { switch (i) { case 0: Skip = !QuatTransform.HasTranslation; break; case 1: Skip = !QuatTransform.HasRotation; break; case 2: Skip = !QuatTransform.HasRotation; break; case 3: Skip = !QuatTransform.HasRotation; break; case 4: Skip = !QuatTransform.HasScale; break; } } } if (Skip) { continue; } for (int Frame = 0; Frame < ThisAnimFrames; Frame++) { string StrTrans = string.Empty; H3DAnimationElement PElem = SklAnim.Elements.FirstOrDefault(x => x.Name == Parent?.Name); Vector3 InvScale = Vector3.One; if (Elem.Content is H3DAnimTransform Transform) { //Compensate parent bone scale (basically, don't inherit scales) if (Parent != null && (SklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0) { if (PElem != null) { H3DAnimTransform PTrans = (H3DAnimTransform)PElem.Content; InvScale /= new Vector3( PTrans.ScaleX.Exists ? PTrans.ScaleX.GetFrameValue(Frame) : Parent.Scale.X, PTrans.ScaleY.Exists ? PTrans.ScaleY.GetFrameValue(Frame) : Parent.Scale.Y, PTrans.ScaleZ.Exists ? PTrans.ScaleZ.GetFrameValue(Frame) : Parent.Scale.Z); } else { InvScale /= Parent.Scale; } } switch (i) { //Translation case 0: StrTrans = DAEUtils.VectorStr(new Vector3( Transform.TranslationX.Exists //X ? Transform.TranslationX.GetFrameValue(Frame) : SklBone.Translation.X, Transform.TranslationY.Exists //Y ? Transform.TranslationY.GetFrameValue(Frame) : SklBone.Translation.Y, Transform.TranslationZ.Exists //Z ? Transform.TranslationZ.GetFrameValue(Frame) : SklBone.Translation.Z)); break; //Scale case 4: StrTrans = DAEUtils.VectorStr(InvScale * new Vector3( Transform.ScaleX.Exists //X ? Transform.ScaleX.GetFrameValue(Frame) : SklBone.Scale.X, Transform.ScaleY.Exists //Y ? Transform.ScaleY.GetFrameValue(Frame) : SklBone.Scale.Y, Transform.ScaleZ.Exists //Z ? Transform.ScaleZ.GetFrameValue(Frame) : SklBone.Scale.Z)); break; //Rotation case 1: StrTrans = DAEUtils.RadToDegStr(Transform.RotationX.GetFrameValue(Frame)); break; case 2: StrTrans = DAEUtils.RadToDegStr(Transform.RotationY.GetFrameValue(Frame)); break; case 3: StrTrans = DAEUtils.RadToDegStr(Transform.RotationZ.GetFrameValue(Frame)); break; } } else if (Elem.Content is H3DAnimQuatTransform QuatTransform) { //Compensate parent bone scale (basically, don't inherit scales) if (Parent != null && (SklBone.Flags & H3DBoneFlags.IsSegmentScaleCompensate) != 0) { if (PElem != null) { InvScale /= ((H3DAnimQuatTransform)PElem.Content).GetScaleValue(Frame); } else { InvScale /= Parent.Scale; } } switch (i) { case 0: StrTrans = DAEUtils.VectorStr(QuatTransform.GetTranslationValue(Frame)); break; case 1: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().X); break; case 2: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().Y); break; case 3: StrTrans = DAEUtils.RadToDegStr(QuatTransform.GetRotationValue(Frame).ToEuler().Z); break; case 4: StrTrans = DAEUtils.VectorStr(InvScale * QuatTransform.GetScaleValue(Frame)); break; } } //This is the Time in seconds, so we divide by the target FPS AnimTimes[Frame] = ((Frame + FrameOffset) / 30f).ToString(CultureInfo.InvariantCulture); AnimPoses[Frame] = StrTrans; AnimLerps[Frame] = "LINEAR"; } string key = $"{Elem.Name}_{AnimElemNames[i]}"; if (Combined.ContainsKey(key)) { Combined[key].AnimTimes.AddRange(AnimTimes); Combined[key].AnimLerps.AddRange(AnimLerps); Combined[key].AnimPoses.AddRange(AnimPoses); } else { var AnimData = new AnimMergeCache { AnimName = $"mm_{Elem.Name}_{AnimElemNames[i]}", ElemName = Elem.Name, Type = AnimElemNames[i], IsRotation = IsRotation, //WARN: this might* be a problem, so far no issues trying to fluff previously unused bones AnimTimes = Enumerable.Repeat(AnimTimes[0], FrameOffset).ToList().Concat(AnimTimes.ToList()).ToList(), AnimLerps = Enumerable.Repeat(AnimLerps[0], FrameOffset).ToList().Concat(AnimLerps.ToList()).ToList(), AnimPoses = Enumerable.Repeat(AnimPoses[0], FrameOffset).ToList().Concat(AnimPoses.ToList()).ToList() }; Combined.Add($"{Elem.Name}_{AnimElemNames[i]}", AnimData); } } //Axis 0-5 } //SklAnim.Elements FrameOffset += (int)SklAnim.FramesCount + 1; } //add animations finally foreach (AnimMergeCache merged in Combined.Values) { DAEAnimation Anim = new DAEAnimation(); Anim.name = merged.AnimName; Anim.id = $"{Anim.name}_id"; Anim.src.Add(new DAESource($"{Anim.name}_frame", 1, merged.AnimTimes.ToArray(), "TIME", "float")); Anim.src.Add(new DAESource($"{Anim.name}_interp", 1, merged.AnimLerps.ToArray(), "INTERPOLATION", "Name")); Anim.src.Add(merged.IsRotation ? new DAESource($"{Anim.name}_pose", 1, merged.AnimPoses.ToArray(), "ANGLE", "float") : new DAESource($"{Anim.name}_pose", 3, merged.AnimPoses.ToArray(), "X", "float", "Y", "float", "Z", "float")); Anim.sampler.AddInput("INPUT", $"#{Anim.src[0].id}"); Anim.sampler.AddInput("INTERPOLATION", $"#{Anim.src[1].id}"); Anim.sampler.AddInput("OUTPUT", $"#{Anim.src[2].id}"); Anim.sampler.id = $"{Anim.name}_samp_id"; Anim.channel.source = $"#{Anim.sampler.id}"; Anim.channel.target = $"{merged.ElemName}_bone_id/{merged.Type}"; if (merged.IsRotation) { Anim.channel.target += ".ANGLE"; } library_animations.Add(Anim); } } //AnimIndices.Length > 1 }
public static H3D OpenAsH3D(Stream input, GFPackage.Header header, H3DDict <H3DBone> skeleton = null) { var output = default(H3D); var reader = new BinaryReader(input); input.Seek(header.Entries[0].Address, SeekOrigin.Begin); var magicNum = reader.ReadUInt32(); switch (magicNum) { case GFModelConstant: var mdlPack = new GFModelPack(); //High Poly Pokémon model input.Seek(header.Entries[0].Address, SeekOrigin.Begin); mdlPack.Models.Add(new GFModel(reader, "PM_HighPoly")); //Low Poly Pokémon model input.Seek(header.Entries[1].Address, SeekOrigin.Begin); mdlPack.Models.Add(new GFModel(reader, "PM_LowPoly")); //Pokémon Shader package input.Seek(header.Entries[2].Address, SeekOrigin.Begin); var psHeader = GFPackage.GetPackageHeader(input); foreach (var entry in psHeader.Entries) { input.Seek(entry.Address, SeekOrigin.Begin); mdlPack.Shaders.Add(new GFShader(reader)); } //More shaders input.Seek(header.Entries[3].Address, SeekOrigin.Begin); if (GFPackage.IsValidPackage(input)) { var pcHeader = GFPackage.GetPackageHeader(input); foreach (var entry in pcHeader.Entries) { input.Seek(entry.Address, SeekOrigin.Begin); mdlPack.Shaders.Add(new GFShader(reader)); } } output = mdlPack.ToH3D(); break; case GFTextureConstant: output = new H3D(); foreach (var entry in header.Entries) { input.Seek(entry.Address, SeekOrigin.Begin); output.Textures.Add(new GFTexture(reader).ToH3DTexture()); } break; case GFMotionConstant: output = new H3D(); if (skeleton == null) { break; } for (var index = 0; index < header.Entries.Length; index++) { input.Seek(header.Entries[index].Address, SeekOrigin.Begin); if (input.Position + 4 > input.Length) { break; } if (reader.ReadUInt32() != GFMotionConstant) { continue; } input.Seek(-4, SeekOrigin.Current); var mot = new GFMotion(reader, index); var sklAnim = mot.ToH3DSkeletalAnimation(skeleton); var matAnim = mot.ToH3DMaterialAnimation(); var visAnim = mot.ToH3DVisibilityAnimation(); if (sklAnim != null) { sklAnim.Name = $"Motion_{mot.Index}"; output.SkeletalAnimations.Add(sklAnim); } if (matAnim != null) { matAnim.Name = $"Motion_{mot.Index}"; output.MaterialAnimations.Add(matAnim); } if (visAnim != null) { visAnim.Name = $"Motion_{mot.Index}"; output.VisibilityAnimations.Add(visAnim); } } break; case BCHConstant: output = new H3D(); foreach (var entry in header.Entries) { input.Seek(entry.Address, SeekOrigin.Begin); magicNum = reader.ReadUInt32(); if (magicNum != BCHConstant) { continue; } input.Seek(-4, SeekOrigin.Current); var buffer = reader.ReadBytes(entry.Length); output.Merge(H3D.Open(buffer)); } break; } return(output); }