243 lines
8.5 KiB
C#
Raw Permalink Normal View History

#region Using Statements
using ANX.Framework.Graphics;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.IO;
using System.Globalization;
#endregion
// This file is part of the ANX.Framework created by the
// "ANX.Framework developer group" and released under the Ms-PL license.
// For details see: http://anxframework.codeplex.com/license
namespace ANX.Framework.Content.Pipeline.Graphics
{
public class PixelBitmapContent<T> : BitmapContent where T : struct, IEquatable<T>
{
private T[,] pixels;
private int pixelSize;
protected PixelBitmapContent()
{
this.pixelSize = Marshal.SizeOf(typeof(T));
}
public PixelBitmapContent(int width, int height)
: base(width, height)
{
pixels = new T[width, height];
this.pixelSize = Marshal.SizeOf(typeof(T));
}
public T GetPixel(int x, int y)
{
return pixels[x, y];
}
public override byte[] GetPixelData()
{
int rowSize = Marshal.SizeOf(typeof(T)) * base.Width;
byte[] array = new byte[rowSize * base.Height];
int destinationIndex = 0;
for (int i = 0; i < base.Height; i++)
{
T[] row = GetRow(i);
for (int x = 0; x < row.Length; x++)
{
Array.Copy(GetBytes<T>(row[x]), 0, array, destinationIndex, pixelSize);
destinationIndex += pixelSize;
}
}
return array;
}
private static byte[] GetBytes<Tv>(Tv value)
{
byte[] buffer = new byte[Marshal.SizeOf(typeof(Tv))];
GCHandle handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
try
{
Marshal.StructureToPtr(value, handle.AddrOfPinnedObject(), false);
}
finally
{
handle.Free();
}
return buffer;
}
public T[] GetRow(int y)
{
T[] row = new T[Width];
for (int col = 0; col < Width; col++)
{
row[col] = pixels[col, y];
}
return row;
}
public void SetPixel(int x, int y, T value)
{
pixels[x, y] = value;
}
public override void SetPixelData(byte[] sourceData)
{
if (sourceData == null)
throw new ArgumentNullException("sourceData");
int copiedBytes = Width * Height * pixelSize;
if (copiedBytes != sourceData.Length)
throw new ArgumentException(string.Format("The length of sourceData (Length: {0}) must be equal to the size of the contained data within the {1} (Length: {2}).", sourceData.Length, this.GetType().FullName, copiedBytes));
var dataHandle = GCHandle.Alloc(pixels, GCHandleType.Pinned);
try
{
var dataPtr = (IntPtr)dataHandle.AddrOfPinnedObject().ToInt64();
Marshal.Copy(sourceData, copiedBytes, dataPtr, copiedBytes);
}
finally
{
dataHandle.Free();
}
}
public override string ToString()
{
//The type name would be PixelBitmapContent`1. That's why we have to write the name ourselves.
return string.Format(CultureInfo.InvariantCulture, "PixelBitmapContent<{0}>, {1}x{2}", typeof(T).Name, Width, Height);
}
protected override bool TryCopyFrom(BitmapContent sourceBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
{
BitmapContent.ValidateCopyArguments(sourceBitmap, sourceRegion, this, destinationRegion);
if (sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
{
return Draw(sourceBitmap, sourceRegion, this, destinationRegion, TextureFilter.Anisotropic);
}
if (sourceBitmap is PixelBitmapContent<T>)
{
PixelBitmapContent<T> pixelBitmapContent = (PixelBitmapContent<T>)sourceBitmap;
for (int x = 0; x < sourceRegion.Width; x++)
for (int y = 0; y < sourceRegion.Height; y++)
{
this.SetPixel(x + destinationRegion.X, y + destinationRegion.Y, pixelBitmapContent.GetPixel(x + sourceRegion.X, y + sourceRegion.Y));
}
return true;
}
return false;
}
protected override bool TryCopyTo(BitmapContent destinationBitmap, Rectangle sourceRegion, Rectangle destinationRegion)
{
BitmapContent.ValidateCopyArguments(this, sourceRegion, destinationBitmap, destinationRegion);
if (sourceRegion.Width != destinationRegion.Width || sourceRegion.Height != destinationRegion.Height)
{
return Draw(this, sourceRegion, destinationBitmap, destinationRegion, TextureFilter.Anisotropic);
}
if (destinationBitmap is PixelBitmapContent<T>)
{
PixelBitmapContent<T> pixelBitmapContent = (PixelBitmapContent<T>)destinationBitmap;
for (int x = 0; x < sourceRegion.Width; x++)
for (int y = 0; y < sourceRegion.Height; y++)
{
pixelBitmapContent.SetPixel(x + destinationRegion.X, y + destinationRegion.Y, this.GetPixel(x + sourceRegion.X, y + sourceRegion.Y));
}
return true;
}
return false;
}
public void ReplaceColor(T originalColor, T newColor)
{
for (int x = 0, width = pixels.GetLength(0); x < width; x++)
for (int y = 0, height = pixels.GetLength(1); y < height; y++)
{
if (pixels[x, y].Equals(originalColor))
pixels[x, y] = newColor;
}
}
public override bool TryGetFormat(out SurfaceFormat format)
{
string type = typeof(T).Name.ToLowerInvariant();
switch (type)
{
case "float":
format = SurfaceFormat.Single;
return true;
case "vector2":
format = SurfaceFormat.Single;
return true;
case "vector4":
format = SurfaceFormat.Vector4;
return true;
case "halfsingle":
format = SurfaceFormat.HalfVector2;
return true;
case "halfvector2":
format = SurfaceFormat.HalfVector2;
return true;
case "halfvector4":
format = SurfaceFormat.HalfVector4;
return true;
case "bgra5551":
format = SurfaceFormat.Bgra5551;
return true;
case "bgr565":
format = SurfaceFormat.Bgr565;
return true;
case "bgra4444":
format = SurfaceFormat.Bgra4444;
return true;
case "color":
format = SurfaceFormat.Color;
return true;
case "rg32":
format = SurfaceFormat.Rg32;
return true;
case "rgba64":
format = SurfaceFormat.Rgba64;
return true;
case "rgba1010102":
format = SurfaceFormat.Rgba1010102;
return true;
case "alpha8":
format = SurfaceFormat.Alpha8;
return true;
case "normalizedbyte2":
format = SurfaceFormat.NormalizedByte2;
return true;
case "normalizedbyte4":
format = SurfaceFormat.NormalizedByte4;
return true;
default:
format = Framework.Graphics.SurfaceFormat.Color;
return false;
}
}
}
}