From b32aee6d593b7a1d0544d8d1bf78e43add9f8412 Mon Sep 17 00:00:00 2001 From: Jesse Freeman Date: Sat, 13 Feb 2021 19:05:58 -0500 Subject: [PATCH] Optimizing pixel data utilitiy APIs. --- SDK/Player/Chips/Game/GameChip.MetaSprite.cs | 28 +++ SDK/Player/Data/ImageData.cs | 22 +- SDK/Player/Data/PixelData.cs | 9 +- SDK/Player/Utils/Utilities.PixelData.cs | 209 +++++++++---------- 4 files changed, 142 insertions(+), 126 deletions(-) diff --git a/SDK/Player/Chips/Game/GameChip.MetaSprite.cs b/SDK/Player/Chips/Game/GameChip.MetaSprite.cs index 71cc0805..8fb19f65 100755 --- a/SDK/Player/Chips/Game/GameChip.MetaSprite.cs +++ b/SDK/Player/Chips/Game/GameChip.MetaSprite.cs @@ -24,6 +24,34 @@ namespace PixelVision8.Player { + + public partial class Utilities + { + public static void FlipPixelData(ref int[] pixelData, int sWidth, int sHeight, bool flipH = false, + bool flipV = false) + { + var total = pixelData.Length; + + var pixels = new int[total]; + + // if (pixels.Length < total) Array.Resize(ref pixels, total); + + Array.Copy(pixelData, pixels, total); + + for (var ix = 0; ix < sWidth; ix++) + for (var iy = 0; iy < sHeight; iy++) + { + var newx = ix; + var newY = iy; + if (flipH) newx = sWidth - 1 - ix; + + if (flipV) newY = sHeight - 1 - iy; + + pixelData[ix + iy * sWidth] = pixels[newx + newY * sWidth]; + } + } + } + /// /// The GameChip represents the foundation of a game class /// with all the logic it needs to work correctly in the PixelVisionEngine. diff --git a/SDK/Player/Data/ImageData.cs b/SDK/Player/Data/ImageData.cs index 8fc5280a..c97f1aac 100755 --- a/SDK/Player/Data/ImageData.cs +++ b/SDK/Player/Data/ImageData.cs @@ -47,17 +47,17 @@ public struct ImageData private Point _pos; private int[] _tmpPixelData; - public int SpriteWidth - { - get => _spriteSize.X; - set => _spriteSize.X = value; // TODO this should be divisible by 8 - } - - public int SpriteHeight - { - get => _spriteSize.Y; - set => _spriteSize.Y = value; // TODO this should be divisible by 8 - } + // public int SpriteWidth + // { + // get => _spriteSize.X; + // set => _spriteSize.X = value; // TODO this should be divisible by 8 + // } + // + // public int SpriteHeight + // { + // get => _spriteSize.Y; + // set => _spriteSize.Y = value; // TODO this should be divisible by 8 + // } public ImageData(int width, int height, int[] pixels = null, string[] colors = null) // : base(width, height) { diff --git a/SDK/Player/Data/PixelData.cs b/SDK/Player/Data/PixelData.cs index d5f9f091..bca061d3 100755 --- a/SDK/Player/Data/PixelData.cs +++ b/SDK/Player/Data/PixelData.cs @@ -63,10 +63,15 @@ public void SetPixels(int[] pixels, int width, int height) if (width * height != pixels.Length) return; - _pixels = pixels; + Total = pixels.Length; + + if(_pixels.Length != Total) + Array.Resize(ref _pixels, Total); + + Array.Copy(pixels, _pixels, Total); + Width = width; Height = height; - Total = pixels.Length; } diff --git a/SDK/Player/Utils/Utilities.PixelData.cs b/SDK/Player/Utils/Utilities.PixelData.cs index 1578b996..a3e1f0f9 100755 --- a/SDK/Player/Utils/Utilities.PixelData.cs +++ b/SDK/Player/Utils/Utilities.PixelData.cs @@ -27,81 +27,77 @@ namespace PixelVision8.Player public static partial class Utilities { - private static int[] _pixels = new int[0]; + public static int[] GetPixels(PixelData pixelData) + { + + // Create a new temporary array to copy the pixel data into + var tmpPixels = new int[pixelData.Total]; + + // Use the Array.Copy() method to quickly copy all of the pixel data into the new temporary array + Array.Copy(pixelData.Pixels, tmpPixels, pixelData.Total); - public static int[] GetPixels(PixelData pixelData) => - GetPixels(pixelData, 0, 0, pixelData.Width, pixelData.Height); + // Return the temporary pixels + return tmpPixels; + } public static int[] GetPixels(PixelData pixelData, int x, int y, int blockWidth, int blockHeight) { - var _tmpPixels = new int[blockWidth * blockHeight]; + + // Create a new temporary array to copy the pixel data into + var tmpPixels = new int[blockWidth * blockHeight]; - CopyPixels(pixelData, x, y, blockWidth, blockHeight, ref _tmpPixels); + CopyPixels(pixelData, x, y, blockWidth, blockHeight, ref tmpPixels); - return _tmpPixels; + return tmpPixels; } - public static void FlipPixelData(ref int[] pixelData, int sWidth, int sHeight, bool flipH = false, - bool flipV = false) + public static void SetPixels(int[] srcPixels, PixelData destPixelData) { - var total = pixelData.Length; - if (_pixels.Length < total) Array.Resize(ref _pixels, total); - - Array.Copy(pixelData, _pixels, total); - - for (var ix = 0; ix < sWidth; ix++) - for (var iy = 0; iy < sHeight; iy++) - { - var newx = ix; - var newY = iy; - if (flipH) newx = sWidth - 1 - ix; - - if (flipV) newY = sHeight - 1 - iy; - - pixelData[ix + iy * sWidth] = _pixels[newx + newY * sWidth]; - } + if (srcPixels.Length != destPixelData.Total) + return; + + destPixelData.SetPixels(srcPixels, destPixelData.Width, destPixelData.Height); } - public static void SetPixels(int[] srcPixels, PixelData destPixelData) => SetPixels(srcPixels, 0, 0, - destPixelData.Width, destPixelData.Height, destPixelData); - public static void SetPixels(int[] srcPixels, int x, int y, int blockWidth, int blockHeight, PixelData destPixelData) { - ValidateBounds(ref blockWidth, ref blockHeight, ref x, ref y, destPixelData.Width, destPixelData.Height); - - // Exit if the width or height is not valid - if (blockWidth < 1 || blockHeight < 1) - return; + for (var i = blockHeight - 1; i > -1; i--) { - try - { - Array.Copy( - srcPixels, - i * blockWidth, - destPixelData.Pixels, - x + (i + y) * destPixelData.Width, - blockWidth - ); - } - catch (Exception e) - { - Debug.WriteLine(e); - // throw; - } + Array.Copy( + srcPixels, + i * blockWidth, + destPixelData.Pixels, + x + (i + y) * destPixelData.Width, + blockWidth + ); } } - + + /// + /// A fast copy method that takes a selection of ints from a PixelData sources and copies them + /// in-line to a supplied destination array. The destPixels array will be resized to accomidate the + /// pixels about to be copied into it. + /// + /// + /// + /// + /// + /// + /// public static void CopyPixels(PixelData srcPixelData, int x, int y, int sampleWidth, int sampleHeight, ref int[] destPixels) { - ValidateBounds(ref sampleWidth, ref sampleHeight, ref x, ref y, srcPixelData.Width, srcPixelData.Height); + // ValidateBounds(ref sampleWidth, ref sampleHeight, ref x, ref y, srcPixelData.Width, srcPixelData.Height); if (sampleWidth < 1 || sampleHeight < 1) return; - + + if(destPixels.Length != (sampleWidth * sampleHeight)) + Array.Resize(ref destPixels, sampleWidth * sampleHeight); + // Copy each entire line at once. for (var i = sampleHeight - 1; i > -1; --i) { @@ -119,80 +115,66 @@ public static void Clear(PixelData pixelData, int colorRef = -1) { for (var i = pixelData.Total - 1; i > -1; i--) pixelData[i] = colorRef; } - - public static void MergePixels(PixelData src, int sampleX, int sampleY, int sampleWidth, int sampleHeight, + + public static void MergePixels( + // The source pixel data + PixelData src, + // The sample area + int srcX, + int srcY, + int srcWidth, + int srcHeight, + // The destination pixel data PixelData dest, - int destX, int destY, bool flipH = false, bool flipV = false, int colorOffset = 0, - bool ignoreTransparent = true) + // Destination position + int destX, + int destY, + // Flip pixel data when copying + bool flipH = false, + bool flipV = false, + // Apply a color offset + int colorOffset = 0, + bool ignoreTransparent = true + ) { - - ValidateBounds(ref sampleWidth, ref sampleHeight, ref destX, ref destY, dest.Width, dest.Height); - - if (sampleWidth < 1 || sampleHeight < 1) - return; - - var total = sampleWidth * sampleHeight; + var srcPWidth = src.Width; + var destPWidth = dest.Width; + var destPHeight = dest.Height; + + var total = srcWidth * srcHeight; + if (total == 0) return; + + int col = 0, row = 0; - int mergeCol = 0, mergeRow = 0; - - for (var i = 0; i < total; i++) + int tmpX, tmpY, tmpPixel, i; + + for (i = 0; i < total; i++) { - var mergeX = mergeCol; - var mergeY = mergeRow; - - var tmpPixel = src.Pixels[(mergeX + sampleX) + (src.Width * (mergeY + sampleY))]; - + tmpX = col + srcX; + tmpY = row+ srcY; + + tmpPixel = src.Pixels[tmpX + srcPWidth * tmpY]; + if (tmpPixel != -1 || ignoreTransparent != true) { - if (flipH) - mergeX = sampleWidth - 1 - mergeX; - - if (flipV) - mergeY = sampleWidth - 1 - mergeY; - - dest.Pixels[(mergeX + destX) + dest.Width * (mergeY + destY)] = tmpPixel + colorOffset; - } - - mergeCol++; - - if (mergeCol >= sampleWidth) - { - mergeCol = 0; - mergeRow++; + tmpX = (flipH ? srcWidth - 1 - col : col) + destX; + + tmpY = (flipV ? srcWidth - 1 - row : row) + destY; + + if (tmpX >= 0 && tmpX < destPWidth && tmpY >= 0 && tmpY < destPHeight) + { + dest.Pixels[tmpX + destPWidth * tmpY] = tmpPixel + colorOffset; + } } - } - } - - private static void ValidateBounds(ref int srcWidth, ref int srcHeight, ref int destX, - ref int destY, int destWidth, int destHeight) - { - // Adjust X - if (destX < 0) - { - srcWidth += destX; - destX = 0; - } - - // Adjust Y - if (destY < 0) - { - srcHeight += destY; - destY = 0; - } - - // Adjust Width - if (destX + srcWidth > destWidth) - { - srcWidth -= (destX + srcWidth) - destWidth; - } + + col++; - // Adjust Height. - if (destY + srcHeight > destHeight) - { - srcHeight -= destY + srcHeight - destHeight; + if (col < srcWidth) continue; + col = 0; + row++; } } @@ -203,5 +185,6 @@ public static void Resize(PixelData pixelData, int blockWidth, int blockHeight) Clear(pixelData); } + } } \ No newline at end of file