/// <summary> /// Creates a new drawgroup sprite instance. /// </summary> /// <param name="type">The type of this sprite.</param> /// <param name="flags">The flags for this sprite.</param> /// <param name="spriteOffset">The offset of this sprite in the drawgroup (specified in pixels).</param> /// <param name="objectOffset">The offset of the object (drawgroup) in the world.</param> /// <param name="frame">The spriteframe for this drawgroup sprite.</param> public DrawGroupSprite(ushort type, uint flags, PixelOffset spriteOffset, WorldOffset objectOffset, SpriteFrame frame) { m_Type = type; m_Flags = flags; m_SpriteOffset = spriteOffset; m_ObjectOffset = objectOffset; m_Sprite = frame; m_Bitmap = (Bitmap)frame.BitmapData.BitMap.Clone(); if ((m_Flags & 0x1) == 0x1) { m_Bitmap.RotateFlip(RotateFlipType.RotateNoneFlipX); } }
/// <summary> /// Reads a frame from this SPR. /// </summary> /// <param name="Index">The index of the frame.</param> /// <returns>A SpriteFrame instance.</returns> private SpriteFrame ReadFrame(int Index) { MemoryStream MemStream = new MemoryStream(m_ChunkData); BinaryReader Reader = new BinaryReader(MemStream); Reader.BaseStream.Position = m_OffsetTable[Index]; SpriteFrame Frame = new SpriteFrame(); if (!m_IsBigEndian) { Reader.ReadBytes(4); //Reserved. Frame.Height = Reader.ReadUInt16(); Frame.Width = Reader.ReadUInt16(); Frame.PaletteID = (ushort)m_PaletteID; } else { Reader.ReadBytes(4); //Reserved. Frame.Height = Endian.SwapUInt16(Reader.ReadUInt16()); Frame.Width = Endian.SwapUInt16(Reader.ReadUInt16()); Frame.PaletteID = (ushort)m_PaletteID; } Frame.Init(true, false); //SPR#s don't have alpha channels, but alpha is used to plot transparent pixels. DecompressFrame2(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. //Store the frame to avoid having to decompress in the future. m_Frames.Add(Frame); return(Frame); }
public SPR2Parser(IffChunk Chunk, List<PaletteMap> PMaps) : base(Chunk) { m_Name = Name; int[] offsets; MemoryStream MemStream = new MemoryStream(Chunk.Data); BinaryReader Reader = new BinaryReader(MemStream); m_Version = Reader.ReadUInt32(); //In version 1001, all frames are decompressed from the beginning, and there's no point in storing //the compressed data AS WELL as the decompressed frames...! if (m_Version == 1000) m_ChunkData = Chunk.Data; if (m_Version == 1001) { m_PaletteID = Reader.ReadUInt32(); m_FrameCount = Reader.ReadUInt32(); } else { m_FrameCount = Reader.ReadUInt32(); m_PaletteID = Reader.ReadUInt32(); } if (PMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PMaps[0]; } else m_PMap = PMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return true; } return false; }); //Some SPR2s blatantly specify the wrong ID because there's only one palettemap... if (m_PMap == null) { m_PMap = PMaps[0]; } offsets = new int[m_FrameCount]; if (m_Version == 1000) { for (int i = 0; i < m_FrameCount; i++) { offsets[i] = Reader.ReadInt32(); m_FrameOffsets.Add(offsets[i]); } } if (m_Version == 1001) { for (int l = 0; l < m_FrameCount; l++) { SpriteFrame Frame = new SpriteFrame(); Frame.Version = Reader.ReadUInt32(); Frame.Size = Reader.ReadUInt32(); Frame.Width = Reader.ReadUInt16(); Frame.Height = Reader.ReadUInt16(); Frame.Flag = Reader.ReadUInt32(); Frame.PaletteID = Reader.ReadUInt16(); Frame.TransparentPixel = m_PMap.GetColorAtIndex(Reader.ReadUInt16()); Frame.YLocation = Reader.ReadUInt16(); Frame.XLocation = Reader.ReadUInt16(); if ((SPR2Flags)Frame.Flag == SPR2Flags.HasAlphaChannel) Frame.Init(true); else Frame.Init(false); DecompressFrame(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. m_Frames.Add(Frame); } } Reader.Close(); }
private void DecompressFrame(ref SpriteFrame Frame, ref BinaryReader Reader) { int row = 0; int column = 0; bool quit = false; int lastType = 0; int numCodesTillNewline = 0; try { while (quit == false) { int[] rowHeader = GetDecryptedValues(Reader.ReadUInt16()); switch (rowHeader[0]) { case 0: column = 0; numCodesTillNewline = rowHeader[1]; for (int bytesRead = 0; bytesRead < numCodesTillNewline - 2; bytesRead += 2) { int[] rowHeader2 = GetDecryptedValues(Reader.ReadUInt16()); try { switch (rowHeader2[0]) { case 1: for (int i = 0; i < rowHeader2[1]; i++) { int Z = Reader.ReadByte(); byte b = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(column++, row), m_PMap.GetColorAtIndex(b)); Color c = m_PMap.GetColorAtIndex(b); bytesRead += 2; } break; case 2: for (int i = 0; i < rowHeader2[1]; i++) { int Z = Reader.ReadByte(); byte b = Reader.ReadByte(); Color clr = m_PMap.GetColorAtIndex(b); Frame.BitmapData.SetPixel(new Point(column++, row), Color.FromArgb(Reader.ReadByte(), clr)); bytesRead += 3; } if (Reader.BaseStream.Position % 2 == 1) { Reader.ReadByte(); bytesRead++; } break; case 3: column += rowHeader2[1]; break; case 6: for (int i = 0; i < rowHeader2[1]; i++) { byte b = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(column++, row), m_PMap.GetColorAtIndex(b)); bytesRead++; } if (Reader.BaseStream.Position % 2 == 1) { Reader.ReadByte(); bytesRead++; } break; default: break; } } catch (Exception e) { Log.LogThis(String.Format("Error reading code {0} ({1}). Last code read was {2}.", rowHeader2[0], e.Message, lastType), eloglevel.error); } lastType = rowHeader2[0]; } row++; break; case 4: for (int i = 0; i < rowHeader[1]; i++) { row++; column = 0; } break; case 5: quit = true; break; default: Log.LogThis("Error reading code " + lastType + '!', eloglevel.error); break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) break; lastType = rowHeader[0]; } } catch (Exception E) { Log.LogThis("Unable to parse SPR2! \r\n" + "Version: " + m_Version + "\r\n" + "PaletteID: " + m_PaletteID + "\r\n" + "FrameCount: " + m_FrameCount + "\r\n" + E.ToString() + "\r\n", eloglevel.error); } }
public SpriteFrame ReadFrame(int Index) { BinaryReader Reader = new BinaryReader(new MemoryStream(m_ChunkData)); Reader.BaseStream.Seek(m_FrameOffsets[Index], SeekOrigin.Begin); SpriteFrame Frame = new SpriteFrame(); Frame.FrameIndex = (uint)Index; Frame.Width = Reader.ReadUInt16(); Frame.Height = Reader.ReadUInt16(); Frame.Flag = Reader.ReadUInt32(); Frame.PaletteID = Reader.ReadUInt16(); Frame.TransparentPixel = m_PMap.GetColorAtIndex(Reader.ReadUInt16()); Frame.YLocation = Reader.ReadUInt16(); Frame.XLocation = Reader.ReadUInt16(); if (Frame.Flag == 0x07) Frame.Init(true); else Frame.Init(false); DecompressFrame(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. Reader.Close(); //Store the frame to avoid having to decompress in the future. m_Frames.Add(Frame); return Frame; }
/// <summary> /// Creates a new SPR instance. /// </summary> /// <param name="Chunk">The data for the chunk.</param> /// <param name="PMaps">The palettemaps for this SPR.</param> public SPRParser(IffChunk Chunk, List<PaletteMap> PaletteMaps) : base(Chunk) { MemoryStream MemStream = new MemoryStream(Chunk.Data); BinaryReader Reader = new BinaryReader(MemStream); //The two first bytes aren't used by the version... ushort FirstBytes = Reader.ReadUInt16(); if (FirstBytes == 0) { m_IsBigEndian = true; m_Version = (uint)Endian.SwapUInt16(Reader.ReadUInt16()); } else { m_Version = (uint)FirstBytes; Reader.ReadUInt16(); } //In version 1001, all frames are decompressed from the beginning, and there's no point in storing //the compressed data AS WELL as the decompressed frames...! if (m_Version != 1001) m_ChunkData = Chunk.Data; if (m_IsBigEndian) { if (m_Version != 1001) { m_FrameCount = Endian.SwapUInt32(Reader.ReadUInt32()); m_PaletteID = Endian.SwapUInt32(Reader.ReadUInt32()); for (uint i = 0; i < m_FrameCount; i++) m_OffsetTable.Add(Endian.SwapUInt32(Reader.ReadUInt32())); //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return true; } return false; }); } else { m_FrameCount = Endian.SwapUInt32(Reader.ReadUInt32()); m_PaletteID = Endian.SwapUInt32(Reader.ReadUInt32()); //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return true; } return false; }); } } else { if (m_Version != 1001) { m_FrameCount = Reader.ReadUInt32(); m_PaletteID = Reader.ReadUInt32(); for (uint i = 0; i < m_FrameCount; i++) m_OffsetTable.Add(Reader.ReadUInt32()); //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return true; } return false; }); } else { m_FrameCount = Reader.ReadUInt32(); m_PaletteID = Reader.ReadUInt32(); //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return true; } return false; }); } } if (m_Version == 1001) { //Framecount may be set to -1 and should be ignored... while(true) { SpriteFrame Frame = new SpriteFrame(); Frame.Version = Reader.ReadUInt32(); Frame.Size = Reader.ReadUInt32(); Reader.ReadBytes(4); //Reserved. Frame.Height = Reader.ReadUInt16(); Frame.Width = Reader.ReadUInt16(); Frame.Init(true, false); //SPR#s don't have alpha channels, but alpha is used to plot transparent pixels. DecompressFrame2(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. m_Frames.Add(Frame); if ((Reader.BaseStream.Position == Reader.BaseStream.Length) || (Reader.BaseStream.Position - Reader.BaseStream.Length < 14)) break; } } Reader.Close(); }
/// <summary> /// Reads a frame from this SPR. /// </summary> /// <param name="Index">The index of the frame.</param> /// <returns>A SpriteFrame instance.</returns> private SpriteFrame ReadFrame(int Index) { MemoryStream MemStream = new MemoryStream(m_ChunkData); BinaryReader Reader = new BinaryReader(MemStream); Reader.BaseStream.Position = m_OffsetTable[Index]; SpriteFrame Frame = new SpriteFrame(); if (!m_IsBigEndian) { Reader.ReadBytes(4); //Reserved. Frame.Height = Reader.ReadUInt16(); Frame.Width = Reader.ReadUInt16(); Frame.PaletteID = (ushort)m_PaletteID; } else { Reader.ReadBytes(4); //Reserved. Frame.Height = Endian.SwapUInt16(Reader.ReadUInt16()); Frame.Width = Endian.SwapUInt16(Reader.ReadUInt16()); Frame.PaletteID = (ushort)m_PaletteID; } Frame.Init(true, false); //SPR#s don't have alpha channels, but alpha is used to plot transparent pixels. DecompressFrame2(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. //Store the frame to avoid having to decompress in the future. m_Frames.Add(Frame); return Frame; }
private SpriteFrame ReadFrame(int Index) { MemoryStream MemStream = new MemoryStream(m_ChunkData); BinaryReader Reader = new BinaryReader(MemStream); Reader.BaseStream.Position = m_OffsetTable[Index]; SpriteFrame Frame = new SpriteFrame(); if (!m_IsBigEndian) { Reader.ReadBytes(4); //Reserved. Frame.Height = Reader.ReadUInt16(); Frame.Width = Reader.ReadUInt16(); Frame.PaletteID = (ushort)m_PaletteID; } else { Reader.ReadBytes(4); //Reserved. Frame.Height = Reader.ReadUInt16(); Frame.Width = Reader.ReadUInt16(); Frame.PaletteID = (ushort)m_PaletteID; } Frame.Init(false); //SPR#s don't have alpha channels. DecompressFrame(ref Frame, ref Reader); return Frame; }
/// <summary> /// Decompresses a frame stored in this SPR2. /// </summary> /// <param name="Frame">A SpriteFrame instance that will contain the decompressed frame.</param> /// <param name="Reader">The binary reader to read the frame with.</param> private void DecompressFrame2(ref SpriteFrame Frame, ref BinaryReader Reader) { bool Quit = false; int CurrentRow = 0, CurrentColumn = 0; int Padding = 0; Color Clr, ZClr; //The current color and the current color for the z-buffer. while (Quit == false) { int[] RowHeader = GetDecryptedValues(Reader.ReadUInt16()); switch (RowHeader[0]) { case 0: //Fill this row with pixel data that directly follows; the count byte of the row //command denotes the size in bytes of the row's command/count bytes together //with the supplied pixel data. int RowCount = RowHeader[1]; RowCount -= 2; //Row command + count bytes. while (RowCount > 0) { int[] PixelHeader = GetDecryptedValues(Reader.ReadUInt16()); RowCount -= 2; int PixelCount = PixelHeader[1]; switch (PixelHeader[0]) { case 1: //Set the next pixel count pixels in the z-buffer and color sprites to the //values defined by the pixel data provided directly after this command. RowCount -= PixelCount * 2; while (PixelCount > 0) { Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(Reader.ReadByte(), 0, 0, 0)); Clr = m_PMap.GetColorAtIndex(Reader.ReadByte()); if (Clr != Frame.TransparentPixel) { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Clr); } else { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); } PixelCount--; CurrentColumn++; } break; case 2: //Set the next pixel count pixels in the z-buffer, color, and alpha //sprites to the values defined by the pixel data provided directly after //this command. Padding = PixelCount % 2; RowCount -= (PixelCount * 3) + Padding; while (PixelCount > 0) { ZClr = Color.FromArgb(Reader.ReadByte()); Clr = m_PMap.GetColorAtIndex(Reader.ReadByte()); //Read the alpha. Clr = Color.FromArgb(Reader.ReadByte(), Clr); ZClr = Color.FromArgb(Clr.A, ZClr); Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Clr); Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), ZClr); PixelCount--; CurrentColumn++; } if (Padding != 0) { Reader.ReadByte(); } break; case 3: //Leave the next pixel count pixels in the color sprite filled with the //transparent color, in the z-buffer sprite filled with 255, and in the //alpha sprite filled with 0. This pixel command has no pixel data. while (PixelCount > 0) { //This is completely transparent regardless of whether the frame //supports alpha. Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); if (Frame.HasZBuffer) { Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 255, 255, 255)); } PixelCount--; CurrentColumn++; } break; case 6: //Set the next pixel count pixels in the color sprite to the palette color //indices defined by the pixel data provided directly after this command. Padding = PixelCount % 2; RowCount -= PixelCount + Padding; while (PixelCount > 0) { Clr = m_PMap.GetColorAtIndex(Reader.ReadByte()); if (Clr != Frame.TransparentPixel) { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Clr); } else { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); } if (Frame.HasZBuffer) { if (Clr != Frame.TransparentPixel) { Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 1, 1, 1)); } else { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 255, 255, 255)); } } PixelCount--; CurrentColumn++; } if (Padding != 0) { Reader.ReadByte(); } break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) { break; } } CurrentRow++; CurrentColumn = 0; break; case 4: //Leave the next count rows in the color sprite filled with the transparent color, //in the z-buffer sprite filled with 255, and in the alpha sprite filled with 0. for (int i = 0; i < RowHeader[1]; i++) { for (int j = 0; j < Frame.Width; j++) { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); if (Frame.HasZBuffer) { Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 255, 255, 255)); } CurrentColumn++; } CurrentColumn = 0; CurrentRow++; } CurrentColumn = 0; break; case 5: //Sprite end marker; the count byte is always 0, but may be ignored. Quit = true; break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) { break; } } }
/// <summary> /// Creates a new SPR2 instance. /// </summary> /// <param name="Chunk">The data for the chunk.</param> /// <param name="PMaps">The palettemaps for this SPR2.</param> public SPR2Parser(IffChunk Chunk, List <PaletteMap> PMaps) : base(Chunk) { m_Name = Name; int[] offsets; MemoryStream MemStream = new MemoryStream(Chunk.Data); BinaryReader Reader = new BinaryReader(MemStream); m_Version = Reader.ReadUInt32(); //In version 1001, all frames are decompressed from the beginning, and there's no point in storing //the compressed data AS WELL as the decompressed frames...! if (m_Version == 1000) { m_ChunkData = Chunk.Data; } if (m_Version == 1001) { m_PaletteID = Reader.ReadUInt32(); m_FrameCount = Reader.ReadUInt32(); } else { m_FrameCount = Reader.ReadUInt32(); m_PaletteID = Reader.ReadUInt32(); } if (PMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PMaps[0]; } else { m_PMap = PMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return(true); } return(false); }); } //Some SPR2s blatantly specify the wrong ID because there's only one palettemap... if (m_PMap == null) { m_PMap = PMaps[0]; } offsets = new int[m_FrameCount]; if (m_Version == 1000) { for (int i = 0; i < m_FrameCount; i++) { offsets[i] = Reader.ReadInt32(); m_FrameOffsets.Add(offsets[i]); } } if (m_Version == 1001) { for (int l = 0; l < m_FrameCount; l++) { SpriteFrame Frame = new SpriteFrame(); Frame.Version = Reader.ReadUInt32(); Frame.Size = Reader.ReadUInt32(); Frame.Width = Reader.ReadUInt16(); Frame.Height = Reader.ReadUInt16(); Frame.Flag = Reader.ReadUInt32(); Frame.PaletteID = Reader.ReadUInt16(); Frame.TransparentPixel = m_PMap.GetColorAtIndex(Reader.ReadUInt16()); Frame.YLocation = Reader.ReadUInt16(); Frame.XLocation = Reader.ReadUInt16(); if ((SPR2Flags)Frame.Flag == SPR2Flags.HasAlphaChannel) { Frame.Init(true, true); } else { if ((SPR2Flags)Frame.Flag == SPR2Flags.HasZBufferChannel) { Frame.Init(false, true); } else { Frame.Init(false, false); } } DecompressFrame2(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. if (Frame.HasZBuffer) { Frame.ZBuffer.Unlock(true); //The bitmapdata is locked when the frame is created. } m_Frames.Add(Frame); } } Reader.Close(); }
private void DecompressFrame2(ref SpriteFrame Frame, ref BinaryReader Reader) { bool Quit = false; int CurrentRow = 0, CurrentColumn = 0; int Padding = 0; Color Clr, ZClr; //The current color and the current color for the z-buffer. while (Quit == false) { int[] RowHeader = GetDecryptedValues(Reader.ReadUInt16()); switch (RowHeader[0]) { case 0: //Fill this row with pixel data that directly follows; the count byte of the row //command denotes the size in bytes of the row's command/count bytes together //with the supplied pixel data. int RowCount = RowHeader[1]; RowCount -= 2; //Row command + count bytes. while (RowCount > 0) { int[] PixelHeader = GetDecryptedValues(Reader.ReadUInt16()); RowCount -= 2; int PixelCount = PixelHeader[1]; switch (PixelHeader[0]) { case 1: //Set the next pixel count pixels in the z-buffer and color sprites to the //values defined by the pixel data provided directly after this command. RowCount -= PixelCount * 2; while (PixelCount > 0) { Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(Reader.ReadByte(), 0, 0, 0)); Clr = m_PMap.GetColorAtIndex(Reader.ReadByte()); if (Clr != Frame.TransparentPixel) Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Clr); else Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); PixelCount--; CurrentColumn++; } break; case 2: //Set the next pixel count pixels in the z-buffer, color, and alpha //sprites to the values defined by the pixel data provided directly after //this command. Padding = PixelCount % 2; RowCount -= (PixelCount * 3) + Padding; while (PixelCount > 0) { ZClr = Color.FromArgb(Reader.ReadByte()); Clr = m_PMap.GetColorAtIndex(Reader.ReadByte()); //Read the alpha. Clr = Color.FromArgb(Reader.ReadByte(), Clr); ZClr = Color.FromArgb(Clr.A, ZClr); Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Clr); Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), ZClr); PixelCount--; CurrentColumn++; } if (Padding != 0) Reader.ReadByte(); break; case 3: //Leave the next pixel count pixels in the color sprite filled with the //transparent color, in the z-buffer sprite filled with 255, and in the //alpha sprite filled with 0. This pixel command has no pixel data. while (PixelCount > 0) { //This is completely transparent regardless of whether the frame //supports alpha. Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); if(Frame.HasZBuffer) Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 255, 255, 255)); PixelCount--; CurrentColumn++; } break; case 6: //Set the next pixel count pixels in the color sprite to the palette color //indices defined by the pixel data provided directly after this command. Padding = PixelCount % 2; RowCount -= PixelCount + Padding; while (PixelCount > 0) { Clr = m_PMap.GetColorAtIndex(Reader.ReadByte()); if (Clr != Frame.TransparentPixel) Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Clr); else Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); if (Frame.HasZBuffer) { if (Clr != Frame.TransparentPixel) Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 1, 1, 1)); else Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 255, 255, 255)); } PixelCount--; CurrentColumn++; } if (Padding != 0) Reader.ReadByte(); break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) break; } CurrentRow++; CurrentColumn = 0; break; case 4: //Leave the next count rows in the color sprite filled with the transparent color, //in the z-buffer sprite filled with 255, and in the alpha sprite filled with 0. for (int i = 0; i < RowHeader[1]; i++) { for (int j = 0; j < Frame.Width; j++) { Frame.BitmapData.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(0, 0, 0, 0)); if (Frame.HasZBuffer) { Frame.ZBuffer.SetPixel(new Point(CurrentColumn, CurrentRow), Color.FromArgb(255, 255, 255, 255)); } CurrentColumn++; } CurrentColumn = 0; CurrentRow++; } CurrentColumn = 0; break; case 5: //Sprite end marker; the count byte is always 0, but may be ignored. Quit = true; break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) break; } }
/// <summary> /// Creates a new SPR instance. /// </summary> /// <param name="Chunk">The data for the chunk.</param> /// <param name="PMaps">The palettemaps for this SPR.</param> public SPRParser(IffChunk Chunk, List <PaletteMap> PaletteMaps) : base(Chunk) { MemoryStream MemStream = new MemoryStream(Chunk.Data); BinaryReader Reader = new BinaryReader(MemStream); //The two first bytes aren't used by the version... ushort FirstBytes = Reader.ReadUInt16(); if (FirstBytes == 0) { m_IsBigEndian = true; m_Version = (uint)Endian.SwapUInt16(Reader.ReadUInt16()); } else { m_Version = (uint)FirstBytes; Reader.ReadUInt16(); } //In version 1001, all frames are decompressed from the beginning, and there's no point in storing //the compressed data AS WELL as the decompressed frames...! if (m_Version != 1001) { m_ChunkData = Chunk.Data; } if (m_IsBigEndian) { if (m_Version != 1001) { m_FrameCount = Endian.SwapUInt32(Reader.ReadUInt32()); m_PaletteID = Endian.SwapUInt32(Reader.ReadUInt32()); for (uint i = 0; i < m_FrameCount; i++) { m_OffsetTable.Add(Endian.SwapUInt32(Reader.ReadUInt32())); } //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else { m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return(true); } return(false); }); } } else { m_FrameCount = Endian.SwapUInt32(Reader.ReadUInt32()); m_PaletteID = Endian.SwapUInt32(Reader.ReadUInt32()); //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else { m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return(true); } return(false); }); } } } else { if (m_Version != 1001) { m_FrameCount = Reader.ReadUInt32(); m_PaletteID = Reader.ReadUInt32(); for (uint i = 0; i < m_FrameCount; i++) { m_OffsetTable.Add(Reader.ReadUInt32()); } //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else { m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return(true); } return(false); }); } } else { m_FrameCount = Reader.ReadUInt32(); m_PaletteID = Reader.ReadUInt32(); //Find and set the correct palettemap... if (PaletteMaps.Count == 1 && m_PaletteID == 1) { m_PMap = PaletteMaps[0]; } else { m_PMap = PaletteMaps.Find(delegate(PaletteMap PMap) { if (PMap.ID == m_PaletteID) { return(true); } return(false); }); } } } if (m_Version == 1001) { //Framecount may be set to -1 and should be ignored... while (true) { SpriteFrame Frame = new SpriteFrame(); Frame.Version = Reader.ReadUInt32(); Frame.Size = Reader.ReadUInt32(); Reader.ReadBytes(4); //Reserved. Frame.Height = Reader.ReadUInt16(); Frame.Width = Reader.ReadUInt16(); Frame.Init(true, false); //SPR#s don't have alpha channels, but alpha is used to plot transparent pixels. DecompressFrame2(ref Frame, ref Reader); Frame.BitmapData.Unlock(true); //The bitmapdata is locked when the frame is created. m_Frames.Add(Frame); if ((Reader.BaseStream.Position == Reader.BaseStream.Length) || (Reader.BaseStream.Position - Reader.BaseStream.Length < 14)) { break; } } } Reader.Close(); }
/// <summary> /// Decompresses a frame stored in this SPR. /// </summary> /// <param name="Frame">A SpriteFrame instance that will contain the decompressed frame.</param> /// <param name="Reader">The binary reader to read the frame with.</param> private void DecompressFrame2(ref SpriteFrame Frame, ref BinaryReader Reader) { bool quit = false; byte Clr = 0; Color Transparent; int CurrentRow = 0, CurrentColumn = 0; byte PixCommand, PixCount = 0; if (m_PMap == null) { m_PMap = new PaletteMap(); } while (quit == false) { byte RowCommand = Reader.ReadByte(); byte RowCount = Reader.ReadByte(); switch (RowCommand) { case 0x00: //Start marker; the count byte is ignored. break; //Fill this row with pixel data that directly follows; the count byte of the row command denotes the //size in bytes of the row and pixel data. case 0x04: RowCount -= 2; CurrentColumn = 0; while (RowCount > 0) { PixCommand = Reader.ReadByte(); PixCount = Reader.ReadByte(); RowCount -= 2; switch (PixCommand) { case 1: //Leave the next pixel count pixels as transparent. Transparent = Color.FromArgb(0, 0, 0, 0); for (int j = CurrentColumn; j < (CurrentColumn + PixCount); j++) { Frame.BitmapData.SetPixel(new Point(j, CurrentRow), Transparent); } CurrentColumn += PixCount; break; case 2: //Fill the next pixel count pixels with a palette color. //The pixel data is two bytes: the first byte denotes the palette color index, and the //second byte is padding (which is always equal to the first byte but is ignored). Clr = Reader.ReadByte(); Reader.ReadByte(); //Padding RowCount -= 2; for (int j = CurrentColumn; j < (CurrentColumn + PixCount); j++) { Frame.BitmapData.SetPixel(new Point(j, CurrentRow), m_PMap.GetColorAtIndex(Clr)); } CurrentColumn += PixCount; break; case 3: //Set the next pixel count pixels to the palette color indices defined by the //pixel data provided directly after this command. byte Padding = (byte)(PixCount % 2); if (Padding != 0) { RowCount -= (byte)(PixCount + Padding); } else { RowCount -= PixCount; } for (int j = CurrentColumn; j < (CurrentColumn + PixCount); j++) { Clr = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(j, CurrentRow), m_PMap.GetColorAtIndex(Clr)); } CurrentColumn += PixCount; if (Padding != 0) { Reader.ReadByte(); } break; } } CurrentRow++; break; case 0x05: //End marker. The count byte is always 0, but may be ignored. //Some sprites don't have these, so read them using ReadBytes(), which //simply returns an empty array if the stream couldn't be read. Reader.ReadBytes(2); //PixCommand and PixCount. quit = true; break; case 0x09: //Leave the next count rows as transparent. PixCommand = Reader.ReadByte(); PixCount = Reader.ReadByte(); Transparent = Color.FromArgb(0, 0, 0, 0); for (int i = 0; i < RowCount; i++) { for (int j = CurrentColumn; j < Frame.Width; j++) { Frame.BitmapData.SetPixel(new Point(j, CurrentRow), Transparent); } CurrentRow++; } break; case 0x10: //Start marker, equivalent to 0x00; the count byte is ignored. break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) { break; } } }
/// <summary> /// Creates a new drawgroup instance. /// </summary> /// <param name="ChunkData">The data for the chunk.</param> /// <param name="Sprites">The sprites that the DGRP consists of.</param> public DrawGroup(IffChunk Chunk, List <SPR2Parser> Sprites) : base(Chunk) { MemoryStream MemStream = new MemoryStream(Chunk.Data); BinaryReader Reader = new BinaryReader(MemStream); m_ID = ID; m_Sprites = Sprites; m_Version = Reader.ReadUInt16() - 20000; uint Count = (m_Version < 3) ? Reader.ReadUInt16() : Reader.ReadUInt32(); uint SpriteCount, DirectionFlag, Zoom; for (int i = 0; i < Count; i++) { if (m_Version < 3) { SpriteCount = Reader.ReadUInt16(); DirectionFlag = Reader.ReadByte(); Zoom = Reader.ReadByte(); } else { DirectionFlag = Reader.ReadUInt32(); Zoom = Reader.ReadUInt32(); SpriteCount = Reader.ReadUInt32(); } DrawGroupImg Image = new DrawGroupImg(SpriteCount, DirectionFlag, Zoom); for (int j = 0; j < SpriteCount; j++) { ushort Tag = 0; int PixelX = 0, PixelY = 0; uint SprID = 0, SprFrameID = 0, Flags = 0; float ZOffset = 0, XOffset = 0, YOffset = 0; if (m_Version < 3) { Tag = Reader.ReadUInt16(); SprID = Reader.ReadUInt16(); SprFrameID = Reader.ReadUInt16(); Flags = Reader.ReadUInt16(); PixelX = Reader.ReadInt16(); PixelY = Reader.ReadInt16(); if (m_Version == 1) { ZOffset = Reader.ReadUInt32(); } } else { SprID = Reader.ReadUInt32(); SprFrameID = Reader.ReadUInt32(); PixelX = Reader.ReadInt32(); PixelY = Reader.ReadInt32(); ZOffset = Reader.ReadUInt32(); Flags = Reader.ReadUInt32(); if (m_Version == 4) { XOffset = Reader.ReadUInt32(); YOffset = Reader.ReadUInt32(); } } SpriteFrame Frame = FindSpriteFrame(SprID, SprFrameID); if (Frame != null) { DrawGroupSprite Sprite = new DrawGroupSprite(Tag, Flags, new PixelOffset(PixelX, PixelY), new WorldOffset(XOffset, YOffset, ZOffset), Frame); Image.Sprites.Insert(0, Sprite); } } m_Images.Add(Image); } }
/// <summary> /// Decompresses a frame stored in this SPR. /// </summary> /// <param name="Frame">A SpriteFrame instance that will contain the decompressed frame.</param> /// <param name="Reader">The binary reader to read the frame with.</param> private void DecompressFrame2(ref SpriteFrame Frame, ref BinaryReader Reader) { bool quit = false; byte Clr = 0; Color Transparent; int CurrentRow = 0, CurrentColumn = 0; byte PixCommand, PixCount = 0; if (m_PMap == null) m_PMap = new PaletteMap(); while (quit == false) { byte RowCommand = Reader.ReadByte(); byte RowCount = Reader.ReadByte(); switch (RowCommand) { case 0x00: //Start marker; the count byte is ignored. break; //Fill this row with pixel data that directly follows; the count byte of the row command denotes the //size in bytes of the row and pixel data. case 0x04: RowCount -= 2; CurrentColumn = 0; while (RowCount > 0) { PixCommand = Reader.ReadByte(); PixCount = Reader.ReadByte(); RowCount -= 2; switch (PixCommand) { case 1: //Leave the next pixel count pixels as transparent. Transparent = Color.FromArgb(0, 0, 0, 0); for (int j = CurrentColumn; j < (CurrentColumn + PixCount); j++) { Frame.BitmapData.SetPixel(new Point(j, CurrentRow), Transparent); } CurrentColumn += PixCount; break; case 2: //Fill the next pixel count pixels with a palette color. //The pixel data is two bytes: the first byte denotes the palette color index, and the //second byte is padding (which is always equal to the first byte but is ignored). Clr = Reader.ReadByte(); Reader.ReadByte(); //Padding RowCount -= 2; for (int j = CurrentColumn; j < (CurrentColumn + PixCount); j++) { Frame.BitmapData.SetPixel(new Point(j, CurrentRow), m_PMap.GetColorAtIndex(Clr)); } CurrentColumn += PixCount; break; case 3: //Set the next pixel count pixels to the palette color indices defined by the //pixel data provided directly after this command. byte Padding = (byte)(PixCount % 2); if (Padding != 0) RowCount -= (byte)(PixCount + Padding); else RowCount -= PixCount; for (int j = CurrentColumn; j < (CurrentColumn + PixCount); j++) { Clr = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(j, CurrentRow), m_PMap.GetColorAtIndex(Clr)); } CurrentColumn += PixCount; if (Padding != 0) Reader.ReadByte(); break; } } CurrentRow++; break; case 0x05: //End marker. The count byte is always 0, but may be ignored. //Some sprites don't have these, so read them using ReadBytes(), which //simply returns an empty array if the stream couldn't be read. Reader.ReadBytes(2); //PixCommand and PixCount. quit = true; break; case 0x09: //Leave the next count rows as transparent. PixCommand = Reader.ReadByte(); PixCount = Reader.ReadByte(); Transparent = Color.FromArgb(0, 0, 0, 0); for (int i = 0; i < RowCount; i++) { for (int j = CurrentColumn; j < Frame.Width; j++) Frame.BitmapData.SetPixel(new Point(j, CurrentRow), Transparent); CurrentRow++; } break; case 0x10: //Start marker, equivalent to 0x00; the count byte is ignored. break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) break; } }
private void DecompressFrame(ref SpriteFrame Frame, ref BinaryReader Reader) { int row = 0; int column = 0; bool quit = false; int lastType = 0; int numCodesTillNewline = 0; while (quit == false) { ushort rowHeader = Reader.ReadUInt16(); if (m_IsBigEndian) rowHeader = Endian.SwapUInt16(rowHeader); ushort RowControlCode = (ushort)(rowHeader >> 13); ushort BytesInThisRow = (ushort)(rowHeader & 0x1FFF); switch (RowControlCode) { case 0: //Start marker; the count byte is ignored break; case 4: column = 0; numCodesTillNewline = BytesInThisRow; for (int bytesRead = 0; bytesRead < numCodesTillNewline - 2; bytesRead += 2) { ushort rowHeader2 = Reader.ReadUInt16(); if (m_IsBigEndian) rowHeader2 = Endian.SwapUInt16(rowHeader2); ushort ColumnControlCode = (ushort)(rowHeader2 >> 13); ushort BytesInThisColumn = (ushort)(rowHeader2 & 0x1FFF); try { switch (ColumnControlCode) { case 1: //Fill pixels with background. //column += BytesInThisColumn; for (int i = 0; i < BytesInThisColumn; i++) { int Z = Reader.ReadByte(); byte b = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(column++, row), m_PMap.GetColorAtIndex(b)); Color c = m_PMap.GetColorAtIndex(b); bytesRead += 2; } break; case 2: //TODO: Run-length encoding. for (int i = 0; i < BytesInThisColumn; i++) { byte b1 = Reader.ReadByte(); byte b2 = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(column++, row), m_PMap.GetColorAtIndex(b1)); Frame.BitmapData.SetPixel(new Point(column++, row), m_PMap.GetColorAtIndex(b2)); bytesRead += 2; } break; case 3: //Copy image pixels. for (int i = 0; i < BytesInThisColumn; i++) { byte b = Reader.ReadByte(); Frame.BitmapData.SetPixel(new Point(column++, row), m_PMap.GetColorAtIndex(b)); bytesRead++; } if (Reader.BaseStream.Position % 2 == 1) { Reader.ReadByte(); bytesRead++; } break; default: break; } } catch (Exception e) { Log.LogThis(String.Format("Error reading code {0} ({1}). Last code read was {2}.", ColumnControlCode, e.Message, lastType), eloglevel.error); } lastType = ColumnControlCode; } row++; break; case 5: quit = true; break; case 9: //Fill lines with background. for (int i = 0; i < BytesInThisRow; i++) { row++; column = 0; } break; case 10: //Start marker; the count byte is ignored break; default: //MessageBox.Show("Error reading code " + lastType + '!'); Log.LogThis(String.Format("Error reading code: " + lastType + "!"), eloglevel.error); break; } if (Reader.BaseStream.Position == Reader.BaseStream.Length) break; lastType = RowControlCode; } }