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
This commit is contained in:
Gered 2013-08-18 11:54:22 -04:00
parent a914c2bcab
commit b48a13757b
9 changed files with 176 additions and 26 deletions

View file

@ -41,6 +41,7 @@
<Reference Include="SDL2#">
<HintPath>..\Libs\SDL2#.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
</ItemGroup>
<ItemGroup>
<Compile Include="Properties\AssemblyInfo.cs" />
@ -53,6 +54,7 @@
<Compile Include="CurrentOS.cs" />
<Compile Include="Input\SDLKeyMapper.cs" />
<Compile Include="SDLApplication.cs" />
<Compile Include="Graphics\SDLBitmap.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<ItemGroup>
@ -64,5 +66,6 @@
<ItemGroup>
<Folder Include="Input\" />
<Folder Include="IO\" />
<Folder Include="Graphics\" />
</ItemGroup>
</Project>

View file

@ -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;
}
}
}
}

View file

@ -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()

View file

@ -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.");

View file

@ -124,6 +124,8 @@
<Compile Include="Graphics\BuiltinShaders\Sprite2DShader.cs" />
<Compile Include="Graphics\BuiltinShaders\Sprite3DShader.cs" />
<Compile Include="Support\StringExtensions.cs" />
<Compile Include="Graphics\ImageFormat.cs" />
<Compile Include="Graphics\IPlatformBitmap.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<ItemGroup>

View file

@ -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; }
}
}

View file

@ -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)

View file

@ -0,0 +1,11 @@
using System;
namespace Blarg.GameFramework.Graphics
{
public enum ImageFormat
{
RGB,
RGBA,
A
}
}

View file

@ -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);
}
}