mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-09-11 00:26:28 -04:00
Optimise pixel operations with FastBitmap.
This commit is contained in:
parent
80d684b83f
commit
12f82d926e
@ -164,11 +164,12 @@ namespace ClassicalSharp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MovePortion( int srcX, int srcY, int destX, int destY, FastBitmap src, int size ) {
|
unsafe static void MovePortion( int srcX, int srcY, int dstX, int dstY, FastBitmap src, int size ) {
|
||||||
for( int y = 0; y < size; y++ ) {
|
for( int y = 0; y < size; y++ ) {
|
||||||
|
int* srcRow = src.GetRowPtr( srcY + y );
|
||||||
|
int* dstRow = src.GetRowPtr( dstY + y );
|
||||||
for( int x = 0; x < size; x++ ) {
|
for( int x = 0; x < size; x++ ) {
|
||||||
int col = src.GetPixel( srcX + x, srcY + y );
|
dstRow[dstX + x] = srcRow[srcX + x];
|
||||||
src.SetPixel( destX + x, destY + y, col );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,33 +6,8 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
/// <summary> Represents a wrapper around a bitmap. Provides
|
/// <summary> Represents a wrapper around a bitmap. Provides
|
||||||
/// a fast implementation for getting and setting pixels in that bitmap. </summary>
|
/// a fast implementation for getting and setting pixels in that bitmap. </summary>
|
||||||
public class FastBitmap : IDisposable {
|
/// <remarks> Only supports 32 bit RGBA pixel format. </remarks>
|
||||||
|
public unsafe class FastBitmap : IDisposable {
|
||||||
unsafe abstract class PixelAccessor {
|
|
||||||
public byte* scan0;
|
|
||||||
public int stride;
|
|
||||||
|
|
||||||
public abstract int GetPixel( int x, int y );
|
|
||||||
|
|
||||||
public abstract void SetPixel( int x, int y, int col );
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe class _32bppARGBAccessor : PixelAccessor {
|
|
||||||
|
|
||||||
public override int GetPixel( int x, int y ) {
|
|
||||||
// row + ( x << 2 ) points to the B part of the pixel at (x, bottomY/row)
|
|
||||||
// casting to Int* then returning the value is a cheap way of
|
|
||||||
// doing the bitwise arithmetic that would otherwise be used.
|
|
||||||
// TODO: Does this work with big-endian systems? I don't know.
|
|
||||||
int* row = (int*)( scan0 + ( y * stride ) );
|
|
||||||
return row[x]; // b g r a
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void SetPixel( int x, int y, int col ) {
|
|
||||||
int* row = (int*)( scan0 + ( y * stride ) );
|
|
||||||
row[x] = col;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary> Constructs a new FastBitmap wrapped around the specified Bitmap. </summary>
|
/// <summary> Constructs a new FastBitmap wrapped around the specified Bitmap. </summary>
|
||||||
/// <param name="bmp"> Bitmap which is wrapped. </param>
|
/// <param name="bmp"> Bitmap which is wrapped. </param>
|
||||||
@ -47,7 +22,8 @@ namespace ClassicalSharp {
|
|||||||
|
|
||||||
public Bitmap Bitmap;
|
public Bitmap Bitmap;
|
||||||
BitmapData data;
|
BitmapData data;
|
||||||
PixelAccessor accessor;
|
byte* scan0;
|
||||||
|
int stride;
|
||||||
|
|
||||||
public bool IsLocked {
|
public bool IsLocked {
|
||||||
get { return data != null; }
|
get { return data != null; }
|
||||||
@ -58,7 +34,7 @@ namespace ClassicalSharp {
|
|||||||
get { return data.Scan0; }
|
get { return data.Scan0; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets the stride width/scan width of the bitmap.
|
/// <summary> Gets the stride width/scan width of the bitmap.
|
||||||
/// (i.e. the actual size of each scanline, including padding) </summary>
|
/// (i.e. the actual size of each scanline, including padding) </summary>
|
||||||
public int Stride {
|
public int Stride {
|
||||||
get { return data.Stride; }
|
get { return data.Stride; }
|
||||||
@ -74,26 +50,23 @@ namespace ClassicalSharp {
|
|||||||
get { return data.Height; }
|
get { return data.Height; }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Locks the wrapped bitmap into system memory,
|
/// <summary> Locks the wrapped bitmap into system memory,
|
||||||
/// so that fast get/set pixel operations can be performed. </summary>
|
/// so that fast get/set pixel operations can be performed. </summary>
|
||||||
/// <remarks> Only 24 and 32 bit bitmap formats are supported. </remarks>
|
public void LockBits() {
|
||||||
public unsafe void LockBits() {
|
|
||||||
if( Bitmap == null ) throw new InvalidOperationException( "Bmp is null." );
|
if( Bitmap == null ) throw new InvalidOperationException( "Bmp is null." );
|
||||||
if( data != null ) {
|
if( data != null ) {
|
||||||
Bitmap.UnlockBits( data );
|
Bitmap.UnlockBits( data );
|
||||||
}
|
}
|
||||||
|
|
||||||
PixelFormat format = Bitmap.PixelFormat;
|
PixelFormat format = Bitmap.PixelFormat;
|
||||||
if( format == PixelFormat.Format32bppArgb ) {
|
if( format != PixelFormat.Format32bppArgb ) {
|
||||||
accessor = new _32bppARGBAccessor();
|
|
||||||
} else {
|
|
||||||
throw new NotSupportedException( "Unsupported bitmap pixel format:" + format );
|
throw new NotSupportedException( "Unsupported bitmap pixel format:" + format );
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle rec = new Rectangle( 0, 0, Bitmap.Width, Bitmap.Height );
|
Rectangle rec = new Rectangle( 0, 0, Bitmap.Width, Bitmap.Height );
|
||||||
data = Bitmap.LockBits( rec, ImageLockMode.ReadWrite, format );
|
data = Bitmap.LockBits( rec, ImageLockMode.ReadWrite, format );
|
||||||
accessor.scan0 = (byte*)data.Scan0;
|
scan0 = (byte*)data.Scan0;
|
||||||
accessor.stride = data.Stride;
|
stride = data.Stride;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose() {
|
public void Dispose() {
|
||||||
@ -104,26 +77,24 @@ namespace ClassicalSharp {
|
|||||||
if( data != null ) {
|
if( data != null ) {
|
||||||
Bitmap.UnlockBits( data );
|
Bitmap.UnlockBits( data );
|
||||||
data = null;
|
data = null;
|
||||||
accessor = null;
|
scan0 = (byte*)IntPtr.Zero;
|
||||||
|
stride = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Gets the colour of the pixel at the specified coordinates. </summary>
|
|
||||||
/// <param name="x">X coordinate of the pixel.</param>
|
|
||||||
/// <param name="bottomY">Y coordinate of the pixel.</param>
|
|
||||||
/// <remarks>Does *not* perform bounds checking for performance reasons. </remarks>
|
|
||||||
/// <returns>The colour at that pixel, in ARGB form. (A is highest 24 bits)</returns>
|
|
||||||
public int GetPixel( int x, int y ) {
|
public int GetPixel( int x, int y ) {
|
||||||
return accessor.GetPixel( x, y );
|
// TODO: Does this work with big-endian systems?
|
||||||
|
int* row = (int*)( scan0 + ( y * stride ) );
|
||||||
|
return row[x]; // b g r a
|
||||||
|
}
|
||||||
|
|
||||||
|
public int* GetRowPtr( int y ) {
|
||||||
|
return (int*)( scan0 + ( y * stride ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Sets the colour of the pixel at the specified coordinates. </summary>
|
|
||||||
/// <param name="x">X coordinate of the pixel.</param>
|
|
||||||
/// <param name="bottomY">Y coordinate of the pixel.</param>
|
|
||||||
/// <param name="col">The new colour of the pixel, in ARGB form. (A is highest 8 bits)</param>
|
|
||||||
/// <remarks>Does *not* perform bounds checking for performance reasons. </remarks>
|
|
||||||
public void SetPixel( int x, int y, int col ) {
|
public void SetPixel( int x, int y, int col ) {
|
||||||
accessor.SetPixel( x, y, col );
|
int* row = (int*)( scan0 + ( y * stride ) );
|
||||||
|
row[x] = col;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -146,13 +146,14 @@ namespace ClassicalSharp {
|
|||||||
y = id / ElementsPerRow;
|
y = id / ElementsPerRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyPortion( int x, int y, int destX, int destY, FastBitmap atlas, FastBitmap dest ) {
|
unsafe void CopyPortion( int tileX, int tileY, int dstX, int dstY, FastBitmap atlas, FastBitmap dst ) {
|
||||||
int atlasX = x * horElementSize;
|
int atlasX = tileX * horElementSize;
|
||||||
int atlasY = y * verElementSize;
|
int atlasY = tileY * verElementSize;
|
||||||
for( int pixelY = 0; pixelY < verElementSize; pixelY++ ) {
|
for( int y = 0; y < verElementSize; y++ ) {
|
||||||
for( int pixelX = 0; pixelX < horElementSize; pixelX++ ) {
|
int* srcRow = atlas.GetRowPtr( atlasY + y );
|
||||||
int col = atlas.GetPixel( atlasX + pixelX, atlasY + pixelY );
|
int* dstRow = dst.GetRowPtr( dstY + y );
|
||||||
dest.SetPixel( destX + pixelX, destY + pixelY, col );
|
for( int x = 0; x < horElementSize; x++ ) {
|
||||||
|
dstRow[dstX + x] = srcRow[atlasX + x];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user