public void FillTextureBlock(Texture2D tex, int blockX, int blockY, int relX, int relY, byte[] imageBuffer, int imageBufferOffset, IList<ARGB1555Color> pal, int paletteInd, bool flipX, bool flipY) { var offset1 = imageBufferOffset; var offset2 = imageBufferOffset + 16; for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) { int actualX = blockX + relX * 8 + (flipX ? (8 - x - 1) : x); int actualY = blockY + relY * 8 + (flipY ? (8 - y - 1) : y); int off = y * 8 + (8 - x - 1); var bit0 = BitHelpers.ExtractBits(imageBuffer[offset1 + ((off / 8) * 2)], 1, off % 8); var bit1 = BitHelpers.ExtractBits(imageBuffer[offset1 + ((off / 8) * 2 + 1)], 1, off % 8); var bit2 = BitHelpers.ExtractBits(imageBuffer[offset2 + ((off / 8) * 2)], 1, off % 8); var bit3 = BitHelpers.ExtractBits(imageBuffer[offset2 + ((off / 8) * 2 + 1)], 1, off % 8); int b = 0; b = BitHelpers.SetBits(b, bit0, 1, 0); b = BitHelpers.SetBits(b, bit1, 1, 1); b = BitHelpers.SetBits(b, bit2, 1, 2); b = BitHelpers.SetBits(b, bit3, 1, 3); Color c = pal[paletteInd * 0x10 + b].GetColor(); if (b != 0) c = new Color(c.r, c.g, c.b, 1f); tex.SetPixel(actualX, actualY, c); } } }
private void Insert(HuffmanCode <T> code) { Node currentNode = root; for (int bitIndex = code.Length - 1; bitIndex >= 0; bitIndex--) { int bit = BitHelpers.ExtractBits(code.Code, 1, bitIndex); if (bit == 1) { if (currentNode.Node1 == null) { currentNode.Node1 = new Node(); } currentNode = currentNode.Node1; } else { if (currentNode.Node0 == null) { currentNode.Node0 = new Node(); } currentNode = currentNode.Node0; } } currentNode.Value = code.Value; }
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { Flags = s.Serialize <byte>(Flags, name: nameof(Flags)); if (BitHelpers.ExtractBits(Flags, 1, 7) == 1) { if (BitHelpers.ExtractBits(Flags, 1, 0) == 1) { Note = s.Serialize <byte>(Note, name: nameof(Note)); } if (BitHelpers.ExtractBits(Flags, 1, 1) == 1) { Instrument = s.Serialize <byte>(Instrument, name: nameof(Instrument)); } if (BitHelpers.ExtractBits(Flags, 1, 2) == 1) { VolumeColumnByte = s.Serialize <byte>(VolumeColumnByte, name: nameof(VolumeColumnByte)); } if (BitHelpers.ExtractBits(Flags, 1, 3) == 1) { EffectType = s.Serialize <byte>(EffectType, name: nameof(EffectType)); } if (BitHelpers.ExtractBits(Flags, 1, 4) == 1) { EffectParameter = s.Serialize <byte>(EffectParameter, name: nameof(EffectParameter)); } } else { Note = Flags; Instrument = s.Serialize <byte>(Instrument, name: nameof(Instrument)); VolumeColumnByte = s.Serialize <byte>(VolumeColumnByte, name: nameof(VolumeColumnByte)); EffectType = s.Serialize <byte>(EffectType, name: nameof(EffectType)); EffectParameter = s.Serialize <byte>(EffectParameter, name: nameof(EffectParameter)); } }
public override void SerializeBlock(SerializerObject s) { if (s.GameSettings.GBA_IsMilan && s.GameSettings.EngineVersion != EngineVersion.GBA_TomClancysRainbowSixRogueSpear) { // Copied from function at 0x080087e4 in The Mummy (US) // Serialize header s.DoAt(ShanghaiOffsetTable.GetPointer(0), () => { Milan_Ushort_00 = s.Serialize <ushort>(Milan_Ushort_00, name: nameof(Milan_Ushort_00)); Milan_Ushort_02 = s.Serialize <ushort>(Milan_Ushort_02, name: nameof(Milan_Ushort_02)); }); // Go to palette data s.Goto(ShanghaiOffsetTable.GetPointer(1)); if (Milan_Palettes == null) { Milan_Palettes = new Dictionary <int, RGBA5551Color[]>(); if (Milan_Ushort_00 == 0) { var palIndex = 0; do { if (BitHelpers.ExtractBits(Milan_Ushort_02, 1, palIndex) == 1) { var pal = s.SerializeObjectArray <RGBA5551Color>(default, 0x10, name: $"Palette[{palIndex}]");
public override void SerializeImpl(SerializerObject s) { Byte_00 = s.Serialize <byte>(Byte_00, name: nameof(Byte_00)); Byte_01 = s.Serialize <byte>(Byte_01, name: nameof(Byte_01)); YPosition = s.Serialize <short>(YPosition, name: nameof(YPosition)); XPosition = s.Serialize <short>(XPosition, name: nameof(XPosition)); ImageIndex = s.Serialize <ushort>(ImageIndex, name: nameof(ImageIndex)); IsFlippedHorizontally = BitHelpers.ExtractBits(Byte_00, 1, 6) == 1; IsFlippedVertically = BitHelpers.ExtractBits(Byte_00, 1, 7) == 1; SpriteShape = (Shape)BitHelpers.ExtractBits(Byte_01, 2, 2); SpriteSize = BitHelpers.ExtractBits(Byte_01, 2, 0); // Calculate size XSize = 1; YSize = 1; switch (SpriteShape) { case Shape.Square: XSize = 1 << SpriteSize; YSize = XSize; break; case Shape.Wide: switch (SpriteSize) { case 0: XSize = 2; YSize = 1; break; case 1: XSize = 4; YSize = 1; break; case 2: XSize = 4; YSize = 2; break; case 3: XSize = 8; YSize = 4; break; } break; case Shape.Tall: switch (SpriteSize) { case 0: XSize = 1; YSize = 2; break; case 1: XSize = 1; YSize = 4; break; case 2: XSize = 2; YSize = 4; break; case 3: XSize = 4; YSize = 8; break; } break; } }
public void DecompressBlock_Bits(byte[] compressed, byte[] decompressed, ref int inPos, ref int outPos, ref int toDecompress) { uint commandOffset = (uint)(compressed[inPos] | (compressed[inPos + 1] << 8)); uint endOffset = (uint)(compressed[inPos + 2] | (compressed[inPos + 3] << 8)); inPos += 4; int curCommandOffset = 0; byte curCommand = 0; uint startOffset = (uint)inPos; uint curOffset = 0; int curCommandBit = 0; void GetNewCommandBit(int bytesLeft) { if (curCommandBit == 0) { curCommandBit = 7; if (bytesLeft > 0) { curCommand = compressed[startOffset + commandOffset + curCommandOffset++]; } } else { curCommandBit--; } } GetNewCommandBit(toDecompress); while (toDecompress > 0) { if (BitHelpers.ExtractBits(curCommand, 1, curCommandBit) == 1) { curOffset += 2; } byte bVar1 = compressed[startOffset + curOffset + 1]; if (bVar1 == 0) { decompressed[outPos++] = compressed[startOffset + curOffset]; toDecompress--; curOffset = 0; } else { curOffset += (uint)bVar1 * 2; } GetNewCommandBit(toDecompress); } inPos = compressed.Length; }
void ExportVignette(GBC_PalmOS_Vignette vignette, string outputPath) { if (vignette == null) { throw new Exception("Not a vignette"); } if (vignette.Width > 0x1000 || vignette.Height > 0x1000 || vignette.Width == 0 || vignette.Height == 0) { throw new Exception("Not a vignette"); } int w = (int)vignette.Width; int h = (int)vignette.Height; var palette = vignette.BPP == 8 ? Util.CreateDummyPalette(256, firstTransparent: false) : Util.CreateDummyPalette(16, firstTransparent: false).Reverse().ToArray(); Texture2D tex = TextureHelpers.CreateTexture2D(w, h); for (int y = 0; y < h; y++) { for (int x = 0; x < w; x++) { int ind = y * w + x; if (vignette.BPP == 16) { BaseColor col = vignette.DataPPC[ind]; tex.SetPixel(x, h - 1 - y, col.GetColor()); } else if (vignette.BPP == 8) { int col = vignette.Data[ind]; tex.SetPixel(x, h - 1 - y, palette[col].GetColor()); } else { int col = vignette.Data[ind / 2]; if (ind % 2 == 0) { col = BitHelpers.ExtractBits(col, 4, 4); } else { col = BitHelpers.ExtractBits(col, 4, 0); } tex.SetPixel(x, h - 1 - y, palette[col].GetColor()); } } } tex.Apply(); Util.ByteArrayToFile(outputPath, tex.EncodeToPNG()); }
public void DecompressBlock_Shorts(byte[] compressed, byte[] decompressed, ref int inPos, ref int outPos, ref int toDecompress) { using (Reader reader = new Reader(new MemoryStream(compressed))) { reader.BaseStream.Position = inPos; using (Writer writer = new Writer(new MemoryStream())) { while (toDecompress > 0) { ushort cmd = reader.ReadUInt16(); ushort toWrite = (ushort)BitHelpers.ExtractBits(cmd, 14, 0); bool flag14 = BitHelpers.ExtractBits(cmd, 1, 14) == 1; bool flag15 = BitHelpers.ExtractBits(cmd, 1, 15) == 1; if (!flag15) { if (flag14) { writer.Write(toWrite); toDecompress -= 2; } writer.Write(toWrite); toDecompress -= 2; } else { if (!flag14) { byte count = reader.ReadByte(); for (int i = 0; i < count; i++) { writer.Write(toWrite); } toDecompress -= 2 * count; } else { writer.Write(toWrite); writer.Write(toWrite); writer.Write(toWrite); toDecompress -= 6; } } } writer.BaseStream.Position = 0; byte[] decompressed2 = (writer.BaseStream as MemoryStream).ToArray(); Array.Copy(decompressed2, 0, decompressed, outPos, decompressed2.Length); outPos += decompressed2.Length; } inPos = (int)reader.BaseStream.Position; } }
public override void SerializeBlock(SerializerObject s) { Flags = s.Serialize <byte>(Flags, name: nameof(Flags)); if (!s.GameSettings.GBA_IsMilan) { Byte_01 = s.Serialize <byte>(Byte_01, name: nameof(Byte_01)); AffineMatricesIndex = s.Serialize <byte>((byte)AffineMatricesIndex, name: nameof(AffineMatricesIndex)); Byte_03 = s.Serialize <byte>(Byte_03, name: nameof(Byte_03)); FrameCount = (byte)BitHelpers.ExtractBits(Byte_03, 6, 0); LayersPerFrame = s.SerializeArray <byte>(LayersPerFrame, FrameCount, name: nameof(LayersPerFrame)); s.Align(); if (Layers == null) { Layers = new GBA_AnimationChannel[FrameCount][]; } for (int i = 0; i < FrameCount; i++) { Layers[i] = s.SerializeObjectArray <GBA_AnimationChannel>(Layers[i], LayersPerFrame[i], name: $"{nameof(Layers)}[{i}]"); } } else { FrameCount = s.Serialize <byte>(FrameCount, name: nameof(FrameCount)); Milan_Ushort_02 = s.Serialize <ushort>(Milan_Ushort_02, name: nameof(Milan_Ushort_02)); AffineMatricesIndex = s.Serialize <ushort>(AffineMatricesIndex, name: nameof(AffineMatricesIndex)); Milan_Int_06 = s.Serialize <int>(Milan_Int_06, name: nameof(Milan_Int_06)); var offsetBase = s.CurrentPointer; Milan_LayerOffsets = s.SerializeArray <ushort>(Milan_LayerOffsets, FrameCount + 1, name: nameof(Milan_LayerOffsets)); // +1 since last offset is the end if (Layers == null) { Layers = new GBA_AnimationChannel[FrameCount][]; } for (int i = 0; i < FrameCount; i++) { Layers[i] = s.DoAt(offsetBase + Milan_LayerOffsets[i], () => s.SerializeObjectArray <GBA_AnimationChannel>(Layers[i], (Milan_LayerOffsets[i + 1] - Milan_LayerOffsets[i]) / 6, name: $"{nameof(Layers)}[{i}]")); } s.Goto(offsetBase + Milan_LayerOffsets.LastOrDefault()); } }
public void DecompressBlock_Window(byte[] compressed, byte[] decompressed, ref int inPos, ref int outPos, ref int toDecompress) { while (toDecompress > 0) { byte cmd = compressed[inPos++]; if (BitHelpers.ExtractBits(cmd, 1, 7) == 0) { if (cmd == 0 || 8 < cmd) { //UnityEngine.Debug.Log($"1: td{toDecompress}: ip{inPos}, op{outPos}, cmd{cmd}"); decompressed[outPos++] = cmd; toDecompress--; } else { //UnityEngine.Debug.Log($"2: td{toDecompress}: ip{inPos}, op{outPos}, cmd{cmd}"); for (int i = 0; i < cmd; i++) { decompressed[outPos++] = compressed[inPos++]; } toDecompress -= cmd; } } else { if (cmd < 0xc0) { int bits = (cmd << 8) | compressed[inPos++]; int count = BitHelpers.ExtractBits(bits, 4, 0) + 3; int lookBack = BitHelpers.ExtractBits(bits, 10, 4) + 1; //UnityEngine.Debug.Log($"window lookback: td{toDecompress}: ip{inPos}, op{outPos}, lb{lookBack}, c{count}"); for (int i = 0; i < count; i++) { decompressed[outPos] = decompressed[outPos - lookBack]; outPos++; } toDecompress -= count; } else { //UnityEngine.Debug.Log($"3: td{toDecompress}: ip{inPos}, op{outPos}, cmd{cmd}"); decompressed[outPos++] = 0x20; decompressed[outPos++] = (byte)((cmd & 0x3f) + 0x41); toDecompress -= 2; } } } }
public void DecompressBlock_Buffer(byte[] compressed, byte[] decompressed, ref int inPos, ref int outPos, ref int toDecompress) { while (toDecompress > 0) { int blockSz = Math.Min(0x800, toDecompress); // Fill temp buffer ushort[] buffer = new ushort[0x100]; for (int i = 0; i < buffer.Length; i++) { buffer[i] = (ushort)i; } byte fillBufferCount = compressed[inPos++]; for (int i = 0; i < fillBufferCount; i++) { byte location = compressed[inPos++]; byte msb = compressed[inPos++]; byte lsb = compressed[inPos++]; buffer[location] = (ushort)((msb << 8) | lsb); } int curSz = 0; Stack <byte> puVar6 = new Stack <byte>(); //UnityEngine.Debug.Log($"1: td{toDecompress}: ip{inPos}, op{outPos}"); while (curSz != blockSz) { uint unk = compressed[inPos++]; //UnityEngine.Debug.Log($"2: td{toDecompress}: ip{inPos}, op{outPos}, unk{unk}"); while (true) { while (buffer[unk] != unk) { ushort buf = buffer[unk]; unk = (uint)BitHelpers.ExtractBits(buf, 8, 0); puVar6.Push((byte)BitHelpers.ExtractBits(buf, 8, 8)); } decompressed[outPos++] = (byte)unk; //UnityEngine.Debug.Log($"3: td{toDecompress}: ip{inPos}, op{outPos}, unk{unk}"); curSz++; if (puVar6.Count == 0) { break; } unk = puVar6.Pop(); } } toDecompress -= blockSz; } }
public override void SerializeOffsetData(SerializerObject s) { Palette = s.DoAt(OffsetTable.GetPointer(Index_Palette), () => s.SerializeObject <GBA_SpritePalette>(Palette, name: nameof(Palette))); if (!s.GameSettings.GBA_IsMilan) { TileSet = s.DoAt(OffsetTable.GetPointer(Index_TileSet), () => s.SerializeObject <GBA_SpriteTileSet>(TileSet, onPreSerialize: x => { if (s.GameSettings.EngineVersion == EngineVersion.GBA_Sabrina) { x.IsDataCompressed = BitHelpers.ExtractBits(Byte_04, 1, 5) == 0; } }, name: nameof(TileSet))); } else { Milan_TileKit = s.DoAt(OffsetTable.GetPointer(Index_TileSet), () => s.SerializeObject <GBA_TileKit>(Milan_TileKit, name: nameof(Milan_TileKit))); } if (Animations == null) { Animations = new GBA_Animation[AnimationsCount]; } for (int i = 0; i < Animations.Length; i++) { Animations[i] = s.DoAt(OffsetTable.GetPointer(AnimationIndexTable[i]), () => s.SerializeObject <GBA_Animation>(Animations[i], name: $"{nameof(Animations)}[{i}]")); } for (int i = 0; i < Animations.Length; i++) { if (Animations[i] == null) { continue; } int matrixIndex = Animations[i].AffineMatricesIndex; if (matrixIndex != 0) { Matrices[matrixIndex] = s.DoAt(OffsetTable.GetPointer(matrixIndex), () => s.SerializeObject <GBA_AffineMatrixList>( Matrices.ContainsKey(matrixIndex) ? Matrices[matrixIndex] : null, onPreSerialize: ml => ml.FrameCount = Animations[i].FrameCount, name: $"{nameof(Matrices)}[{matrixIndex}]")); } } }
public void DecompressString(Reader reader, byte[] outBuffer) { byte bits = 0; int curBit = -1; int curHelper = 0; int outPos = 0; while (outPos < outBuffer.Length) { if (curBit < 0) { bits = reader.ReadByte(); curBit += 8; } if (BitHelpers.ExtractBits(bits, 1, curBit) == 0) { if (BitHelpers.ExtractBits(Helpers[curHelper].b0, 1, 0) == 1) { outBuffer[outPos++] = (byte)(Helpers[curHelper].b1); curHelper = 0; } else { curHelper = Helpers[curHelper].b1; } } else { if (BitHelpers.ExtractBits(Helpers[curHelper].b0, 1, 1) == 1) { outBuffer[outPos++] = (byte)(Helpers[curHelper].b2); curHelper = 0; } else { curHelper = Helpers[curHelper].b2; } } curBit--; } }
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { SampleLength = s.Serialize <uint>(SampleLength, name: nameof(SampleLength)); SampleLoopStart = s.Serialize <uint>(SampleLoopStart, name: nameof(SampleLoopStart)); SampleLoopLength = s.Serialize <uint>(SampleLoopLength, name: nameof(SampleLoopLength)); Volume = s.Serialize <byte>(Volume, name: nameof(Volume)); FineTune = s.Serialize <sbyte>(FineTune, name: nameof(FineTune)); Type = s.Serialize <byte>(Type, name: nameof(Type)); Panning = s.Serialize <byte>(Panning, name: nameof(Panning)); RelativeNoteNumber = s.Serialize <sbyte>(RelativeNoteNumber, name: nameof(RelativeNoteNumber)); DataType = s.Serialize <byte>(DataType, name: nameof(DataType)); SampleName = s.SerializeString(SampleName, 22, Encoding.ASCII, name: nameof(SampleName)); if (BitHelpers.ExtractBits(Type, 1, 4) == 1) { SampleData16 = s.SerializeArray <short>(SampleData16, SampleLength / 2, name: nameof(SampleData16)); } else { SampleData8 = s.SerializeArray <sbyte>(SampleData8, SampleLength, name: nameof(SampleData8)); } }
public void DecompressString(byte[] compressed, Writer writer) { byte bits = 0; int curBit = -1; int curHelper = 0; int inPos = 0; while (true) { if (curBit < 0) { if (inPos >= compressed.Length) { break; } bits = compressed[inPos++]; curBit += 8; } if (BitHelpers.ExtractBits(bits, 1, curBit) == 0) { curHelper = Helpers[curHelper].Left; if (Helpers[curHelper].IsLeaf) { writer.Write(Helpers[curHelper].Value); curHelper = 0; } } else { curHelper = Helpers[curHelper].Right; if (Helpers[curHelper].IsLeaf) { writer.Write(Helpers[curHelper].Value); curHelper = 0; } } curBit--; } }
private Stream XORStream(Stream s) { byte compr_incremental_xor = 0x57; var decompressedStream = new MemoryStream(); Reader reader = new Reader(s, isLittleEndian: true); // No using, because we don't want to close the stream byte bytes_in_window = reader.ReadByte(); bytes_in_window ^= 0x53; decompressedStream.WriteByte(bytes_in_window); uint decompressedSize = reader.ReadUInt32(); decompressedSize ^= 0x54555657; decompressedStream.Write(BitConverter.GetBytes(decompressedSize), 0, 4); while (s.Position < s.Length) { byte b = reader.ReadByte(); byte xor = 0; // Bit reverse for (int i = 0; i < 8; i++) { xor = (byte)BitHelpers.SetBits(xor, BitHelpers.ExtractBits(compr_incremental_xor, 1, i), 1, 7 - i); } b = (byte)(b ^ (xor ^ 0xB9)); if (compr_incremental_xor == 0xFF) { compr_incremental_xor = 0x0; } else { compr_incremental_xor++; } decompressedStream.WriteByte(b); } decompressedStream.Position = 0; return(decompressedStream); }
/// <summary> /// Gets the sprite texture for an event /// </summary> /// <param name="context">The context</param> /// <param name="imgBuffer">The image buffer, if available</param> /// <param name="s">The image descriptor to use</param> /// <returns>The texture</returns> public override Texture2D GetSpriteTexture(Context context, byte[] imgBuffer, R1_ImageDescriptor img) { if (img.ImageType != 2 && img.ImageType != 3) { return(null); } if (img.Unknown2 == 0) { return(null); } ImageBuffer buf = context.GetStoredObject <ImageBuffer>("vram"); // Get the image properties var width = img.Width; var height = img.Height; var offset = img.ImageBufferOffset; Texture2D tex = TextureHelpers.CreateTexture2D(width, height); var palette = FileFactory.Read <R1_PS1_Executable>(ExeFilePath, context).Saturn_Palettes; var paletteOffset = img.PaletteInfo; var isBigRay = img.Offset.file.filePath == GetBigRayFilePath(); var isFont = context.GetStoredObject <R1_PS1_FontData[]>("Font")?.SelectMany(x => x.ImageDescriptors).Contains(img) == true; //paletteOffset = (ushort)(256 * (img.Unknown2 >> 4)); if (img.ImageType == 3) { //paletteOffset = 20 * 256; paletteOffset = isBigRay ? (ushort)(21 * 256) : isFont ? (ushort)(19 * 256) : (ushort)((GetPaletteIndex(context) * 256)); } else { paletteOffset = isBigRay ? (ushort)(21 * 256) : isFont ? (ushort)(19 * 256) : (ushort)((GetPaletteIndex(context) * 256) + ((img.PaletteInfo >> 8)) * 16); //paletteOffset = (ushort)((GetPaletteIndex(context) * 256) + ((img.Unknown2 >> 4) - 1) * 16); //paletteOffset = (ushort)(19 * 256 + ((img.Unknown2 >> 4) - 1) * 16); } // Set every pixel if (img.ImageType == 3) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var paletteIndex = buf.GetPixel8((uint)(offset + width * y + x)); // Set the pixel var color = palette[paletteOffset + paletteIndex].GetColor(); if (paletteIndex == 0) { color = new Color(color.r, color.g, color.b, 0f); } else { color = new Color(color.r, color.g, color.b, 1f); } tex.SetPixel(x, height - 1 - y, color); } } } else if (img.ImageType == 2) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var paletteIndex = buf.GetPixel8((uint)(offset + (width * y + x) / 2)); if (x % 2 == 0) { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 4); } else { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 0); } // Set the pixel var color = palette[paletteOffset + paletteIndex].GetColor(); if (paletteIndex == 0) { color = new Color(color.r, color.g, color.b, 0f); } else { color = new Color(color.r, color.g, color.b, 1f); } tex.SetPixel(x, height - 1 - y, color); } } } //tex.SetPixels(Enumerable.Repeat(Color.blue, tex.width * tex.height).ToArray()); tex.Apply(); return(tex); }
/// <summary> /// Gets the sprite texture for an event /// </summary> /// <param name="context">The context</param> /// <param name="imgBuffer">The image buffer, if available</param> /// <param name="s">The image descriptor to use</param> /// <returns>The texture</returns> public override Texture2D GetSpriteTexture(Context context, byte[] imgBuffer, R1_ImageDescriptor s) { if (s.ImageType != 2 && s.ImageType != 3) { return(null); } // Ignore dummy sprites if (s.IsDummySprite()) { return(null); } // Get the image properties var width = s.Width; var height = s.Height; var offset = s.ImageBufferOffset; var pal4 = FileFactory.Read <ObjectArray <RGBA5551Color> >(GetPalettePath(context.Settings, 4), context, (y, x) => x.Length = 256); var pal8 = FileFactory.Read <ObjectArray <RGBA5551Color> >(GetPalettePath(context.Settings, 8), context, (y, x) => x.Length = 256); // Select correct palette var palette = s.ImageType == 3 ? pal8.Value : pal4.Value; var paletteOffset = 16 * s.Unknown1; // Create the texture Texture2D tex = TextureHelpers.CreateTexture2D(width, height); // Set every pixel if (s.ImageType == 3) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { var paletteIndex = imgBuffer[offset + width * y + x]; // Set the pixel tex.SetPixel(x, height - 1 - y, palette[paletteIndex].GetColor()); } } } else if (s.ImageType == 2) { for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { int actualX = (s.ImageOffsetInPageX + x) / 2; var paletteIndex = imgBuffer[offset + (width * y + x) / 2]; if (x % 2 == 0) { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 0); } else { paletteIndex = (byte)BitHelpers.ExtractBits(paletteIndex, 4, 4); } // Set the pixel tex.SetPixel(x, height - 1 - y, palette[paletteOffset + paletteIndex].GetColor()); } } } // Apply the changes tex.Apply(); // Return the texture return(tex); }
public override void SerializeImpl(SerializerObject s) { Attr0 = s.Serialize <ushort>(Attr0, name: nameof(Attr0)); if (IsEndAttribute) { return; } // Parse Attr1 = s.Serialize <ushort>(Attr1, name: nameof(Attr1)); Attr2 = s.Serialize <ushort>(Attr2, name: nameof(Attr2)); // Attr0 YPosition = (short)BitHelpers.ExtractBits(Attr0, 8, 0); if (YPosition >= 128) { YPosition -= 256; } TransformMode = (AffineObjectMode)BitHelpers.ExtractBits(Attr0, 2, 8); RenderMode = (GfxMode)BitHelpers.ExtractBits(Attr0, 2, 10); Mosaic = BitHelpers.ExtractBits(Attr0, 1, 12) == 1; Color = (GBA_ColorMode)BitHelpers.ExtractBits(Attr0, 1, 13); SpriteShape = (Shape)BitHelpers.ExtractBits(Attr0, 2, 14); // Attr1 XPosition = (short)BitHelpers.ExtractBits(Attr1, 9, 0); bool bit9 = false, bit10 = false, bit11 = false; //if (XPosition >= 256) XPosition -= 512; if (XPosition >= 128) { XPosition -= 256; } if (TransformMode == AffineObjectMode.Affine || TransformMode == AffineObjectMode.AffineDouble) { AffineMatrixIndex = BitHelpers.ExtractBits(Attr1, 5, 9); } else { bit9 = BitHelpers.ExtractBits(Attr1, 1, 9) == 1; bit10 = BitHelpers.ExtractBits(Attr1, 1, 10) == 1; bit11 = BitHelpers.ExtractBits(Attr1, 1, 11) == 1; IsFlippedHorizontally = BitHelpers.ExtractBits(Attr1, 1, 12) == 1; IsFlippedVertically = BitHelpers.ExtractBits(Attr1, 1, 13) == 1; } SpriteSize = BitHelpers.ExtractBits(Attr1, 2, 14); ImageIndex = (short)BitHelpers.ExtractBits(Attr2, 10, 0); Priority = BitHelpers.ExtractBits(Attr2, 2, 10); PaletteIndex = BitHelpers.ExtractBits(Attr2, 4, 12); s.Log($"{nameof(XPosition)}: {XPosition}"); s.Log($"{nameof(YPosition)}: {YPosition}"); s.Log($"{nameof(TransformMode)}: {TransformMode}"); s.Log($"{nameof(RenderMode)}: {RenderMode}"); s.Log($"{nameof(Color)}: {Color}"); s.Log($"{nameof(Mosaic)}: {Mosaic}"); s.Log($"{nameof(SpriteShape)}: {SpriteShape}"); s.Log($"{nameof(SpriteSize)}: {SpriteSize}"); s.Log($"{nameof(ImageIndex)}: {ImageIndex}"); s.Log($"{nameof(Priority)}: {Priority}"); s.Log($"{nameof(PaletteIndex)}: {PaletteIndex}"); if (TransformMode == AffineObjectMode.Affine || TransformMode == AffineObjectMode.AffineDouble) { s.Log($"{nameof(AffineMatrixIndex)}: {AffineMatrixIndex}"); } else { s.Log($"{nameof(IsFlippedHorizontally)}: {IsFlippedHorizontally}"); s.Log($"{nameof(IsFlippedVertically)}: {IsFlippedVertically}"); } if (bit9) { s.Log("BIT9"); } if (bit10) { s.Log("BIT10"); } if (bit11) { s.Log("BIT11"); } // Calculate size XSize = 1; YSize = 1; switch (SpriteShape) { case Shape.Square: XSize = 1 << SpriteSize; YSize = XSize; break; case Shape.Wide: switch (SpriteSize) { case 0: XSize = 2; YSize = 1; break; case 1: XSize = 4; YSize = 1; break; case 2: XSize = 4; YSize = 2; break; case 3: XSize = 8; YSize = 4; break; } break; case Shape.Tall: switch (SpriteSize) { case 0: XSize = 1; YSize = 2; break; case 1: XSize = 1; YSize = 4; break; case 2: XSize = 2; YSize = 4; break; case 3: XSize = 4; YSize = 8; break; } break; } }
public override void SerializeImpl(SerializerObject s) { TrackLength = s.Serialize <ushort>(TrackLength, name: nameof(TrackLength)); TrackBlocks = s.SerializeObjectArray <TrackBlock>(TrackBlocks, TrackLength, name: nameof(TrackBlocks)); Structs12Count = s.Serialize <byte>(Structs12Count, name: nameof(Structs12Count)); BM_Byte0 = s.Serialize <byte>(BM_Byte0, name: nameof(BM_Byte0)); BM_Bool1 = s.Serialize <bool>(BM_Bool1, name: nameof(BM_Bool1)); BM_Byte2 = s.Serialize <byte>(BM_Byte2, name: nameof(BM_Byte2)); BM_Byte3 = s.Serialize <byte>(BM_Byte3, name: nameof(BM_Byte3)); MapSpriteMapping = s.SerializeObjectArray <TrackMapping>(MapSpriteMapping, TrackLength - 1, name: nameof(MapSpriteMapping)); if (s.GameSettings.GameModeSelection == GameModeSelection.RaymanKartMobile_320x240) { RoadTextureID_0 = s.Serialize <byte>(RoadTextureID_0, name: nameof(RoadTextureID_0)); RoadTextureID_1 = s.Serialize <byte>(RoadTextureID_1, name: nameof(RoadTextureID_1)); } aW = s.Serialize <byte>(aW, name: nameof(aW)); aUCount = s.Serialize <byte>(aUCount, name: nameof(aUCount)); bB = s.Serialize <byte>(bB, name: nameof(bB)); Color_bC = s.SerializeObject <RGB888Color>(Color_bC, name: nameof(Color_bC)); Color_bD_Road1 = s.SerializeObject <RGB888Color>(Color_bD_Road1, name: nameof(Color_bD_Road1)); Color_bA = s.SerializeObject <RGB888Color>(Color_bA, name: nameof(Color_bA)); Color_bE_Road2 = s.SerializeObject <RGB888Color>(Color_bE_Road2, name: nameof(Color_bE_Road2)); Color_bF = s.SerializeObject <RGB888Color>(Color_bF, name: nameof(Color_bF)); bG = s.Serialize <short>(bG, name: nameof(bG)); aU_2 = s.Serialize <short>(aU_2, name: nameof(aU_2)); N = s.Serialize <byte>(N, name: nameof(N)); gF = s.Serialize <byte>(gF, name: nameof(gF)); bp = s.Serialize <bool>(bp, name: nameof(bp)); bJ = s.Serialize <short>(bJ, name: nameof(bJ)); bK = s.Serialize <short>(bK, name: nameof(bK)); Color_afterbK_0 = s.SerializeObject <RGB888Color>(Color_afterbK_0, name: nameof(Color_afterbK_0)); Color_afterbK_1 = s.SerializeObject <RGB888Color>(Color_afterbK_1, name: nameof(Color_afterbK_1)); bL = s.Serialize <byte>(bL, name: nameof(bL)); Color_bH_TunnelDark = s.SerializeObject <RGB888Color>(Color_bH_TunnelDark, name: nameof(Color_bH_TunnelDark)); Color_bI_TunnelLight = s.SerializeObject <RGB888Color>(Color_bI_TunnelLight, name: nameof(Color_bI_TunnelLight)); byte_afterBI = s.Serialize <byte>(byte_afterBI, name: nameof(byte_afterBI)); if (BitHelpers.ExtractBits(aW, 1, 2) == 1) { Color_dj_BridgeDark = s.SerializeObject <RGB888Color>(Color_dj_BridgeDark, name: nameof(Color_dj_BridgeDark)); Color_dk_BridgeLight = s.SerializeObject <RGB888Color>(Color_dk_BridgeLight, name: nameof(Color_dk_BridgeLight)); dl = s.Serialize <byte>(dl, name: nameof(dl)); dm = s.Serialize <byte>(dm, name: nameof(dm)); } if (s.GameSettings.GameModeSelection != GameModeSelection.RaymanKartMobile_320x240) { Color_dq = s.SerializeObject <RGB888Color>(Color_dq, name: nameof(Color_dq)); Color_dr = s.SerializeObject <RGB888Color>(Color_dr, name: nameof(Color_dr)); Color_ds = s.SerializeObject <RGB888Color>(Color_ds, name: nameof(Color_ds)); Color_dt = s.SerializeObject <RGB888Color>(Color_dt, name: nameof(Color_dt)); Color_du = s.SerializeObject <RGB888Color>(Color_du, name: nameof(Color_du)); dx = s.Serialize <short>(dx, name: nameof(dx)); dw = s.Serialize <short>(dw, name: nameof(dw)); dv = s.Serialize <short>(dv, name: nameof(dv)); } Structs1Count = s.Serialize <ushort>(Structs1Count, name: nameof(Structs1Count)); Structs1 = s.SerializeObjectArray <Struct1>(Structs1, Structs1Count, name: nameof(Structs1)); Structs2Count = s.Serialize <byte>(Structs2Count, name: nameof(Structs2Count)); Structs2 = s.SerializeObjectArray <Struct2>(Structs2, Structs2Count, name: nameof(Structs2)); BackgroundLayers = s.SerializeObjectArray <BackgroundLayer>(BackgroundLayers, aUCount, name: nameof(BackgroundLayers)); bs_Struct0_BackgroundIndex = s.SerializeArraySize <byte[], byte>(bs_Struct0_BackgroundIndex, name: nameof(bs_Struct0_BackgroundIndex)); for (int i = 0; i < bs_Struct0_BackgroundIndex.Length; i++) { bs_Struct0_BackgroundIndex[i] = s.SerializeArray <byte>(bs_Struct0_BackgroundIndex[i], TrackLength, name: $"{nameof(bs_Struct0_BackgroundIndex)}[{i}]"); } Structs4Count = s.Serialize <byte>(Structs4Count, name: nameof(Structs4Count)); Structs4 = s.SerializeObjectArray <Struct4>(Structs4, Structs4Count, name: nameof(Structs4)); Structs5Count = s.Serialize <byte>(Structs5Count, name: nameof(Structs5Count)); Structs5 = s.SerializeObjectArray <Struct5>(Structs5, Structs5Count, name: nameof(Structs5)); Structs6Count = s.Serialize <ushort>(Structs6Count, name: nameof(Structs6Count)); Structs6 = s.SerializeObjectArray <Struct6>(Structs6, Structs6Count, name: nameof(Structs6)); Structs7Count = s.Serialize <ushort>(Structs7Count, name: nameof(Structs7Count)); Structs7 = s.SerializeObjectArray <Struct7>(Structs7, Structs7Count, name: nameof(Structs7)); TrackObjectsCount = s.Serialize <ushort>(TrackObjectsCount, name: nameof(TrackObjectsCount)); TrackObjects = s.SerializeObjectArray <TrackObject>(TrackObjects, TrackObjectsCount, name: nameof(TrackObjects)); cF = s.Serialize <ushort>(cF, name: nameof(cF)); TrackObjectInstances = s.SerializeObjectArray <TrackObjectInstance>(TrackObjectInstances, cF, name: nameof(TrackObjectInstances)); if (cF > 0) { TrackObjectCollections = s.SerializeObjectArray <TrackObjectCollection>(TrackObjectCollections, TrackLength, name: nameof(TrackObjectCollections)); } Structs11Count = s.Serialize <byte>(Structs11Count, name: nameof(Structs11Count)); Types = s.SerializeObjectArray <Type>(Types, Structs11Count, name: nameof(Types)); Structs12 = s.SerializeObjectArray <Struct12>(Structs12, Structs12Count, name: nameof(Structs12)); }
public override void SerializeImpl(SerializerObject s) { Attr0 = s.Serialize <ushort>(Attr0, name: nameof(Attr0)); // Parse if ((Attr0 & BOX_FLAG) == 0x800) { ChannelType = Type.Unknown8; } if ((Attr0 & BOX_FLAG) == 0xC00) { ChannelType = Type.UnknownC; } if ((Attr0 & BOX_FLAG) == 0x1000) { ChannelType = Type.AttackBox; } if ((Attr0 & BOX_FLAG) == 0x1400) { ChannelType = Type.VulnerabilityBox; } if (ChannelType == Type.Sprite) { Attr1 = s.Serialize <ushort>(Attr1, name: nameof(Attr1)); Attr2 = s.Serialize <ushort>(Attr2, name: nameof(Attr2)); if (Attr0 == 0 && Attr1 == 0 && Attr2 == 0) { ChannelType = Type.Null; return; } // Attr0 YPosition = (short)BitHelpers.ExtractBits(Attr0, 8, 0); /*if (s.GameSettings.Game == Game.GBA_Rayman3) { * if (YPosition >= 96) YPosition -= 256; // Hack. Since usually more of the top sprite is visible, this is more likely. * } else { * if (YPosition >= 128) YPosition -= 256; * }*/ if (YPosition >= 128) { YPosition -= 256; } TransformMode = (AffineObjectMode)BitHelpers.ExtractBits(Attr0, 2, 8); RenderMode = (GfxMode)BitHelpers.ExtractBits(Attr0, 2, 10); //Controller.print(BitHelpers.ExtractBits(Attr0, 2, 10)); Color = (GBA_ColorMode)BitHelpers.ExtractBits(Attr0, 1, 13); SpriteShape = (Shape)BitHelpers.ExtractBits(Attr0, 2, 14); // Attr1 XPosition = (short)BitHelpers.ExtractBits(Attr1, 9, 0); bool bit9 = false, bit10 = false, bit11 = false; if (XPosition >= 256) { XPosition -= 512; } if (TransformMode == AffineObjectMode.Affine || TransformMode == AffineObjectMode.AffineDouble) { AffineMatrixIndex = BitHelpers.ExtractBits(Attr1, 5, 9); } else { bit9 = BitHelpers.ExtractBits(Attr1, 1, 9) == 1; bit10 = BitHelpers.ExtractBits(Attr1, 1, 10) == 1; bit11 = BitHelpers.ExtractBits(Attr1, 1, 11) == 1; IsFlippedHorizontally = BitHelpers.ExtractBits(Attr1, 1, 12) == 1; IsFlippedVertically = BitHelpers.ExtractBits(Attr1, 1, 13) == 1; } SpriteSize = BitHelpers.ExtractBits(Attr1, 2, 14); if (s.GameSettings.EngineVersion == EngineVersion.GBA_Sabrina) { ImageIndex = (ushort)BitHelpers.ExtractBits(Attr2, 12, 0); PaletteIndex = BitHelpers.ExtractBits(Attr2, 3, 12); // another flag at byte 0xF? } else if (s.GameSettings.EngineVersion == EngineVersion.GBA_BatmanRiseOfSinTzu) { ImageIndex = (ushort)BitHelpers.ExtractBits(Attr2, 15, 0); PaletteIndex = BitHelpers.ExtractBits(Attr2, 1, 15); // another flag at byte 0xF? } else if (s.GameSettings.EngineVersion == EngineVersion.GBA_StarWarsTrilogy) { ImageIndex = (ushort)BitHelpers.ExtractBits(Attr2, 14, 0); PaletteIndex = BitHelpers.ExtractBits(Attr2, 1, 14); // another flag at byte 0xF? } else if (s.GameSettings.EngineVersion >= EngineVersion.GBA_SplinterCell) { ImageIndex = (ushort)BitHelpers.ExtractBits(Attr2, 14, 0); PaletteIndex = BitHelpers.ExtractBits(Attr2, 2, 14); // another flag at byte 0xF? } else if (s.GameSettings.GBA_IsMilan) { ImageIndex = Attr2; } else { ImageIndex = (ushort)BitHelpers.ExtractBits(Attr2, 11, 0); Priority = BitHelpers.ExtractBits(Attr2, 1, 11); PaletteIndex = BitHelpers.ExtractBits(Attr2, 3, 12); // another flag at byte 0xF? } bool paletteFlag = BitHelpers.ExtractBits(Attr2, 1, 15) == 1; s.Log($"{nameof(XPosition)}: {XPosition}"); s.Log($"{nameof(YPosition)}: {YPosition}"); s.Log($"{nameof(TransformMode)}: {TransformMode}"); s.Log($"{nameof(RenderMode)}: {RenderMode}"); s.Log($"{nameof(Color)}: {Color}"); s.Log($"{nameof(SpriteShape)}: {SpriteShape}"); s.Log($"{nameof(SpriteSize)}: {SpriteSize}"); s.Log($"{nameof(ImageIndex)}: {ImageIndex}"); s.Log($"{nameof(Priority)}: {Priority}"); s.Log($"{nameof(PaletteIndex)}: {PaletteIndex}"); s.Log($"{nameof(paletteFlag)}: {paletteFlag}"); if (TransformMode == AffineObjectMode.Affine || TransformMode == AffineObjectMode.AffineDouble) { s.Log($"{nameof(AffineMatrixIndex)}: {AffineMatrixIndex}"); } else { s.Log($"{nameof(IsFlippedHorizontally)}: {IsFlippedHorizontally}"); s.Log($"{nameof(IsFlippedVertically)}: {IsFlippedVertically}"); } if (bit9) { s.Log("BIT9"); } if (bit10) { s.Log("BIT10"); } if (bit11) { s.Log("BIT11"); } // Calculate size XSize = 1; YSize = 1; switch (SpriteShape) { case Shape.Square: XSize = 1 << SpriteSize; YSize = XSize; break; case Shape.Wide: switch (SpriteSize) { case 0: XSize = 2; YSize = 1; break; case 1: XSize = 4; YSize = 1; break; case 2: XSize = 4; YSize = 2; break; case 3: XSize = 8; YSize = 4; break; } break; case Shape.Tall: switch (SpriteSize) { case 0: XSize = 1; YSize = 2; break; case 1: XSize = 1; YSize = 4; break; case 2: XSize = 2; YSize = 4; break; case 3: XSize = 4; YSize = 8; break; } break; } } else if (ChannelType == Type.Unknown8) { Unknown8 = s.Serialize <int>(Unknown8, name: nameof(Unknown8)); } else if (ChannelType == Type.UnknownC) { UnknownC = s.Serialize <int>(UnknownC, name: nameof(UnknownC)); } else { s.Log($"{nameof(ChannelType)}: {ChannelType}"); Box_MinY = s.Serialize <sbyte>(Box_MinY, name: nameof(Box_MinY)); Box_MaxY = s.Serialize <sbyte>(Box_MaxY, name: nameof(Box_MaxY)); Box_MinX = s.Serialize <sbyte>(Box_MinX, name: nameof(Box_MinX)); Box_MaxX = s.Serialize <sbyte>(Box_MaxX, name: nameof(Box_MaxX)); } }
public override void SerializeBlock(SerializerObject s) { if (s.GameSettings.EngineVersion == EngineVersion.GBA_BatmanVengeance) { if (StructType != Type.Collision) { Unk_02 = s.Serialize <byte>(Unk_02, name: nameof(Unk_02)); Unk_03 = s.Serialize <byte>(Unk_03, name: nameof(Unk_03)); LayerID = s.Serialize <byte>(LayerID, name: nameof(LayerID)); ClusterIndex = s.Serialize <byte>(ClusterIndex, name: nameof(ClusterIndex)); // TODO: figure out what this is. One of these UnkBytes = s.SerializeArray <byte>(UnkBytes, 5, name: nameof(UnkBytes)); ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending)); Unk_0E = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E)); ColorMode = s.Serialize <GBA_ColorMode>(ColorMode, name: nameof(ColorMode)); } } else if (s.GameSettings.GBA_IsMilan) { ColorMode = GBA_ColorMode.Color4bpp; // Serialize cluster Cluster = s.DoAt(ShanghaiOffsetTable.GetPointer(0), () => s.SerializeObject <GBA_Cluster>(Cluster, name: nameof(Cluster))); IStreamEncoder encoder = null; switch (Cluster.Milan_MapCompressionType) { case GBA_Cluster.Milan_CompressionType.Collision_RL: case GBA_Cluster.Milan_CompressionType.Map_RL: encoder = new GBA_RLEEncoder(); break; case GBA_Cluster.Milan_CompressionType.Collsiion_LZSS: case GBA_Cluster.Milan_CompressionType.Map_LZSS: encoder = new GBA_LZSSEncoder(); break; } // Go to the map data s.Goto(ShanghaiOffsetTable.GetPointer(2)); if (StructType == Type.Layer2D) { s.DoEncodedIf(encoder, encoder != null, () => Shanghai_MapIndices_16 = s.SerializeArray <ushort>(Shanghai_MapIndices_16, ((Width + Width % 2) * (Height + Height % 2)) / 4, name: nameof(Shanghai_MapIndices_16))); var end = s.CurrentPointer; // Go to the map tiles s.Goto(ShanghaiOffsetTable.GetPointer(1)); s.DoEncodedIf(encoder, encoder != null, () => Shanghai_MapTiles = s.SerializeObjectArray <MapTile>(Shanghai_MapTiles, (Shanghai_MapIndices_16.Max(x => BitHelpers.ExtractBits(x, 12, 0)) + 1) * 4, name: nameof(Shanghai_MapTiles))); s.Goto(end); } else // Collision { s.DoEncodedIf(encoder, encoder != null, () => SerializeTileMap(s)); } s.Align(); // Return to avoid serializing the map tile array normally return; } else if (s.GameSettings.GBA_IsShanghai) { ColorMode = GBA_ColorMode.Color4bpp; IsCompressed = false; if (StructType == Type.Layer2D) { // Serialize cluster Cluster = s.DoAt(ShanghaiOffsetTable.GetPointer(0), () => s.SerializeObject <GBA_Cluster>(Cluster, name: nameof(Cluster))); // Go to the map data s.Goto(ShanghaiOffsetTable.GetPointer(2)); // If the map tile size is not 0 the map is split into a 32x8 index array and 8x8 map tiles if (Cluster.Shanghai_MapTileSize != 0) { var indexArrayLength = Mathf.CeilToInt(Width / 4f) * Height; // The tile size is either 1 or 2 bytes if (Cluster.Shanghai_MapTileSize == 1) { Shanghai_MapIndices_8 = s.SerializeArray <byte>(Shanghai_MapIndices_8, indexArrayLength, name: nameof(Shanghai_MapIndices_8)); } else { Shanghai_MapIndices_16 = s.SerializeArray <ushort>(Shanghai_MapIndices_16, indexArrayLength, name: nameof(Shanghai_MapIndices_16)); } var indexArray = Cluster.Shanghai_MapTileSize == 1 ? Shanghai_MapIndices_8.Select(x => (ushort)x).ToArray() : Shanghai_MapIndices_16; Shanghai_MapTiles = s.SerializeObjectArray <MapTile>(Shanghai_MapTiles, (indexArray.Max() + 1) * 4, name: nameof(Shanghai_MapTiles)); // Return to avoid serializing the map tile array normally return; } } else { // Go to the collision data s.Goto(ShanghaiOffsetTable.GetPointer(0)); // Serialize header properties Shanghai_CollisionValue1 = s.Serialize <ushort>(Shanghai_CollisionValue1, name: nameof(Shanghai_CollisionValue1)); Width = s.Serialize <ushort>(Width, name: nameof(Width)); Height = s.Serialize <ushort>(Height, name: nameof(Height)); Shanghai_CollisionValue2 = s.Serialize <ushort>(Shanghai_CollisionValue2, name: nameof(Shanghai_CollisionValue2)); } } else { StructType = s.Serialize <Type>(StructType, name: nameof(StructType)); if (StructType != Type.TextLayerMode7) { IsCompressed = s.Serialize <bool>(IsCompressed, name: nameof(IsCompressed)); } else { Unk_01 = s.Serialize <bool>(Unk_01, name: nameof(Unk_01)); } Unk_02 = s.Serialize <byte>(Unk_02, name: nameof(Unk_02)); Unk_03 = s.Serialize <byte>(Unk_03, name: nameof(Unk_03)); Width = s.Serialize <ushort>(Width, name: nameof(Width)); Height = s.Serialize <ushort>(Height, name: nameof(Height)); switch (StructType) { case Type.TextLayerMode7: LayerID = s.Serialize <byte>(LayerID, name: nameof(LayerID)); ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending)); AlphaBlending_Coeff = s.Serialize <sbyte>(AlphaBlending_Coeff, name: nameof(AlphaBlending_Coeff)); UnkBytes = s.SerializeArray <byte>(UnkBytes, 0x14, name: nameof(UnkBytes)); ColorMode = s.Serialize <GBA_ColorMode>(ColorMode, name: nameof(ColorMode)); // 21 bytes // Prio is 0x1D // ColorMode is 0x1F // Width & height seems duplicates again (is it actually width and height?) break; case Type.RotscaleLayerMode7: LayerID = s.Serialize <byte>(LayerID, name: nameof(LayerID)); ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending)); AlphaBlending_Coeff = s.Serialize <sbyte>(AlphaBlending_Coeff, name: nameof(AlphaBlending_Coeff)); // The game hard-codes the color mode ColorMode = GBA_ColorMode.Color8bpp; Unk_0C = s.Serialize <byte>(Unk_0C, name: nameof(Unk_0C)); Unk_0D = s.Serialize <byte>(Unk_0D, name: nameof(Unk_0D)); Unk_0E = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E)); Unk_0F = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F)); Mode7_10 = s.Serialize <byte>(Mode7_10, name: nameof(Mode7_10)); Mode7_11 = s.Serialize <byte>(Mode7_11, name: nameof(Mode7_11)); Mode7_12 = s.Serialize <byte>(Mode7_12, name: nameof(Mode7_12)); Mode7_13 = s.Serialize <byte>(Mode7_13, name: nameof(Mode7_13)); Mode7_14 = s.Serialize <byte>(Mode7_14, name: nameof(Mode7_14)); break; case Type.SplinterCellZoom: if (LayerID < 2) { Unk_0C = s.Serialize <byte>(Unk_0C, name: nameof(Unk_0C)); Unk_0D = s.Serialize <byte>(Unk_0D, name: nameof(Unk_0D)); Unk_0E = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E)); Unk_0F = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F)); if (s.GameSettings.EngineVersion == EngineVersion.GBA_SplinterCell_NGage) { ColorMode = GBA_ColorMode.Color8bpp; } else { ColorMode = GBA_ColorMode.Color4bpp; } } else { ColorMode = GBA_ColorMode.Color8bpp; } UsesTileKitDirectly = true; break; case Type.PoP: Unk_0C = s.Serialize <byte>(Unk_0C, name: nameof(Unk_0C)); Unk_0D = s.Serialize <byte>(Unk_0D, name: nameof(Unk_0D)); Unk_0E = s.Serialize <byte>(Unk_0E, name: nameof(Unk_0E)); Unk_0F = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F)); ColorMode = GBA_ColorMode.Color8bpp; break; case Type.Layer2D: LayerID = s.Serialize <byte>(LayerID, name: nameof(LayerID)); ClusterIndex = s.Serialize <byte>(ClusterIndex, name: nameof(ClusterIndex)); ShouldSetBGAlphaBlending = s.Serialize <bool>(ShouldSetBGAlphaBlending, name: nameof(ShouldSetBGAlphaBlending)); AlphaBlending_Coeff = s.Serialize <sbyte>(AlphaBlending_Coeff, name: nameof(AlphaBlending_Coeff)); UsesTileKitDirectly = s.Serialize <bool>(UsesTileKitDirectly, name: nameof(UsesTileKitDirectly)); ColorMode = s.Serialize <GBA_ColorMode>(ColorMode, name: nameof(ColorMode)); TileKitIndex = s.Serialize <byte>(TileKitIndex, name: nameof(TileKitIndex)); Unk_0F = s.Serialize <byte>(Unk_0F, name: nameof(Unk_0F)); break; } } if (StructType != Type.TextLayerMode7) { if (!IsCompressed) { SerializeTileMap(s); } else if (s.GameSettings.EngineVersion >= EngineVersion.GBA_PrinceOfPersia && StructType != Type.PoP) { s.DoEncoded(new GBA_Huffman4Encoder(), () => s.DoEncoded(new GBA_LZSSEncoder(), () => SerializeTileMap(s))); } else { s.DoEncoded(new GBA_LZSSEncoder(), () => SerializeTileMap(s)); } s.Align(); } }
public byte[] ReadBlock(Reader reader, int decompressedBlockSize) { reader.Align(4); bool log = false; //bool log = true; string logOffset = $"{reader.BaseStream.Position:X8}"; ushort head = reader.ReadUInt16(); byte unk0 = reader.ReadByte(); byte unk1 = reader.ReadByte(); int compressedSize = reader.ReadInt32(); byte cmd = (byte)BitHelpers.ExtractBits(head, 7, 0); int byte2UpperNibble = BitHelpers.ExtractBits(head, 4, 12); int byte2LowerNibble = BitHelpers.ExtractBits(head, 4, 8); uint local_2c = 0; if (byte2UpperNibble > 4) { throw new NotImplementedException(); } if (byte2UpperNibble == 5) { local_2c = reader.ReadUInt32(); compressedSize -= 4; } byte[] compressed = reader.ReadBytes(compressedSize); int inPos = 0; int outPos = 0; int toDecompress = decompressedBlockSize; byte[] decompressed = new byte[decompressedBlockSize]; if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_compressed.bin", compressed); } try { switch (cmd) { case 0: // Uncompressed DecompressBlock_Copy(compressed, decompressed, ref inPos, ref outPos, ref toDecompress); break; case 1: // RLE DecompressBlock_RLE(compressed, decompressed, ref inPos, ref outPos, ref toDecompress); break; case 2: // Shorts DecompressBlock_Shorts(compressed, decompressed, ref inPos, ref outPos, ref toDecompress); break; case 3: // Bits DecompressBlock_Bits(compressed, decompressed, ref inPos, ref outPos, ref toDecompress); break; case 4: // Window DecompressBlock_Window(compressed, decompressed, ref inPos, ref outPos, ref toDecompress); break; case 5: // Block DecompressBlock_Buffer(compressed, decompressed, ref inPos, ref outPos, ref toDecompress); break; } if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_after_1.bin", decompressed); } switch (byte2LowerNibble) { case 1: DecodeBlock_Sum_Byte(decompressed, 0, decompressed.Length); break; case 2: DecodeBlock_Sum_Short(decompressed, 0, decompressed.Length); break; case 3: DecodeBlock_Copy(decompressed, 0, decompressed.Length); break; case 4: DecodeBlock_Buffer(decompressed, 0, decompressed.Length); break; } if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_after_2.bin", decompressed); } switch (byte2UpperNibble) { case 1: DecodeBlock_Sum_Byte(decompressed, 0, decompressed.Length); break; case 2: DecodeBlock_Sum_Short(decompressed, 0, decompressed.Length); break; case 3: DecodeBlock_Copy(decompressed, 0, decompressed.Length); break; case 4: DecodeBlock_Buffer(decompressed, 0, decompressed.Length); break; case 5: case 6: case 7: throw new NotImplementedException(); //break; } if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_after_3.bin", decompressed); } } catch (Exception ex) { if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_crashedBlock.bin", decompressed); } throw new Exception($"{cmd}:{byte2LowerNibble}:{byte2UpperNibble} - {ex.Message}", ex); } return(decompressed); }
private byte[] ReadBlock(Reader reader, int decompressedBlockSize, ushort step) { reader.Align(4); bool log = false; //bool log = true; string logOffset = $"{reader.BaseStream.Position:X8}"; ushort head = reader.ReadUInt16(); byte unk0 = reader.ReadByte(); byte unk1 = reader.ReadByte(); int compressedSize = 0; if (Mode == EncoderMode.Full) { compressedSize = reader.ReadInt32(); } else if (Mode == EncoderMode.TileData) { compressedSize = TileCompressedSize; } byte cmd = (byte)BitHelpers.ExtractBits(head, 7, 0); int byte2UpperNibble = BitHelpers.ExtractBits(head, 4, 12); int byte2LowerNibble = BitHelpers.ExtractBits(head, 4, 8); uint startBufferIndex = 0; /*if (byte2UpperNibble > 4) { * throw new NotImplementedException(); * }*/ if (byte2UpperNibble == 5) { startBufferIndex = reader.ReadUInt32(); compressedSize -= 4; } byte[] compressed = reader.ReadBytes(compressedSize); int inPos = 0; int outPos = 0; int toDecompress = decompressedBlockSize; byte[] decompressed = new byte[decompressedBlockSize]; byte[] tempBuffer = byte2UpperNibble > 4 ? GetTempBuffer(decompressed.Length) : null; byte[] targetBuffer = tempBuffer ?? decompressed; if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_compressed.bin", compressed); } try { switch (cmd) { case 0: // Uncompressed DecompressBlock_Copy(compressed, targetBuffer, ref inPos, ref outPos, ref toDecompress); break; case 1: // RLE DecompressBlock_RLE(compressed, targetBuffer, ref inPos, ref outPos, ref toDecompress); break; case 2: // Shorts DecompressBlock_Shorts(compressed, targetBuffer, ref inPos, ref outPos, ref toDecompress); break; case 3: // Bits DecompressBlock_Bits(compressed, targetBuffer, ref inPos, ref outPos, ref toDecompress); break; case 4: // Window DecompressBlock_Window(compressed, targetBuffer, ref inPos, ref outPos, ref toDecompress); break; case 5: // Block DecompressBlock_Buffer(compressed, targetBuffer, ref inPos, ref outPos, ref toDecompress); break; } if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_after_1.bin", targetBuffer); } switch (byte2LowerNibble) { case 1: DecodeBlock_Sum_Byte(targetBuffer, 0, targetBuffer.Length); break; case 2: DecodeBlock_Sum_Short(targetBuffer, 0, targetBuffer.Length); break; case 3: DecodeBlock_Copy(targetBuffer, 0, targetBuffer.Length); break; case 4: DecodeBlock_Buffer(targetBuffer, 0, targetBuffer.Length); break; } if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_after_2.bin", targetBuffer); } switch (byte2UpperNibble) { case 1: DecodeBlock_Sum_Byte(decompressed, 0, decompressed.Length); break; case 2: DecodeBlock_Sum_Short(decompressed, 0, decompressed.Length); break; case 3: DecodeBlock_Copy(decompressed, 0, decompressed.Length); break; case 4: DecodeBlock_Buffer(decompressed, 0, decompressed.Length); break; case 5: ushort[] tempShortBuffer = GetTempShortBuffer(decompressed.Length); DecodeBlock_TempBuffer_Short(decompressed, 0, decompressed.Length, startBufferIndex, tempBuffer, tempShortBuffer); SaveTempShortBuffer(tempShortBuffer); break; case 6: DecodeBlock_TempBuffer_Step(decompressed, 0, decompressed.Length, tempBuffer, step); break; case 7: DecodeBlock_TempBuffer_StepShort(decompressed, 0, decompressed.Length, tempBuffer, step); break; } SaveTempBuffer(tempBuffer); if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_after_3.bin", decompressed); } } catch (Exception ex) { if (log) { Util.ByteArrayToFile(LevelEditorData.MainContext.BasePath + $"blocks/{logOffset}_{cmd}-{byte2LowerNibble}-{byte2UpperNibble}_crashedBlock.bin", decompressed); } throw new Exception($"{cmd}:{byte2LowerNibble}:{byte2UpperNibble} - {ex.Message}", ex); } return(decompressed); }
private Track CreateTrack(R1Jaguar_MusicDescriptor jagFile) { Track t = new Track(); TempoChangeBuilder b = new TempoChangeBuilder(); b.Tempo = 22000; b.Build(); t.Insert(0, b.Result); ChannelMessageBuilder builder = new ChannelMessageBuilder(); Dictionary <int, int> curNoteOnChannel = new Dictionary <int, int>(); int timeScale = 1; for (int i = 0; i < jagFile.MusicData.Length; i++) { R1Jaguar_MusicData e = jagFile.MusicData[i]; if (e.Time != int.MaxValue) { int channelByte = BitHelpers.ExtractBits(e.Command, 8, 24); if (channelByte == 0x7F) // special point in the song { int idByte = BitHelpers.ExtractBits(e.Command, 8, 0); if (idByte == 0xFF && i >= jagFile.MusicData.Length - 2) // End point { t.EndOfTrackOffset = e.Time / timeScale; break; } else { // Loop point, or command to return to loop point } } else { int channel = BitHelpers.ExtractBits(e.Command, 4, 26); int command = BitHelpers.ExtractBits(e.Command, 1, 31); if (command == 1) { // Note off if (curNoteOnChannel.ContainsKey(channel)) { builder.Command = ChannelCommand.NoteOff; int note = curNoteOnChannel.TryGetValue(channel, out int val) ? val : 0; if (note >= 128) { builder.MidiChannel = 9; builder.Data1 = note - 128; } else { builder.MidiChannel = channel; builder.Data1 = note; } builder.Data2 = 127; builder.Build(); t.Insert(e.Time / timeScale, builder.Result); } // Program change int instrument = BitHelpers.ExtractBits(e.Command, 5, 21); if (PercussionInstruments[instrument] != Percussion.None) { builder.MidiChannel = 9; } else { builder.MidiChannel = channel; builder.Command = ChannelCommand.ProgramChange; builder.Data1 = GeneralMidiInstruments[instrument] == Instrument.None ? 0 : (int)GeneralMidiInstruments[instrument]; if (GeneralMidiInstruments[instrument] == Instrument.Sitar) { Controller.print("unknown @ " + jagFile.MusicDataPointer); } builder.Build(); t.Insert(e.Time / timeScale, builder.Result); } // Note on builder.Command = ChannelCommand.NoteOn; int freq = BitHelpers.ExtractBits(e.Command, 13, 8); int vel = BitHelpers.ExtractBits(e.Command, 7, 0); //bool hasVelocity = BitHelpers.ExtractBits(e.Command, 1, 7) == 1; builder.Data1 = GetMidiPitch(freq, 349f); //builder.Data2 = UnityEngine.Mathf.RoundToInt(127f * (vel / 7f)); float velf = ((vel + 1) / 128f); // hack int veli = Mathf.RoundToInt(velf * 127f); /*if (!hasVelocity) { * veli = 127; * }*/ if (PercussionInstruments[instrument] != Percussion.None) { builder.Data1 = (int)PercussionInstruments[instrument]; builder.Data2 = PercussionInstruments[instrument] == Percussion.None ? 0 : veli; curNoteOnChannel[channel] = builder.Data1 + 128; } else { builder.Data2 = GeneralMidiInstruments[instrument] == Instrument.None ? 0 : veli; curNoteOnChannel[channel] = builder.Data1; } builder.Build(); t.Insert(e.Time / timeScale, builder.Result); } else { builder.Command = ChannelCommand.NoteOff; int note = curNoteOnChannel.TryGetValue(channel, out int val) ? val : 0; if (note >= 128) { builder.MidiChannel = 9; builder.Data1 = note - 128; } else { builder.MidiChannel = channel; builder.Data1 = note; } builder.Data2 = 127; curNoteOnChannel.Remove(channel); builder.Build(); t.Insert(e.Time / timeScale, builder.Result); } } } } return(t); }
/// <summary> /// Handles the data serialization /// </summary> /// <param name="s">The serializer object</param> public override void SerializeImpl(SerializerObject s) { if (s.GameSettings.GameModeSelection == GameModeSelection.MapperPC || s.GameSettings.EngineVersion == EngineVersion.R1_GBA || s.GameSettings.EngineVersion == EngineVersion.R1_DSi) { TileMapY = s.Serialize <ushort>(TileMapY, name: nameof(TileMapY)); TileMapX = 0; CollisionType = (byte)s.Serialize <ushort>((ushort)CollisionType, name: nameof(CollisionType)); } else if (s.GameSettings.EngineVersion == EngineVersion.R1_PC || s.GameSettings.EngineVersion == EngineVersion.R1_PC_Kit || s.GameSettings.EngineVersion == EngineVersion.R1_PC_Edu || s.GameSettings.EngineVersion == EngineVersion.R1_PS1_Edu || s.GameSettings.EngineVersion == EngineVersion.R1_PocketPC) { TileMapY = s.Serialize <ushort>(TileMapY, name: nameof(TileMapY)); TileMapX = 0; CollisionType = s.Serialize <byte>(CollisionType, name: nameof(CollisionType)); PC_Unk1 = s.Serialize <byte>(PC_Unk1, name: nameof(PC_Unk1)); PC_TransparencyMode = s.Serialize <R1_PC_MapTileTransparencyMode>(PC_TransparencyMode, name: nameof(PC_TransparencyMode)); PC_Unk2 = s.Serialize <byte>(PC_Unk2, name: nameof(PC_Unk2)); } else if (s.GameSettings.EngineVersion == EngineVersion.R1_PS1_JPDemoVol3 || s.GameSettings.EngineVersion == EngineVersion.R1_PS1_JPDemoVol6) { s.SerializeBitValues <int>(bitFunc => { TileMapX = (ushort)bitFunc(TileMapX, 10, name: nameof(TileMapX)); TileMapY = (ushort)bitFunc(TileMapY, 6, name: nameof(TileMapY)); CollisionType = (byte)bitFunc(CollisionType, 8, name: nameof(CollisionType)); }); } else if (s.GameSettings.EngineVersion == EngineVersion.R1_Saturn) { s.SerializeBitValues <ushort>(bitFunc => { TileMapX = (ushort)bitFunc(TileMapX, 4, name: nameof(TileMapX)); TileMapY = (ushort)bitFunc(TileMapY, 12, name: nameof(TileMapY)); }); CollisionType = s.Serialize <byte>(CollisionType, name: nameof(CollisionType)); s.Serialize <byte>(0, name: "Padding"); } else if (s.GameSettings.MajorEngineVersion == MajorEngineVersion.Rayman1_Jaguar) { s.SerializeBitValues <ushort>(bitFunc => { TileMapY = (ushort)bitFunc(TileMapY, 12, name: nameof(TileMapY)); CollisionType = (byte)bitFunc(CollisionType, 4, name: nameof(CollisionType)); }); TileMapX = 0; } else if (s.GameSettings.MajorEngineVersion == MajorEngineVersion.SNES) { s.SerializeBitValues <ushort>(bitFunc => { TileMapY = (ushort)bitFunc(TileMapY, 10, name: nameof(TileMapY)); HorizontalFlip = bitFunc(HorizontalFlip ? 1 : 0, 1, name: nameof(HorizontalFlip)) == 1; VerticalFlip = bitFunc(VerticalFlip ? 1 : 0, 1, name: nameof(VerticalFlip)) == 1; CollisionType = (byte)bitFunc(CollisionType, 4, name: nameof(CollisionType)); }); TileMapX = 0; } else if (s.GameSettings.MajorEngineVersion == MajorEngineVersion.GBA) { // TODO: Use SerializeBitValues if ((GBATileType == GBA_TileType.BGTile || GBATileType == GBA_TileType.FGTile) && s.GameSettings.EngineVersion != EngineVersion.GBA_SplinterCell_NGage && s.GameSettings.EngineVersion != EngineVersion.GBA_BatmanVengeance) { int numBits = Is8Bpp ? 9 : 10; if (s.GameSettings.EngineVersion <= EngineVersion.GBA_BatmanVengeance) { numBits = 8; }/*else if(s.GameSettings.EngineVersion >= EngineVersion.GBA_StarWarsTrilogy) { * numBits = Is8Bpp ? 9 : 10; * } else if (s.GameSettings.EngineVersion >= EngineVersion.GBA_SplinterCell) { * numBits = 9; * if (GBATileType == GBA_TileType.FGTile) numBits = 10; * }*/ ushort value = 0; value = (ushort)BitHelpers.SetBits(value, TileMapY, numBits, 0); //value = (ushort)BitHelpers.SetBits(value, VerticalFlip ? 1 : 0, 1, numBits); value = (ushort)BitHelpers.SetBits(value, HorizontalFlip ? 1 : 0, 1, numBits); value = (ushort)BitHelpers.SetBits(value, PaletteIndex, 4, 12); value = s.Serialize <ushort>(value, name: nameof(value)); TileMapY = (ushort)BitHelpers.ExtractBits(value, numBits, 0); TileMapX = 0; if (Is8Bpp) { IsFirstBlock = BitHelpers.ExtractBits(value, 1, 9) == 1; } HorizontalFlip = BitHelpers.ExtractBits(value, 1, 10) == 1; VerticalFlip = BitHelpers.ExtractBits(value, 1, 11) == 1; PaletteIndex = (byte)BitHelpers.ExtractBits(value, 4, 12); s.Log($"{nameof(TileMapY)}: {TileMapY}"); s.Log($"{nameof(HorizontalFlip)}: {HorizontalFlip}"); s.Log($"{nameof(IsFirstBlock)}: {IsFirstBlock}"); s.Log($"{nameof(PaletteIndex)}: {PaletteIndex}"); } else if (GBATileType == GBA_TileType.Mode7Tile) { ushort value = 0; value = (ushort)BitHelpers.SetBits(value, TileMapY, 9, 0); //value = (ushort)BitHelpers.SetBits(value, VerticalFlip ? 1 : 0, 1, numBits); value = (ushort)BitHelpers.SetBits(value, HorizontalFlip ? 1 : 0, 1, 9); value = s.Serialize <ushort>(value, name: nameof(value)); TileMapY = (ushort)BitHelpers.ExtractBits(value, 9, 0); TileMapX = 0; IsFirstBlock = BitHelpers.ExtractBits(value, 1, 9) == 1; HorizontalFlip = BitHelpers.ExtractBits(value, 1, 10) == 1; VerticalFlip = BitHelpers.ExtractBits(value, 1, 11) == 1; s.Log($"{nameof(TileMapY)}: {TileMapY}"); s.Log($"{nameof(HorizontalFlip)}: {HorizontalFlip}"); s.Log($"{nameof(IsFirstBlock)}: {IsFirstBlock}"); } else { int numBits = Is8Bpp ? 14 : 11; if (s.GameSettings.EngineVersion <= EngineVersion.GBA_BatmanVengeance) { numBits = 10; } else if (s.GameSettings.EngineVersion == EngineVersion.GBA_SplinterCell_NGage) { numBits = Is8Bpp ? 14 : 12; } else if (s.GameSettings.EngineVersion >= EngineVersion.GBA_SplinterCell) { numBits = Is8Bpp ? 14 : 12; } ushort value = 0; value = (ushort)BitHelpers.SetBits(value, TileMapY, numBits, 0); value = (ushort)BitHelpers.SetBits(value, HorizontalFlip ? 1 : 0, 1, numBits); value = (ushort)BitHelpers.SetBits(value, PaletteIndex, 4, 12); value = s.Serialize <ushort>(value, name: nameof(value)); TileMapY = (ushort)BitHelpers.ExtractBits(value, numBits, 0); if (s.GameSettings.EngineVersion == EngineVersion.GBA_SplinterCell_NGage && Is8Bpp) { TileMapY = (ushort)BitHelpers.ExtractBits(value, numBits - 1, 0); } TileMapX = 0; HorizontalFlip = BitHelpers.ExtractBits(value, 1, numBits) == 1; if (s.GameSettings.EngineVersion == EngineVersion.GBA_BatmanVengeance) { VerticalFlip = BitHelpers.ExtractBits(value, 1, numBits + 1) == 1; } if (!Is8Bpp) { if (s.GameSettings.EngineVersion >= EngineVersion.GBA_SplinterCell) { PaletteIndex = (byte)BitHelpers.ExtractBits(value, 3, 13); } else { PaletteIndex = (byte)BitHelpers.ExtractBits(value, 4, 12); } if (s.GameSettings.EngineVersion == EngineVersion.GBA_SplinterCell) { PaletteIndex += 8; } } else if (s.GameSettings.EngineVersion != EngineVersion.GBA_BatmanVengeance) { VerticalFlip = BitHelpers.ExtractBits(value, 1, numBits + 1) == 1; } s.Log($"{nameof(TileMapY)}: {TileMapY}"); s.Log($"{nameof(HorizontalFlip)}: {HorizontalFlip}"); s.Log($"{nameof(PaletteIndex)}: {PaletteIndex}"); } } else if (s.GameSettings.EngineVersion == EngineVersion.R1_PS1 || s.GameSettings.EngineVersion == EngineVersion.R2_PS1) { s.SerializeBitValues <ushort>(bitFunc => { TileMapX = (ushort)bitFunc(TileMapX, 4, name: nameof(TileMapX)); TileMapY = (ushort)bitFunc(TileMapY, 6, name: nameof(TileMapY)); CollisionType = (byte)bitFunc(CollisionType, 6, name: nameof(CollisionType)); }); } else if (s.GameSettings.EngineVersion == EngineVersion.R1_PS1_JP) { s.SerializeBitValues <ushort>(bitFunc => { TileMapX = (ushort)bitFunc(TileMapX, 9, name: nameof(TileMapX)); CollisionType = (byte)bitFunc(CollisionType, 7, name: nameof(CollisionType)); }); } else if (s.GameSettings.MajorEngineVersion == MajorEngineVersion.GBARRR) { if (GBARRRType == GBARRR_MapBlock.MapType.Collision) { CollisionType = s.Serialize <byte>(CollisionType, name: nameof(CollisionType)); } else if (GBARRRType == GBARRR_MapBlock.MapType.Tiles) { TileMapY = s.Serialize <ushort>(TileMapY, name: nameof(TileMapY)); } else if (GBARRRType == GBARRR_MapBlock.MapType.Foreground) { s.SerializeBitValues <ushort>(bitFunc => { TileMapY = (ushort)bitFunc(TileMapY, 10, name: nameof(TileMapY)); HorizontalFlip = bitFunc(HorizontalFlip ? 1 : 0, 1, name: nameof(HorizontalFlip)) == 1; VerticalFlip = bitFunc(VerticalFlip ? 1 : 0, 1, name: nameof(VerticalFlip)) == 1; PaletteIndex = (byte)bitFunc(PaletteIndex, 4, name: nameof(PaletteIndex)); //Unk = (byte)bitFunc(Unk, 4, name: nameof(Unk)); }); } else if (GBARRRType == GBARRR_MapBlock.MapType.Menu) { s.SerializeBitValues <ushort>(bitFunc => { TileMapY = (ushort)bitFunc(TileMapY, 8, name: nameof(TileMapY)); GBARRR_MenuUnk = (byte)bitFunc(GBARRR_MenuUnk, 2, name: nameof(GBARRR_MenuUnk)); HorizontalFlip = bitFunc(HorizontalFlip ? 1 : 0, 1, name: nameof(HorizontalFlip)) == 1; VerticalFlip = bitFunc(VerticalFlip ? 1 : 0, 1, name: nameof(VerticalFlip)) == 1; PaletteIndex = (byte)bitFunc(PaletteIndex, 4, name: nameof(PaletteIndex)); //Unk = (byte)bitFunc(Unk, 4, name: nameof(Unk)); }); } else if (GBARRRType == GBARRR_MapBlock.MapType.Mode7Tiles) { TileMapY = s.Serialize <byte>((byte)TileMapY, name: nameof(TileMapY)); } } }
public byte[] Convert(ushort imageFormat, int width, int height, int paletteLength) { int inPos = 0; int outPos = 0; byte[] outBuf = new byte[width * height]; while (outPos < outBuf.Length) { switch (imageFormat) { case 0x27F1: if (Data[inPos] >= 128) { int repeatCount = Data[inPos++] - 128; byte color = Data[inPos++]; for (int i = 0; i < repeatCount; i++) { outBuf[outPos++] = color; } } else { outBuf[outPos++] = Data[inPos++]; } break; case 0x1600: // 16 colors if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 4, 4); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 4, 0); } inPos++; break; case 0x400: // 4 colors if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 2, 6); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 2, 4); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 2, 2); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 2, 0); } inPos++; break; case 0x200: // 2 colors if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 7); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 6); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 5); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 4); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 3); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 2); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 1); } if (outPos < outBuf.Length) { outBuf[outPos++] = (byte)BitHelpers.ExtractBits(Data[inPos], 1, 0); } inPos++; break; case 0x5602: System.Array.Copy(Data, outBuf, outBuf.Length); outPos = outBuf.Length; break; case 0x64F0: int numColors = paletteLength - 1; int colorBits = 0; while (numColors != 0) { numColors >>= 1; colorBits++; } while (outPos < outBuf.Length) { byte color = (byte)BitHelpers.ExtractBits(Data[inPos], colorBits, 0); int repeatCount = BitHelpers.ExtractBits(Data[inPos], 8 - colorBits, colorBits); inPos++; for (int i = 0; i < repeatCount + 1; i++) { outBuf[outPos++] = color; } } break; default: outPos = outBuf.Length; break; } } return(outBuf); }
public override Unity_ObjGraphics GetCommonDesign(GBA_ActorGraphicData graphicData) { // Create the design var des = new Unity_ObjGraphics { Sprites = new List <Sprite>(), Animations = new List <Unity_ObjAnimation>(), }; if (graphicData == null) { return(des); } var tileMap = graphicData.SpriteGroup_BatmanVengeance.TileMap; var pal = graphicData.SpriteGroup_BatmanVengeance.Palette.Palette; const int tileWidth = 8; const int tileSize = (tileWidth * tileWidth) / 2; var numPalettes = graphicData.SpriteGroup_BatmanVengeance.Palette.Palette.Length / 16; // Add sprites for each palette for (int palIndex = 0; palIndex < numPalettes; palIndex++) { for (int i = 0; i < tileMap.TileMapLength; i++) { var tex = TextureHelpers.CreateTexture2D(CellSize, CellSize); for (int y = 0; y < tileWidth; y++) { for (int x = 0; x < tileWidth; x++) { int index = (i * tileSize) + ((y * tileWidth + x) / 2); var b = tileMap.TileMap[index]; var v = BitHelpers.ExtractBits(b, 4, x % 2 == 0 ? 0 : 4); Color c = pal[palIndex * 16 + v].GetColor(); if (v != 0) { c = new Color(c.r, c.g, c.b, 1f); } tex.SetPixel(x, (tileWidth - 1 - y), c); } } tex.Apply(); des.Sprites.Add(tex.CreateSprite()); } } Unity_ObjAnimationPart[] GetPartsForLayer(GBA_BatmanVengeance_SpriteGroup s, GBA_BatmanVengeance_Animation a, int frame, GBA_BatmanVengeance_AnimationChannel l) { /*if (l.TransformMode == GBA_AnimationLayer.AffineObjectMode.Hide || l.RenderMode == GBA_AnimationLayer.GfxMode.Window || l.RenderMode == GBA_AnimationLayer.GfxMode.Regular || l.Mosaic) return new Unity_ObjAnimationPart[0]; || if (l.Color == GBA_AnimationLayer.ColorMode.Color8bpp) { || Debug.LogWarning("Animation Layer @ " + l.Offset + " has 8bpp color mode, which is currently not supported."); || return new Unity_ObjAnimationPart[0]; || }*/ Unity_ObjAnimationPart[] parts = new Unity_ObjAnimationPart[l.XSize * l.YSize]; if (l.ImageIndex > graphicData.SpriteGroup_BatmanVengeance.TileMap.TileMapLength) { Controller.print("Image index too high: " + graphicData.Offset + " - " + l.Offset); } if (l.PaletteIndex > graphicData.SpriteGroup_BatmanVengeance.Palette.Palette.Length / 16) { Controller.print("Palette index too high: " + graphicData.Offset + " - " + l.Offset + " - " + l.PaletteIndex + " - " + (graphicData.SpriteGroup_BatmanVengeance.Palette.Palette.Length / 16)); } float rot = 0; // l.GetRotation(a, s, frame); Vector2?scl = null; // l.GetScale(a, s, frame); for (int y = 0; y < l.YSize; y++) { for (int x = 0; x < l.XSize; x++) { parts[y * l.XSize + x] = new Unity_ObjAnimationPart { ImageIndex = tileMap.TileMapLength * l.PaletteIndex + (l.ImageIndex + y * l.XSize + x), IsFlippedHorizontally = l.IsFlippedHorizontally, IsFlippedVertically = l.IsFlippedVertically, XPosition = (l.XPosition + (l.IsFlippedHorizontally ? (l.XSize - 1 - x) : x) * CellSize), YPosition = (l.YPosition + (l.IsFlippedVertically ? (l.YSize - 1 - y) : y) * CellSize), Rotation = rot, Scale = scl, TransformOriginX = (l.XPosition + l.XSize * CellSize / 2f), TransformOriginY = (l.YPosition + l.YSize * CellSize / 2f) }; } } return(parts); } // Add first animation for now foreach (var a in graphicData.SpriteGroup_BatmanVengeance.Animations) { var unityAnim = new Unity_ObjAnimation(); var frames = new List <Unity_ObjAnimationFrame>(); for (int i = 0; i < a.FrameCount; i++) { frames.Add(new Unity_ObjAnimationFrame(a.Frames[i].Layers /*.OrderByDescending(l => l.Priority)*/.SelectMany(l => GetPartsForLayer(graphicData.SpriteGroup_BatmanVengeance, a, i, l)).Reverse().ToArray())); } unityAnim.Frames = frames.ToArray(); unityAnim.AnimSpeed = 1; des.Animations.Add(unityAnim); } return(des); }