private static void ArrangeSlices(Bitmap bm, List <ImageSlice> slices, List <Palette> palettes, List <GTMPFile.PositionData> posData) { Rectangle lockRect = new Rectangle(0, 0, bm.Width, bm.Height); BitmapData bd = bm.LockBits(lockRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); // docs say this is pixel width, it's a dirty liar. It's the byte width int byteStride = bd.Stride; foreach (GTMPFile.PositionData pd in posData) { int[] colourData = new int[16 * 8]; bool makeTopLeftBlack = false; ushort actualTile = pd.tile; //if ((pd.tile & 0x0800) != 0) //{ // actualTile = (ushort)(pd.tile & ~0x800); // makeTopLeftBlack = true; //} if (pd.palette != 0xFF) { ImageSlice tile = slices[actualTile]; Palette p = palettes[pd.palette]; Color topLeft = p.colours[tile.rect[0]]; for (int i = 0; i < (16 * 8); ++i) { byte colourIndex = tile.rect[i]; Color pixelColour = p.colours[colourIndex]; if (makeTopLeftBlack && (pixelColour == topLeft)) { colourData[i] = Color.Black.ToArgb(); //(int)(pixelColour.ToArgb() & 0x00FFFFFF); } else { colourData[i] = pixelColour.ToArgb(); } } } else { Color blockColour = GTMPFile.MakeColorFromBGR555(actualTile); int colourRGB = blockColour.ToArgb(); for (int i = 0; i < (16 * 8); ++i) { colourData[i] = colourRGB; } } IntPtr scanLineIter = new IntPtr(bd.Scan0.ToInt64() + ((pd.y * byteStride) + (pd.x * 4))); for (int i = 0; i < 8; ++i) { Marshal.Copy(colourData, i * 16, scanLineIter, 16); scanLineIter = new IntPtr(scanLineIter.ToInt64() + bd.Stride); } } bm.UnlockBits(bd); }
static void PlotBitmap(BitmapData bmData, List <int> pixels, List <int> palette) { IntPtr pData = bmData.Scan0; int width = bmData.Width; int numPixels = pixels.Count; List <int> linePixels = new List <int>(bmData.Width); int paletteEntries = palette.Count; int lastColour = 0; for (int i = 0; i < numPixels; ++i) { int paletteIndex = pixels[i]; bool justColour = false; if (paletteIndex > paletteEntries) { Debug.WriteLine(String.Format("Found palette index of {0:x}, there are only {1:x} in the palette", paletteIndex, paletteEntries)); paletteIndex = GTMPFile.MakeColorFromBGR555((ushort)paletteIndex).ToArgb(); justColour = true; } if ((linePixels.Count > 1) && ((linePixels.Count % bmData.Width) == 0)) { Marshal.Copy(linePixels.ToArray(), 0, pData, linePixels.Count); pData = new IntPtr(pData.ToInt64() + (linePixels.Count * 4)); linePixels.Clear(); } //int palColour = palette[paletteIndex]; //int alphaVal = (int)((palColour & 0xFF000000) >> 24); //if (alphaVal != 0x80) //{ // int percentOfThisColour = (int)((alphaVal / 128.0f) * 100); // int blended = BlendColours(palColour, lastColour, percentOfThisColour); // palColour = blended; //} //else //{ // lastColour = palColour; //} linePixels.Add(justColour ? paletteIndex : palette[paletteIndex]); } Marshal.Copy(linePixels.ToArray(), 0, pData, linePixels.Count); }
public static Bitmap Parse(string file) { List <Palette> paletteList = new List <Palette>(); byte[] fileData = File.ReadAllBytes(file); if (Encoding.ASCII.GetString(fileData, 0, 3) != "GM\x3") { return(null); } int[] gmllPositions = FindPattern(fileData, Encoding.ASCII.GetBytes("GMLL"), 4); if (gmllPositions.Length == 0) { return(null); } int gmllPos1 = gmllPositions[0]; List <Rectangle> clickablePos = FindClickRects(fileData, gmllPos1); int numPositionsEntries = BitConverter.ToInt32(fileData, gmllPos1 + 4); // first +4 for GMLL, second 4 for the number of entries int paletteOffset = gmllPos1 + 4 + 4 + (numPositionsEntries * 4); int pixelDataOffset = paletteOffset + 0x404; int numImageBytes = (int)(fileData.Length - pixelDataOffset); byte[] imageArray = new byte[numImageBytes]; Array.Copy(fileData, pixelDataOffset, imageArray, 0, numImageBytes); int palettePosIter = paletteOffset; for (int i = 0; i < 32; ++i) { Palette p = new Palette(); for (int j = 0; j < p.colours.Length; ++j, palettePosIter += 2) { // colours are in BGR format ushort color = BitConverter.ToUInt16(fileData, palettePosIter); Color rgbColor = GTMPFile.MakeColorFromBGR555(color); p.colours[j] = rgbColor; } paletteList.Add(p); } List <ImageSlice> slices = ParseSlices(imageArray); // image positiioning seems to be on an absolute 512x504 canvas even if there's // only enough image data in the file to cover 512x8 Bitmap bm = new Bitmap(512, 504, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(bm)) { g.FillRectangle(Brushes.Black, new Rectangle(0, 0, 512, 504)); } byte[] positionArray = new byte[numPositionsEntries * 4]; Array.Copy(fileData, gmllPos1 + 8, positionArray, 0, positionArray.Length); List <GTMPFile.PositionData> pd = ParsePositionData(positionArray, positionArray.Length); ArrangeSlices(bm, slices, paletteList, pd); if (clickablePos.Count > 0) { using (Graphics g = Graphics.FromImage(bm)) { foreach (Rectangle r in clickablePos) { g.DrawRectangle(Pens.YellowGreen, r); } } } return(bm); }