예제 #1
0
파일: GFTexture.cs 프로젝트: yorki00/SPICA
        public GFTexture(BinaryReader Reader)
        {
            uint MagicNumber  = Reader.ReadUInt32();
            uint TextureCount = Reader.ReadUInt32();

            GFSection TextureSection = new GFSection(Reader);

            uint TextureLength = Reader.ReadUInt32();

            Reader.BaseStream.Seek(0xc, SeekOrigin.Current); //Padding? Always zero it seems

            Name = Reader.ReadPaddedString(0x40);

            Width      = Reader.ReadUInt16();
            Height     = Reader.ReadUInt16();
            Format     = (GFTextureFormat)Reader.ReadUInt16();
            MipmapSize = Reader.ReadUInt16();

            Reader.BaseStream.Seek(0x10, SeekOrigin.Current); //Padding

            RawBuffer = Reader.ReadBytes((int)TextureLength);
        }
예제 #2
0
파일: GFModel.cs 프로젝트: yorki00/SPICA
        public GFModel(BinaryReader Reader, string ModelName) : this()
        {
            Name = ModelName;

            uint MagicNumber   = Reader.ReadUInt32();
            uint SectionsCount = Reader.ReadUInt32();

            GFSection.SkipPadding(Reader.BaseStream);

            GFSection ModelSection = new GFSection(Reader);

            GFHashName[] ShaderNames   = ReadHashTable(Reader);
            GFHashName[] TextureNames  = ReadHashTable(Reader);
            GFHashName[] MaterialNames = ReadHashTable(Reader);
            GFHashName[] MeshNames     = ReadHashTable(Reader);

            BBoxMinVector = Reader.ReadVector4();
            BBoxMaxVector = Reader.ReadVector4();
            Transform     = Reader.ReadMatrix4x4();

            //TODO: Investigate what is this (maybe Tile permissions?)
            uint  UnknownDataLength = Reader.ReadUInt32();
            uint  UnknownDataOffset = Reader.ReadUInt32();
            ulong Padding           = Reader.ReadUInt64();

            Reader.BaseStream.Seek(UnknownDataOffset + UnknownDataLength, SeekOrigin.Current);

            int BonesCount = Reader.ReadInt32();

            Reader.BaseStream.Seek(0xc, SeekOrigin.Current);

            for (int Index = 0; Index < BonesCount; Index++)
            {
                Skeleton.Add(new GFBone(Reader));
            }

            GFSection.SkipPadding(Reader.BaseStream);

            int LUTsCount = Reader.ReadInt32();
            int LUTLength = Reader.ReadInt32();

            GFSection.SkipPadding(Reader.BaseStream);

            for (int Index = 0; Index < LUTsCount; Index++)
            {
                LUTs.Add(new GFLUT(Reader, LUTLength));
            }

            for (int Index = 0; Index < MaterialNames.Length; Index++)
            {
                Materials.Add(new GFMaterial(Reader));
            }

            for (int Index = 0; Index < MeshNames.Length; Index++)
            {
                Meshes.Add(new GFMesh(Reader));
            }

            foreach (GFLUT LUT in LUTs)
            {
                foreach (GFHashName HN in TextureNames)
                {
                    GFNV1 FNV = new GFNV1();

                    FNV.Hash(HN.Name);

                    if (LUT.HashId == FNV.HashCode)
                    {
                        LUT.Name = HN.Name;

                        break;
                    }
                }
            }
        }
예제 #3
0
파일: GFModel.cs 프로젝트: yorki00/SPICA
        public void Write(BinaryWriter Writer)
        {
            uint SectionsCount = (uint)(Materials.Count + Meshes.Count + 1);

            Writer.Write(MagicNum);
            Writer.Write(SectionsCount);

            GFSection.SkipPadding(Writer.BaseStream);

            long StartPosition = Writer.BaseStream.Position;

            new GFSection(MagicStr).Write(Writer);

            List <string> ShaderNames   = new List <string>();
            List <string> TextureNames  = new List <string>();
            List <string> MaterialNames = new List <string>();
            List <string> MeshNames     = new List <string>();

            foreach (GFMaterial Mat in Materials)
            {
                ShaderNames.Add(Mat.ShaderName);
                TextureNames.Add(Mat.TextureCoords[0].Name);
                TextureNames.Add(Mat.TextureCoords[1].Name);
                TextureNames.Add(Mat.TextureCoords[2].Name);
                TextureNames.Add(GetLUTName(Mat.LUT0HashId));
                TextureNames.Add(GetLUTName(Mat.LUT1HashId));
                TextureNames.Add(GetLUTName(Mat.LUT2HashId));
                MaterialNames.Add(Mat.MaterialName);
            }

            foreach (GFMesh Mesh in Meshes)
            {
                MeshNames.Add(Mesh.Name);
            }

            WriteHashTable(Writer, ShaderNames);
            WriteHashTable(Writer, TextureNames);
            WriteHashTable(Writer, MaterialNames);
            WriteHashTable(Writer, MeshNames);

            Writer.Write(BBoxMinVector);
            Writer.Write(BBoxMaxVector);
            Writer.Write(Transform);

            //TODO: Figure out what is this.
            Writer.Write(0);
            Writer.Write(0x10);
            Writer.Write(0ul);
            Writer.Write(0ul);
            Writer.Write(0ul);

            Writer.Write((uint)Skeleton.Count);

            Writer.BaseStream.Seek(0xc, SeekOrigin.Current);

            foreach (GFBone Bone in Skeleton)
            {
                Bone.Write(Writer);
            }

            GFSection.SkipPadding(Writer.BaseStream);

            Writer.Write(LUTs.Count);
            Writer.Write(0x420);

            GFSection.SkipPadding(Writer.BaseStream);

            foreach (GFLUT LUT in LUTs)
            {
                LUT.Write(Writer);
            }

            long EndPosition = Writer.BaseStream.Position;

            Writer.BaseStream.Seek(StartPosition + 8, SeekOrigin.Begin);

            Writer.Write((uint)(EndPosition - StartPosition - 0x10));

            Writer.BaseStream.Seek(EndPosition, SeekOrigin.Begin);

            foreach (GFMaterial Mat in Materials)
            {
                Mat.Write(Writer);
            }

            foreach (GFMesh Mesh in Meshes)
            {
                Mesh.Write(Writer);
            }
        }
예제 #4
0
파일: GFMesh.cs 프로젝트: HelloOO7/SPICA
        public GFMesh(BinaryReader Reader) : this()
        {
            GFSection MeshSection = new GFSection(Reader);

            long Position = Reader.BaseStream.Position;

            uint   NameHash = Reader.ReadUInt32();
            string NameStr  = Reader.ReadPaddedString(0x40);

            Name = NameStr;

            Reader.ReadUInt32();

            BBoxMinVector = Reader.ReadVector4(); //Is it right? seems to be 0, 0, 0, 1
            BBoxMaxVector = Reader.ReadVector4(); //Is it right? seems to be 0, 0, 0, 1

            uint SubMeshesCount = Reader.ReadUInt32();

            BoneIndicesPerVertex = Reader.ReadInt32();

            Reader.BaseStream.Seek(0x10, SeekOrigin.Current); //Padding

            List <uint[]> CmdList = new List <uint[]>();

            uint CommandsLength;
            uint CommandIndex;
            uint CommandsCount;
            uint Padding;

            do
            {
                CommandsLength = Reader.ReadUInt32();
                CommandIndex   = Reader.ReadUInt32();
                CommandsCount  = Reader.ReadUInt32();
                Padding        = Reader.ReadUInt32();

                uint[] Commands = new uint[CommandsLength >> 2];

                for (int Index = 0; Index < Commands.Length; Index++)
                {
                    Commands[Index] = Reader.ReadUInt32();
                }

                CmdList.Add(Commands);
            }while (CommandIndex < CommandsCount - 1);

            SubMeshSize[] SMSizes = new SubMeshSize[SubMeshesCount];

            //Add SubMesh with Hash, Name and Bone Indices.
            //The rest is added latter (because the data is split inside the file).
            for (int MeshIndex = 0; MeshIndex < SubMeshesCount; MeshIndex++)
            {
                GFSubMesh SM = new GFSubMesh();

                uint SMNameHash = Reader.ReadUInt32();

                SM.Name             = Reader.ReadIntLengthString();
                SM.BoneIndicesCount = Reader.ReadByte();

                for (int Bone = 0; Bone < 0x1f; Bone++)
                {
                    SM.BoneIndices[Bone] = Reader.ReadByte();
                }

                SMSizes[MeshIndex] = new SubMeshSize()
                {
                    VerticesCount  = Reader.ReadInt32(),
                    IndicesCount   = Reader.ReadInt32(),
                    VerticesLength = Reader.ReadInt32(),
                    IndicesLength  = Reader.ReadInt32()
                };

                SubMeshes.Add(SM);
            }

            for (int MeshIndex = 0; MeshIndex < SubMeshesCount; MeshIndex++)
            {
                GFSubMesh SM = SubMeshes[MeshIndex];

                uint[] EnableCommands  = CmdList[MeshIndex * 3 + 0];
                uint[] DisableCommands = CmdList[MeshIndex * 3 + 1];
                uint[] IndexCommands   = CmdList[MeshIndex * 3 + 2];

                PICACommandReader CmdReader;

                CmdReader = new PICACommandReader(EnableCommands);

                PICAVectorFloat24[] Fixed = new PICAVectorFloat24[12];

                ulong BufferFormats     = 0;
                ulong BufferAttributes  = 0;
                ulong BufferPermutation = 0;
                int   AttributesCount   = 0;
                int   AttributesTotal   = 0;

                int FixedIndex = 0;

                while (CmdReader.HasCommand)
                {
                    PICACommand Cmd = CmdReader.GetCommand();

                    uint Param = Cmd.Parameters[0];

                    switch (Cmd.Register)
                    {
                    case PICARegister.GPUREG_ATTRIBBUFFERS_FORMAT_LOW:  BufferFormats |= (ulong)Param << 0; break;

                    case PICARegister.GPUREG_ATTRIBBUFFERS_FORMAT_HIGH: BufferFormats |= (ulong)Param << 32; break;

                    case PICARegister.GPUREG_ATTRIBBUFFER0_CONFIG1:
                        BufferAttributes |= Param;
                        break;

                    case PICARegister.GPUREG_ATTRIBBUFFER0_CONFIG2:
                        BufferAttributes |= (ulong)(Param & 0xffff) << 32;
                        SM.VertexStride   = (byte)(Param >> 16);
                        AttributesCount   = (int)(Param >> 28);
                        break;

                    case PICARegister.GPUREG_FIXEDATTRIB_INDEX: FixedIndex = (int)Param; break;

                    case PICARegister.GPUREG_FIXEDATTRIB_DATA0: Fixed[FixedIndex].Word0 = Param; break;

                    case PICARegister.GPUREG_FIXEDATTRIB_DATA1: Fixed[FixedIndex].Word1 = Param; break;

                    case PICARegister.GPUREG_FIXEDATTRIB_DATA2: Fixed[FixedIndex].Word2 = Param; break;

                    case PICARegister.GPUREG_VSH_NUM_ATTR: AttributesTotal = (int)(Param + 1); break;

                    case PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_LOW:  BufferPermutation |= (ulong)Param << 0; break;

                    case PICARegister.GPUREG_VSH_ATTRIBUTES_PERMUTATION_HIGH: BufferPermutation |= (ulong)Param << 32; break;
                    }
                }

                for (int Index = 0; Index < AttributesTotal; Index++)
                {
                    if (((BufferFormats >> (48 + Index)) & 1) != 0)
                    {
                        PICAAttributeName Name = (PICAAttributeName)((BufferPermutation >> Index * 4) & 0xf);

                        float Scale =
                            Name == PICAAttributeName.Color ||
                            Name == PICAAttributeName.BoneWeight ? Scales[1] : 1;

                        SM.FixedAttributes.Add(new PICAFixedAttribute()
                        {
                            Name  = Name,
                            Value = Fixed[Index] * Scale
                        });
                    }
                    else
                    {
                        int PermutationIdx = (int)((BufferAttributes >> Index * 4) & 0xf);
                        int AttributeName  = (int)((BufferPermutation >> PermutationIdx * 4) & 0xf);
                        int AttributeFmt   = (int)((BufferFormats >> PermutationIdx * 4) & 0xf);

                        PICAAttribute Attrib = new PICAAttribute()
                        {
                            Name     = (PICAAttributeName)AttributeName,
                            Format   = (PICAAttributeFormat)(AttributeFmt & 3),
                            Elements = (AttributeFmt >> 2) + 1,
                            Scale    = Scales[AttributeFmt & 3]
                        };

                        if (Attrib.Name == PICAAttributeName.BoneIndex)
                        {
                            Attrib.Scale = 1;
                        }

                        SM.Attributes.Add(Attrib);
                    }
                }

                CmdReader = new PICACommandReader(IndexCommands);

                uint BufferAddress = 0;
                uint BufferCount   = 0;

                while (CmdReader.HasCommand)
                {
                    PICACommand Cmd = CmdReader.GetCommand();

                    uint Param = Cmd.Parameters[0];

                    switch (Cmd.Register)
                    {
                    case PICARegister.GPUREG_INDEXBUFFER_CONFIG: BufferAddress = Param; break;

                    case PICARegister.GPUREG_NUMVERTICES:        BufferCount = Param; break;

                    case PICARegister.GPUREG_PRIMITIVE_CONFIG:
                        SM.PrimitiveMode = (PICAPrimitiveMode)(Param >> 8);
                        break;
                    }
                }

                SM.RawBuffer = Reader.ReadBytes(SMSizes[MeshIndex].VerticesLength);

                SM.Indices = new ushort[BufferCount];

                long IndexAddress = Reader.BaseStream.Position;

                for (int Index = 0; Index < BufferCount; Index++)
                {
                    if ((BufferAddress >> 31) != 0)
                    {
                        SM.Indices[Index] = Reader.ReadUInt16();
                    }
                    else
                    {
                        SM.Indices[Index] = Reader.ReadByte();
                    }
                }

                Reader.BaseStream.Seek(IndexAddress + SMSizes[MeshIndex].IndicesLength, SeekOrigin.Begin);
            }

            Reader.BaseStream.Seek(Position + MeshSection.Length, SeekOrigin.Begin);
        }
예제 #5
0
파일: GFShader.cs 프로젝트: yorki00/SPICA
        public GFShader(BinaryReader Reader) : this()
        {
            uint MagicNumber = Reader.ReadUInt32();
            uint ShaderCount = Reader.ReadUInt32();

            GFSection.SkipPadding(Reader.BaseStream);

            GFSection ShaderSection = new GFSection(Reader);

            Name = Reader.ReadPaddedString(0x40);

            uint Hash  = Reader.ReadUInt32();
            uint Count = Reader.ReadUInt32();

            GFSection.SkipPadding(Reader.BaseStream);

            uint CommandsLength = Reader.ReadUInt32();
            uint CommandsCount  = Reader.ReadUInt32();
            uint CommandsHash   = Reader.ReadUInt32();
            uint Padding        = Reader.ReadUInt32();

            string FileName = Reader.ReadPaddedString(0x40);

            uint[] Commands = new uint[CommandsLength >> 2];

            for (int Index = 0; Index < Commands.Length; Index++)
            {
                Commands[Index] = Reader.ReadUInt32();
            }

            uint[] OutMap = new uint[7];

            List <uint>  ShaderExecutable = new List <uint>();
            List <ulong> ShaderSwizzles   = new List <ulong>();

            PICACommandReader CmdReader = new PICACommandReader(Commands);

            while (CmdReader.HasCommand)
            {
                PICACommand Cmd = CmdReader.GetCommand();

                uint Param = Cmd.Parameters[0];

                int Stage = ((int)Cmd.Register >> 3) & 7;

                if (Stage >= 6)
                {
                    Stage -= 2;
                }

                switch (Cmd.Register)
                {
                /* Shader */

                case PICARegister.GPUREG_SH_OUTMAP_O0: OutMap[0] = Param; break;

                case PICARegister.GPUREG_SH_OUTMAP_O1: OutMap[1] = Param; break;

                case PICARegister.GPUREG_SH_OUTMAP_O2: OutMap[2] = Param; break;

                case PICARegister.GPUREG_SH_OUTMAP_O3: OutMap[3] = Param; break;

                case PICARegister.GPUREG_SH_OUTMAP_O4: OutMap[4] = Param; break;

                case PICARegister.GPUREG_SH_OUTMAP_O5: OutMap[5] = Param; break;

                case PICARegister.GPUREG_SH_OUTMAP_O6: OutMap[6] = Param; break;

                /* Fragment Shader */

                case PICARegister.GPUREG_TEXENV0_SOURCE:
                case PICARegister.GPUREG_TEXENV1_SOURCE:
                case PICARegister.GPUREG_TEXENV2_SOURCE:
                case PICARegister.GPUREG_TEXENV3_SOURCE:
                case PICARegister.GPUREG_TEXENV4_SOURCE:
                case PICARegister.GPUREG_TEXENV5_SOURCE:
                    TexEnvStages[Stage].Source = new PICATexEnvSource(Param);
                    break;

                case PICARegister.GPUREG_TEXENV0_OPERAND:
                case PICARegister.GPUREG_TEXENV1_OPERAND:
                case PICARegister.GPUREG_TEXENV2_OPERAND:
                case PICARegister.GPUREG_TEXENV3_OPERAND:
                case PICARegister.GPUREG_TEXENV4_OPERAND:
                case PICARegister.GPUREG_TEXENV5_OPERAND:
                    TexEnvStages[Stage].Operand = new PICATexEnvOperand(Param);
                    break;

                case PICARegister.GPUREG_TEXENV0_COMBINER:
                case PICARegister.GPUREG_TEXENV1_COMBINER:
                case PICARegister.GPUREG_TEXENV2_COMBINER:
                case PICARegister.GPUREG_TEXENV3_COMBINER:
                case PICARegister.GPUREG_TEXENV4_COMBINER:
                case PICARegister.GPUREG_TEXENV5_COMBINER:
                    TexEnvStages[Stage].Combiner = new PICATexEnvCombiner(Param);
                    break;

                case PICARegister.GPUREG_TEXENV0_COLOR:
                case PICARegister.GPUREG_TEXENV1_COLOR:
                case PICARegister.GPUREG_TEXENV2_COLOR:
                case PICARegister.GPUREG_TEXENV3_COLOR:
                case PICARegister.GPUREG_TEXENV4_COLOR:
                case PICARegister.GPUREG_TEXENV5_COLOR:
                    TexEnvStages[Stage].Color = new RGBA(Param);
                    break;

                case PICARegister.GPUREG_TEXENV0_SCALE:
                case PICARegister.GPUREG_TEXENV1_SCALE:
                case PICARegister.GPUREG_TEXENV2_SCALE:
                case PICARegister.GPUREG_TEXENV3_SCALE:
                case PICARegister.GPUREG_TEXENV4_SCALE:
                case PICARegister.GPUREG_TEXENV5_SCALE:
                    TexEnvStages[Stage].Scale = new PICATexEnvScale(Param);
                    break;

                case PICARegister.GPUREG_TEXENV_UPDATE_BUFFER: PICATexEnvStage.SetUpdateBuffer(TexEnvStages, Param); break;

                case PICARegister.GPUREG_TEXENV_BUFFER_COLOR: TexEnvBufferColor = new RGBA(Param); break;

                /* Geometry Shader */

                case PICARegister.GPUREG_GSH_ENTRYPOINT:
                    if (GeoShader == null)
                    {
                        GeoShader = new ShaderProgram();
                    }

                    GeoShader.MainOffset = Param & 0xffff;
                    break;

                /* Vertex Shader */

                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA0:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA1:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA2:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA3:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA4:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA5:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA6:
                case PICARegister.GPUREG_VSH_CODETRANSFER_DATA7:
                    ShaderExecutable.AddRange(Cmd.Parameters);
                    break;

                case PICARegister.GPUREG_VSH_OPDESCS_DATA0:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA1:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA2:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA3:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA4:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA5:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA6:
                case PICARegister.GPUREG_VSH_OPDESCS_DATA7:
                    for (int i = 0; i < Cmd.Parameters.Length; i++)
                    {
                        ShaderSwizzles.Add(Cmd.Parameters[i]);
                    }
                    break;

                case PICARegister.GPUREG_VSH_ENTRYPOINT:
                    if (VtxShader == null)
                    {
                        VtxShader = new ShaderProgram();
                    }

                    VtxShader.MainOffset = Param & 0xffff;
                    break;
                }
            }

            Executable = ShaderExecutable.ToArray();
            Swizzles   = ShaderSwizzles.ToArray();

            for (int i = 0; i < OutMap.Length; i++)
            {
                if (OutMap[i] == 0)
                {
                    continue;
                }

                ShaderOutputReg Reg = new ShaderOutputReg();

                for (int j = 0; j < 4; j++)
                {
                    uint Value = (OutMap[i] >> j * 8) & 0x1f;

                    if (Value != 0x1f)
                    {
                        Reg.Mask |= 1u << j;

                        if (Value < 0x4)
                        {
                            Reg.Name = ShaderOutputRegName.Position;
                        }
                        else if (Value < 0x8)
                        {
                            Reg.Name = ShaderOutputRegName.QuatNormal;
                        }
                        else if (Value < 0xc)
                        {
                            Reg.Name = ShaderOutputRegName.Color;
                        }
                        else if (Value < 0xe)
                        {
                            Reg.Name = ShaderOutputRegName.TexCoord0;
                        }
                        else if (Value < 0x10)
                        {
                            Reg.Name = ShaderOutputRegName.TexCoord1;
                        }
                        else if (Value < 0x11)
                        {
                            Reg.Name = ShaderOutputRegName.TexCoord0W;
                        }
                        else if (Value < 0x12)
                        {
                            Reg.Name = ShaderOutputRegName.Generic;
                        }
                        else if (Value < 0x16)
                        {
                            Reg.Name = ShaderOutputRegName.View;
                        }
                        else if (Value < 0x18)
                        {
                            Reg.Name = ShaderOutputRegName.TexCoord2;
                        }
                        else
                        {
                            Reg.Name = ShaderOutputRegName.Generic;
                        }
                    }
                }

                if (VtxShader != null)
                {
                    VtxShader.OutputRegs[i] = Reg;
                }

                if (GeoShader != null)
                {
                    GeoShader.OutputRegs[i] = Reg;
                }
            }

            HashSet <uint> Dsts = new HashSet <uint>();

            uint LblId = 0;

            for (uint i = 0; i < Executable.Length; i++)
            {
                ShaderOpCode OpCode = (ShaderOpCode)(Executable[i] >> 26);

                if (OpCode == ShaderOpCode.Call ||
                    OpCode == ShaderOpCode.CallC ||
                    OpCode == ShaderOpCode.CallU ||
                    OpCode == ShaderOpCode.JmpC ||
                    OpCode == ShaderOpCode.JmpU)
                {
                    uint Dst = (Executable[i] >> 10) & 0xfff;

                    if (!Dsts.Contains(Dst))
                    {
                        Dsts.Add(Dst);

                        string Name = "label_" + Dst.ToString("x4");

                        ShaderLabel Label = new ShaderLabel()
                        {
                            Id     = LblId++,
                            Offset = Dst,
                            Length = 0,
                            Name   = Name
                        };

                        if (VtxShader != null)
                        {
                            VtxShader.Labels.Add(Label);
                        }

                        if (GeoShader != null)
                        {
                            GeoShader.Labels.Add(Label);
                        }
                    }
                }
            }

            MakeArray(VtxShader?.Vec4Uniforms, "v_c");
            MakeArray(GeoShader?.Vec4Uniforms, "g_c");

            FindProgramEnd(VtxShader, Executable);
            FindProgramEnd(GeoShader, Executable);

            VtxShaderUniforms = CmdReader.GetAllVertexShaderUniforms();
            GeoShaderUniforms = CmdReader.GetAllGeometryShaderUniforms();
        }