From b48a13757bb87b6212716fc7896849d45a4f3ed1 Mon Sep 17 00:00:00 2001 From: gered Date: Sun, 18 Aug 2013 11:54:22 -0400 Subject: [PATCH] add platform-independant interface for loading Image objects from streams. add SDL backend support SDL2# does not include anything suitable for using Streams with, so we just use System.Drawing instead for now --- .../Blarg.GameFramework.SDL2.csproj | 3 + .../Graphics/SDLBitmap.cs | 125 ++++++++++++++++++ Blarg.GameFramework.SDL2/SDLApplication.cs | 10 ++ Blarg.GameFramework/BaseApplication.cs | 3 + .../Blarg.GameFramework.csproj | 2 + .../Graphics/IPlatformBitmap.cs | 12 ++ Blarg.GameFramework/Graphics/Image.cs | 33 +---- Blarg.GameFramework/Graphics/ImageFormat.cs | 11 ++ Blarg.GameFramework/IApplication.cs | 3 + 9 files changed, 176 insertions(+), 26 deletions(-) create mode 100644 Blarg.GameFramework.SDL2/Graphics/SDLBitmap.cs create mode 100644 Blarg.GameFramework/Graphics/IPlatformBitmap.cs create mode 100644 Blarg.GameFramework/Graphics/ImageFormat.cs diff --git a/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj b/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj index 8c7a8ee..11cc35a 100644 --- a/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj +++ b/Blarg.GameFramework.SDL2/Blarg.GameFramework.SDL2.csproj @@ -41,6 +41,7 @@ ..\Libs\SDL2#.dll + @@ -53,6 +54,7 @@ + @@ -64,5 +66,6 @@ + \ No newline at end of file diff --git a/Blarg.GameFramework.SDL2/Graphics/SDLBitmap.cs b/Blarg.GameFramework.SDL2/Graphics/SDLBitmap.cs new file mode 100644 index 0000000..2b76424 --- /dev/null +++ b/Blarg.GameFramework.SDL2/Graphics/SDLBitmap.cs @@ -0,0 +1,125 @@ +using System; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Runtime.InteropServices; + +namespace Blarg.GameFramework.Graphics +{ + public class SDLBitmap : IPlatformBitmap + { + byte[] _pixels; + int _width; + int _height; + Graphics.ImageFormat _format; + + public byte[] Pixels + { + get { return _pixels; } + } + + public int Width + { + get { return _width; } + } + + public int Height + { + get { return _height; } + } + + public Graphics.ImageFormat Format + { + get { return _format; } + } + + public SDLBitmap(Stream file) + { + _pixels = GetBitmap(file, out _width, out _height, out _format); + } + + private byte[] GetBitmap(Stream file, out int width, out int height, out Graphics.ImageFormat format) + { + if (file == null) + throw new ArgumentNullException("file"); + + using (Bitmap bitmap = (Bitmap)Bitmap.FromStream(file)) + { + int bpp = 0; + if (bitmap.PixelFormat == PixelFormat.Format32bppArgb) + { + bpp = 32; + format = Graphics.ImageFormat.RGBA; + } + else if (bitmap.PixelFormat == PixelFormat.Format24bppRgb) + { + bpp = 24; + format = Graphics.ImageFormat.RGB; + } + else if (bitmap.PixelFormat == PixelFormat.Alpha) + { + bpp = 8; + format = Graphics.ImageFormat.A; + } + else + throw new InvalidOperationException(String.Format("Unsupported bitmap pixel format: {0}", bitmap.PixelFormat.ToString())); + + width = bitmap.Width; + height = bitmap.Height; + + byte[] pixels; + + var lockRegion = new Rectangle(0, 0, bitmap.Width, bitmap.Height); + var bitmapData = bitmap.LockBits(lockRegion, ImageLockMode.ReadOnly, bitmap.PixelFormat); + try + { + int bitmapSizeInBytes = bitmap.Width * bitmap.Height * (bpp / 8); + int expectedPitch = bitmap.Width * (bpp / 8); + int actualPitch = bitmapData.Stride; + + if (expectedPitch != actualPitch) + throw new InvalidOperationException("Expected bitmap pitch mismatch. Uncaught unsupported bitmap format?"); + + pixels = new byte[bitmapData.Stride * bitmap.Height]; + Marshal.Copy(bitmapData.Scan0, pixels, 0, bitmapSizeInBytes); + } + finally + { + bitmap.UnlockBits(bitmapData); + } + + // TODO: are there any cases where this should *not* be run? + SwapRgbOrdering(pixels, format); + + return pixels; + } + } + + private void SwapRgbOrdering(byte[] pixels, Graphics.ImageFormat pixelFormat) + { + if (pixelFormat == Graphics.ImageFormat.A) + return; + + // assumption is that this will only ever be 3 or 4 (RGB, or RGBA) + int pixelSizeBytes; + if (pixelFormat == Graphics.ImageFormat.RGB) + pixelSizeBytes = 3; + else + pixelSizeBytes = 4; + + if (pixels.Length % pixelSizeBytes != 0) + throw new InvalidDataException("Pixel data format mismatch."); + + // swap R and B values for each pixel + for (int i = 0; i < pixels.Length; i += pixelSizeBytes) + { + byte r = pixels[i]; + byte b = pixels[i + 2]; + pixels[i] = b; + pixels[i + 2] = r; + } + } + + } +} + diff --git a/Blarg.GameFramework.SDL2/SDLApplication.cs b/Blarg.GameFramework.SDL2/SDLApplication.cs index e058207..a0a5371 100644 --- a/Blarg.GameFramework.SDL2/SDLApplication.cs +++ b/Blarg.GameFramework.SDL2/SDLApplication.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using System.IO; using SDL2; using PortableGL; using PortableGL.SDL; @@ -612,6 +613,15 @@ namespace Blarg.GameFramework #endregion + #region Support Functions + + public override IPlatformBitmap LoadBitmap(Stream file) + { + return new SDLBitmap(file); + } + + #endregion + #region IDisposable protected override void Release() diff --git a/Blarg.GameFramework/BaseApplication.cs b/Blarg.GameFramework/BaseApplication.cs index e1743f6..3bdcb45 100644 --- a/Blarg.GameFramework/BaseApplication.cs +++ b/Blarg.GameFramework/BaseApplication.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using PortableGL; using Blarg.GameFramework.Graphics; using Blarg.GameFramework.Input; @@ -38,6 +39,8 @@ namespace Blarg.GameFramework public abstract void Run(IGameApp gameApp, IPlatformConfiguration config); public abstract void Quit(); + public abstract IPlatformBitmap LoadBitmap(Stream file); + protected void OnInit() { Logger.Info(LOG_TAG, "Initializing application objects."); diff --git a/Blarg.GameFramework/Blarg.GameFramework.csproj b/Blarg.GameFramework/Blarg.GameFramework.csproj index 1ec5ad3..99a9cb3 100644 --- a/Blarg.GameFramework/Blarg.GameFramework.csproj +++ b/Blarg.GameFramework/Blarg.GameFramework.csproj @@ -124,6 +124,8 @@ + + diff --git a/Blarg.GameFramework/Graphics/IPlatformBitmap.cs b/Blarg.GameFramework/Graphics/IPlatformBitmap.cs new file mode 100644 index 0000000..a7930be --- /dev/null +++ b/Blarg.GameFramework/Graphics/IPlatformBitmap.cs @@ -0,0 +1,12 @@ +using System; + +namespace Blarg.GameFramework.Graphics +{ + public interface IPlatformBitmap + { + byte[] Pixels { get; } + int Width { get; } + int Height { get; } + ImageFormat Format { get; } + } +} diff --git a/Blarg.GameFramework/Graphics/Image.cs b/Blarg.GameFramework/Graphics/Image.cs index 1625d85..7bf814c 100644 --- a/Blarg.GameFramework/Graphics/Image.cs +++ b/Blarg.GameFramework/Graphics/Image.cs @@ -1,14 +1,8 @@ using System; +using System.IO; namespace Blarg.GameFramework.Graphics { - public enum ImageFormat - { - RGB, - RGBA, - A - } - public partial class Image { private byte[] _pixels; @@ -47,28 +41,15 @@ namespace Blarg.GameFramework.Graphics Create(source, copyX, copyY, copyWidth, copyHeight); } - private Image(byte[] pixels, int width, int height, ImageFormat format) + public Image(Stream file) { - if (pixels == null) - throw new ArgumentNullException("pixels"); + if (file == null) + throw new ArgumentNullException("file"); - int bpp = 0; - if (format == ImageFormat.RGB) - bpp = 24; - else if (format == ImageFormat.RGBA) - bpp = 32; - else if (format == ImageFormat.A) - bpp = 8; + var bitmap = Platform.Application.LoadBitmap(file); - if (bpp == 0) - throw new ArgumentException("pixelFormat"); - - _pixels = pixels; - Width = width; - Height = height; - BitsPerPixel = bpp; - PixelFormat = format; - Pitch = Width * (BitsPerPixel / 8); + CreateBaseImage(bitmap.Width, bitmap.Height, bitmap.Format); + Buffer.BlockCopy(bitmap.Pixels, 0, _pixels, 0, bitmap.Pixels.Length); } private void CreateBaseImage(int width, int height, ImageFormat pixelFormat) diff --git a/Blarg.GameFramework/Graphics/ImageFormat.cs b/Blarg.GameFramework/Graphics/ImageFormat.cs new file mode 100644 index 0000000..156fb7c --- /dev/null +++ b/Blarg.GameFramework/Graphics/ImageFormat.cs @@ -0,0 +1,11 @@ +using System; + +namespace Blarg.GameFramework.Graphics +{ + public enum ImageFormat + { + RGB, + RGBA, + A + } +} diff --git a/Blarg.GameFramework/IApplication.cs b/Blarg.GameFramework/IApplication.cs index 05d6946..7c28034 100644 --- a/Blarg.GameFramework/IApplication.cs +++ b/Blarg.GameFramework/IApplication.cs @@ -1,4 +1,5 @@ using System; +using System.IO; using PortableGL; using Blarg.GameFramework.Graphics; using Blarg.GameFramework.Input; @@ -30,6 +31,8 @@ namespace Blarg.GameFramework void Run(IGameApp gameApp, IPlatformConfiguration config); void Quit(); + + IPlatformBitmap LoadBitmap(Stream file); } }