public int ImageToMCBitmapData(Dictionary <int, List <ColorMappingTarget> > ForceBitPattern, List <Formats.CharData> Chars, bool[,] ErrornousBlocks, out GR.Memory.ByteBuffer bitmapData, out GR.Memory.ByteBuffer screenChar, out GR.Memory.ByteBuffer screenColor) { int numErrors = 0; Dictionary <int, GR.Collections.Set <ColorMappingTarget> > usedPatterns = new Dictionary <int, GR.Collections.Set <ColorMappingTarget> >(); screenChar = new GR.Memory.ByteBuffer((uint)(BlockWidth * BlockHeight)); screenColor = new GR.Memory.ByteBuffer((uint)(BlockWidth * BlockHeight)); bitmapData = new GR.Memory.ByteBuffer((uint)(8 * BlockWidth * BlockHeight)); 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 < BlockHeight; ++y) { for (int x = 0; x < BlockWidth; ++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 < 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]); switch (recommendedPattern[colorIndex]) { case ColorMappingTarget.BITS_01: { // upper screen char nibble byte value = screenChar.ByteAt(x + y * BlockWidth); value &= 0x0f; value |= (byte)(colorIndex << 4); screenChar.SetU8At(x + y * BlockWidth, value); } break; case ColorMappingTarget.BITS_10: { // lower nibble in screen char byte value = screenChar.ByteAt(x + y * BlockWidth); value &= 0xf0; value |= (byte)(colorIndex); screenChar.SetU8At(x + y * BlockWidth, value); } break; case ColorMappingTarget.BITS_11: // color ram screenColor.SetU8At(x + y * BlockWidth, colorIndex); break; } continue; } if (!usedPatterns.ContainsKey(colorIndex)) { usedPatterns.Add(colorIndex, new GR.Collections.Set <ColorMappingTarget>()); } switch (colorTarget) { case 0: usedPatterns[colorIndex].Add(ColorMappingTarget.BITS_01); break; case 1: usedPatterns[colorIndex].Add(ColorMappingTarget.BITS_10); break; case 2: usedPatterns[colorIndex].Add(ColorMappingTarget.BITS_11); break; } if (colorTarget == 0) { // upper screen char nibble byte value = screenChar.ByteAt(x + y * BlockWidth); value &= 0x0f; value |= (byte)(colorIndex << 4); screenChar.SetU8At(x + y * BlockWidth, value); usedColors[colorIndex] = ColorMappingTarget.BITS_01; } else if (colorTarget == 1) { // lower nibble in screen char byte value = screenChar.ByteAt(x + y * BlockWidth); value &= 0xf0; value |= (byte)(colorIndex); screenChar.SetU8At(x + y * BlockWidth, value); usedColors[colorIndex] = ColorMappingTarget.BITS_10; } else if (colorTarget == 2) { // color ram screenColor.SetU8At(x + y * BlockWidth, colorIndex); usedColors[colorIndex] = ColorMappingTarget.BITS_11; } ++colorTarget; } } // write out bits 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 * BlockWidth + 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); }
private bool LoadVersion4(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); MultiColor = (Data.ByteAt(9) != 0); NumChars = Data.UInt16At(10) + 1; NumTiles = Data.ByteAt(12) + 1; TileWidth = Data.ByteAt(13); TileHeight = Data.ByteAt(14); MapWidth = Data.UInt16At(15); MapHeight = Data.UInt16At(17); bool isExpanded = (Data.ByteAt(19) != 0); int offsetToCharAttribs = 24 + NumChars * 8; for (int charIndex = 0; charIndex < NumChars; ++charIndex) { SingleChar newChar = new SingleChar(); newChar.Data = Data.SubBuffer(24 + charIndex * 8, 8); newChar.Color = Data.ByteAt(offsetToCharAttribs + charIndex) & 0x0f; Characters.Add(newChar); } 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 { // CELL_DATA. Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded") int offsetCellData = 24 + NumChars * 8 + NumChars; for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, Data.UInt16At(offsetCellData + i * TileWidth * TileHeight * 2 + j * 2)); } } } // CELL_ATTRIBS. Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes (exists for ALL modes) int offsetCellAttribs = 24 + NumChars * 8 + NumChars; if (!isExpanded) { offsetCellAttribs += NumTiles * TileWidth * TileHeight * 2; } for (int i = 0; i < NumTiles; ++i) { for (int y = 0; y < TileHeight; ++y) { for (int x = 0; x < TileWidth; ++x) { if (TileColorMode == ColorMode.PER_TILE_CELL) { Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight) & 0x0f)); } else { Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)CustomColor); } } } } // TILE_ATTRIBS. Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile) int offsetTileAttribs = offsetCellAttribs + NumTiles * TileWidth * TileHeight; 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(offsetTileAttribs + i) & 0x0f)); } } } } /* * 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. int offsetMapData = offsetTileAttribs; if (TileColorMode == ColorMode.PER_TILE) { offsetMapData += NumTiles; } MapData = Data.SubBuffer(offsetMapData, MapWidth * MapHeight); return(true); }
public bool ReadFromBuffer(GR.Memory.ByteBuffer DataIn) { if (DataIn == null) { return(false); } SpriteLayers.Clear(); GR.IO.MemoryReader memIn = DataIn.MemoryReader(); GR.Memory.ByteBuffer header = new GR.Memory.ByteBuffer(); if (memIn.ReadBlock(header, 9) != 9) { return(false); } if ((header.ByteAt(0) != 0x53) || (header.ByteAt(1) != 0x50) || (header.ByteAt(2) != 0x44)) { // no SPD return(false); } NumSprites = header.ByteAt(4) + 1; int numAnims = header.ByteAt(5) + 1; BackgroundColor = header.ByteAt(6); MultiColor1 = header.ByteAt(7); MultiColor2 = header.ByteAt(8); Sprites = new List <SpriteData>(); GR.Memory.ByteBuffer tempData = new GR.Memory.ByteBuffer(); for (int i = 0; i < NumSprites; ++i) { Sprites.Add(new SpriteData()); PaletteManager.ApplyPalette(Sprites[i].Image); tempData.Clear(); memIn.ReadBlock(tempData, 63); tempData.CopyTo(Sprites[i].Data, 0, 63); Sprites[i].Color = memIn.ReadUInt8(); Sprites[i].Multicolor = (((Sprites[i].Color) & 0x80) != 0); Sprites[i].Color &= 0x0f; } if (numAnims > 0) { GR.Memory.ByteBuffer animFrom = new GR.Memory.ByteBuffer(); GR.Memory.ByteBuffer animTo = new GR.Memory.ByteBuffer(); GR.Memory.ByteBuffer animNumFrames = new GR.Memory.ByteBuffer(); GR.Memory.ByteBuffer animAttributes = new GR.Memory.ByteBuffer(); memIn.ReadBlock(animFrom, (uint)numAnims); memIn.ReadBlock(animTo, (uint)numAnims); memIn.ReadBlock(animNumFrames, (uint)numAnims); memIn.ReadBlock(animAttributes, (uint)numAnims); } UsedSprites = (uint)NumSprites; return(true); }
public int ImageToHiresBitmapData(List <Formats.CharData> Chars, bool[,] ErrornousBlocks, out GR.Memory.ByteBuffer bitmapData, out GR.Memory.ByteBuffer screenChar, out GR.Memory.ByteBuffer screenColor) { int numErrors = 0; screenChar = new GR.Memory.ByteBuffer((uint)(BlockWidth * BlockHeight)); screenColor = new GR.Memory.ByteBuffer((uint)(BlockWidth * BlockHeight)); bitmapData = new GR.Memory.ByteBuffer((uint)(8 * BlockWidth * BlockHeight)); GR.Collections.Map <byte, byte> usedColors = new GR.Collections.Map <byte, byte>(); for (int y = 0; y < BlockHeight; ++y) { for (int x = 0; x < BlockWidth; ++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 * BlockWidth); value &= 0x0f; value |= (byte)(colorIndex << 4); screenChar.SetU8At(x + y * BlockWidth, value); usedColors[colorIndex] = 1; firstColorIndex = colorIndex; } else if (colorTarget == 1) { // lower nibble in screen char byte value = screenChar.ByteAt(x + y * BlockWidth); value &= 0xf0; value |= (byte)(colorIndex); screenChar.SetU8At(x + y * BlockWidth, 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 * BlockWidth * 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 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); }
public override bool Load(string Filename) { _LastError = ""; GR.Memory.ByteBuffer diskData = GR.IO.File.ReadAllBytes(Filename); if (diskData == null) { _LastError = "Could not open/read file"; return(false); } /* * 35 track, no errors 174848 * 35 track, 683 error bytes 175531 * 40 track, no errors 196608 * 40 track, 768 error bytes 197376 */ if ((diskData.Length != 174848) && (diskData.Length != 175531) && (diskData.Length != 196608) && (diskData.Length != 197376)) { _LastError = "disk image size is not supported"; return(false); } switch (diskData.Length) { case 174848: case 175531: CreateEmptyMedia(); break; case 196608: case 197376: CreateEmptyMedia40Tracks(); break; } int dataPos = 0; for (int i = 0; i < Tracks.Count; ++i) { for (int j = 0; j < Tracks[i].Sectors.Count; ++j) { diskData.CopyTo(Tracks[i].Sectors[j].Data, dataPos, 256); dataPos += 256; } } for (int i = 0; i < Tracks.Count; ++i) { for (int j = 0; j < Tracks[i].Sectors.Count; ++j) { Tracks[i].Sectors[j].Free = !IsSectorMarkedAsUsedInBAM(i + 1, j); } } if ((diskData.Length == 175531) || (diskData.Length == 197376)) { // error info appended for (int i = 0; i < Tracks.Count; ++i) { for (int j = 0; j < Tracks[i].Sectors.Count; ++j) { Tracks[i].Sectors[j].SectorErrorCode = diskData.ByteAt(dataPos); ++dataPos; } } } return(true); }
public void SetPixel(int X, int Y, uint Value) { if ((X < 0) || (X >= m_Width) || (Y < 0) || (Y >= m_Height)) { return; } if (m_ImageData.Empty()) { return; } switch (BitsPerPixel) { case 1: unsafe { int pitch = (Width + 7) / 8; byte origValue = m_ImageData.ByteAt(Y * pitch + X / 8); byte newValue = origValue; if (Value != 0) { newValue = (byte)(origValue | (128 >> (X % 8))); } else { newValue = (byte)(origValue & (~(128 >> (X % 8)))); } m_ImageData.SetU8At(Y * pitch + X / 8, newValue); } break; case 4: unsafe { int pitch = Width / 2; byte origValue = m_ImageData.ByteAt(Y * pitch + X / 2); byte newValue = 0; if ((X % 2) == 0) { newValue = (byte)((origValue & 0x0f) | ((byte)Value << 4)); } else { newValue = (byte)((origValue & 0xf0) | (byte)Value); } m_ImageData.SetU8At(Y * pitch + X / 2, newValue); }; break; case 8: m_ImageData.SetU8At(Y * m_Width + X, (byte)Value); break; case 16: m_ImageData.SetU16At(2 * (Y * m_Width + X), (ushort)((((Value & 0xff0000) >> 19) << 10) + (((Value & 0x00ff00) >> 11) << 5) + (((Value & 0x0000ff) >> 3)))); break; case 24: m_ImageData.SetU8At(3 * (Y * m_Width + X) + 0, (byte)(Value & 0xff)); m_ImageData.SetU8At(3 * (Y * m_Width + X) + 1, (byte)((Value & 0xff00) >> 8)); m_ImageData.SetU8At(3 * (Y * m_Width + X) + 2, (byte)((Value & 0xff0000) >> 16)); break; case 32: m_ImageData.SetU32At(4 * (Y * m_Width + X), Value); break; default: throw new NotSupportedException("Bitdepth " + BitsPerPixel + " not supported yet"); } }
public static GR.Image.MemoryImage BitmapFromKoala(GR.Memory.ByteBuffer koala) { byte fullValue; byte value; byte currentColor; int xCooBase = 0; int yCooBase = 0; GR.Image.MemoryImage Image = new GR.Image.MemoryImage(320, 200, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); // Set the palette to the C64 one PaletteManager.ApplyPalette(Image); if (koala.Length >= 10002) { // Last Byte is Background Color and global Byte backgroundColor = koala.ByteAt(10002); for (int y = 0; y < 1000; y++) { // koala has 3 colors which can be selected for ech "cell" (8x8 pixel) byte lowerNibbleColor = (byte)(((((koala.ByteAt(y + 8002)) << 4) & 0xFF) >> 4)); byte upperNibbleColor = (byte)(koala.ByteAt(y + 8002) >> 4); byte colorRamColor = koala.ByteAt(y + 9002); for (int x = 0; x < 8; x++) { fullValue = koala.ByteAt((8 * y) + x + 2); for (int z = 0; z < 4; z++) { value = (byte)(((fullValue << (z * 2)) & 0xFF) >> 6); switch (value) { case 0: currentColor = backgroundColor; break; case 1: currentColor = upperNibbleColor; break; case 2: currentColor = lowerNibbleColor; break; default: currentColor = colorRamColor; break; } Image.SetPixel(((xCooBase * 4) * 2 + (z * 2)), yCooBase * 8 + x, currentColor); // koala is doublepixel, so we repeat it for the right neighbour Image.SetPixel(((xCooBase * 4) * 2 + (z * 2) + 1), yCooBase * 8 + x, currentColor); } } xCooBase++; if (xCooBase == 40) { xCooBase = 0; yCooBase++; } } } return(Image); }
public static string ToASMData(GR.Memory.ByteBuffer Data, bool WrapData, int WrapByteCount, string DataByteDirective, bool AsHex) { StringBuilder sb = new StringBuilder(); if (WrapData) { sb.Append(DataByteDirective); sb.Append(' '); int byteCount = 0; for (int i = 0; i < Data.Length; ++i) { if (AsHex) { sb.Append('$'); sb.Append(Data.ByteAt(i).ToString("x2")); } else { sb.Append(Data.ByteAt(i).ToString()); } ++byteCount; if ((byteCount < WrapByteCount) && (i < Data.Length - 1)) { sb.Append(','); } if (byteCount == WrapByteCount) { byteCount = 0; sb.AppendLine(); if (i < Data.Length - 1) { sb.Append(DataByteDirective); sb.Append(' '); } } } } else { sb.Append(DataByteDirective); sb.Append(' '); for (int i = 0; i < Data.Length; ++i) { if (AsHex) { sb.Append('$'); sb.Append(Data.ByteAt(i).ToString("x2")); } else { sb.Append(Data.ByteAt(i).ToString()); } if (i < Data.Length - 1) { sb.Append(','); } } } return(sb.ToString()); }
public void UpdateValue(string WatchVar, bool IndexedX, bool IndexedY, GR.Memory.ByteBuffer Data) { foreach (ListViewItem item in listWatch.Items) { WatchEntry watchEntry = (WatchEntry)item.Tag; if ((watchEntry.Name == WatchVar) && (watchEntry.IndexedX == IndexedX) && (watchEntry.IndexedY == IndexedY)) { watchEntry.CurrentValue = Data; if (watchEntry.SizeInBytes != watchEntry.CurrentValue.Length) { Debug.Log("Watch entry received different size than expected!"); } if (watchEntry.CurrentValue.Length == 0) { item.SubItems[2].Text = "(unread)"; continue; } switch (watchEntry.Type) { case WatchEntry.DisplayType.HEX: if (watchEntry.DisplayMemory) { StringBuilder sb = new StringBuilder(); sb.Append("$"); if (watchEntry.BigEndian) { for (int i = 0; i < Data.Length; ++i) { sb.Append(Data.ByteAt(i).ToString("x2")); if (i + 1 < Data.Length) { sb.Append(" "); } } } else { for (int i = 0; i < Data.Length; ++i) { sb.Append(Data.ByteAt((int)Data.Length - 1 - i).ToString("x2")); if (i + 1 < Data.Length) { sb.Append(" "); } } } item.SubItems[2].Text = sb.ToString(); } else { item.SubItems[2].Text = "$" + watchEntry.Address.ToString("x4"); } break; case WatchEntry.DisplayType.DEZ: if (!watchEntry.DisplayMemory) { item.SubItems[2].Text = watchEntry.Address.ToString(); } else if (watchEntry.SizeInBytes == 1) { item.SubItems[2].Text = Data.ByteAt(0).ToString(); } else if (watchEntry.BigEndian) { string totalText = ""; for (uint i = 0; i < Data.Length; ++i) { totalText += Data.ByteAt((int)i).ToString("d") + " "; } item.SubItems[2].Text = totalText; } else { string totalText = ""; for (uint i = 0; i < Data.Length; ++i) { totalText += Data.ByteAt((int)Data.Length - 1 - (int)i).ToString("d") + " "; } item.SubItems[2].Text = totalText; } break; case WatchEntry.DisplayType.BINARY: if (!watchEntry.DisplayMemory) { item.SubItems[2].Text = "%" + Convert.ToString(watchEntry.Address, 2); } else if (watchEntry.SizeInBytes == 1) { item.SubItems[2].Text = "%" + Convert.ToString(Data.ByteAt(0), 2); } else if (watchEntry.SizeInBytes == 2) { item.SubItems[2].Text = "%" + Convert.ToString(Data.UInt16At(0), 2); } else { item.SubItems[2].Text = Data.ToString(); } break; default: if (watchEntry.DisplayMemory) { item.SubItems[2].Text = Data.ByteAt(0).ToString(); } else { item.SubItems[2].Text = watchEntry.Address.ToString("x4"); } break; } } } }
private string MnemonicToString(Tiny64.Opcode opcode, GR.Memory.ByteBuffer Data, int DataStartAddress, int CodePos, GR.Collections.Set <ushort> AccessedAddresses, GR.Collections.Map <int, string> NamedLabels) { string output = opcode.Mnemonic.ToLower(); ushort targetAddress = 0; bool twoBytes = true; switch (opcode.Addressing) { case Tiny64.Opcode.AddressingType.IMPLICIT: break; case Tiny64.Opcode.AddressingType.ABSOLUTE: targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress); break; case Tiny64.Opcode.AddressingType.ABSOLUTE_X: targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress); break; case Tiny64.Opcode.AddressingType.ABSOLUTE_Y: targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress); break; case Tiny64.Opcode.AddressingType.IMMEDIATE: targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress); twoBytes = false; break; case Tiny64.Opcode.AddressingType.INDIRECT: targetAddress = Data.UInt16At(CodePos + 1 - DataStartAddress); break; case Tiny64.Opcode.AddressingType.INDIRECT_X: targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress); twoBytes = false; break; case Tiny64.Opcode.AddressingType.INDIRECT_Y: targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress); twoBytes = false; break; case Tiny64.Opcode.AddressingType.RELATIVE: { // int delta = value - lineInfo.AddressStart - 2; sbyte relValue = (sbyte)Data.ByteAt(CodePos + 1 - DataStartAddress); targetAddress = (ushort)(relValue + 2 + CodePos); } break; case Tiny64.Opcode.AddressingType.ZEROPAGE: targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress); twoBytes = false; break; case Tiny64.Opcode.AddressingType.ZEROPAGE_X: targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress); twoBytes = false; break; case Tiny64.Opcode.AddressingType.ZEROPAGE_Y: targetAddress = Data.ByteAt(CodePos + 1 - DataStartAddress); twoBytes = false; break; } string addressPlacement; if (twoBytes) { addressPlacement = "$" + targetAddress.ToString("x4"); } else { addressPlacement = "$" + targetAddress.ToString("x2"); } if (AccessedAddresses.ContainsValue(targetAddress)) { addressPlacement = "label_" + targetAddress.ToString("x4"); } if (NamedLabels.ContainsKey(targetAddress)) { addressPlacement = NamedLabels[targetAddress]; } switch (opcode.Addressing) { case Tiny64.Opcode.AddressingType.IMPLICIT: break; case Tiny64.Opcode.AddressingType.ABSOLUTE: output += " " + addressPlacement; break; case Tiny64.Opcode.AddressingType.ABSOLUTE_X: output += " " + addressPlacement + ", x"; break; case Tiny64.Opcode.AddressingType.ABSOLUTE_Y: output += " " + addressPlacement + ", y"; break; case Tiny64.Opcode.AddressingType.IMMEDIATE: output += " #" + addressPlacement; break; case Tiny64.Opcode.AddressingType.INDIRECT: output += " ( " + addressPlacement + " )"; break; case Tiny64.Opcode.AddressingType.INDIRECT_X: output += " ( " + addressPlacement + ", x)"; break; case Tiny64.Opcode.AddressingType.INDIRECT_Y: output += " ( " + addressPlacement + " ), y"; break; case Tiny64.Opcode.AddressingType.RELATIVE: { // int delta = value - lineInfo.AddressStart - 2; output += " " + addressPlacement; //output += " (" + delta.ToString( "X2" ) + ")"; } break; case Tiny64.Opcode.AddressingType.ZEROPAGE: output += " " + addressPlacement; break; case Tiny64.Opcode.AddressingType.ZEROPAGE_X: output += " " + addressPlacement + ", x"; break; case Tiny64.Opcode.AddressingType.ZEROPAGE_Y: output += " " + addressPlacement + ", y"; break; } return(output); }
bool AddDirectoryEntry(GR.Memory.ByteBuffer Filename, int StartTrack, int StartSector, int SectorsWritten, C64Studio.Types.FileType Type) { _LastError = ""; Track dirTrack = Tracks[TRACK_DIRECTORY - 1]; byte dirTrackIndex = (byte)TRACK_DIRECTORY; int directoryInterleave = 3; int sector = 1; do { Sector sect = dirTrack.Sectors[sector]; for (int i = 0; i < 8; ++i) { if (sect.Data.ByteAt(BYTES_PER_DIR_ENTRY * i + 2) == 0) { // scratched (empty) entry // default set PRG if (i > 0) { // set track/sector of next dir sector sect.Data.SetU8At(0, 0); sect.Data.SetU8At(1, 0); } sect.Data.SetU8At(BYTES_PER_DIR_ENTRY * i + 2, (byte)Type); sect.Data.SetU8At(BYTES_PER_DIR_ENTRY * i + 3, (byte)StartTrack); sect.Data.SetU8At(BYTES_PER_DIR_ENTRY * i + 4, (byte)StartSector); for (int j = 0; j < 16; ++j) { sect.Data.SetU8At(BYTES_PER_DIR_ENTRY * i + 5 + j, Filename.ByteAt(j)); } sect.Data.SetU16At(BYTES_PER_DIR_ENTRY * i + 30, (UInt16)SectorsWritten); return(true); } } // do we need to alloc next dir sector? do { sector = (sector + directoryInterleave) % dirTrack.Sectors.Count; // do NOT write into BAM }while (sector == SECTOR_BAM); if (sector == 1) { // arrived at starting sector, disk full! break; } if (sect.Data.ByteAt(0) == 0) { // current sector was last dir sector sect.Data.SetU8At(0, dirTrackIndex); sect.Data.SetU8At(1, (byte)(sector)); AllocSector(dirTrackIndex, sector); dirTrack.Sectors[sector].Data.SetU8At(0, 0); dirTrack.Sectors[sector].Data.SetU8At(1, 0xff); } }while (true); _LastError = "disk is full"; return(false); }
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 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); MultiColor = ((flags & 0x04) != 0); 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_TILE_CELL) { 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_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 (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_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 ) ); * } * } * } * }*/ // 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); }
public bool LoadFromFile(GR.Memory.ByteBuffer Data) { Characters.Clear(); MapData.Clear(); if ((Data == null) || (Data.Length < 24) || (Data.ByteAt(0) != 'C') || (Data.ByteAt(1) != 'T') || (Data.ByteAt(2) != 'M')) { // not a valid CTM file return(false); } int version = Data.ByteAt(3); if (version != 4) { System.Windows.Forms.MessageBox.Show("Currently only version 4 of Charpad project files is supported. Sorry!", "Unsupported version " + version); return(false); } BackgroundColor = Data.ByteAt(4); MultiColor1 = Data.ByteAt(5); MultiColor2 = Data.ByteAt(6); CustomColor = Data.ByteAt(7); TileColorMode = (ColorMode)Data.ByteAt(8); MultiColor = (Data.ByteAt(9) != 0); NumChars = Data.UInt16At(10) + 1; NumTiles = Data.ByteAt(12) + 1; TileWidth = Data.ByteAt(13); TileHeight = Data.ByteAt(14); MapWidth = Data.UInt16At(15); MapHeight = Data.UInt16At(17); bool isExpanded = (Data.ByteAt(19) != 0); int offsetToCharAttribs = 24 + NumChars * 8; for (int charIndex = 0; charIndex < NumChars; ++charIndex) { SingleChar newChar = new SingleChar(); newChar.Data = Data.SubBuffer(24 + charIndex * 8, 8); newChar.Color = Data.ByteAt(offsetToCharAttribs + charIndex) & 0x0f; Characters.Add(newChar); } 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 { // CELL_DATA. Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes * 2 bytes. (only exists if CHAR_DATA is not "Expanded") int offsetCellData = 24 + NumChars * 8 + NumChars; for (int i = 0; i < NumTiles; ++i) { for (int j = 0; j < TileWidth * TileHeight; ++j) { Tiles[i].CharData.SetU16At(j * 2, Data.UInt16At(offsetCellData + i * TileWidth * TileHeight * 2 + j * 2)); } } } // CELL_ATTRIBS. Size = NUM_TILES * TILE_SIZE * TILE_SIZE bytes (exists for ALL modes) int offsetCellAttribs = 24 + NumChars * 8 + NumChars; if (!isExpanded) { offsetCellAttribs += NumTiles * TileWidth * TileHeight * 2; } for (int i = 0; i < NumTiles; ++i) { for (int y = 0; y < TileHeight; ++y) { for (int x = 0; x < TileWidth; ++x) { if (TileColorMode == ColorMode.PER_TILE_CELL) { Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)(Data.ByteAt(offsetCellAttribs + i * TileWidth * TileHeight + x + y * TileHeight) & 0x0f)); } else { Tiles[i].ColorData.SetU8At(x + y * TileWidth, (byte)CustomColor); } } } } // TILE_ATTRIBS. Size = NUM_TILES bytes (1 byte per tile = "RAM colour". only exists if COLOR_MODE = 1 (Per Tile) int offsetTileAttribs = offsetCellAttribs + NumTiles * TileWidth * TileHeight; 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(offsetTileAttribs + i) & 0x0f)); } } } } /* * 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. int offsetMapData = offsetTileAttribs; if (TileColorMode == ColorMode.PER_TILE) { offsetMapData += NumTiles; } MapData = Data.SubBuffer(offsetMapData, MapWidth * MapHeight); 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 = (Types.CharsetMode)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); }
public override bool Load(string Filename) { _LastError = ""; Clear(); GR.Memory.ByteBuffer data = GR.IO.File.ReadAllBytes(Filename); if (data == null) { _LastError = "could not open/read file"; return(false); } if (data.Length < 64) { _LastError = "file size is too small"; return(false); } // Tape Header // 0 32 DOS tape description + EOF (for type) // 32 2 tape version ($0200) // 34 2 number of directory entries // 36 2 number of used entries (can be 0 in my loader) // 38 2 free // 40 24 user description as displayed in tape menu for (int i = 0; i < 32; ++i) { if (data.ByteAt(i) == (char)0x1a) { break; } TapeInfo.Description += (char)data.ByteAt(i); } ushort version = data.UInt16At(32); /* * if ( version != 0x0200 ) * { * return false; * }*/ TapeInfo.NumberEntries = data.UInt16At(34); TapeInfo.NumberUsedEntries = data.UInt16At(36); for (int i = 0; i < 24; ++i) { if (data.ByteAt(40 + i) == (char)0x20) { break; } TapeInfo.UserDescription += (char)data.ByteAt(i); } int entryPos = 64; for (int i = 0; i < TapeInfo.NumberEntries; ++i) { // File Header // Offset Size Description // 0 1 entry type (see below) // 1 1 C64 file type // 2 2 start address // 4 2 end address // 6 2 free // 8 4 offset of file contents start within T64 file // 12 4 free // 16 16 C64 file name // Code Explanation // 0 free entry // 1 normal tape file // 2 tape file with header: header is saved just before file data // 3 memory snapshot v0.9, uncompressed // 4 tape block // 5 digitized stream // 6 ... 255 reserved FileRecord file = new FileRecord(); file.EntryType = data.ByteAt(entryPos + 0); if ((file.EntryType != 1) && (file.EntryType != 0)) { // unsupported type! _LastError = "unsupported entry type"; return(false); } if (file.EntryType == 0) { FileRecords.Add(file); FileDatas.Add(new GR.Memory.ByteBuffer()); entryPos += 32; continue; } file.C64FileType = (C64Studio.Types.FileType)data.ByteAt(entryPos + 1); file.StartAddress = data.UInt16At(entryPos + 2); file.EndAddress = data.UInt16At(entryPos + 4); file.FileOffset = data.UInt32At(entryPos + 8); for (int j = 0; j < 16; ++j) { file.Filename.AppendU8(data.ByteAt(entryPos + 16 + j)); } FileRecords.Add(file); FileDatas.Add(data.SubBuffer((int)file.FileOffset, (int)(file.EndAddress - file.StartAddress))); entryPos += 32; } return(true); }
public override float ReadF32() { if (m_Buffer == null) { return(0.0f); } if (m_Position + 4 > m_Buffer.Length) { return(0.0f); } System.UInt32 ui32 = (uint)m_Buffer.ByteAt(m_Position); ui32 |= ((uint)m_Buffer.ByteAt(m_Position + 1) << 8); ui32 |= ((uint)m_Buffer.ByteAt(m_Position + 2) << 16); ui32 |= ((uint)m_Buffer.ByteAt(m_Position + 3) << 24); m_Position += 4; return(System.BitConverter.ToSingle(System.BitConverter.GetBytes(ui32), 0)); }
public override float ReadF32() { if (m_Buffer == null) { return(0.0f); } if (m_Position + 4 > m_Buffer.Length) { return(0.0f); } System.UInt32 ui32 = (uint)m_Buffer.ByteAt(m_Position); ui32 |= ((uint)m_Buffer.ByteAt(m_Position + 1) << 8); ui32 |= ((uint)m_Buffer.ByteAt(m_Position + 2) << 16); ui32 |= ((uint)m_Buffer.ByteAt(m_Position + 3) << 24); m_Position += 4; float Value = System.BitConverter.ToSingle(System.BitConverter.GetBytes(ui32), 0); /* * unsafe * { * Value = *(float*)( &ui32 ); * }*/ return(Value); }