private void SaveTilemapButton_Click(object sender, EventArgs e) { // Create a new resource int tilemapAddress = Convert.ToInt32(TilemapAddress.Text, 16); int width = Convert.ToInt32(Width.Text); int height = Convert.ToInt32(Height.Text); Resource resource = new Resource() { Name = "Tile Editor Map", Length = width * height, FileType = ResourceType.tilemap, StartAddress = tilemapAddress }; // if this resource is already in the list of resource Resource oldRes = resCheckerRef.Find(ResourceType.tilemap, tilemapAddress); resCheckerRef.Items.Remove(oldRes); resCheckerRef.Add(resource); AssetWindow.Instance.UpdateAssets(); }
private unsafe void ConvertBitmapToRaw(Bitmap bitmap, ResourceChecker.Resource resource, byte lutIndex, int stride, int maxHeight) { if (ResChecker.Add(resource)) { // Load LUT from memory - ignore indexes 0 and 1 int lutBaseAddress = MemoryLocations.MemoryMap.GRP_LUT_BASE_ADDR + lutIndex * 0x400 - MemoryLocations.MemoryMap.VICKY_BASE_ADDR; // Limit how much data is imported based on the type of image int importedLines = maxHeight < bitmap.Height ? maxHeight : bitmap.Height; int importedCols = stride < bitmap.Width ? stride : bitmap.Width; byte[] data = new byte[stride * importedLines]; // the bitmap is based on resolution of the machine resource.Length = stride * bitmap.Height; // one byte per pixel - palette is separate Rectangle rect = new Rectangle(0, 0, bitmap.Width, bitmap.Height); BitmapData bitmapData = bitmap.LockBits(rect, ImageLockMode.ReadOnly, bitmap.PixelFormat); int bytesPerPixel = bitmapData.Stride / bitmap.Width; byte * bitmapPointer = (byte *)bitmapData.Scan0.ToPointer(); bool tooManyColours = false; bool done = false; byte mask = 0xFF; List <int> lut = null; while (!done && mask != 0xc0) { int transparentColor = 0; try { transparentColor = Convert.ToInt32(textTransparentColor.Text, 16) & ((mask << 16) + (mask << 8) + mask); } finally { } done = true; // Reset the Lookup Table lut = new List <int>(256) { // Always add black (transparent) and white 0, 0xFFFFFF }; // The user may decide to overwrite the palette from this bitmap if (!checkOverwriteLUT.Checked) { for (int i = 2; i < 256; i++) { int value = MemMgrRef.VICKY.ReadLong(lutBaseAddress + 4 * i); if (value != 0) { lut.Add(value); } else { break; } } } for (int line = 0; line < importedLines; line++) { for (int col = 0; col < importedCols; col++) { byte b = 0; byte r = 0; byte g = 0; switch (bytesPerPixel) { case 1: byte palIndex = bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel]; System.Drawing.Color palValue = bitmap.Palette.Entries[palIndex]; b = (byte)(palValue.B & mask); g = (byte)(palValue.G & mask); r = (byte)(palValue.R & mask); break; case 2: ushort wordValue = (ushort)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel] + bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel + 1] * 256); b = (byte)(wordValue & 0x1F); // 5bits g = (byte)((wordValue >> 5) & 0x3F); // 6 bits r = (byte)(wordValue >> 11); // 5 bits break; case 3: b = (byte)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel] & mask); g = (byte)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel + 1] & mask); r = (byte)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel + 2] & mask); break; case 4: b = (byte)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel] & mask); g = (byte)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel + 1] & mask); r = (byte)(bitmapPointer[line * bitmapData.Stride + col * bytesPerPixel + 2] & mask); //alpha is ignored break; } int rgb = b + g * 256 + r * 256 * 256; // Check if the RBG matches the transparent color int index = 0; if (rgb != transparentColor) { // if not, look in the LUT index = lut.IndexOf(rgb); } // If the index is undefined, add a new entry if (index == -1) { if (lut.Count < 256) { lut.Add(rgb); index = (byte)lut.IndexOf(rgb); } else { tooManyColours = true; break; } } if (index != -1) { data[line * stride + col] = (byte)index; } } if (tooManyColours) { // TODO should use a colour histogram to count how many times a colour is used and then decimate here, based on low usage. done = false; tooManyColours = false; mask <<= 1; break; } } } if (mask != 0xc0) { int videoAddress = resource.StartAddress - 0xB0_0000; MemMgrRef.VIDEO.CopyBuffer(data, 0, videoAddress, data.Length); if (lut != null) { for (int i = 0; i < lut.Count; i++) { int rbg = lut[i]; MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i, LowByte(rbg)); MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 1, MidByte(rbg)); MemMgrRef.VICKY.WriteByte(lutBaseAddress + 4 * i + 2, HighByte(rbg)); } } // Check if a LUT matching our index is present in the Resources, if so don't do anything. Resource resLut = ResChecker.Find(ResourceType.lut, lutBaseAddress + MemoryLocations.MemoryMap.VICKY_BASE_ADDR); if (resLut == null) { Resource lutPlaceholder = new Resource { Length = 0x400, FileType = ResourceType.lut, Name = "Generated LUT", StartAddress = lutBaseAddress + MemoryLocations.MemoryMap.VICKY_BASE_ADDR }; ResChecker.Add(lutPlaceholder); } } else { MessageBox.Show("An error occured converting the image colors to LUT.\n" + "You can try loading the image with a different LUT or\n" + "Zero one of the LUTs or\n" + "Check the Overwrite Existing LUT checkbox"); ResChecker.Items.Remove(resource); resource.Length = -1; } } else { resource.Length = -1; } }