diff --git a/3DS/3DS.csproj b/3DS/3DS.csproj index de5bf80..ad2edd5 100644 --- a/3DS/3DS.csproj +++ b/3DS/3DS.csproj @@ -65,6 +65,7 @@ + @@ -106,6 +107,12 @@ CFNTViewer.cs + + Form + + + CGFXGenDialog.cs + Form @@ -197,6 +204,9 @@ CFNTViewer.cs + + CGFXGenDialog.cs + CLIMViewer.cs diff --git a/3DS/NintendoWare/GFX/BoundingVolume.cs b/3DS/NintendoWare/GFX/BoundingVolume.cs index 3e07dcf..82b12e4 100644 --- a/3DS/NintendoWare/GFX/BoundingVolume.cs +++ b/3DS/NintendoWare/GFX/BoundingVolume.cs @@ -9,6 +9,7 @@ namespace _3DS.NintendoWare.GFX { public class BoundingVolume { + public BoundingVolume() { } public BoundingVolume(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -51,6 +52,15 @@ namespace _3DS.NintendoWare.GFX public class OrientedBoundingBox : BoundingVolume { + public OrientedBoundingBox() + : base() + { + Type = 0x80000000; + //All to be set by the user + CenterPosition = new Vector3(0, 0, 0); + OrientationMatrix = new float[] { 1, 0, 0, 0, 1, 0, 0, 0, 1 }; + Size = new Vector3(1, 1, 1); + } public OrientedBoundingBox(EndianBinaryReader er) : base(er) { diff --git a/3DS/NintendoWare/GFX/CGFX.cs b/3DS/NintendoWare/GFX/CGFX.cs index 595c225..905c24e 100644 --- a/3DS/NintendoWare/GFX/CGFX.cs +++ b/3DS/NintendoWare/GFX/CGFX.cs @@ -14,8 +14,14 @@ using LibEveryFileExplorer.Collections; namespace _3DS.NintendoWare.GFX { - public class CGFX : FileFormat, IViewable, IWriteable + public class CGFX : FileFormat, IFileCreatable, IViewable, IWriteable { + public CGFX() + { + Header = new CGFXHeader(); + Data = new DATA(); + } + public CGFX(byte[] Data) { EndianBinaryReader er = new EndianBinaryReader(new MemoryStream(Data), Endianness.LittleEndian); @@ -66,9 +72,31 @@ namespace _3DS.NintendoWare.GFX return result; } + public bool CreateFromFile() + { + System.Windows.Forms.OpenFileDialog f = new System.Windows.Forms.OpenFileDialog(); + f.Filter = OBJ.Identifier.GetFileFilter(); + if (f.ShowDialog() == System.Windows.Forms.DialogResult.OK + && f.FileName.Length > 0) + { + UI.CGFXGenDialog d = new UI.CGFXGenDialog(); + d.ShowDialog(); + CGFXGenerator.FromOBJ(this, f.FileName, d.ModelName); + return true; + } + return false; + } + public CGFXHeader Header; public class CGFXHeader { + public CGFXHeader() + { + Signature = "CGFX"; + Endianness = 0xFEFF; + HeaderSize = 0x14; + Version = 0x5000000; + } public CGFXHeader(EndianBinaryReader er) { Signature = er.ReadString(Encoding.ASCII, 4); @@ -98,6 +126,12 @@ namespace _3DS.NintendoWare.GFX public DATA Data; public class DATA { + public DATA() + { + Signature = "DATA"; + DictionaryEntries = new DictionaryInfo[16]; + Dictionaries = new DICT[16]; + } public DATA(EndianBinaryReader er) { Signature = er.ReadString(Encoding.ASCII, 4); diff --git a/3DS/NintendoWare/GFX/CGFXGenerator.cs b/3DS/NintendoWare/GFX/CGFXGenerator.cs new file mode 100644 index 0000000..ea557f3 --- /dev/null +++ b/3DS/NintendoWare/GFX/CGFXGenerator.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using CommonFiles; +using System.IO; +using System.Drawing; +using LibEveryFileExplorer.Collections; +using LibEveryFileExplorer.IO; + +namespace _3DS.NintendoWare.GFX +{ + public class CGFXGenerator + { + public static void FromOBJ(CGFX c, String OBJPath, String ModelName = "EFEModel") + { + OBJ Model = new OBJ(File.ReadAllBytes(OBJPath)); + if (Model.MTLPath == null) throw new Exception("Model without materials not supported!"); + String MtlPath = Path.GetDirectoryName(OBJPath) + "\\" + Model.MTLPath; + MTL MatLib = new MTL(File.ReadAllBytes(MtlPath)); + List MatNames = new List(); + foreach (var f in Model.Faces) + { + if (!MatNames.Contains(f.Material)) MatNames.Add(f.Material); + } + Bitmap[] Textures = new Bitmap[MatLib.Materials.Count]; + int q = 0; + int NrTextures = 0; + foreach (var v in MatLib.Materials) + { + if (!MatNames.Contains(v.Name)) { q++; continue; } + if (v.DiffuseMapPath != null) + { + Textures[q] = new Bitmap(new MemoryStream(File.ReadAllBytes(Path.GetDirectoryName(MtlPath) + "\\" + v.DiffuseMapPath))); + NrTextures++; + } + q++; + } + c.Data.Dictionaries[0] = new DICT(); + c.Data.Dictionaries[0].Add(ModelName); + c.Data.Models = new CMDL[1]; + c.Data.Models[0] = new CMDL(ModelName); + CMDL cmdl = c.Data.Models[0]; + //Mesh Node Visibility + { + cmdl.NrMeshNodes = 1; + cmdl.MeshNodeVisibilitiesDict = new DICT(); + cmdl.MeshNodeVisibilitiesDict.Add("CompleteModel"); + cmdl.MeshNodeVisibilities = new CMDL.MeshNodeVisibilityCtr[] { new CMDL.MeshNodeVisibilityCtr("CompleteModel") }; + } + //Meshes + { + cmdl.NrMeshes = (uint)MatNames.Count; + cmdl.Meshes = new CMDL.Mesh[MatNames.Count]; + for (int i = 0; i < MatNames.Count; i++) + { + cmdl.Meshes[i] = new CMDL.Mesh(); + cmdl.Meshes[i].MeshNodeName = "CompleteModel"; + cmdl.Meshes[i].MaterialIndex = (uint)i; + cmdl.Meshes[i].ShapeIndex = (uint)i; + } + } + //Materials + { + cmdl.NrMaterials = (uint)MatNames.Count; + cmdl.MaterialsDict = new DICT(); + cmdl.Materials = new CMDL.MTOB[MatNames.Count]; + for (int i = 0; i < MatNames.Count; i++) + { + cmdl.MaterialsDict.Add(MatNames[i]); + cmdl.Materials[i] = new CMDL.MTOB(MatNames[i]); + cmdl.Materials[i].FragShader.TextureCombiners[0].SrcRgb = 0xEE0; + cmdl.Materials[i].FragShader.TextureCombiners[0].SrcAlpha = 0xEE0; + for (int qq = 1; qq < 6; qq++) + { + cmdl.Materials[i].FragShader.TextureCombiners[qq].SrcRgb = 0xEEF; + cmdl.Materials[i].FragShader.TextureCombiners[qq].SrcAlpha = 0xEEF; + } + Bitmap tex = Textures[MatLib.Materials.IndexOf(MatLib.GetMaterialByName(MatNames[i]))]; + if (tex != null) + { + cmdl.Materials[i].NrActiveTextureCoordiators = 1; + cmdl.Materials[i].TextureCoordiators[0].Scale = new LibEveryFileExplorer.Collections.Vector2(1, 1); + cmdl.Materials[i].Tex0 = new CMDL.MTOB.TexInfo(MatNames[i]); + cmdl.Materials[i].FragShader.TextureCombiners[0].SrcRgb = 0xE30; + cmdl.Materials[i].FragShader.TextureCombiners[0].SrcAlpha = 0xE30; + cmdl.Materials[i].FragShader.TextureCombiners[0].CombineRgb = 1; + cmdl.Materials[i].FragShader.TextureCombiners[0].CombineAlpha = 1; + } + } + } + //Shapes + { + cmdl.NrShapes = (uint)MatNames.Count; + cmdl.Shapes = new CMDL.SeparateDataShape[MatNames.Count]; + for (int i = 0; i < MatNames.Count; i++) + { + cmdl.Shapes[i] = new CMDL.SeparateDataShape(); + Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue); + Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue); + int nrfaces = 0; + bool texcoords = false; + foreach (var f in Model.Faces) + { + if (f.Material != MatNames[i]) continue; + nrfaces++; + if (f.TexCoordIndieces.Count > 0) texcoords = true; + foreach (var qqq in f.VertexIndieces) + { + if (Model.Vertices[qqq].X < min.X) min.X = Model.Vertices[qqq].X; + if (Model.Vertices[qqq].Y < min.Y) min.Y = Model.Vertices[qqq].Y; + if (Model.Vertices[qqq].Z < min.Z) min.Z = Model.Vertices[qqq].Z; + if (Model.Vertices[qqq].X > max.X) max.X = Model.Vertices[qqq].X; + if (Model.Vertices[qqq].Y > max.Y) max.Y = Model.Vertices[qqq].Y; + if (Model.Vertices[qqq].Z > max.Z) max.Z = Model.Vertices[qqq].Z; + } + } + ((OrientedBoundingBox)cmdl.Shapes[i].BoundingBox).CenterPosition = (min + max) / 2; + ((OrientedBoundingBox)cmdl.Shapes[i].BoundingBox).Size = max - min; + cmdl.Shapes[i].NrPrimitiveSets = 1; + cmdl.Shapes[i].PrimitiveSets = new CMDL.SeparateDataShape.PrimitiveSet[1]; + cmdl.Shapes[i].PrimitiveSets[0] = new CMDL.SeparateDataShape.PrimitiveSet(); + cmdl.Shapes[i].PrimitiveSets[0].NrPrimitives = 1; + cmdl.Shapes[i].PrimitiveSets[0].Primitives = new CMDL.SeparateDataShape.PrimitiveSet.Primitive[1]; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0] = new CMDL.SeparateDataShape.PrimitiveSet.Primitive(); + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].NrBufferObjects = 1; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].BufferObjects = new uint[] { 0 }; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].NrIndexStreams = 1; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams = new CMDL.SeparateDataShape.PrimitiveSet.Primitive.IndexStreamCtr[1]; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0] = new CMDL.SeparateDataShape.PrimitiveSet.Primitive.IndexStreamCtr(); + if (nrfaces * 3 > 255) cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FormatType = 0x1403; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceDataLength = (uint)(nrfaces * 3 * ((nrfaces * 3 > 255) ? 2 : 1)); + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData = new byte[cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceDataLength]; + int offs = 0; + int idx = 0; + foreach (var f in Model.Faces) + { + if (f.Material != MatNames[i]) continue; + if (nrfaces * 3 > 255) + { + IOUtil.WriteU16LE(cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData, offs, (ushort)idx); + IOUtil.WriteU16LE(cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData, offs + 2, (ushort)(idx + 1)); + IOUtil.WriteU16LE(cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData, offs + 4, (ushort)(idx + 2)); + offs += 2 * 3; + } + else + { + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData[idx] = (byte)idx; + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData[idx + 1] = (byte)(idx + 1); + cmdl.Shapes[i].PrimitiveSets[0].Primitives[0].IndexStreams[0].FaceData[idx + 2] = (byte)(idx + 2); + offs += 3; + } + idx += 3; + } + cmdl.Shapes[i].NrVertexAttributes = 2; + cmdl.Shapes[i].VertexAttributes = new CMDL.SeparateDataShape.VertexAttributeCtr[2]; + //interleaved + cmdl.Shapes[i].VertexAttributes[0] = new CMDL.SeparateDataShape.InterleavedVertexStreamCtr(); + ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).NrVertexStreams = (texcoords ? 2u : 1u); + ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexStreams = new CMDL.SeparateDataShape.InterleavedVertexStreamCtr.VertexStreamCtr[texcoords ? 2 : 1]; + ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexStreams[0] = new CMDL.SeparateDataShape.InterleavedVertexStreamCtr.VertexStreamCtr(CMDL.SeparateDataShape.VertexAttributeCtr.VertexAttributeUsage.Position, CMDL.SeparateDataShape.DataType.GL_FLOAT, 3, 0); + if (texcoords) ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexStreams[1] = new CMDL.SeparateDataShape.InterleavedVertexStreamCtr.VertexStreamCtr(CMDL.SeparateDataShape.VertexAttributeCtr.VertexAttributeUsage.TextureCoordinate0, CMDL.SeparateDataShape.DataType.GL_FLOAT, 2, 12); + ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexDataEntrySize = (texcoords ? 20u : 12u); + byte[] Result = new byte[nrfaces * 3 * ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexDataEntrySize]; + offs = 0; + foreach (var f in Model.Faces) + { + if (f.Material != MatNames[i]) continue; + for (int qqq = 0; qqq < 3; qqq++) + { + Vector3 Pos = Model.Vertices[f.VertexIndieces[qqq]]; + IOUtil.WriteSingleLE(Result, offs, Pos.X); + IOUtil.WriteSingleLE(Result, offs + 4, Pos.Y); + IOUtil.WriteSingleLE(Result, offs + 8, Pos.Z); + offs += 12; + if (texcoords) + { + Vector2 Tex = Model.TexCoords[f.TexCoordIndieces[qqq]]; + IOUtil.WriteSingleLE(Result, offs, Tex.X); + IOUtil.WriteSingleLE(Result, offs + 4, Tex.Y); + offs += 8; + } + } + } + ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexStreamLength = (uint)Result.Length; + ((CMDL.SeparateDataShape.InterleavedVertexStreamCtr)cmdl.Shapes[i].VertexAttributes[0]).VertexStream = Result; + //color + cmdl.Shapes[i].VertexAttributes[1] = new CMDL.SeparateDataShape.VertexParamAttributeCtr(CMDL.SeparateDataShape.VertexAttributeCtr.VertexAttributeUsage.Color, 1, 1, 1, MatLib.GetMaterialByName(MatNames[i]).Alpha); + } + } + if (NrTextures != 0) + { + c.Data.Dictionaries[1] = new DICT(); + c.Data.Textures = new TXOB[NrTextures]; + int qqq = 0; + int idx = 0; + foreach (Bitmap b in Textures) + { + if (b == null) { qqq++; continue; } + c.Data.Dictionaries[1].Add(MatLib.Materials[qqq].Name); + c.Data.Textures[idx] = new ImageTextureCtr(MatLib.Materials[qqq].Name, b, GPU.Textures.ImageFormat.ETC1A4); + idx++; + qqq++; + } + } + } + } +} diff --git a/3DS/NintendoWare/GFX/CMDL.cs b/3DS/NintendoWare/GFX/CMDL.cs index 02ac6a8..f442cca 100644 --- a/3DS/NintendoWare/GFX/CMDL.cs +++ b/3DS/NintendoWare/GFX/CMDL.cs @@ -15,6 +15,21 @@ namespace _3DS.NintendoWare.GFX { public class CMDL { + public CMDL(String Name) + { + Type = 0x40000012; + Signature = "CMDL"; + Revision = 0x9000000; + this.Name = Name; + Flags = 1; + IsBranchVisible = true; + Scale = new Vector3(1, 1, 1); + Rotation = new Vector3(0, 0, 0); + Translation = new Vector3(0, 0, 0); + LocalMatrix = new float[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }; + WorldMatrix = new float[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }; + Unknown23 = 1;//unknown what this does... + } public CMDL(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -29,7 +44,8 @@ namespace _3DS.NintendoWare.GFX NrChildren = er.ReadUInt32(); Unknown7 = er.ReadUInt32(); NrAnimationGroupDescriptions = er.ReadUInt32(); - AnimationGroupDescriptionsDictOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); + AnimationGroupDescriptionsDictOffset =er.ReadUInt32(); + if (AnimationGroupDescriptionsDictOffset != 0) AnimationGroupDescriptionsDictOffset += (UInt32)er.BaseStream.Position - 4; Scale = er.ReadVector3(); Rotation = er.ReadVector3(); Translation = er.ReadVector3(); @@ -52,8 +68,11 @@ namespace _3DS.NintendoWare.GFX long curpos = er.BaseStream.Position; er.BaseStream.Position = NameOffset; Name = er.ReadStringNT(Encoding.ASCII); - er.BaseStream.Position = AnimationGroupDescriptionsDictOffset; - AnimationInfoDict = new DICT(er); + if (AnimationGroupDescriptionsDictOffset != 0) + { + er.BaseStream.Position = AnimationGroupDescriptionsDictOffset; + AnimationInfoDict = new DICT(er); + } er.BaseStream.Position = MeshOffsetsOffset; MeshOffsets = new UInt32[NrMeshes]; for (int i = 0; i < NrMeshes; i++) @@ -180,16 +199,22 @@ namespace _3DS.NintendoWare.GFX er.Write(new uint[NrShapes], 0, (int)NrShapes); long anmgrpdict = er.BaseStream.Position; - er.BaseStream.Position = anmgrpdescdictoffs; - er.Write((uint)(anmgrpdict - anmgrpdescdictoffs)); - er.BaseStream.Position = anmgrpdict; - AnimationInfoDict.Write(er, c); + if (NrAnimationGroupDescriptions != 0 && AnimationInfoDict != null) + { + er.BaseStream.Position = anmgrpdescdictoffs; + er.Write((uint)(anmgrpdict - anmgrpdescdictoffs)); + er.BaseStream.Position = anmgrpdict; + AnimationInfoDict.Write(er, c); + } long matdict = er.BaseStream.Position; - er.BaseStream.Position = matdictoffs; - er.Write((uint)(matdict - matdictoffs)); - er.BaseStream.Position = matdict; - MaterialsDict.Write(er, c); + if (NrMaterials != 0 && MaterialsDict != null) + { + er.BaseStream.Position = matdictoffs; + er.Write((uint)(matdict - matdictoffs)); + er.BaseStream.Position = matdict; + MaterialsDict.Write(er, c); + } long mshnoddict = er.BaseStream.Position; if (NrMeshNodes != 0 && MeshNodeVisibilitiesDict != null) @@ -703,6 +728,11 @@ namespace _3DS.NintendoWare.GFX public MeshNodeVisibilityCtr[] MeshNodeVisibilities; public class MeshNodeVisibilityCtr { + public MeshNodeVisibilityCtr(String Name) + { + this.Name = Name; + Visible = true; + } public MeshNodeVisibilityCtr(EndianBinaryReader er) { NameOffset = (uint)er.BaseStream.Position + er.ReadUInt32(); @@ -743,6 +773,24 @@ namespace _3DS.NintendoWare.GFX ParticleMaterialEnabled = 32 } + public MTOB(String Name) + { + Type = 0x8000000; + Signature = "MTOB"; + Revision = 0x6000003; + this.Name = Name; + MaterialColor = new MaterialColorCtr(); + Rasterization = new RasterizationCtr(); + FragmentOperation = new FragmentOperationCtr(); + NrActiveTextureCoordiators = 0; + TextureCoordiators = new TextureCoordinatorCtr[3]; + TextureCoordiators[0] = new TextureCoordinatorCtr(); + TextureCoordiators[1] = new TextureCoordinatorCtr(); + TextureCoordiators[2] = new TextureCoordinatorCtr(); + + Shader = new SHDR(); + FragShader = new FragmentShader(); + } public MTOB(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -1064,6 +1112,32 @@ namespace _3DS.NintendoWare.GFX public class MaterialColorCtr { + public MaterialColorCtr() + { + Emission = new Vector4(0, 0, 0, 0); + EmissionU32 = Color.FromArgb(0); + Ambient = new Vector4(1, 1, 1, 1); + AmbientU32 = Color.White; + Diffuse = new Vector4(1, 1, 1, 1); + DiffuseU32 = Color.White; + Specular0 = new Vector4(0.33f, 0.33f, 0.33f, 0); + Specular0U32 = Color.FromArgb(0, 84, 84, 84); + Specular1 = new Vector4(0, 0, 0, 0); + Specular1U32 = Color.FromArgb(0); + Constant0 = new Vector4(0, 0, 0, 0); + Constant0U32 = Color.FromArgb(0); + Constant1 = new Vector4(0, 0, 0, 0); + Constant1U32 = Color.FromArgb(0); + Constant2 = new Vector4(0, 0, 0, 0); + Constant2U32 = Color.FromArgb(0); + Constant3 = new Vector4(0, 0, 0, 0); + Constant3U32 = Color.FromArgb(0); + Constant4 = new Vector4(0, 0, 0, 0); + Constant4U32 = Color.FromArgb(0); + Constant5 = new Vector4(0, 0, 0, 0); + Constant5U32 = Color.FromArgb(0); + CommandCache = 0; + } public MaterialColorCtr(EndianBinaryReader er) { Emission = er.ReadVector4(); @@ -1182,6 +1256,14 @@ namespace _3DS.NintendoWare.GFX { PolygonOffsetEnabled = 1 } + public RasterizationCtr() + { + Flags = 0; + CullingMode = 3; + PolygonOffsetUnit = 0; + Command1 = 0; + Command2 = 0x00010040; + } public RasterizationCtr(EndianBinaryReader er) { Flags = (RasterizationFlags)er.ReadUInt32(); @@ -1216,6 +1298,12 @@ namespace _3DS.NintendoWare.GFX public class FragmentOperationCtr { + public FragmentOperationCtr() + { + DepthOperation = new DepthOperationCtr(); + BlendOperation = new BlendOperationCtr(); + StencilOperation = new StencilOperationCtr(); + } public FragmentOperationCtr(EndianBinaryReader er) { DepthOperation = new DepthOperationCtr(er); @@ -1301,6 +1389,14 @@ namespace _3DS.NintendoWare.GFX TestEnabled = 1, MaskEnabled = 2 } + public DepthOperationCtr() + { + Flags = DepthFlags.TestEnabled | DepthFlags.MaskEnabled; + Command1 = 0x41; + Command2 = 0x10107; + Command3 = 0x3000000; + Command4 = 0x80126; + } public DepthOperationCtr(EndianBinaryReader er) { Flags = (DepthFlags)er.ReadUInt32(); @@ -1326,6 +1422,17 @@ namespace _3DS.NintendoWare.GFX public BlendOperationCtr BlendOperation; public class BlendOperationCtr { + public BlendOperationCtr() + { + Mode = 0; + BlendColor = new Vector4(0, 0, 0, 1); + Command1 = 0xe40100; + Command2 = 0x803f0100; + Command3 = 0x01010000; + Command4 = 0; + Command5 = 0xff000000; + Command6 = 0; + } public BlendOperationCtr(EndianBinaryReader er) { Mode = er.ReadUInt32(); @@ -1419,6 +1526,13 @@ namespace _3DS.NintendoWare.GFX public StencilOperationCtr StencilOperation; public class StencilOperationCtr { + public StencilOperationCtr() + { + Command1 = 0xff000000; + Command2 = 0xd0105; + Command3 = 0; + Command4 = 0xf0106; + } public StencilOperationCtr(EndianBinaryReader er) { Command1 = er.ReadUInt32(); @@ -1442,6 +1556,18 @@ namespace _3DS.NintendoWare.GFX public class TextureCoordinatorCtr { + public TextureCoordinatorCtr() + { + SourceCoordinate = 0; + MappingMethod = 0; + ReferenceCamera = 0; + MatrixMode = 0; + Scale = new Vector2(0, 0); + Rotate = 0; + Translate = new Vector2(0, 0); + Unknown3 = 0; + Matrix = new float[] { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0 }; + } public TextureCoordinatorCtr(EndianBinaryReader er) { SourceCoordinate = er.ReadUInt32(); @@ -1479,6 +1605,21 @@ namespace _3DS.NintendoWare.GFX public class TexInfo { + public TexInfo(String RefTex) + { + Type = 0x80000000; + DynamicAllocator = 0; + Unknown4 = 0; + Unknown5 = 0x8E; + Unknown6 = 1; + Unknown7 = 0xFF000000; + Unknown8 = 0x81; + Unknown9 = 0x809f; + Unknown12 = 0x1002206; + CommandSizeToSend = 0x38; + TextureObject = new ReferenceTexture(RefTex); + Sampler = new StandardTextureSamplerCtr(); + } public TexInfo(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -1578,67 +1719,14 @@ namespace _3DS.NintendoWare.GFX //Procedural Texture Mapper = 0x40000000 public TXOB TextureObject; - /*public TXOB TextureObject; - public class TXOB - { - public TXOB(EndianBinaryReader er) - { - Type = er.ReadUInt32(); - Signature = er.ReadString(Encoding.ASCII, 4); - if (Signature != "TXOB") throw new SignatureNotCorrectException(Signature, "TXOB", er.BaseStream.Position); - Revision = er.ReadUInt32(); - NameOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); - Unknown2 = er.ReadUInt32(); - Unknown3 = er.ReadUInt32(); - LinkedTextureNameOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); - LinkedTextureOffset = (UInt32)er.BaseStream.Position + er.ReadUInt32(); - - long curpos = er.BaseStream.Position; - er.BaseStream.Position = NameOffset; - Name = er.ReadStringNT(Encoding.ASCII); - er.BaseStream.Position = LinkedTextureNameOffset; - LinkedTextureName = er.ReadStringNT(Encoding.ASCII); - er.BaseStream.Position = curpos; - } - public void Write(EndianBinaryWriter er, CGFXWriterContext c) - { - er.Write(Type); - er.Write(Signature, Encoding.ASCII, false); - er.Write(Revision); - c.WriteStringReference(Name, er); - er.Write(Unknown2); - er.Write(Unknown3); - c.WriteStringReference(LinkedTextureName, er); - er.Write((uint)0);//TODO: Texture Offset - } - public UInt32 Type; - public String Signature; - public UInt32 Revision; - public UInt32 NameOffset; - public UInt32 Unknown2; - public UInt32 Unknown3; - public UInt32 LinkedTextureNameOffset; - public UInt32 LinkedTextureOffset; - - public String Name; - public String LinkedTextureName; - - public override string ToString() - { - return Name; - } - - //The types are like this: - //Image Texture = 0x20000011 - //Cube Texture = 0x20000009 - //Reference Texture = 0x20000004 (this structure) - //Procedural Texture = 0x20000002 - //Shadow Texture = 0x20000021 - }*/ public TextureSamplerCtr Sampler; public class TextureSamplerCtr { + public TextureSamplerCtr() + { + MinFilter = 5; + } public TextureSamplerCtr(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -1669,6 +1757,13 @@ namespace _3DS.NintendoWare.GFX public class StandardTextureSamplerCtr : TextureSamplerCtr { + public StandardTextureSamplerCtr() + : base() + { + Type = 0x80000000; + BorderColor = new Vector4(0, 0, 0, 1); + LodBias = 0; + } public StandardTextureSamplerCtr(EndianBinaryReader er) : base(er) { @@ -1688,6 +1783,14 @@ namespace _3DS.NintendoWare.GFX public SHDR Shader; public class SHDR { + public SHDR() + { + Type = 0x80000001; + Signature = "SHDR"; + Revision = 0x6000000; + Name = ""; + LinkedShaderName = "DefaultShader"; + } public SHDR(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -1740,6 +1843,26 @@ namespace _3DS.NintendoWare.GFX public FragmentShader FragShader; public class FragmentShader { + public FragmentShader() + { + BufferColor = new Vector4(0, 0, 0, 1); + FragmentLighting = new FragmentLightingCtr(); + TextureCombiners = new TextureCombinerCtr[6]; + TextureCombiners[0] = new TextureCombinerCtr(0); + TextureCombiners[1] = new TextureCombinerCtr(1); + TextureCombiners[2] = new TextureCombinerCtr(2); + TextureCombiners[3] = new TextureCombinerCtr(3); + TextureCombiners[4] = new TextureCombinerCtr(4); + TextureCombiners[5] = new TextureCombinerCtr(5); + AlphaTest = new AlphaTestCtr(); + BufferCommand1 = 0xFF000000; + BufferCommand2 = 0xF00FD; + BufferCommand3 = 0; + BufferCommand4 = 0x200E0; + BufferCommand5 = 0x400; + BufferCommand6 = 0x201C3; + FragmentLightingTable = new FragmentLightingTableCtr(); + } public FragmentShader(EndianBinaryReader er) { BufferColor = er.ReadVector4(); @@ -1807,7 +1930,10 @@ namespace _3DS.NintendoWare.GFX UseGeometricFactor1 = 16, UseReflection = 32 } - + public FragmentLightingCtr() + { + IsBumpRenormalize = false; + } public FragmentLightingCtr(EndianBinaryReader er) { Flags = (FragmentLightingFlags)er.ReadUInt32(); @@ -1839,6 +1965,7 @@ namespace _3DS.NintendoWare.GFX public FragmentLightingTableCtr FragmentLightingTable; public class FragmentLightingTableCtr { + public FragmentLightingTableCtr() { } public FragmentLightingTableCtr(EndianBinaryReader er) { ReflectanceRSamplerOffset = er.ReadUInt32(); @@ -2053,6 +2180,14 @@ namespace _3DS.NintendoWare.GFX public class TextureCombinerCtr { + private static readonly uint[] Addresses = { 0xC0, 0xC8, 0xD0, 0xD8, 0xF0, 0xF8 }; + public TextureCombinerCtr(int Index) + { + SrcRgb = 0xEE0; + SrcAlpha = 0xEE0; + Address = 0x804F0000 | Addresses[Index]; + ConstRgba = Color.Black; + } public TextureCombinerCtr(EndianBinaryReader er) { Constant = er.ReadUInt32(); @@ -2093,6 +2228,11 @@ namespace _3DS.NintendoWare.GFX public class AlphaTestCtr { + public AlphaTestCtr() + { + Command1 = 0x10; + Command2 = 0xF0104; + } public AlphaTestCtr(EndianBinaryReader er) { Command1 = er.ReadUInt32(); @@ -2152,6 +2292,14 @@ namespace _3DS.NintendoWare.GFX public class Mesh { + public Mesh() + { + Type = 0x1000000; + Signature = "SOBJ"; + Revision = 0; + Name = ""; + IsVisible = true; + } public Mesh(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -2196,8 +2344,11 @@ namespace _3DS.NintendoWare.GFX long curpos = er.BaseStream.Position; er.BaseStream.Position = NameOffset; Name = er.ReadStringNT(Encoding.ASCII); - er.BaseStream.Position = MeshNodeNameOffset; - MeshNodeName = er.ReadStringNT(Encoding.ASCII); + if (MeshNodeNameOffset != 0) + { + er.BaseStream.Position = MeshNodeNameOffset; + MeshNodeName = er.ReadStringNT(Encoding.ASCII); + } er.BaseStream.Position = curpos; } public void Write(EndianBinaryWriter er, CGFXWriterContext c, long OwnerOffset) @@ -2232,7 +2383,8 @@ namespace _3DS.NintendoWare.GFX er.Write(Unknown23); er.Write(Unknown24); er.Write(Unknown25); - c.WriteStringReference(MeshNodeName, er); + if (MeshNodeName != null) c.WriteStringReference(MeshNodeName, er); + else er.Write((uint)0); er.Write(Unknown27); er.Write(Unknown28); er.Write(Unknown29); @@ -2298,6 +2450,15 @@ namespace _3DS.NintendoWare.GFX GL_SHORT = 0x1402,//might also be unsigned short GL_FLOAT = 0x1406 } + public SeparateDataShape() + { + Type = 0x10000001; + Signature = "SOBJ"; + Revision = 0; + Name = ""; + BoundingBox = new OrientedBoundingBox(); + PositionOffset = new Vector3(0, 0, 0); + } public SeparateDataShape(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -2456,6 +2617,11 @@ namespace _3DS.NintendoWare.GFX public PrimitiveSet[] PrimitiveSets; public class PrimitiveSet { + public PrimitiveSet() + { + NrRelatedBones = 0; + SkinningMode = 0; + } public PrimitiveSet(EndianBinaryReader er) { NrRelatedBones = er.ReadUInt32(); @@ -2522,6 +2688,7 @@ namespace _3DS.NintendoWare.GFX public Primitive[] Primitives; public class Primitive { + public Primitive() { } public Primitive(EndianBinaryReader er) { NrIndexStreams = er.ReadUInt32(); @@ -2588,6 +2755,13 @@ namespace _3DS.NintendoWare.GFX public IndexStreamCtr[] IndexStreams; public class IndexStreamCtr { + public IndexStreamCtr() + { + FormatType = 0x1401; + PrimitiveMode = 0; + IsVisible = true; + + } public IndexStreamCtr(EndianBinaryReader er) { FormatType = er.ReadUInt32(); @@ -2722,6 +2896,7 @@ namespace _3DS.NintendoWare.GFX VertexParam = 1, Interleave = 2 } + public VertexAttributeCtr() { } public VertexAttributeCtr(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -2757,6 +2932,13 @@ namespace _3DS.NintendoWare.GFX } public class InterleavedVertexStreamCtr : VertexAttributeCtr { + public InterleavedVertexStreamCtr() + : base() + { + Type = 0x40000002; + Usage = VertexAttributeUsage.Interleave; + Flags = VertexAttributeFlags.Interleave; + } public InterleavedVertexStreamCtr(EndianBinaryReader er) : base(er) { @@ -2829,6 +3011,17 @@ namespace _3DS.NintendoWare.GFX public VertexStreamCtr[] VertexStreams; public class VertexStreamCtr : VertexAttributeCtr { + public VertexStreamCtr(VertexAttributeUsage Usage, DataType FormatType, int NrComponents, int Offset, Single Scale = 1) + : base() + { + Type = 0x40000001; + Flags = 0; + this.Usage = Usage; + this.FormatType = FormatType; + this.NrComponents = (uint)NrComponents; + this.Scale = Scale; + this.Offset = (uint)Offset; + } public VertexStreamCtr(EndianBinaryReader er) : base(er) { @@ -3007,6 +3200,17 @@ namespace _3DS.NintendoWare.GFX } public class VertexParamAttributeCtr : VertexAttributeCtr { + public VertexParamAttributeCtr(VertexAttributeUsage Usage, params Single[] Attributes) + : base() + { + Type = 0x80000000; + Flags = VertexAttributeFlags.VertexParam; + this.Usage = Usage; + FormatType = DataType.GL_FLOAT; + Scale = 1; + NrAttributes = (uint)Attributes.Length; + this.Attributes = Attributes; + } public VertexParamAttributeCtr(EndianBinaryReader er) : base(er) { diff --git a/3DS/NintendoWare/GFX/DICT.cs b/3DS/NintendoWare/GFX/DICT.cs index b69f0b0..81bb6c2 100644 --- a/3DS/NintendoWare/GFX/DICT.cs +++ b/3DS/NintendoWare/GFX/DICT.cs @@ -9,6 +9,12 @@ namespace _3DS.NintendoWare.GFX { public class DICT { + public DICT() + { + Signature = "DICT"; + RootNode = new Node(); + Entries = new List(); + } public DICT(EndianBinaryReader er) { Signature = er.ReadString(Encoding.ASCII, 4); diff --git a/3DS/NintendoWare/GFX/TXOB.cs b/3DS/NintendoWare/GFX/TXOB.cs index f74b4c9..2d8ccf3 100644 --- a/3DS/NintendoWare/GFX/TXOB.cs +++ b/3DS/NintendoWare/GFX/TXOB.cs @@ -11,6 +11,12 @@ namespace _3DS.NintendoWare.GFX { public class TXOB { + public TXOB() + { + Signature = "TXOB"; + Revision = 0x5000000; + Name = ""; + } public TXOB(EndianBinaryReader er) { Type = er.ReadUInt32(); @@ -70,6 +76,12 @@ namespace _3DS.NintendoWare.GFX public class ReferenceTexture : TXOB { + public ReferenceTexture(String RefTex) + : base() + { + Type = 0x20000004; + LinkedTextureName = RefTex; + } public ReferenceTexture(EndianBinaryReader er) : base(er) { @@ -97,13 +109,28 @@ namespace _3DS.NintendoWare.GFX public class PixelBasedTexture : TXOB { + protected static readonly uint[] GLFormats = + { + 0x6752, 0x6754, 0x6752, 0x6754, 0x6752, 0x6758, 0x6759, 0x6757, 0x6756, 0x6758, 0x6757, 0x6756, 0x675A, 0x675B + }; + + protected static readonly uint[] GLTypes = + { + 0x1401, 0x1401, 0x8034, 0x8363, 0x8033, 0x1401, 0x1401, 0x1401, 0x1401, 0x6760, 0x6761 , 0x6761 , 0, 0 + }; + + public PixelBasedTexture() + : base() + { + + } public PixelBasedTexture(EndianBinaryReader er) : base(er) { Height = er.ReadUInt32(); Width = er.ReadUInt32(); GLFormat = er.ReadUInt32(); - Type = er.ReadUInt32(); + GLType = er.ReadUInt32(); NrLevels = er.ReadUInt32(); TextureObject = er.ReadUInt32(); LocationFlag = er.ReadUInt32(); @@ -115,7 +142,7 @@ namespace _3DS.NintendoWare.GFX er.Write(Height); er.Write(Width); er.Write(GLFormat); - er.Write(Type); + er.Write(GLType); er.Write(NrLevels); er.Write(TextureObject); er.Write(LocationFlag); @@ -124,7 +151,7 @@ namespace _3DS.NintendoWare.GFX public UInt32 Height; public UInt32 Width; public UInt32 GLFormat; - public UInt32 Type; + public UInt32 GLType; public UInt32 NrLevels;//mipmaps public UInt32 TextureObject; public UInt32 LocationFlag; @@ -133,6 +160,19 @@ namespace _3DS.NintendoWare.GFX public class ImageTextureCtr : PixelBasedTexture { + public ImageTextureCtr(String Name, Bitmap Tex, Textures.ImageFormat Format) + : base() + { + Type = 0x20000011; + this.Name = Name; + Width = (uint)Tex.Width; + Height = (uint)Tex.Height; + HWFormat = Format; + GLFormat = GLFormats[(int)Format]; + GLType = GLTypes[(int)Format]; + NrLevels = 1; + TextureImage = new PixelBasedImageCtr(Tex, Format); + } public ImageTextureCtr(EndianBinaryReader er) : base(er) { @@ -154,6 +194,14 @@ namespace _3DS.NintendoWare.GFX public PixelBasedImageCtr TextureImage; public class PixelBasedImageCtr { + public PixelBasedImageCtr(Bitmap Tex, Textures.ImageFormat Format) + { + Width = (uint)Tex.Width; + Height = (uint)Tex.Height; + BitsPerPixel = (uint)Textures.GetBpp(Format); + Data = Textures.FromBitmap(Tex, Format); + DataSize = (uint)Data.Length; + } public PixelBasedImageCtr(EndianBinaryReader er) { Height = er.ReadUInt32(); diff --git a/3DS/UI/CGFXGenDialog.Designer.cs b/3DS/UI/CGFXGenDialog.Designer.cs new file mode 100644 index 0000000..8c503b6 --- /dev/null +++ b/3DS/UI/CGFXGenDialog.Designer.cs @@ -0,0 +1,89 @@ +namespace _3DS.UI +{ + partial class CGFXGenDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.button1 = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(73, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Model Name: "; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(91, 12); + this.textBox1.Name = "textBox1"; + this.textBox1.Size = new System.Drawing.Size(197, 20); + this.textBox1.TabIndex = 1; + this.textBox1.Text = "EFEModel"; + this.textBox1.TextChanged += new System.EventHandler(this.textBox1_TextChanged); + // + // button1 + // + this.button1.DialogResult = System.Windows.Forms.DialogResult.OK; + this.button1.Location = new System.Drawing.Point(213, 38); + this.button1.Name = "button1"; + this.button1.Size = new System.Drawing.Size(75, 23); + this.button1.TabIndex = 2; + this.button1.Text = "OK"; + this.button1.UseVisualStyleBackColor = true; + // + // CGFXGenDialog + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(300, 66); + this.ControlBox = false; + this.Controls.Add(this.button1); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.label1); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "CGFXGenDialog"; + this.Text = "Generate CGFX"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox textBox1; + private System.Windows.Forms.Button button1; + } +} \ No newline at end of file diff --git a/3DS/UI/CGFXGenDialog.cs b/3DS/UI/CGFXGenDialog.cs new file mode 100644 index 0000000..745a507 --- /dev/null +++ b/3DS/UI/CGFXGenDialog.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Windows.Forms; + +namespace _3DS.UI +{ + public partial class CGFXGenDialog : Form + { + public String ModelName; + public CGFXGenDialog() + { + InitializeComponent(); + ModelName = textBox1.Text; + } + + private void textBox1_TextChanged(object sender, EventArgs e) + { + ModelName = textBox1.Text; + if (textBox1.Text.Length == 0) button1.Enabled = false; + } + } +} diff --git a/3DS/UI/CGFXGenDialog.resx b/3DS/UI/CGFXGenDialog.resx new file mode 100644 index 0000000..1af7de1 --- /dev/null +++ b/3DS/UI/CGFXGenDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/CommonFiles/MTL.cs b/CommonFiles/MTL.cs index 5afa600..267e89b 100644 --- a/CommonFiles/MTL.cs +++ b/CommonFiles/MTL.cs @@ -5,6 +5,7 @@ using System.Text; using LibEveryFileExplorer.Files; using System.Drawing; using System.IO; +using System.Globalization; namespace CommonFiles { @@ -17,6 +18,8 @@ namespace CommonFiles public MTL(byte[] Data) { + var enusculture = new CultureInfo("en-US"); + Materials = new List(); MTLMaterial CurrentMaterial = null; TextReader tr = new StreamReader(new MemoryStream(Data)); String line; @@ -37,39 +40,41 @@ namespace CommonFiles case "Ka": { if (parts.Length < 4) continue; - float r = float.Parse(parts[1]); - float g = float.Parse(parts[2]); - float b = float.Parse(parts[3]); + float r = float.Parse(parts[1], enusculture); + float g = float.Parse(parts[2], enusculture); + float b = float.Parse(parts[3], enusculture); CurrentMaterial.AmbientColor = Color.FromArgb((int)(r * 255f), (int)(g * 255f), (int)(b * 255f)); break; } case "Kd": { if (parts.Length < 4) continue; - float r = float.Parse(parts[1]); - float g = float.Parse(parts[2]); - float b = float.Parse(parts[3]); + float r = float.Parse(parts[1], enusculture); + float g = float.Parse(parts[2], enusculture); + float b = float.Parse(parts[3], enusculture); CurrentMaterial.DiffuseColor = Color.FromArgb((int)(r * 255f), (int)(g * 255f), (int)(b * 255f)); break; } case "Ks": { if (parts.Length < 4) continue; - float r = float.Parse(parts[1]); - float g = float.Parse(parts[2]); - float b = float.Parse(parts[3]); + float r = float.Parse(parts[1], enusculture); + float g = float.Parse(parts[2], enusculture); + float b = float.Parse(parts[3], enusculture); CurrentMaterial.SpecularColor = Color.FromArgb((int)(r * 255f), (int)(g * 255f), (int)(b * 255f)); break; } case "d": if (parts.Length < 2) continue; - CurrentMaterial.Alpha = float.Parse(parts[1]); + CurrentMaterial.Alpha = float.Parse(parts[1], enusculture); break; case "map_Kd": CurrentMaterial.DiffuseMapPath = line.Substring(parts[0].Length + 1).Trim(); break; } } + if(CurrentMaterial != null && !Materials.Contains(CurrentMaterial)) + Materials.Add(CurrentMaterial); tr.Close(); }