private static void LoadMTShader(string FileName) { using (FileStream FS = new FileStream(FileName, FileMode.Open)) { MTShader = new MTShaderEffects(FS); } }
public MTMesh( BinaryReader Reader, MTShaderEffects Shader, uint VerticesBufferAddress, uint IndicesBufferAddress) { ushort MeshTypeFlags = Reader.ReadUInt16(); //? ushort VerticesCount = Reader.ReadUInt16(); uint MatMeshIndices = Reader.ReadUInt32(); byte MeshFlags = Reader.ReadByte(); //? byte RenderPriority = Reader.ReadByte(); byte VertexStride = Reader.ReadByte(); byte AttributesCount = Reader.ReadByte(); uint VerticesIndex = Reader.ReadUInt32(); uint VerticesOffset = Reader.ReadUInt32(); uint VertexFormatHash = Reader.ReadUInt32(); uint IndicesIndex = Reader.ReadUInt32(); uint IndicesCount = Reader.ReadUInt32(); uint IndicesOffset = Reader.ReadUInt32(); byte BoneIndicesCount = Reader.ReadByte(); //Always 0? Probably wrong byte BoneIndicesIndex = Reader.ReadByte(); ushort MeshIndex = Reader.ReadUInt16(); this.VertexStride = VertexStride; this.RenderPriority = RenderPriority; this.BoneIndicesIndex = BoneIndicesIndex; MeshGroupIndex = (MatMeshIndices >> 0) & 0xfff; //? MaterialIndex = (MatMeshIndices >> 12) & 0xfff; RenderType = (sbyte)(MatMeshIndices >> 24); Attributes = Shader.GetDescriptor <MTAttributesGroup>(VertexFormatHash).Attributes; Reader.BaseStream.Seek(IndicesBufferAddress + IndicesIndex * 2, SeekOrigin.Begin); Indices = new ushort[(IndicesCount - 1) * 3]; for (int Index = 0; Index < Indices.Length; Index++) { //Convert Triangle Strip Index Buffer to Triangle List if (Index > 2) { Indices[Index + 0] = Indices[Index - 2]; Indices[Index + 1] = Indices[Index - 1]; Index += 2; } Indices[Index] = (ushort)(Reader.ReadUInt16() - VerticesIndex); } VerticesOffset += VerticesIndex * VertexStride; Reader.BaseStream.Seek(VerticesBufferAddress + VerticesOffset, SeekOrigin.Begin); RawBuffer = Reader.ReadBytes(VerticesCount * VertexStride); }
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 MTModel(BinaryReader Reader, MTMaterials MRLData, MTShaderEffects Shader) : this() { string Magic = Reader.ReadPaddedString(4); ushort Version = Reader.ReadUInt16(); ushort BonesCount = Reader.ReadUInt16(); ushort MeshesCount = Reader.ReadUInt16(); ushort MaterialsCount = Reader.ReadUInt16(); uint TotalVerticesCount = Reader.ReadUInt32(); uint TotalIndicesCount = Reader.ReadUInt32(); uint TotalTrianglesCount = Reader.ReadUInt32(); uint VerticesBufferLength = Reader.ReadUInt32(); uint HeaderPadding1c = Reader.ReadUInt32(); //? uint MeshGroupsCount = Reader.ReadUInt32(); uint BoneIndicesCount = Reader.ReadUInt32(); uint SkeletonAddress = Reader.ReadUInt32(); uint MeshGroupsAddr = Reader.ReadUInt32(); uint MaterialNamesAddress = Reader.ReadUInt32(); uint MeshesAddress = Reader.ReadUInt32(); uint VerticesBufferAddress = Reader.ReadUInt32(); uint IndicesBufferAddress = Reader.ReadUInt32(); uint ModelFileLength = Reader.ReadUInt32(); BoundingSphere = Reader.ReadVector4(); BoundingBoxMin = Reader.ReadVector4(); BoundingBoxMax = Reader.ReadVector4(); string[] MaterialNames = new string[MaterialsCount]; Reader.BaseStream.Seek(MaterialNamesAddress, SeekOrigin.Begin); for (int Index = 0; Index < MaterialsCount; Index++) { MaterialNames[Index] = Reader.ReadPaddedString(0x80); } for (int Index = 0; Index < MeshesCount; Index++) { Reader.BaseStream.Seek(MeshesAddress + Index * 0x30, SeekOrigin.Begin); MTMesh Mesh = new MTMesh( Reader, Shader, VerticesBufferAddress, IndicesBufferAddress); string MaterialName = MaterialNames[Mesh.MaterialIndex]; uint MaterialHash = CRC32Hash.Hash(MaterialName); int MaterialIndex = Materials.FindIndex(x => x.NameHash == MaterialHash); if (MaterialIndex == -1) { MTMaterial Mat = MRLData.Materials.FirstOrDefault(x => x.NameHash == MaterialHash); if (Mat != null) { Mat.Name = MaterialName; MaterialIndex = Materials.Count; Materials.Add(Mat); } else { MaterialIndex = 0; } } Mesh.MaterialIndex = (uint)MaterialIndex; Meshes.Add(Mesh); } for (int Index = 0; Index < BonesCount; Index++) { Reader.BaseStream.Seek(SkeletonAddress + Index * 0x18, SeekOrigin.Begin); sbyte BoneIndex = Reader.ReadSByte(); sbyte Parent = Reader.ReadSByte(); sbyte Opposite = Reader.ReadSByte(); byte Padding = Reader.ReadByte(); float ChildDistance = Reader.ReadSingle(); float ParentDistance = Reader.ReadSingle(); Vector3 Position = Reader.ReadVector3(); Skeleton.Add(new MTBone() { ParentIndex = Parent, OppositeIndex = Opposite, ChildDistance = ChildDistance, ParentDistance = ParentDistance, Position = Position }); } for (int Index = 0; Index < BonesCount; Index++) { Skeleton[Index].LocalTransform = Reader.ReadMatrix4x4RH(); } for (int Index = 0; Index < BonesCount; Index++) { Skeleton[Index].WorldTransform = Reader.ReadMatrix4x4RH(); } Reader.BaseStream.Seek(0x100, SeekOrigin.Current); BoneIndicesGroups = new byte[BoneIndicesCount][]; for (int i = 0; i < BoneIndicesCount; i++) { int Count = Reader.ReadInt32(); BoneIndicesGroups[i] = new byte[Count]; for (int j = 0; j < Count; j++) { BoneIndicesGroups[i][j] = Reader.ReadByte(); } Reader.BaseStream.Seek(0x18 - Count, SeekOrigin.Current); } }
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 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); }
private static void LoadMTShader(string fileName) { using (var fs = new FileStream(fileName, FileMode.Open)) _mtShader = new MTShaderEffects(fs); }
public MTMaterials(BinaryReader Reader, MTShaderEffects Shader) : this() { string Magic = Reader.ReadPaddedString(4); uint Version = Reader.ReadUInt32(); uint MaterialsCount = Reader.ReadUInt32(); uint TexLUTsCount = Reader.ReadUInt32(); uint MFXShaderHash = Reader.ReadUInt32(); if (Version == 0xc) { //Version 0xC (Street Fighter) have values like 0x1b here, unknown what it is //It also have an extra section (Address located after MaterialsAddress), use is unknown Reader.ReadUInt32(); } uint TexLUTsAddress = Reader.ReadUInt32(); uint MaterialsAddress = Reader.ReadUInt32(); for (int Index = 0; Index < MaterialsCount; Index++) { long BaseAddr = MaterialsAddress + Index * 0x3c; /* * Note: It's just amazing how they can't keep the same format even on the same platform. * Yea, different games have those values in different order inside the struct. * TODO: Figure out exact version numbers where stuff changes (or the closest based on released games). */ Reader.BaseStream.Seek(BaseAddr + 4, SeekOrigin.Begin); uint MaterialNameHash = Reader.ReadUInt32(); uint TextureDescLength = Reader.ReadUInt32(); Reader.BaseStream.Seek(BaseAddr + 0x34, SeekOrigin.Begin); uint TextureDescAddress = Reader.ReadUInt32(); uint MatConfig1Address = Reader.ReadUInt32(); Reader.BaseStream.Seek(BaseAddr + (Version < 0x20 ? 0x10 : 0xc), SeekOrigin.Begin); uint AlphaBlendHash = Reader.ReadUInt32(); //Alpha blending related config uint DepthStencilHash = Reader.ReadUInt32(); //Depth Buffer and Stencil Buffer config uint MeshScissorHash = Reader.ReadUInt32(); //Mesh and Scissor stuff (Culling, Z-Bias, ...) byte TextureDescCount = Reader.ReadByte(); string DiffuseName = null; for (int DescIndex = 0; DescIndex < TextureDescCount; DescIndex++) { /* * Bits 00-03 = Entry type * Bits 04-15 = Memory garbage * Bits 16-31 = Unknown * Entry types: * 1 = Combiner * 2 = Sampler * 3 = Texture map */ Reader.BaseStream.Seek(TextureDescAddress + DescIndex * 0xc, SeekOrigin.Begin); byte EntryType = (byte)(Reader.ReadUInt32() & 0xf); switch (EntryType) { case 3: /* * This can be either a Texture name or a LUT. * LUTs seems to be interpolated from some quantized values. * It's possible that they use Hermite to interpolate the values, * or maybe it's just Linear but it only have 16 values so the step is pretty large. */ int TextureIndex = Reader.ReadInt32() - 1; if (TextureIndex != -1) { MTTextureMap TextureMap = Shader.GetDescriptor <MTTextureMap>(Reader.ReadUInt32()); Reader.BaseStream.Seek(TexLUTsAddress + TextureIndex * 0x4c + 0xc, SeekOrigin.Begin); switch (TextureMap.Type) { case "BaseMap": DiffuseName = Reader.ReadPaddedString(0x40); break; case "LutToon": ReadLUT(Reader); break; case "LutShininess": ReadLUT(Reader); break; case "LutShininessR": ReadLUT(Reader); break; case "LutShininessG": ReadLUT(Reader); break; case "LutShininessB": ReadLUT(Reader); break; case "LutFresnel": ReadLUT(Reader); break; } } break; } } Materials.Add(new MTMaterial() { NameHash = MaterialNameHash, AlphaBlend = Shader.GetDescriptor <MTAlphaBlend>(AlphaBlendHash), DepthStencil = Shader.GetDescriptor <MTDepthStencil>(DepthStencilHash), Texture0Name = DiffuseName }); } }
public MTMaterials(Stream Input, MTShaderEffects Shader) : this(new BinaryReader(Input), Shader) { }