void ICustomSerialization.Deserialize(BinaryDeserializer Deserializer) { PICACommandReader Reader = new PICACommandReader(Commands); while (Reader.HasCommand) { PICACommand Cmd = Reader.GetCommand(); uint Param = Cmd.Parameters[0]; switch (Cmd.Register) { case PICARegister.GPUREG_STENCIL_TEST: Test = new PICAStencilTest(Param); break; case PICARegister.GPUREG_STENCIL_OP: Operation = new PICAStencilOperation(Param); break; } } }
void ICustomSerialization.Deserialize(BinaryDeserializer Deserializer) { PICACommandReader Reader = new PICACommandReader(Commands); int Index = 0; while (Reader.HasCommand && Index++ < 5) { PICACommand Cmd = Reader.GetCommand(); uint Param = Cmd.Parameters[0]; switch (Cmd.Register) { case PICARegister.GPUREG_TEXUNIT0_BORDER_COLOR: case PICARegister.GPUREG_TEXUNIT1_BORDER_COLOR: case PICARegister.GPUREG_TEXUNIT2_BORDER_COLOR: BorderColor = new RGBA(Param); break; case PICARegister.GPUREG_TEXUNIT0_PARAM: case PICARegister.GPUREG_TEXUNIT1_PARAM: case PICARegister.GPUREG_TEXUNIT2_PARAM: MagFilter = (PICATextureFilter)((Param >> 1) & 1); MinFilter = (PICATextureFilter)((Param >> 2) & 1); MipFilter = (PICATextureFilter)((Param >> 24) & 1); WrapV = (PICATextureWrap)((Param >> 8) & 3); WrapU = (PICATextureWrap)((Param >> 12) & 3); break; case PICARegister.GPUREG_TEXUNIT0_LOD: case PICARegister.GPUREG_TEXUNIT1_LOD: case PICARegister.GPUREG_TEXUNIT2_LOD: LODBias = (((int)Param << 20) >> 20) / (float)0x100; MinLOD = (byte)((Param >> 24) & 0xf); break; } } }
void ICustomSerialization.Deserialize(BinaryDeserializer Deserializer) { PICACommandReader Reader = new PICACommandReader(Commands); while (Reader.HasCommand) { PICACommand Cmd = Reader.GetCommand(); uint Param = Cmd.Parameters[0]; switch (Cmd.Register) { case PICARegister.GPUREG_COLOR_OPERATION: ColorOperation = new PICAColorOperation(Param); break; case PICARegister.GPUREG_BLEND_FUNC: Function = new PICABlendFunction(Param); break; case PICARegister.GPUREG_LOGIC_OP: LogicalOperation = (PICALogicalOp)(Param & 0xf); break; case PICARegister.GPUREG_BLEND_COLOR: Color = new RGBA(Param); break; } } }
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); }
public static RenderBase.OModel loadModel(Stream data, bool keepOpen = false) { RenderBase.OModel mdl = new RenderBase.OModel(); BinaryReader input = new BinaryReader(data); mdl.name = "model"; long mdlStart = data.Position; data.Seek(0x10, SeekOrigin.Current); ulong mdlMagic = input.ReadUInt64(); //gfmodel string uint mdlLength = input.ReadUInt32(); input.ReadUInt32(); //-1 string[] effectNames = getStrTable(input); string[] textureNames = getStrTable(input); string[] materialNames = getStrTable(input); string[] meshNames = getStrTable(input); input.BaseStream.Seek(0x20, SeekOrigin.Current); //2 float4 (Maybe 2 Quaternions?) mdl.transform = new RenderBase.OMatrix(); mdl.transform.M11 = input.ReadSingle(); mdl.transform.M12 = input.ReadSingle(); mdl.transform.M13 = input.ReadSingle(); mdl.transform.M14 = input.ReadSingle(); mdl.transform.M21 = input.ReadSingle(); mdl.transform.M22 = input.ReadSingle(); mdl.transform.M23 = input.ReadSingle(); mdl.transform.M24 = input.ReadSingle(); mdl.transform.M31 = input.ReadSingle(); mdl.transform.M32 = input.ReadSingle(); mdl.transform.M33 = input.ReadSingle(); mdl.transform.M34 = input.ReadSingle(); mdl.transform.M41 = input.ReadSingle(); mdl.transform.M42 = input.ReadSingle(); mdl.transform.M43 = input.ReadSingle(); mdl.transform.M44 = input.ReadSingle(); uint unkDataLen = input.ReadUInt32(); uint unkDataRelStart = input.ReadUInt32(); input.ReadUInt32(); input.ReadUInt32(); input.BaseStream.Seek(unkDataRelStart + unkDataLen, SeekOrigin.Current); //??? uint bonesCount = input.ReadUInt32(); input.BaseStream.Seek(0xc, SeekOrigin.Current); List <string> boneNames = new List <string>(); for (int b = 0; b < bonesCount; b++) { string boneName = IOUtils.readStringWithLength(input, input.ReadByte()); string parentName = IOUtils.readStringWithLength(input, input.ReadByte()); byte flags = input.ReadByte(); RenderBase.OBone bone = new RenderBase.OBone(); bone.name = boneName; bone.parentId = (short)boneNames.IndexOf(parentName); bone.scale = new RenderBase.OVector3( input.ReadSingle(), input.ReadSingle(), input.ReadSingle()); bone.rotation = new RenderBase.OVector3( input.ReadSingle(), input.ReadSingle(), input.ReadSingle()); bone.translation = new RenderBase.OVector3( input.ReadSingle(), input.ReadSingle(), input.ReadSingle()); bone.absoluteScale = new RenderBase.OVector3(bone.scale); mdl.skeleton.Add(bone); boneNames.Add(boneName); } //Materials List <string> matMeshBinding = new List <string>(); input.BaseStream.Seek(mdlStart + mdlLength + 0x20, SeekOrigin.Begin); for (int m = 0; m < materialNames.Length; m++) { RenderBase.OMaterial mat = new RenderBase.OMaterial(); mat.name = materialNames[m]; ulong matMagic = input.ReadUInt64(); //material string uint matLength = input.ReadUInt32(); input.ReadUInt32(); //-1 long matStart = data.Position; string[] unkNames = new string[4]; for (int n = 0; n < 4; n++) { uint maybeHash = input.ReadUInt32(); byte nameLen = input.ReadByte(); unkNames[n] = IOUtils.readStringWithLength(input, nameLen); } matMeshBinding.Add(unkNames[0]); data.Seek(0xac, SeekOrigin.Current); long textureCoordsStart = data.Position; for (int unit = 0; unit < 3; unit++) { data.Seek(textureCoordsStart + unit * 0x42, SeekOrigin.Begin); uint maybeHash = input.ReadUInt32(); string texName = IOUtils.readStringWithLength(input, input.ReadByte()); if (texName == string.Empty) { break; } switch (unit) { case 0: mat.name0 = texName; break; case 1: mat.name1 = texName; break; case 2: mat.name2 = texName; break; } ushort unitIdx = input.ReadUInt16(); mat.textureCoordinator[unit].scaleU = input.ReadSingle(); mat.textureCoordinator[unit].scaleV = input.ReadSingle(); mat.textureCoordinator[unit].rotate = input.ReadSingle(); mat.textureCoordinator[unit].translateU = input.ReadSingle(); mat.textureCoordinator[unit].translateV = input.ReadSingle(); uint texMapperU = input.ReadUInt32(); uint texMapperV = input.ReadUInt32(); mat.textureMapper[unit].wrapU = (RenderBase.OTextureWrap)(texMapperU & 7); mat.textureMapper[unit].wrapV = (RenderBase.OTextureWrap)(texMapperV & 7); } mdl.material.Add(mat); input.BaseStream.Seek(matStart + matLength, SeekOrigin.Begin); } //Meshes for (int m = 0; m < meshNames.Length; m++) { ulong meshMagic = input.ReadUInt64(); //mesh string uint meshLength = input.ReadUInt32(); input.ReadUInt32(); //-1 long meshStart = data.Position; //Mesh name and other stuff goes here input.BaseStream.Seek(0x80, SeekOrigin.Current); subMeshInfo info = getSubMeshInfo(input); for (int sm = 0; sm < info.count; sm++) { RenderBase.OMesh obj = new RenderBase.OMesh(); obj.isVisible = true; obj.name = info.names[sm]; obj.materialId = (ushort)matMeshBinding.IndexOf(obj.name); ushort[] nodeList = info.nodeLists[sm]; //NOTE: All Addresses on commands are set to 0x99999999 and are probably relocated by game engine PICACommandReader vtxCmdReader = info.cmdBuffers[sm * 3 + 0]; PICACommandReader idxCmdReader = info.cmdBuffers[sm * 3 + 2]; uint vshAttributesBufferStride = vtxCmdReader.getVSHAttributesBufferStride(0); uint vshTotalAttributes = vtxCmdReader.getVSHTotalAttributes(0); PICACommand.vshAttribute[] vshMainAttributesBufferPermutation = vtxCmdReader.getVSHAttributesBufferPermutation(); uint[] vshAttributesBufferPermutation = vtxCmdReader.getVSHAttributesBufferPermutation(0); PICACommand.attributeFormat[] vshAttributesBufferFormat = vtxCmdReader.getVSHAttributesBufferFormat(); for (int attribute = 0; attribute < vshTotalAttributes; attribute++) { switch (vshMainAttributesBufferPermutation[vshAttributesBufferPermutation[attribute]]) { case PICACommand.vshAttribute.normal: obj.hasNormal = true; break; case PICACommand.vshAttribute.tangent: obj.hasTangent = true; break; case PICACommand.vshAttribute.color: obj.hasColor = true; break; case PICACommand.vshAttribute.textureCoordinate0: obj.texUVCount = Math.Max(obj.texUVCount, 1); break; case PICACommand.vshAttribute.textureCoordinate1: obj.texUVCount = Math.Max(obj.texUVCount, 2); break; case PICACommand.vshAttribute.textureCoordinate2: obj.texUVCount = Math.Max(obj.texUVCount, 3); break; } } PICACommand.indexBufferFormat idxBufferFormat = idxCmdReader.getIndexBufferFormat(); uint idxBufferTotalVertices = idxCmdReader.getIndexBufferTotalVertices(); obj.hasNode = true; obj.hasWeight = true; long vtxBufferStart = data.Position; input.BaseStream.Seek(info.vtxLengths[sm], SeekOrigin.Current); long idxBufferStart = data.Position; for (int faceIndex = 0; faceIndex < idxBufferTotalVertices; faceIndex++) { ushort index = 0; switch (idxBufferFormat) { case PICACommand.indexBufferFormat.unsignedShort: index = input.ReadUInt16(); break; case PICACommand.indexBufferFormat.unsignedByte: index = input.ReadByte(); break; } long dataPosition = data.Position; long vertexOffset = vtxBufferStart + (index * vshAttributesBufferStride); data.Seek(vertexOffset, SeekOrigin.Begin); RenderBase.OVertex vertex = new RenderBase.OVertex(); vertex.diffuseColor = 0xffffffff; // Fix weight problems vertex.weight.Add(1); vertex.weight.Add(0); vertex.weight.Add(0); vertex.weight.Add(0); for (int attribute = 0; attribute < vshTotalAttributes; attribute++) { //gdkchan self note: The Attribute type flags are used for something else on Bone Weight (and bone index?) PICACommand.vshAttribute att = vshMainAttributesBufferPermutation[vshAttributesBufferPermutation[attribute]]; PICACommand.attributeFormat format = vshAttributesBufferFormat[vshAttributesBufferPermutation[attribute]]; if (att == PICACommand.vshAttribute.boneWeight) { format.type = PICACommand.attributeFormatType.unsignedByte; } RenderBase.OVector4 vector = getVector(input, format); switch (att) { case PICACommand.vshAttribute.position: vertex.position = new RenderBase.OVector3(vector.x, vector.y, vector.z); break; case PICACommand.vshAttribute.normal: vertex.normal = new RenderBase.OVector3(vector.x, vector.y, vector.z); break; case PICACommand.vshAttribute.tangent: vertex.tangent = new RenderBase.OVector3(vector.x, vector.y, vector.z); break; case PICACommand.vshAttribute.color: uint r = MeshUtils.saturate(vector.x); uint g = MeshUtils.saturate(vector.y); uint b = MeshUtils.saturate(vector.z); uint a = MeshUtils.saturate(vector.w); vertex.diffuseColor = b | (g << 8) | (r << 16) | (a << 24); break; case PICACommand.vshAttribute.textureCoordinate0: vertex.texture0 = new RenderBase.OVector2(vector.x, vector.y); break; case PICACommand.vshAttribute.textureCoordinate1: vertex.texture1 = new RenderBase.OVector2(vector.x, vector.y); break; case PICACommand.vshAttribute.textureCoordinate2: vertex.texture2 = new RenderBase.OVector2(vector.x, vector.y); break; case PICACommand.vshAttribute.boneIndex: addNode(vertex.node, nodeList, (int)vector.x); if (format.attributeLength > 0) { addNode(vertex.node, nodeList, (int)vector.y); } if (format.attributeLength > 1) { addNode(vertex.node, nodeList, (int)vector.z); } if (format.attributeLength > 2) { addNode(vertex.node, nodeList, (int)vector.w); } break; case PICACommand.vshAttribute.boneWeight: vertex.weight[0] = (vector.x / 255f); if (format.attributeLength > 0) { vertex.weight[1] = (vector.y / 255f); } if (format.attributeLength > 1) { vertex.weight[2] = (vector.z / 255f); } if (format.attributeLength > 2) { vertex.weight[3] = (vector.w / 255f); } break; } } //If the node list have 4 or less bones, then there is no need to store the indices per vertex //Instead, the entire list is used, since it supports up to 4 bones. if (vertex.node.Count == 0 && nodeList.Length <= 4) { for (int n = 0; n < nodeList.Length; n++) { vertex.node.Add(nodeList[n]); } if (vertex.weight.Count == 0) { vertex.weight.Add(1); } } MeshUtils.calculateBounds(mdl, vertex); obj.vertices.Add(vertex); data.Seek(dataPosition, SeekOrigin.Begin); } input.BaseStream.Seek(idxBufferStart + info.idxLengths[sm], SeekOrigin.Begin); mdl.mesh.Add(obj); } input.BaseStream.Seek(meshStart + meshLength, SeekOrigin.Begin); } if (!keepOpen) { data.Close(); } return(mdl); }
private bool open(string fileName) { using (FileStream data = new FileStream(fileName, FileMode.Open)) { BinaryReader input = new BinaryReader(data); if (peek(input) == 0x00010000) { currentFile = fileName; bch = new loadedBCH(); bch.isBCH = false; bch.mips.Add(new MIPlayer()); packPNK(data, input, bch); } if (peek(input) == 0x15041213) { currentFile = fileName; bch = new loadedBCH(); bch.isBCH = false; bch.mips.Add(new MIPlayer()); bch.mips[0].textures.Add(loadPKM(data, input)); } string magic2b = getMagic(input, 2); if (magic2b == "PC" || magic2b == "CM") { bch = new loadedBCH(); bch.isBCH = false; currentFile = fileName; data.Seek(2, SeekOrigin.Current); ushort numEntrys = input.ReadUInt16(); for (int i = 0; i < (int)numEntrys; i++) { data.Seek(4 + (i * 4), SeekOrigin.Begin); uint offset = input.ReadUInt32(); uint end = input.ReadUInt32(); uint lenth = end - offset; long rtn = data.Position; data.Seek(offset, SeekOrigin.Begin); if (magic2b == "CM" & i == 0) { packPNK(data, input, bch); } if (lenth > 4) { if (magic2b == "PC") { if (peek(input) == 0x15041213) { bch.mips[0].textures.Add(loadPKM(data, input)); } } } } } string magic = IOUtils.readString(input, 0); if (magic == "BCH") { currentFile = fileName; data.Seek(4, SeekOrigin.Current); byte backwardCompatibility = input.ReadByte(); byte forwardCompatibility = input.ReadByte(); ushort version = input.ReadUInt16(); uint mainHeaderOffset = input.ReadUInt32(); uint stringTableOffset = input.ReadUInt32(); uint gpuCommandsOffset = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint dataExtendedOffset = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableOffset = input.ReadUInt32(); uint mainHeaderLength = input.ReadUInt32(); uint stringTableLength = input.ReadUInt32(); uint gpuCommandsLength = input.ReadUInt32(); uint dataLength = input.ReadUInt32(); uint dataExtendedLength = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableLength = input.ReadUInt32(); data.Seek(mainHeaderOffset, SeekOrigin.Begin); uint modelsPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint modelsPointerTableEntries = input.ReadUInt32(); data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin); uint texturesPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint texturesPointerTableEntries = input.ReadUInt32(); bch = new loadedBCH(); bch.isBCH = true; for (int i = 0; i < 6; i++) { bch.mips.Add(new MIPlayer()); } MipSelect.Enabled = true; //Textures for (int index = 0; index < texturesPointerTableEntries; index++) { data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; tex.gpuCommandsWordCount = input.ReadUInt32(); data.Seek(0x14, SeekOrigin.Current); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset + stringTableOffset); data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin); PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount); tex.offset = textureCommands.getTexUnit0Address() + dataOffset; RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format(); Size textureSize = textureCommands.getTexUnit0Size(); tex.type = fmt; int OGW = textureSize.Width; int OGH = textureSize.Height; for (int i = 0; i < 6; i++) { textureSize.Width = OGW / Convert.ToInt32(Math.Pow(2, i)); textureSize.Height = OGH / Convert.ToInt32(Math.Pow(2, i)); tex.length = returnSize(fmt, textureSize.Width, textureSize.Height); if (textureSize.Height >= 8 & textureSize.Width >= 8) { data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[tex.length]; //data.Seek(tex.length + returnSize(fmt, textureSize.Width / 2, textureSize.Height / 2), SeekOrigin.Current); tex.offset = (uint)data.Position; input.Read(buffer, 0, tex.length); Bitmap texture = TextureCodec.decode( buffer, textureSize.Width, textureSize.Height, fmt); tex.texture = new RenderBase.OTexture(texture, textureName); bch.mips[i].textures.Add(tex); tex.offset = (uint)data.Position; } } } bch.mainHeaderOffset = mainHeaderOffset; bch.gpuCommandsOffset = gpuCommandsOffset; bch.dataOffset = dataOffset; bch.relocationTableOffset = relocationTableOffset; bch.relocationTableLength = relocationTableLength; } else if (magic == "CTPK\u0001") { currentFile = fileName; data.Seek(4, SeekOrigin.Current); ushort ver = input.ReadUInt16(); ushort numTexture = input.ReadUInt16(); uint TextureSectionOffset = input.ReadUInt32(); uint TextureSectionSize = input.ReadUInt32(); uint HashSectionOffset = input.ReadUInt32(); uint TextureInfoSection = input.ReadUInt32(); bch = new loadedBCH(); bch.isBCH = false; bch.mips.Add(new MIPlayer()); for (int i = 0; i < numTexture; i++) { data.Seek(0x20 * (i + 1), SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = (uint)(0x20 * (i + 1)); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset); tex.length = input.ReadInt32(); tex.offset = input.ReadUInt32() + TextureSectionOffset; tex.type = (RenderBase.OTextureFormat)input.ReadUInt32(); ushort Width = input.ReadUInt16(); ushort Height = input.ReadUInt16(); data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[tex.length]; input.Read(buffer, 0, buffer.Length); Bitmap texture = TextureCodec.decode( buffer, Width, Height, tex.type); tex.texture = new RenderBase.OTexture(texture, textureName); tex.gpuCommandsWordCount = 0; bch.mips[0].textures.Add(tex); } } } updateTexturesList(); return(true); }
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(); }
private bool open(string fileName) { using (FileStream data = new FileStream(fileName, FileMode.Open)) { BinaryReader input = new BinaryReader(data); string magic = IOUtils.readString(input, 0); if (magic != "BCH") { return(false); } currentFile = fileName; data.Seek(4, SeekOrigin.Current); byte backwardCompatibility = input.ReadByte(); byte forwardCompatibility = input.ReadByte(); ushort version = input.ReadUInt16(); uint mainHeaderOffset = input.ReadUInt32(); uint stringTableOffset = input.ReadUInt32(); uint gpuCommandsOffset = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint dataExtendedOffset = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableOffset = input.ReadUInt32(); uint mainHeaderLength = input.ReadUInt32(); uint stringTableLength = input.ReadUInt32(); uint gpuCommandsLength = input.ReadUInt32(); uint dataLength = input.ReadUInt32(); uint dataExtendedLength = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableLength = input.ReadUInt32(); data.Seek(mainHeaderOffset, SeekOrigin.Begin); uint modelsPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint modelsPointerTableEntries = input.ReadUInt32(); data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin); uint texturesPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint texturesPointerTableEntries = input.ReadUInt32(); bch = new loadedBCH(); //Textures for (int index = 0; index < texturesPointerTableEntries; index++) { data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; tex.gpuCommandsWordCount = input.ReadUInt32(); data.Seek(0x14, SeekOrigin.Current); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset + stringTableOffset); data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin); PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount); tex.offset = textureCommands.getTexUnit0Address() + dataOffset; RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format(); Size textureSize = textureCommands.getTexUnit0Size(); switch (fmt) { case RenderBase.OTextureFormat.rgba8: tex.length = (textureSize.Width * textureSize.Height) * 4; break; case RenderBase.OTextureFormat.rgb8: tex.length = (textureSize.Width * textureSize.Height) * 3; break; case RenderBase.OTextureFormat.rgba5551: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.rgb565: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.rgba4: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.la8: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.hilo8: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.l8: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.a8: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.la4: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.l4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.a4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.etc1: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.etc1a4: tex.length = textureSize.Width * textureSize.Height; break; default: throw new Exception("OBCHTextureReplacer: Invalid texture format on BCH!"); } while ((tex.length & 0x7f) > 0) { tex.length++; } data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[textureSize.Width * textureSize.Height * 4]; input.Read(buffer, 0, buffer.Length); Bitmap texture = TextureCodec.decode( buffer, textureSize.Width, textureSize.Height, fmt); tex.texture = new RenderBase.OTexture(texture, textureName); bch.textures.Add(tex); } //Materials for (int mdlIndex = 0; mdlIndex < modelsPointerTableEntries; mdlIndex++) { data.Seek(modelsPointerTableOffset + (mdlIndex * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); data.Seek(0x34, SeekOrigin.Current); uint materialsTableOffset = input.ReadUInt32() + mainHeaderOffset; uint materialsTableEntries = input.ReadUInt32(); for (int index = 0; index < materialsTableEntries; index++) { if (backwardCompatibility < 0x21) { data.Seek(materialsTableOffset + (index * 0x58), SeekOrigin.Begin); } else { data.Seek(materialsTableOffset + (index * 0x2c), SeekOrigin.Begin); } loadedMaterial mat; data.Seek(0x10, SeekOrigin.Current); mat.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; mat.gpuCommandsWordCount = input.ReadUInt32(); if (backwardCompatibility < 0x21) { data.Seek(0x30, SeekOrigin.Current); } else { data.Seek(4, SeekOrigin.Current); } uint texture0Offset = input.ReadUInt32() + stringTableOffset; uint texture1Offset = input.ReadUInt32() + stringTableOffset; uint texture2Offset = input.ReadUInt32() + stringTableOffset; mat.texture0 = IOUtils.readString(input, texture0Offset); mat.texture1 = IOUtils.readString(input, texture1Offset); mat.texture2 = IOUtils.readString(input, texture2Offset); bch.materials.Add(mat); } } bch.mainHeaderOffset = mainHeaderOffset; bch.gpuCommandsOffset = gpuCommandsOffset; bch.dataOffset = dataOffset; bch.relocationTableOffset = relocationTableOffset; bch.relocationTableLength = relocationTableLength; } updateTexturesList(); return(true); }