public void Box(int X, int Y, int Width, int Height, uint Value) { if ((X + Width <= 0) || (X >= m_Width) || (Y + Height <= 0) || (Y >= m_Height)) { return; } if (X < 0) { Width += X; X = 0; } if (X + Width >= m_Width) { Width = m_Width - X; } if (Y < 0) { Height += Y; Y = 0; } if (Y + Height >= m_Height) { Height = m_Height - Y; } switch (BitsPerPixel) { case 8: for (int i = 0; i < Height; ++i) { for (int j = 0; j < Width; ++j) { m_ImageData.SetU8At(j + X + BytesPerLine * (Y + i), (byte)Value); } } break; case 24: for (int i = 0; i < Height; ++i) { for (int j = 0; j < Width; ++j) { m_ImageData.SetU8At((j + X) * 3 + BytesPerLine * (Y + i), (byte)(Value & 0xff)); m_ImageData.SetU8At((j + X) * 3 + BytesPerLine * (Y + i) + 1, (byte)((Value & 0xff00) >> 8)); m_ImageData.SetU8At((j + X) * 3 + BytesPerLine * (Y + i) + 2, (byte)((Value & 0xff0000) >> 16)); } } break; case 32: for (int i = 0; i < Height; ++i) { for (int j = 0; j < Width; ++j) { m_ImageData.SetU32At((j + X) * 4 + BytesPerLine * (Y + i), Value); } } break; default: throw new NotSupportedException("Bitdepth " + BitsPerPixel + " not supported yet"); } }
public int ImageToMCBitmapData(Dictionary <int, List <ColorMappingTarget> > ForceBitPattern, List <Formats.CharData> Chars, bool[,] ErrornousBlocks, int CharX, int CharY, int WidthChars, int HeightChars, out GR.Memory.ByteBuffer bitmapData, out GR.Memory.ByteBuffer screenChar, out GR.Memory.ByteBuffer screenColor) { int numErrors = 0; ColorMappingTarget[] bitPattern = new ColorMappingTarget[3] { ColorMappingTarget.BITS_01, ColorMappingTarget.BITS_10, ColorMappingTarget.BITS_11 }; var usedBitPattern = new GR.Collections.Set <ColorMappingTarget>(); Dictionary <int, GR.Collections.Set <ColorMappingTarget> > usedPatterns = new Dictionary <int, GR.Collections.Set <ColorMappingTarget> >(); screenChar = new GR.Memory.ByteBuffer((uint)(WidthChars * HeightChars)); screenColor = new GR.Memory.ByteBuffer((uint)(WidthChars * HeightChars)); bitmapData = new GR.Memory.ByteBuffer((uint)(8 * WidthChars * HeightChars)); GR.Collections.Map <byte, ColorMappingTarget> usedColors = new GR.Collections.Map <byte, ColorMappingTarget>(); /* * ForceBitPattern = new Dictionary<int, byte>(); * ForceBitPattern.Add( 4, 1 ); * ForceBitPattern.Add( 1, 2 ); * ForceBitPattern.Add( 3, 3 );*/ for (int y = 0; y < HeightChars; ++y) { for (int x = 0; x < WidthChars; ++x) { // ein zeichen-block usedColors.Clear(); usedBitPattern.Clear(); if (ErrornousBlocks != null) { ErrornousBlocks[x, y] = false; } for (int charY = 0; charY < 8; ++charY) { for (int charX = 0; charX < 4; ++charX) { byte colorIndex = (byte)Image.GetPixel(x * 8 + charX * 2, y * 8 + charY); if (colorIndex >= 16) { if (Chars != null) { Chars[x + y * BlockWidth].Error = "Color index >= 16 (" + colorIndex + ") at " + (x * 8 + charX * 2).ToString() + ", " + (y * 8 + charY).ToString() + " (" + charX + "," + charY + ")"; } if (ErrornousBlocks != null) { ErrornousBlocks[x, y] = true; } ++numErrors; } if (colorIndex != BackgroundColor) { // remember used color usedColors.Add(colorIndex, 0); } } } // more than 3 colors? if (usedColors.Count > 3) { if (Chars != null) { Chars[x + y * BlockWidth].Error = "Too many colors used"; } if (ErrornousBlocks != null) { ErrornousBlocks[x, y] = true; } ++numErrors; } else { if (usedColors.Count > 0) { int colorTarget = 0; List <byte> keys = new List <byte>(usedColors.Keys); // check for overlaps - two colors are used that would map to the same target pattern? Dictionary <int, ColorMappingTarget> recommendedPattern = new Dictionary <int, ColorMappingTarget>(); numErrors += DetermineBestMapping(keys, x, y, ForceBitPattern, recommendedPattern, ErrornousBlocks); foreach (byte colorIndex in keys) { if (recommendedPattern.ContainsKey(colorIndex)) { usedColors[colorIndex] = recommendedPattern[colorIndex]; if (!usedPatterns.ContainsKey(colorIndex)) { usedPatterns.Add(colorIndex, new GR.Collections.Set <ColorMappingTarget>()); } usedPatterns[colorIndex].Add(recommendedPattern[colorIndex]); usedBitPattern.Add(recommendedPattern[colorIndex]); switch (recommendedPattern[colorIndex]) { case ColorMappingTarget.BITS_01: { // upper screen char nibble byte value = screenChar.ByteAt(x + y * WidthChars); value &= 0x0f; value |= (byte)(colorIndex << 4); screenChar.SetU8At(x + y * WidthChars, value); } break; case ColorMappingTarget.BITS_10: { // lower nibble in screen char byte value = screenChar.ByteAt(x + y * WidthChars); value &= 0xf0; value |= (byte)(colorIndex); screenChar.SetU8At(x + y * WidthChars, value); } break; case ColorMappingTarget.BITS_11: // color ram screenColor.SetU8At(x + y * WidthChars, colorIndex); break; } continue; } if (!usedPatterns.ContainsKey(colorIndex)) { usedPatterns.Add(colorIndex, new GR.Collections.Set <ColorMappingTarget>()); } usedPatterns[colorIndex].Add(bitPattern[colorTarget]); colorTarget = 0; while ((colorTarget < 3) && (usedBitPattern.ContainsValue(bitPattern[colorTarget]))) { ++colorTarget; } usedBitPattern.Add(bitPattern[colorTarget]); if (colorTarget == 0) { // upper screen char nibble byte value = screenChar.ByteAt(x + y * WidthChars); value &= 0x0f; value |= (byte)(colorIndex << 4); screenChar.SetU8At(x + y * WidthChars, value); usedColors[colorIndex] = ColorMappingTarget.BITS_01; } else if (colorTarget == 1) { // lower nibble in screen char byte value = screenChar.ByteAt(x + y * WidthChars); value &= 0xf0; value |= (byte)(colorIndex); screenChar.SetU8At(x + y * WidthChars, value); usedColors[colorIndex] = ColorMappingTarget.BITS_10; } else if (colorTarget == 2) { // color ram screenColor.SetU8At(x + y * WidthChars, colorIndex); usedColors[colorIndex] = ColorMappingTarget.BITS_11; } ++colorTarget; } } // write out bits /* * Debug.Log( "For Char " + x + "," + y ); * foreach ( var usedColor in usedColors ) * { * Debug.Log( " Color " + usedColor.Key + " = " + usedColor.Value ); * }*/ for (int charY = 0; charY < 8; ++charY) { for (int charX = 0; charX < 4; ++charX) { byte colorIndex = (byte)Image.GetPixel(x * 8 + charX * 2, y * 8 + charY); if (colorIndex != BackgroundColor) { // other color byte colorValue = 0; switch (usedColors[colorIndex]) { case ColorMappingTarget.BITS_01: colorValue = 0x01; break; case ColorMappingTarget.BITS_10: colorValue = 0x02; break; case ColorMappingTarget.BITS_11: colorValue = 0x03; break; } int bitmapIndex = x * 8 + y * 8 * WidthChars + charY; byte value = bitmapData.ByteAt(bitmapIndex); if (charX == 0) { value &= 0x3f; value |= (byte)(colorValue << 6); } else if (charX == 1) { value &= 0xcf; value |= (byte)(colorValue << 4); } else if (charX == 2) { value &= 0xf3; value |= (byte)(colorValue << 2); } else { value &= 0xfc; value |= colorValue; } bitmapData.SetU8At(bitmapIndex, value); } } } } } } /* * Debug.Log( "Used patterns:" ); * foreach ( var entry in usedPatterns ) * { * Debug.Log( "Index " + entry.Key ); * foreach ( var pattern in entry.Value ) * { * Debug.Log( " used " + pattern ); * } * }*/ return(numErrors); }
public bool ExportMapsAsAssembly(bool Vertical, out string MapData, string LabelPrefix, bool WrapData, int WrapByteCount, string DataByteDirective) { bool hasExtraData = false; foreach (var map in Maps) { if (map.ExtraDataText.Length > 0) { hasExtraData = true; break; } } StringBuilder sbMaps = new StringBuilder(); sbMaps.Append(LabelPrefix); sbMaps.Append("NUM_MAPS = "); sbMaps.AppendLine(Maps.Count.ToString()); sbMaps.Append(LabelPrefix); sbMaps.AppendLine("MAP_LIST_LO"); for (int i = 0; i < Maps.Count; ++i) { sbMaps.Append(DataByteDirective); sbMaps.Append(' '); sbMaps.AppendLine("<" + LabelPrefix + "MAP_" + NormalizeAsLabel(Maps[i].Name.ToUpper())); } sbMaps.AppendLine(); sbMaps.Append(LabelPrefix); sbMaps.AppendLine("MAP_LIST_HI"); for (int i = 0; i < Maps.Count; ++i) { sbMaps.Append(DataByteDirective); sbMaps.Append(' '); sbMaps.AppendLine(">" + LabelPrefix + "MAP_" + NormalizeAsLabel(Maps[i].Name.ToUpper())); } sbMaps.AppendLine(); if (hasExtraData) { sbMaps.Append(LabelPrefix); sbMaps.AppendLine("MAP_EXTRA_DATA_LIST_LO"); for (int i = 0; i < Maps.Count; ++i) { sbMaps.Append(DataByteDirective); sbMaps.Append(' '); sbMaps.AppendLine("<" + LabelPrefix + "MAP_EXTRA_DATA_" + NormalizeAsLabel(Maps[i].Name.ToUpper())); } sbMaps.Append(LabelPrefix); sbMaps.AppendLine("MAP_EXTRA_DATA_LIST_HI"); for (int i = 0; i < Maps.Count; ++i) { sbMaps.Append(DataByteDirective); sbMaps.Append(' '); sbMaps.AppendLine(">" + LabelPrefix + "MAP_EXTRA_DATA_" + NormalizeAsLabel(Maps[i].Name.ToUpper())); } sbMaps.AppendLine(); } for (int i = 0; i < Maps.Count; ++i) { var map = Maps[i]; sbMaps.AppendLine(); sbMaps.Append(LabelPrefix); sbMaps.AppendLine("MAP_" + NormalizeAsLabel(map.Name.ToUpper())); GR.Memory.ByteBuffer mapDataBuffer = new GR.Memory.ByteBuffer((uint)(map.Tiles.Width * map.Tiles.Height)); if (Vertical) { for (int y = 0; y < map.Tiles.Height; ++y) { for (int x = 0; x < map.Tiles.Width; ++x) { mapDataBuffer.SetU8At(x * map.Tiles.Height + y, (byte)map.Tiles[x, y]); } } } else { for (int y = 0; y < map.Tiles.Height; ++y) { for (int x = 0; x < map.Tiles.Width; ++x) { mapDataBuffer.SetU8At(x + y * map.Tiles.Width, (byte)map.Tiles[x, y]); } } } sbMaps.AppendLine(); sbMaps.Append(Util.ToASMData(mapDataBuffer, WrapData, WrapByteCount, DataByteDirective)); if ((hasExtraData) && (map.ExtraDataText.Length > 0)) { sbMaps.AppendLine(";extra data"); sbMaps.Append(LabelPrefix); sbMaps.AppendLine("MAP_EXTRA_DATA_" + NormalizeAsLabel(map.Name.ToUpper())); // clean extra data GR.Memory.ByteBuffer extraData = new GR.Memory.ByteBuffer(); string[] lines = map.ExtraDataText.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) { string tempLine = line.Trim().Replace(" ", ""); if ((!tempLine.StartsWith(";")) && (!tempLine.StartsWith("#")) && (!tempLine.StartsWith("//"))) { extraData.AppendHex(tempLine); } } sbMaps.Append(Util.ToASMData(extraData, WrapData, WrapByteCount, DataByteDirective)); sbMaps.AppendLine(); } } MapData = sbMaps.ToString(); return(true); }
public int ImageToHiresBitmapData(List <Formats.CharData> Chars, bool[,] ErrornousBlocks, int CharX, int CharY, int WidthChars, int HeightChars, out GR.Memory.ByteBuffer bitmapData, out GR.Memory.ByteBuffer screenChar, out GR.Memory.ByteBuffer screenColor) { screenChar = null; screenColor = null; bitmapData = null; if ((CharX < 0) || (CharX >= BlockWidth) || (CharY < 0) || (CharY >= BlockHeight) || (WidthChars < 0) || (HeightChars < 0) || (CharX + WidthChars > BlockWidth) || (CharY + HeightChars > BlockHeight)) { return(1); } int numErrors = 0; screenChar = new GR.Memory.ByteBuffer((uint)(WidthChars * HeightChars)); screenColor = new GR.Memory.ByteBuffer((uint)(WidthChars * HeightChars)); bitmapData = new GR.Memory.ByteBuffer((uint)(8 * WidthChars * HeightChars)); GR.Collections.Map <byte, byte> usedColors = new GR.Collections.Map <byte, byte>(); for (int y = CharY; y < HeightChars; ++y) { for (int x = CharX; x < WidthChars; ++x) { // ein zeichen-block usedColors.Clear(); if (ErrornousBlocks != null) { ErrornousBlocks[x, y] = false; } for (int charY = 0; charY < 8; ++charY) { for (int charX = 0; charX < 8; ++charX) { byte colorIndex = (byte)Image.GetPixel(x * 8 + charX, y * 8 + charY); if (colorIndex >= 16) { if (Chars != null) { Chars[x + y * BlockWidth].Error = "Color index >= 16 (" + colorIndex + ") at " + (x * 8 + charX).ToString() + ", " + (y * 8 + charY).ToString() + " (" + charX + "," + charY + ")"; } if (ErrornousBlocks != null) { ErrornousBlocks[x, y] = true; } ++numErrors; } if (colorIndex != BackgroundColor) { // remember used color usedColors.Add(colorIndex, 0); } } } // more than 2 colors? if (usedColors.Count > 2) { if (Chars != null) { Chars[x + y * BlockWidth].Error = "Too many colors used"; } if (ErrornousBlocks != null) { ErrornousBlocks[x, y] = true; } ++numErrors; } else { int firstColorIndex = -1; if (usedColors.Count > 0) { int colorTarget = 0; List <byte> keys = new List <byte>(usedColors.Keys); foreach (byte colorIndex in keys) { if (colorTarget == 0) { // upper screen char nibble byte value = screenChar.ByteAt(x + y * WidthChars); value &= 0x0f; value |= (byte)(colorIndex << 4); screenChar.SetU8At(x + y * WidthChars, value); usedColors[colorIndex] = 1; firstColorIndex = colorIndex; } else if (colorTarget == 1) { // lower nibble in screen char byte value = screenChar.ByteAt(x + y * WidthChars); value &= 0xf0; value |= (byte)(colorIndex); screenChar.SetU8At(x + y * WidthChars, value); usedColors[colorIndex] = 2; } ++colorTarget; } } // write out bits for (int charY = 0; charY < 8; ++charY) { for (int charX = 0; charX < 8; ++charX) { byte colorIndex = (byte)Image.GetPixel(x * 8 + charX, y * 8 + charY); if (colorIndex == firstColorIndex) { // other color byte colorValue = usedColors[colorIndex]; int bitmapIndex = x * 8 + y * WidthChars * 8 + charY; byte value = bitmapData.ByteAt(bitmapIndex); int mask = (1 << (7 - charX)); value &= (byte)(0xff ^ mask); value |= (byte)mask; bitmapData.SetU8At(bitmapIndex, value); } } } } } } return(numErrors); }
private bool LoadVersion8(GR.Memory.ByteBuffer Data) { DisplayModeFile = (DisplayMode)Data.ByteAt(4); TileColorMode = (ColorMode)Data.ByteAt(5); byte flags = Data.ByteAt(6); BackgroundColor = Data.ByteAt(7); MultiColor1 = Data.ByteAt(8); MultiColor2 = Data.ByteAt(9); BackgroundColor4 = Data.ByteAt(10); BaseCellColorColorMatrix = Data.ByteAt(11); BaseCellColorScreenLo = Data.ByteAt(12); BaseCellColorScreenHi = Data.ByteAt(13); bool tileSysEnabled = ((flags & 0x01) != 0); ushort charDataBlockID = 0xdab0; ushort charAttributeBlockID = 0xdab1; ushort charSetColorBlockID = 0; ushort tileSetDataBlockID = 0; ushort tileSetColorBlockID = 0; ushort tileSetTagBlockID = 0; ushort tileSetNameBlockID = 0; ushort mapDataBlockID = 0; int curBlockID = 0xdab2; if (TileColorMode == ColorMode.PER_CHAR) { charSetColorBlockID = (ushort)curBlockID++; } if (tileSysEnabled) { tileSetDataBlockID = (ushort)curBlockID++; if (TileColorMode == ColorMode.PER_TILE) { tileSetColorBlockID = (ushort)curBlockID++; } tileSetTagBlockID = (ushort)curBlockID++; tileSetNameBlockID = (ushort)curBlockID++; } mapDataBlockID = (ushort)curBlockID++; if (!tileSysEnabled) { // fake tiles (one per char) TileWidth = 1; TileHeight = 1; NumTiles = 256; for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.CharData.SetU16At(0, (ushort)i); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); tile.ColorData.SetU8At(0, (byte)CustomColor); Tiles.Add(tile); } } var reader = Data.MemoryReader(); reader.Skip(14); while (reader.DataAvailable) { ushort blockID = reader.ReadUInt16NetworkOrder(); if (blockID == charDataBlockID) { // Character data block // CHARCNT: Character image count minus one( 16 - bit, LSBF ). NumChars = reader.ReadUInt16() + 1; // CHARDAT : Character image data( eight bytes / rows per image for CHARCNT images, rows are in TB order ). for (int charIndex = 0; charIndex < NumChars; ++charIndex) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(); newChar.Color = CustomColor; reader.ReadBlock(newChar.Data, 8); Characters.Add(newChar); } if (!tileSysEnabled) { if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); newChar.Color = CustomColor; Characters.Add(newChar); } } } } else if (blockID == charAttributeBlockID) { // char attributes // BLKMARK: Block marker(0xDA, 0xB1). // CHARATTS: Char attribute data, one byte per char image for CHARCNT images, low nybble = colour, high nybble = material. // nb.colours are only stored when the colouring mode is "per character". for (int charIndex = 0; charIndex < NumChars; ++charIndex) { if (TileColorMode == ColorMode.PER_CHAR) { Characters[charIndex].Color = reader.ReadUInt8() & 0x0f; if (!tileSysEnabled) { Tiles[charIndex].ColorData.SetU8At(0, (byte)Characters[charIndex].Color); } } } } else if (blockID == charSetColorBlockID) { // Character set colours block (only present if the project uses per-char colouring)... // // BLKMARK : Block marker (0xDA, 0xBn). // MTRXCOLRS_CHARS : Char colour data, 1-3 bytes per char image for CHARCNT images... // // Colour_CmLo : Colour Matrix Low nybble (0-15) (not present if DISP_MODE is Bitmap_HR). // Colour_SmLo : Screen Matrix Low nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC). // Colour_SmHi : Screen Matrix High nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC). // // Notes:- // - The colours in this block are intended for transfer to the C64 colour RAM cells and/or screen RAM cells. // - The usage / usefulness of a colour will depend on the display mode. // - Only the low nybbles of each byte are currently used, each provides a colour 0-15. for (int i = 0; i < NumChars; ++i) { if (DisplayModeFile != DisplayMode.BITMAP_HIRES) { Characters[i].Color = reader.ReadUInt8(); } if ((DisplayModeFile == DisplayMode.BITMAP_MC) || (DisplayModeFile == DisplayMode.BITMAP_HIRES)) { // screen color lo reader.ReadUInt8(); // screen color hi reader.ReadUInt8(); } if (!tileSysEnabled) { // use the charset color for our faked tiles Tiles[i].ColorData.SetU8At(0, (byte)Characters[i].Color); } } } else if (blockID == tileSetDataBlockID) { // Tile data block // TILECNT: Tile count minus one(16 - bit, LSBF). NumTiles = reader.ReadUInt16() + 1; // TILEWID: Tile width( byte). TileWidth = reader.ReadUInt8(); // TILEHEI: Tile height( byte). TileHeight = reader.ReadUInt8(); // TILEDAT: Tile data, 16 bits per tile cell( LSBF) for TILEWID* TILEHEI cells * TILECNT items, cells are in LRTB order. for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); Tiles.Add(tile); } if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); Characters.Add(newChar); } } for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, reader.ReadUInt16()); } } } else if (blockID == tileSetColorBlockID) { // Tile color block // BLKMARK : Block marker (0xDA, 0xBn). // MTRXCOLRS_TILES : Tile colour data, 1-3 bytes per tile for TILECNT tiles... // // Colour_CmLo : Colour Matrix Low nybble (0-15) (not present if DISP_MODE is Bitmap_HR). // Colour_SmLo : Screen Matrix Low nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC). // Colour_SmHi : Screen Matrix High nybble (0-15) (only present if DISP_MODE is Bitmap_HR or Bitmap_MC). // // Notes:- // - The colours in this block are intended for transfer to the C64 colour RAM cells and/or screen RAM cells. // - The usage / usefulness of a colour will depend on the display mode. // - Only the low nybbles of each byte are currently used, each provides a colour 0-15. for (int i = 0; i < NumTiles; ++i) { if (DisplayModeFile != DisplayMode.BITMAP_HIRES) { // tile generic color reader.ReadUInt8(); } if ((DisplayModeFile == DisplayMode.BITMAP_MC) || (DisplayModeFile == DisplayMode.BITMAP_HIRES)) { // screen color lo reader.ReadUInt8(); // screen color hi reader.ReadUInt8(); } } } else if (blockID == tileSetTagBlockID) { // BLKMARK : Block marker (0xDA, 0xBn). // TILETAGS : Tile tag values, one byte per tile for TILECNT items. for (int i = 0; i < NumTiles; ++i) { byte tileTag = reader.ReadUInt8(); } } else if (blockID == tileSetNameBlockID) { // BLKMARK : Block marker (0xDA, 0xBn). // TILETAGS : Tile tag values, one byte per tile for TILECNT items. for (int i = 0; i < NumTiles; ++i) { // zero terminated strings (urgh) string name = ""; char c = (char)0; do { c = (char)reader.ReadUInt8(); if (c != 0) { name += c; } }while (c != 0); Tiles[i].Name = name; } } else if (blockID == mapDataBlockID) { // BLKMARK : Block marker (0xDA, 0xBn). // MAPWID: Map Width(16 - bit, LSBF). // MAPHEI: Map height(16 - bit, LSBF). // MAPDAT: Map data, 16 bits per cell( LSBF ) for MAPWID* MAPHEI cells, cells are in LRTB order. MapWidth = reader.ReadUInt16(); MapHeight = reader.ReadUInt16(); MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight)); if (!tileSysEnabled) { // map has color data MapColorData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight)); } for (int i = 0; i < MapHeight; ++i) { for (int j = 0; j < MapWidth; ++j) { ushort mapData = reader.ReadUInt16(); // we only support 8 bytes per char MapData.SetU8At(i * MapWidth + j, (byte)mapData); // do we?? Mega65! if (TileColorMode == ColorMode.PER_CHAR) { MapColorData.SetU8At(i * MapWidth + j, (byte)Characters[(byte)mapData].Color); } } } } else { Debug.Log("Unexpected block ID: " + blockID.ToString("X")); return(false); } } return(true); }
private bool LoadVersion7(GR.Memory.ByteBuffer Data) { BackgroundColor = Data.ByteAt(4); MultiColor1 = Data.ByteAt(5); MultiColor2 = Data.ByteAt(6); BackgroundColor4 = Data.ByteAt(7); CustomColor = Data.ByteAt(8); TileColorMode = (ColorMode)Data.ByteAt(9); // only uses values 0 to 2, which maps fine DisplayModeFile = (DisplayMode)Data.ByteAt(10); byte flags = Data.ByteAt(11); bool tileSysEnabled = ((flags & 0x01) != 0); ushort charDataBlockID = 0xdab0; ushort charAttributeBlockID = 0xdab1; ushort mapDataBlockID = 0xdab2; if (!tileSysEnabled) { // fake tiles (one per char) TileWidth = 1; TileHeight = 1; NumTiles = 256; for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.CharData.SetU16At(0, (ushort)i); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); tile.ColorData.SetU8At(0, (byte)CustomColor); Tiles.Add(tile); } } var reader = Data.MemoryReader(); reader.Skip(12); while (reader.DataAvailable) { ushort blockID = reader.ReadUInt16NetworkOrder(); if (blockID == mapDataBlockID) { if (tileSysEnabled) { // Tile data block // TILECNT: Tile count minus one(16 - bit, LSBF). NumTiles = reader.ReadUInt16() + 1; // TILEWID: Tile width( byte). TileWidth = reader.ReadUInt8(); // TILEHEI: Tile height( byte). TileHeight = reader.ReadUInt8(); // TILEDAT: Tile data, 16 bits per tile cell( LSBF) for TILEWID* TILEHEI cells * TILECNT items, cells are in LRTB order. for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); Tiles.Add(tile); } if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); Characters.Add(newChar); } } for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, reader.ReadUInt16()); } } } else { // BLKMARK : Block marker (0xDA, 0xBn). // MAPWID: Map Width(16 - bit, LSBF). // MAPHEI: Map height(16 - bit, LSBF). // MAPDAT: Map data, 16 bits per cell( LSBF ) for MAPWID* MAPHEI cells, cells are in LRTB order. MapWidth = reader.ReadUInt16(); MapHeight = reader.ReadUInt16(); MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight)); for (int i = 0; i < MapHeight; ++i) { for (int j = 0; j < MapWidth; ++j) { MapData.SetU8At(i * MapWidth + j, (byte)reader.ReadUInt16()); } } } } if (blockID == charDataBlockID) { // Character data block // CHARCNT: Character image count minus one( 16 - bit, LSBF ). NumChars = reader.ReadUInt16() + 1; // CHARDAT : Character image data( eight bytes / rows per image for CHARCNT images, rows are in TB order ). for (int charIndex = 0; charIndex < NumChars; ++charIndex) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(); newChar.Color = CustomColor; reader.ReadBlock(newChar.Data, 8); Characters.Add(newChar); } if (!tileSysEnabled) { if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); newChar.Color = CustomColor; Characters.Add(newChar); } } } } else if (blockID == charAttributeBlockID) { // char attributes // BLKMARK: Block marker(0xDA, 0xB1). // CHARATTS: Char attribute data, one byte per char image for CHARCNT images, low nybble = colour, high nybble = material. // nb.colours are only stored when the colouring mode is "per character". for (int charIndex = 0; charIndex < NumChars; ++charIndex) { if (TileColorMode == ColorMode.PER_CHAR) { Characters[charIndex].Color = reader.ReadUInt8() & 0x0f; if (!tileSysEnabled) { Tiles[charIndex].ColorData.SetU8At(0, (byte)Characters[charIndex].Color); } } } } } return(true); }
private bool LoadVersion5(GR.Memory.ByteBuffer Data) { BackgroundColor = Data.ByteAt(4); MultiColor1 = Data.ByteAt(5); MultiColor2 = Data.ByteAt(6); CustomColor = Data.ByteAt(7); TileColorMode = (ColorMode)Data.ByteAt(8); byte flags = Data.ByteAt(9); bool noTiles = ((flags & 0x01) == 0); DisplayModeFile = DisplayMode.HIRES; if ((flags & 0x04) != 0) { DisplayModeFile = DisplayMode.MULTICOLOR; } bool isExpanded = ((flags & 0x02) != 0); NumChars = Data.UInt16At(10) + 1; NumTiles = Data.UInt16At(12) + 1; TileWidth = Data.ByteAt(14); TileHeight = Data.ByteAt(15); MapWidth = Data.UInt16At(16); MapHeight = Data.UInt16At(18); if (noTiles) { // fake tiles TileWidth = 1; TileHeight = 1; NumTiles = 256; } int headerSize = 20; int offsetToCharData = headerSize; int offsetToCharAttribs = offsetToCharData + NumChars * 8; int offsetToTileData = offsetToCharAttribs + NumChars; int offsetToTileColors = offsetToTileData + NumTiles * TileWidth * TileHeight * 2; if ((isExpanded) || (noTiles)) { offsetToTileColors = offsetToTileData; } int offsetToMapData = offsetToTileColors + NumTiles; if ((TileColorMode != ColorMode.PER_TILE) || (noTiles)) { offsetToMapData = offsetToTileColors; } // char_data/char_attribs for (int charIndex = 0; charIndex < NumChars; ++charIndex) { SingleChar newChar = new SingleChar(); newChar.Data = Data.SubBuffer(offsetToCharData + charIndex * 8, 8); if (TileColorMode == ColorMode.PER_CHAR) { newChar.Color = Data.ByteAt(offsetToCharAttribs + charIndex) & 0x0f; } else { newChar.Color = CustomColor; } Characters.Add(newChar); } // tile_data if (noTiles) { for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.CharData.SetU16At(0, (ushort)i); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); tile.ColorData.SetU8At(0, (byte)CustomColor); Tiles.Add(tile); } if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); if (TileColorMode == ColorMode.PER_CHAR) { newChar.Color = Data.ByteAt(offsetToCharAttribs + i) & 0x0f; } else { newChar.Color = CustomColor; } Characters.Add(newChar); } } } else { for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); Tiles.Add(tile); } if (isExpanded) { byte curCharIndex = 0; for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, curCharIndex); ++curCharIndex; } } } else { // tile_data. Size = NUM_TILES * TILE_WIDTH * TILE_HEIGHT bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded") for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, Data.UInt16At(offsetToTileData + i * TileWidth * TileHeight * 2 + j * 2)); } } } } // TILE_COLOURS. Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile) if (TileColorMode == ColorMode.PER_TILE) { for (int i = 0; i < NumTiles; ++i) { for (int y = 0; y < TileHeight; ++y) { for (int x = 0; x < TileWidth; ++x) { Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetToTileColors + i) & 0x0f)); } } } } else if (TileColorMode == ColorMode.PER_CHAR) { // with V5 this actually means per character for (int i = 0; i < NumTiles; ++i) { for (int y = 0; y < TileHeight; ++y) { for (int x = 0; x < TileWidth; ++x) { byte charColor = (byte)Characters[Tiles[i].CharData.ByteAt(2 * (x + y * TileWidth))].Color; Tiles[i].ColorData.SetU8At(x + y * TileWidth, charColor); } } } } else if (TileColorMode == ColorMode.GLOBAL) { for (int i = 0; i < NumTiles; ++i) { for (int y = 0; y < TileHeight; ++y) { for (int x = 0; x < TileWidth; ++x) { Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)CustomColor); } } } } /* * else if ( TileColorMode == ColorMode.PER_TILE_CELL ) * { * for ( int i = 0; i < NumTiles; ++i ) * { * for ( int y = 0; y < TileHeight; ++y ) * { * for ( int x = 0; x < TileWidth; ++x ) * { * Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight ) & 0x0f ) ); * } * } * } * }*/ // MAP_DATA. Size = MAP_WID x MAP_HEI bytes. // tile indices are now 16 bit! for now force 8bit //MapData = Data.SubBuffer( offsetMapData, MapWidth * MapHeight * 2 ); MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight)); for (int i = 0; i < MapHeight; ++i) { for (int j = 0; j < MapWidth; ++j) { MapData.SetU8At(i * MapWidth + j, Data.ByteAt(offsetToMapData + 2 * (i * MapWidth + j))); } } return(true); }
private bool LoadVersion7(GR.Memory.ByteBuffer Data) { BackgroundColor = Data.ByteAt(4); MultiColor1 = Data.ByteAt(5); MultiColor2 = Data.ByteAt(6); BackgroundColor4 = Data.ByteAt(7); CustomColor = Data.ByteAt(8); TileColorMode = (ColorMode)Data.ByteAt(9); CharsetMode = (TextMode)Data.ByteAt(10); byte flags = Data.ByteAt(11); bool tileSysEnabled = ((flags & 0x01) != 0); ushort charDataBlockID = 0xdab0; ushort charAttributeBlockID = 0xdab1; ushort mapDataBlockID = 0xdab2; if (!tileSysEnabled) { // fake tiles (one per char) TileWidth = 1; TileHeight = 1; NumTiles = 256; for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.CharData.SetU16At(0, (ushort)i); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); tile.ColorData.SetU8At(0, (byte)CustomColor); Tiles.Add(tile); } } var reader = Data.MemoryReader(); reader.Skip(12); while (reader.DataAvailable) { ushort blockID = reader.ReadUInt16NetworkOrder(); if (blockID == mapDataBlockID) { if (tileSysEnabled) { // Tile data block // TILECNT: Tile count minus one(16 - bit, LSBF). NumTiles = reader.ReadUInt16() + 1; // TILEWID: Tile width( byte). TileWidth = reader.ReadUInt8(); // TILEHEI: Tile height( byte). TileHeight = reader.ReadUInt8(); // TILEDAT: Tile data, 16 bits per tile cell( LSBF) for TILEWID* TILEHEI cells * TILECNT items, cells are in LRTB order. for (int i = 0; i < NumTiles; ++i) { Tile tile = new Tile(); tile.CharData.Resize((uint)(TileWidth * TileHeight * 2)); tile.ColorData.Resize((uint)(TileWidth * TileHeight)); Tiles.Add(tile); } if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); Characters.Add(newChar); } } for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, reader.ReadUInt16()); } } } else { // BLKMARK : Block marker (0xDA, 0xBn). // MAPWID: Map Width(16 - bit, LSBF). // MAPHEI: Map height(16 - bit, LSBF). // MAPDAT: Map data, 16 bits per cell( LSBF ) for MAPWID* MAPHEI cells, cells are in LRTB order. MapWidth = reader.ReadUInt16(); MapHeight = reader.ReadUInt16(); MapData = new GR.Memory.ByteBuffer((uint)(MapWidth * MapHeight)); for (int i = 0; i < MapHeight; ++i) { for (int j = 0; j < MapWidth; ++j) { MapData.SetU8At(i * MapWidth + j, (byte)reader.ReadUInt16()); } } } } if (blockID == charDataBlockID) { // Character data block // CHARCNT: Character image count minus one( 16 - bit, LSBF ). NumChars = reader.ReadUInt16() + 1; // CHARDAT : Character image data( eight bytes / rows per image for CHARCNT images, rows are in TB order ). for (int charIndex = 0; charIndex < NumChars; ++charIndex) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(); newChar.Color = CustomColor; reader.ReadBlock(newChar.Data, 8); Characters.Add(newChar); } if (!tileSysEnabled) { if (NumChars < 256) { // add all chars for safety reasons for (int i = NumChars; i < 256; ++i) { SingleChar newChar = new SingleChar(); newChar.Data = new GR.Memory.ByteBuffer(8); newChar.Color = CustomColor; Characters.Add(newChar); } } } } else if (blockID == charAttributeBlockID) { // char attributes // BLKMARK: Block marker(0xDA, 0xB1). // CHARATTS: Char attribute data, one byte per char image for CHARCNT images, low nybble = colour, high nybble = material. // nb.colours are only stored when the colouring mode is "per character". for (int charIndex = 0; charIndex < NumChars; ++charIndex) { if (TileColorMode == ColorMode.PER_TILE_CELL) { Characters[charIndex].Color = reader.ReadUInt8() & 0x0f; if (!tileSysEnabled) { Tiles[charIndex].ColorData.SetU8At(0, (byte)Characters[charIndex].Color); } } } } } /* * * * int headerSize = 20; * int offsetToCharData = headerSize; * int offsetToCharAttribs = offsetToCharData + NumChars * 8; * int offsetToTileData = offsetToCharAttribs + NumChars; * int offsetToTileColors = offsetToTileData + NumTiles * TileWidth * TileHeight * 2; * if ( ( tileSysEnabled ) || ( noTiles ) ) ||{ ||offsetToTileColors = offsetToTileData; ||} ||int offsetToMapData = offsetToTileColors + NumTiles; ||if ( ( TileColorMode != ColorMode.PER_TILE ) || ( noTiles ) ) ||{ ||offsetToMapData = offsetToTileColors; ||} || ||// tile_data ||if ( noTiles ) ||{ ||for ( int i = 0; i < NumTiles; ++i ) ||{ || Tile tile = new Tile(); || || tile.CharData.Resize( (uint)( TileWidth * TileHeight * 2 ) ); || tile.CharData.SetU16At( 0, (ushort)i ); || || tile.ColorData.Resize( (uint)( TileWidth * TileHeight ) ); || tile.ColorData.SetU8At( 0, (byte)CustomColor ); || || Tiles.Add( tile ); ||} ||if ( NumChars < 256 ) ||{ || // add all chars for safety reasons || for ( int i = NumChars; i < 256; ++i ) || { || SingleChar newChar = new SingleChar(); || newChar.Data = new GR.Memory.ByteBuffer( 8 ); || if ( TileColorMode == ColorMode.PER_TILE_CELL ) || { || newChar.Color = Data.ByteAt( offsetToCharAttribs + i ) & 0x0f; || } || else || { || newChar.Color = CustomColor; || } || || Characters.Add( newChar ); || } ||} ||} ||else ||{ ||for ( int i = 0; i < NumTiles; ++i ) ||{ || Tile tile = new Tile(); || || tile.CharData.Resize( (uint)( TileWidth * TileHeight * 2 ) ); || tile.ColorData.Resize( (uint)( TileWidth * TileHeight ) ); || || Tiles.Add( tile ); ||} || ||if ( tileSysEnabled ) ||{ || byte curCharIndex = 0; || for ( int i = 0; i < NumTiles; ++i ) || { || for ( int j = 0; j < TileWidth * TileHeight; ++j ) || { || Tiles[i].CharData.SetU16At( j * 2, curCharIndex ); ++curCharIndex; || } || } ||} ||else ||{ || // tile_data. Size = NUM_TILES * TILE_WIDTH * TILE_HEIGHT bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded") || for ( int i = 0; i < NumTiles; ++i ) || { || for ( int j = 0; j < TileWidth * TileHeight; ++j ) || { || Tiles[i].CharData.SetU16At( j * 2, Data.UInt16At( offsetToTileData + i * TileWidth * TileHeight * 2 + j * 2 ) ); || } || } ||} ||} || ||// TILE_COLOURS. Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile) ||if ( TileColorMode == ColorMode.PER_TILE ) ||{ ||for ( int i = 0; i < NumTiles; ++i ) ||{ || for ( int y = 0; y < TileHeight; ++y ) || { || for ( int x = 0; x < TileWidth; ++x ) || { || Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetToTileColors + i ) & 0x0f ) ); || } || } ||} ||} ||else if ( TileColorMode == ColorMode.PER_TILE_CELL ) ||{ ||// with V5 this actually means per character ||for ( int i = 0; i < NumTiles; ++i ) ||{ || for ( int y = 0; y < TileHeight; ++y ) || { || for ( int x = 0; x < TileWidth; ++x ) || { || byte charColor = (byte)Characters[Tiles[i].CharData.ByteAt( 2 * ( x + y * TileWidth ) )].Color; || Tiles[i].ColorData.SetU8At( x + y * TileWidth, charColor ); || } || } ||} ||} ||else if ( TileColorMode == ColorMode.GLOBAL ) ||{ ||for ( int i = 0; i < NumTiles; ++i ) ||{ || for ( int y = 0; y < TileHeight; ++y ) || { || for ( int x = 0; x < TileWidth; ++x ) || { || Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)CustomColor ); || } || } ||} ||} ||else if ( TileColorMode == ColorMode.PER_TILE_CELL ) ||{ ||for ( int i = 0; i < NumTiles; ++i ) ||{ || for ( int y = 0; y < TileHeight; ++y ) || { || for ( int x = 0; x < TileWidth; ++x ) || { || Tiles[i].ColorData.SetU8At( x + y * TileWidth, (byte)( Data.ByteAt( offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight ) & 0x0f ) ); || } || } ||} ||} || */ return(true); }