public void SetPalt(PALT p) { if (this.PaletteID != 0) { var old = Parent.ChunkParent.Get <PALT>(this.PaletteID); if (old != null) { old.References--; } } PaletteID = p.ChunkID; p.References++; }
private void ReplaceSprite(Bitmap[] bmps, int frame) { var pixel = bmps[0]; //first search pixel for the bounding rectangle. var plock = pixel.LockBits(new Rectangle(0, 0, pixel.Width, pixel.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); var pdat = new byte[plock.Stride * plock.Height]; Marshal.Copy(plock.Scan0, pdat, 0, pdat.Length); int maxX = int.MinValue, maxY = int.MinValue, minX = int.MaxValue, minY = int.MaxValue; int index = 0; for (int y = 0; y < pixel.Height; y++) { for (int x = 0; x < pixel.Width; x++) { if (!(pdat[index] == 0 && pdat[index+1] == 255 && pdat[index+2] == 255)) { if (x < minX) minX = x; if (x > maxX) maxX = x; if (y < minY) minY = y; if (y > maxY) maxY = y; } index += 4; } } pixel.UnlockBits(plock); var rect = (minX == int.MaxValue) ? new Rectangle() : new Rectangle(minX, minY, (maxX - minX) + 1, (maxY - minY) + 1); var px = rect.Width * rect.Height; var locks = new BitmapData[3]; var data = new byte[3][]; var pxOut = new Microsoft.Xna.Framework.Color[px]; var depthOut = new byte[px]; for (int i=0; i<3; i++) { locks[i] = bmps[i].LockBits(rect, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); data[i] = new byte[locks[i].Stride * locks[i].Height]; Marshal.Copy(locks[i].Scan0, data[i], 0, data[i].Length); } int scanStart = 0; int dstidx = 0; for (int y=0; y<locks[0].Height; y++) { int srcidx = scanStart; for (int j = 0; j < rect.Width; j++) { pxOut[dstidx] = new Microsoft.Xna.Framework.Color(data[0][srcidx + 2], data[0][srcidx + 1], data[0][srcidx], data[1][srcidx]); depthOut[dstidx] = data[2][srcidx]; srcidx += 4; dstidx++; } scanStart += locks[0].Stride; } //set data first. we also want to get back the a palette we can change PALT targ = null; Microsoft.Xna.Framework.Color[] used; Content.Content.Get().Changes.BlockingResMod(new ResAction(() => { var xnaRect = new Microsoft.Xna.Framework.Rectangle(rect.X, rect.Y, rect.Width, rect.Height); used = GraphicChunk.Frames[frame].SetData(pxOut, depthOut, xnaRect); var ownPalt = GraphicChunk.ChunkParent.Get<PALT>(GraphicChunk.Frames[frame].PaletteID); ushort freePalt = GraphicChunk.ChunkID; if (GraphicChunk.Frames[frame].PaletteID != 0 && ownPalt != null && ownPalt.References == 1) targ = ownPalt; else { var palts = GraphicChunk.ChunkParent.List<PALT>(); palts = (palts == null) ? new List<PALT>() : palts.OrderBy(x => x.ChunkID).ToList(); foreach (var palt in palts) { if (palt.ChunkID == freePalt) freePalt++; if (palt.PalMatch(used) || palt.References == 0) { targ = palt; break; } } } if (targ != null) { //replace existing palt. lock (targ) { if (targ.References == 0 || targ == ownPalt) targ.Colors = used; } Content.Content.Get().Changes.ChunkChanged(targ); GraphicChunk.Frames[frame].SetPalt(targ); } else { //we need to make a new PALT. //a bit hacky for now var nPalt = new PALT() { ChunkID = freePalt, ChunkLabel = GraphicChunk.ChunkLabel + " Auto PALT", AddedByPatch = true, ChunkProcessed = true, ChunkType = "PALT", RuntimeInfo = ChunkRuntimeState.Modified, Colors = used }; GraphicChunk.ChunkParent.AddChunk(nPalt); GraphicChunk.Frames[frame].SetPalt(nPalt); Content.Content.Get().Changes.ChunkChanged(nPalt); } }, GraphicChunk)); for (int i = 0; i < 3; i++) bmps[i].UnlockBits(locks[i]); }
/// <summary> /// Decodes this SPR2Frame. /// </summary> /// <param name="io">An IOBuffer instance used to read a SPR2Frame.</param> private void Decode(IoBuffer io) { var y = 0; var endmarker = false; var hasPixels = (this.Flags & 0x01) == 0x01; var hasZBuffer = (this.Flags & 0x02) == 0x02; var hasAlpha = (this.Flags & 0x04) == 0x04; var numPixels = this.Width * this.Height; if (hasPixels){ this.PixelData = new Color[numPixels]; this.PalData = new byte[numPixels]; } if (hasZBuffer){ this.ZBufferData = new byte[numPixels]; } if (hasAlpha){ this.AlphaData = new byte[numPixels]; } var palette = Parent.ChunkParent.Get<PALT>(this.PaletteID); if (palette == null) palette = new PALT() { Colors = new Color[256] }; palette.References++; var transparentPixel = palette.Colors[TransparentColorIndex]; transparentPixel.A = 0; while (!endmarker) { var marker = io.ReadUInt16(); var command = marker >> 13; var count = marker & 0x1FFF; switch (command) { /** Fill with pixel data **/ case 0x00: var bytes = count; bytes -= 2; var x = 0; while (bytes > 0) { var pxMarker = io.ReadUInt16(); var pxCommand = pxMarker >> 13; var pxCount = pxMarker & 0x1FFF; bytes -= 2; switch (pxCommand) { case 0x01: case 0x02: var pxWithAlpha = pxCommand == 0x02; for (var col = 0; col < pxCount; col++) { var zValue = io.ReadByte(); var pxValue = io.ReadByte(); bytes -= 2; var pxColor = palette.Colors[pxValue]; if (pxWithAlpha) { var alpha = io.ReadByte(); pxColor.A = (byte)(alpha * 8.2258064516129032258064516129032); bytes--; } //this mode draws the transparent colour as solid for some reason. //fixes backdrop theater var offset = (y * Width) + x; this.PixelData[offset] = pxColor; this.PalData[offset] = pxValue; this.ZBufferData[offset] = zValue; x++; } if (pxWithAlpha) { /** Padding? **/ if ((pxCount * 3) % 2 != 0){ bytes--; io.ReadByte(); } } break; case 0x03: for (var col = 0; col < pxCount; col++) { var offset = (y * Width) + x; this.PixelData[offset] = transparentPixel; this.PalData[offset] = (byte)TransparentColorIndex; this.PixelData[offset].A = 0; if (hasZBuffer){ this.ZBufferData[offset] = 255; } x++; } break; case 0x06: for (var col = 0; col < pxCount; col++) { var pxIndex = io.ReadByte(); bytes--; var offset = (y * Width) + x; var pxColor = palette.Colors[pxIndex]; byte z = 0; //not sure if this should happen /*if (pxIndex == TransparentColorIndex) { pxColor.A = 0; z = 255; }*/ this.PixelData[offset] = pxColor; this.PalData[offset] = pxIndex; if (hasZBuffer) { this.ZBufferData[offset] = z; } x++; } if (pxCount % 2 != 0) { bytes--; io.ReadByte(); } break; } } /** If row isnt filled in, the rest is transparent **/ while (x < Width) { var offset = (y * Width) + x; if (hasZBuffer) { this.ZBufferData[offset] = 255; } x++; } break; /** Leave the next count rows in the color channel filled with the transparent color, * in the z-buffer channel filled with 255, and in the alpha channel filled with 0. **/ case 0x04: for (var row = 0; row < count; row++) { for (var col = 0; col < Width; col++) { var offset = ((y+row) * Width) + col; if (hasPixels) { this.PixelData[offset] = transparentPixel; this.PalData[offset] = (byte)TransparentColorIndex; } if (hasAlpha) { this.PixelData[offset].A = 0; } if (hasZBuffer) { ZBufferData[offset] = 255; } } } y += count - 1; break; case 0x05: endmarker = true; break; } y++; } }
/// <summary> /// Decodes this SPR2Frame. /// </summary> /// <param name="io">An IOBuffer instance used to read a SPR2Frame.</param> private void Decode(IoBuffer io) { var y = 0; var endmarker = false; var hasPixels = (this.Flags & 0x01) == 0x01; var hasZBuffer = (this.Flags & 0x02) == 0x02; var hasAlpha = (this.Flags & 0x04) == 0x04; var numPixels = this.Width * this.Height; if (hasPixels) { this.PixelData = new Color[numPixels]; this.PalData = new byte[numPixels]; } if (hasZBuffer) { this.ZBufferData = new byte[numPixels]; } if (hasAlpha) { this.AlphaData = new byte[numPixels]; } var palette = Parent.ChunkParent.Get <PALT>(this.PaletteID); if (palette == null) { palette = new PALT() { Colors = new Color[256] } } ; palette.References++; var transparentPixel = palette.Colors[TransparentColorIndex]; transparentPixel.A = 0; while (!endmarker) { var marker = io.ReadUInt16(); var command = marker >> 13; var count = marker & 0x1FFF; switch (command) { /** Fill with pixel data **/ case 0x00: var bytes = count; bytes -= 2; var x = 0; while (bytes > 0) { var pxMarker = io.ReadUInt16(); var pxCommand = pxMarker >> 13; var pxCount = pxMarker & 0x1FFF; bytes -= 2; switch (pxCommand) { case 0x01: case 0x02: var pxWithAlpha = pxCommand == 0x02; for (var col = 0; col < pxCount; col++) { var zValue = io.ReadByte(); var pxValue = io.ReadByte(); bytes -= 2; var pxColor = palette.Colors[pxValue]; if (pxWithAlpha) { var alpha = io.ReadByte(); pxColor.A = (byte)(alpha * 8.2258064516129032258064516129032); bytes--; } //this mode draws the transparent colour as solid for some reason. //fixes backdrop theater var offset = (y * Width) + x; this.PixelData[offset] = pxColor; this.PalData[offset] = pxValue; this.ZBufferData[offset] = zValue; x++; } if (pxWithAlpha) { /** Padding? **/ if ((pxCount * 3) % 2 != 0) { bytes--; io.ReadByte(); } } break; case 0x03: for (var col = 0; col < pxCount; col++) { var offset = (y * Width) + x; this.PixelData[offset] = transparentPixel; this.PalData[offset] = (byte)TransparentColorIndex; this.PixelData[offset].A = 0; if (hasZBuffer) { this.ZBufferData[offset] = 255; } x++; } break; case 0x06: for (var col = 0; col < pxCount; col++) { var pxIndex = io.ReadByte(); bytes--; var offset = (y * Width) + x; var pxColor = palette.Colors[pxIndex]; byte z = 0; //not sure if this should happen /*if (pxIndex == TransparentColorIndex) * { * pxColor.A = 0; * z = 255; * }*/ this.PixelData[offset] = pxColor; this.PalData[offset] = pxIndex; if (hasZBuffer) { this.ZBufferData[offset] = z; } x++; } if (pxCount % 2 != 0) { bytes--; io.ReadByte(); } break; } } /** If row isnt filled in, the rest is transparent **/ while (x < Width) { var offset = (y * Width) + x; if (hasZBuffer) { this.ZBufferData[offset] = 255; } x++; } break; /** Leave the next count rows in the color channel filled with the transparent color, * in the z-buffer channel filled with 255, and in the alpha channel filled with 0. **/ case 0x04: for (var row = 0; row < count; row++) { for (var col = 0; col < Width; col++) { var offset = ((y + row) * Width) + col; if (hasPixels) { this.PixelData[offset] = transparentPixel; this.PalData[offset] = (byte)TransparentColorIndex; } if (hasAlpha) { this.PixelData[offset].A = 0; } if (hasZBuffer) { ZBufferData[offset] = 255; } } } y += count - 1; break; case 0x05: endmarker = true; break; } y++; } }
public void SetPalt(PALT p) { if (this.PaletteID != 0) { var old = Parent.ChunkParent.Get<PALT>(this.PaletteID); if (old != null) old.References--; } PaletteID = p.ChunkID; p.References++; }