public Sprite() { Frame = new Frame(); Partition = new RectPartition(); Difference = false; }
public void Read( Stream ins, String PackName ) { if (ins.ReadByte() != (byte)'R' ) return; if (ins.ReadByte() != (byte)'B' ) return; if (ins.ReadByte() != (byte)'S' ) return; if (ins.ReadByte() != (byte)'P' ) return; int nSprites = ReadWord( ins ); ReadDword( ins ); ReadDword( ins ); int firstSprite = Sprites.Count; // read header for (int i = 0; i < nSprites; i++) { Sprite sp = new Sprite(); sp.Width = ReadWord( ins ); sp.Height = ReadWord( ins ); sp.ClrFormat = (ColorFormat)ReadWord( ins ); sp.Frame.x = ReadWord( ins ); sp.Frame.y = ReadWord( ins ); sp.Frame.w = ReadWord( ins ); sp.Frame.h = ReadWord( ins ); sp.Name = PackName + i; int bFiltered = ReadWord( ins ); if (bFiltered == 1) sp.Filtered = true; else sp.Filtered = false; int nRects = ReadWord( ins ); sp.PivotX = (short)ReadWord( ins ); sp.PivotY = (short)ReadWord( ins ); sp.ShiftX = (short)ReadWord( ins ); sp.ShiftY = (short)ReadWord( ins ); for (int j = 0; j < nRects; j++) { Frame rc = new Frame(); rc.x = ReadWord( ins ); rc.y = ReadWord( ins ); rc.w = ReadWord( ins ); rc.h = rc.w; ReadWord( ins ); sp.Partition.Rects.Add( rc ); } Sprites.Add( sp ); } // read pixels for (int i = firstSprite; i < Sprites.Count; i++) { Sprite sprite = (Sprite)Sprites[i]; int nBytes = sprite.GetNumBytes(); sprite.Bytes = new byte[nBytes]; ins.Read( sprite.Bytes, 0, nBytes ); } }
bool Subdivide( Bitmap img, Frame rc ) { if (rc.w <= MinQuadSide) return false; int hw = rc.w/2; int hh = rc.h/2; Frame[] subr = new Frame[4]; int[] nutl = new int[4]; subr[0] = new Frame( rc.x, rc.y, hw, hh ); subr[1] = new Frame( rc.x + hw, rc.y, hw, hh ); subr[2] = new Frame( rc.x, rc.y + hh, hw, hh ); subr[3] = new Frame( rc.x + hw, rc.y + hh, hw, hh ); int nPUsed = 0; for (int i = 0; i < 4; i++) { nutl[i] = GetUtilization( img, subr[i] ); nPUsed += nutl[i]; } float used = ((float)nPUsed)/(float)(rc.w*rc.w); if (used > SubdivUsedBias) return false; for (int i = 0; i < 4; i++) { if (nutl[i] > 0) { Rects.Add( subr[i] ); } } return true; }
void CreatePartition( Bitmap bmp ) { Partition = new RectPartition( bmp, Filtered ); Frame = Partition.Frame; int numBytes = Partition.GetNumPixels( Filtered )*GetBytesPerPixel( ClrFormat ); // get pixels Bytes = new byte[numBytes]; int curByte = 0; for (int k = 0; k < Partition.Rects.Count; k++) { Frame rc = (Frame)Partition.Rects[k]; int bX, bY, eX, eY; if (Filtered) { bX = -1; eX = rc.w + 1; bY = -1; eY = rc.h + 1; if (rc.x + eX > Frame.x + Frame.w + 1) eX = Frame.x + Frame.w - rc.x + 1; if (rc.y + eY > Frame.y + Frame.h + 1) eY = Frame.y + Frame.h - rc.y + 1; } else { bX = 0; eX = rc.w; bY = 0; eY = rc.h; if (rc.x + eX > Frame.x + Frame.w) eX = Frame.x + Frame.w - rc.x; if (rc.y + eY > Frame.y + Frame.h) eY = Frame.y + Frame.h - rc.y; } for (int j = bY; j < eY; j++) { for (int i = bX; i < eX; i++) { Color clr = GetPixel( bmp, rc.x + i, rc.y + j ); curByte += AddColor( ref Bytes, curByte, clr, ClrFormat ); } } } }
void CreateUnfiltered( Bitmap img ) { Frame = TrimBitmap( img ); int side = GetCoverSide( Frame, 0 ); CreateUniform( img, side ); bool bWasDivided = true; while (bWasDivided) { bWasDivided = false; for (int i = 0; i < Rects.Count; i++) { Frame r = (Frame)Rects[i]; bool bSubd = Subdivide( img, r ); if (bSubd) { bWasDivided = true; Rects.RemoveAt( i ); break; } } } }
float CreateUniform( Bitmap img, int side ) { Frame rc = TrimBitmap( img ); int nAllPix = 0; int nPix = 0; int nx = rc.w/side + 1; int ny = rc.h/side + 1; Rects.Clear(); for (int j = 0; j < ny; j++) { for (int i = 0; i < nx; i++) { Frame crc = new Frame( rc.x + i*side, rc.y + j*side, side, side ); nAllPix += side*side; int np = GetUtilization( img, crc ); if (np == 0) continue; nPix += np; Rects.Add( crc ); } } return ((float)nPix)/((float)nAllPix); }
void CreateFiltered( Bitmap img ) { Frame = TrimBitmap( img ); int side = GetCoverSide( Frame, 1 ); CreateUniform( img, side - 2 ); while (GetUtilization( img ) < SubdivUsedBias && Rects.Count > 0 && ((Frame)Rects[0]).w > MinQuadSide) { side /= 2; CreateUniform( img, side - 2 ); } }
static int GetCoverSide( Frame rc, int inflate ) { long s = 0; if (rc.w > rc.h) s = (long)rc.w; else s = (long)rc.h; if (BitOps.IsPow2( s ) && s <= MaxQuadSide && s >= MinQuadSide) { return (int)s; } s += inflate*2; s = BitOps.NextPow2( s ); while (s < MinQuadSide) s *= 2; while (s > MaxQuadSide) s /= 2; return (int)s; }
// trims bitmap deleting transparent border // returns trimmed rectangle public static Frame TrimBitmap( Bitmap bmp ) { Frame res = new Frame( 0, 0, bmp.Width, bmp.Height ); while (IsRowEmpty( bmp, res.y ) && res.y < bmp.Height) { res.y++; res.h--; } while (IsRowEmpty( bmp, res.y + res.h - 1 ) && res.h > 0) res.h--; while (IsColEmpty( bmp, res.x ) && res.w < bmp.Width) { res.x++; res.w--; } while (IsColEmpty( bmp, res.x + res.w - 1 ) && res.w > 0) res.w--; return res; }
public static byte MaxAlpha( Bitmap bmp, Frame rc ) { int ex = rc.x + rc.w; int ey = rc.y + rc.h; byte alpha = 0; for (int j = rc.y; j < ey; j++) { for (int i = rc.x; i < ex; i++) { byte ca = (byte)((bmp.GetPixel( i, j ).ToArgb()&0xFF000000)>>24); if (ca > alpha) alpha = ca; } } return alpha; }
public static int GetUtilization( Bitmap bmp, Frame rc ) { int ex = rc.x + rc.w; int ey = rc.y + rc.h; int cFree = 0; for (int j = rc.y; j < ey; j++) { for (int i = rc.x; i < ex; i++) { byte ca = GetAlpha( i, j, bmp ); if (ca == 0) cFree++; } } return rc.w*rc.h - cFree; }