/Silvermoon/Silvermoon/OpenGL/Texture.cs
C# | 526 lines | 380 code | 94 blank | 52 comment | 43 complexity | 4a6814ccc92bf958e89d8e5ea88f91f2 MD5 | raw file
- using System;
-
- using System.Collections.Generic;
- using System.Text;
- using System.IO;
- using System.Runtime.InteropServices;
- using System.Drawing;
- using Silvermoon.Drawing;
- using Silvermoon.OpenGL.Native;
- using Format = Silvermoon.OpenGL.Native.GlesPixelFormat;
- using ValueType = Silvermoon.OpenGL.Native.glValueType;
- using System.Drawing.Imaging;
- using System.Diagnostics;
- using System.Threading;
- using System.Reflection;
-
- namespace Silvermoon.OpenGL
- {
- public class Texture : IDisposable
- {
- const int one = 65536;
- #region statics
-
- public static void Cleanup()
- {
-
- }
-
- #endregion
- #region Fields
-
- private static int maxTextureSize;
- private int[] textCoords = new int[] { one, 0, one, -one, 0, 0, 0, -one };
-
-
- private static IImagingFactory imageFactory;
-
- #endregion
- #region ctor
-
- public Texture()
- : base()
- {
- //Textures.Add(this);
- this.Name = gl.GenTexture();
- if (this.Name == 0) throw new OpenGlException("glGenTexture.");
- }
-
- public virtual void Dispose()
- {
- GC.SuppressFinalize(this);
- if (Name != 0)
- {
- gl.DeleteTexture(Name);
- }
- Name = 0;
- }
-
- ~Texture()
- {
- Dispose();
- }
-
-
- #endregion
- #region Properties
-
- /// <summary>
- /// When set to false, each color in the texture is multiplied with the color value of a shape with the formula value=(textureValue*colorValue)/255,
- /// if set to true, each color in the texture is considered relative from color (128,128,128). which means that a color in the texture
- /// is calculated as value = (textureValue-128)*colorValue/128.
- /// </summary>
- public bool IsSigned { get; set; }
-
- /// <summary>
- /// Gets the maximum size for textures. This is usually a limit of 1024 pixel, but depends on the hardware.
- /// </summary>
- public static int MaxTextureSize
- {
- get
- {
- if (maxTextureSize == 0)
- {
- maxTextureSize = gl.GetIntegerValue(ParameterName.MaxTextureSize);
- }
- return maxTextureSize;
- }
- }
-
- public uint Name { get; protected set; }
-
- /// <summary>
- /// Gets the size that is used to store the image. this is a size that is always 2^n.
- /// </summary>
- public Size StorageSize { get; private set; }
-
- /// <summary>
- /// Gets the original size of the image.
- /// </summary>
- public Size Size { get; private set; }
-
- /// <summary>
- /// Gets the current storage format;
- /// </summary>
- public Format Format { get; private set; }
-
- /// <summary>
- /// Gets the current value type.
- /// </summary>
- public ValueType ValueType { get; private set; }
-
- public int Width { get { return Size.Width; } }
- public int Height { get { return Size.Height; } }
-
- protected static IImagingFactory ImageFactory
- {
- get
- {
- if (imageFactory == null)
- {
- imageFactory = (IImagingFactory)Activator.CreateInstance(Type.GetTypeFromCLSID(new Guid("327ABDA8-072B-11D3-9D7B-0000F81EF32E")));
- }
- return imageFactory;
- }
- }
-
- #endregion
- #region private Methods
-
- public DrawingCanvas CreateCanvas(int width, int height, TextureFormat format)
- {
- return new DrawingCanvas(this, width, height, format, Color.Transparent);
- }
-
-
- /// <summary>
- /// Creates a new graphics for drawing. Note that an existing image will be deleted.
- /// </summary>
- /// <param name="width">The width of the new graphics.</param>
- /// <param name="height">The height of the new graphics.</param>
- /// <param name="format">The pixel format.</param>
- /// <param name="transparentColor">The color that specifies the transparent color.</param>
- /// <returns>A new graphics.</returns>
- public DrawingCanvas CreateCanvas(int width, int height, TextureFormat format, Color transparentColor)
- {
- return new DrawingCanvas(this, width, height, format, transparentColor);
- }
-
-
- internal unsafe byte[] GetBytesFromBitmap(Bitmap bitmap, TextureFormat textureFormat, Color transparentColor)
- {
- Size size = new Size(bitmap.Width, bitmap.Height);
- if (size.Width > MaxTextureSize) throw new OverflowException("Width exceeds system limit of " + MaxTextureSize.ToString());
- if (size.Height > MaxTextureSize) throw new OverflowException("Height exceeds system limit of " + MaxTextureSize.ToString());
-
- PixelFormat pixFormat = TextureUtil.GetPixelFormatFromTextureFormat(textureFormat);
- System.Drawing.Imaging.BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, pixFormat);
- try
- {
- IntPtr scan0;
-
- if (textureFormat != TextureFormat.HiResAlpha)
- {
- scan0 = ConvertData(data, transparentColor, Size.Width, Size.Height, textureFormat);
-
- glValueType valueType = TextureUtil.GetValueTypeFromTextureFormat(textureFormat);
- GlesPixelFormat glFormat = TextureUtil.GetGlFormatFromTextureFormat(textureFormat);
- BitmapImageData imgData = new BitmapImageData(data);
- ReformatRawData(textureFormat, imgData);
- }
- else scan0 = data.Scan0;
-
- int n = data.Height * data.Stride;
- if (textureFormat == TextureFormat.HiResAlpha) n = n / 3;
-
- byte[] result = new byte[n];
-
- if (textureFormat == TextureFormat.HiResAlpha)
- {
- byte* cc = (byte*)((int)data.Scan0);
- for (int i = 0, j = 0; i < result.Length; i++, j += 3)
- {
- result[i] = cc[j];
- }
- }
- else
- {
- byte* cc = (byte*)((int)data.Scan0);
- for (int i = 0; i < result.Length; i++)
- {
- result[i] = *cc;
- cc++;
- }
- }
- return result;
- }
- finally
- {
- bitmap.UnlockBits(data);
- }
- }
-
- internal void CopyBitmap(Bitmap bitmap, TextureFormat textureFormat, Color transparentColor, Size origSize)
- {
- this.Size = origSize;
- Size size = new Size(bitmap.Width, bitmap.Height);
- if (size.Width > MaxTextureSize) throw new OverflowException("Width exceeds system limit of " + MaxTextureSize.ToString());
- if (size.Height > MaxTextureSize) throw new OverflowException("Height exceeds system limit of " + MaxTextureSize.ToString());
-
- PixelFormat pixFormat = TextureUtil.GetPixelFormatFromTextureFormat(textureFormat);
- System.Drawing.Imaging.BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.ImageLockMode.ReadWrite, pixFormat);
- try
- {
- IntPtr scan0 = ConvertData(data, transparentColor, origSize.Width, origSize.Height, textureFormat);
-
- glValueType valueType = TextureUtil.GetValueTypeFromTextureFormat(textureFormat);
- GlesPixelFormat glFormat = TextureUtil.GetGlFormatFromTextureFormat(textureFormat);
- BitmapImageData imgData = new BitmapImageData(data);
- ReformatRawData(textureFormat, imgData);
- LoadPixels(scan0, size, glFormat, valueType);
- }
- finally
- {
- bitmap.UnlockBits(data);
- }
- }
-
- private IntPtr ConvertData(System.Drawing.Imaging.BitmapData data, Color transparentColor, int width, int height, TextureFormat format)
- {
- switch (format)
- {
- //case TextureFormat.Alpha:
- // return TextureUtil.GenerateAlphaPlaneFromRgb565(data, width, height);
-
- case TextureFormat.LuminanceAlpha:
- return TextureUtil.GenerateAlphaPlaneFromARGB(data, transparentColor, width, height);
-
- case TextureFormat.RGBA5551:
- switch (data.PixelFormat)
- {
- case PixelFormat.Format32bppRgb: return TextureUtil.ConvertRGBATo5551(data, transparentColor);
- case PixelFormat.Format16bppRgb555: return TextureUtil.ConvertRGB555toRGBA5551(data, transparentColor);
- default: throw new NotSupportedException();
- }
-
-
- default:
- return data.Scan0;
- }
- }
-
-
-
- public static Texture FromStream(Stream stream, TextureFormat textureFormat)
- {
- Texture texture = new Texture();
- texture.LoadFromStream(stream, textureFormat);
- return texture;
- }
-
- public static Texture FromStream(Stream stream)
- {
- Texture texture = new Texture();
- texture.LoadFromStream(stream, TextureFormat.Automatic);
- return texture;
- }
-
-
- /// <summary>
- /// Loads data from a stream.
- /// </summary>
- /// <param name="stream">The stream where to get the image data.</param>
- /// <param name="textureFormat">The format of the texture.</param>
- public void LoadFromStream(Stream stream, TextureFormat textureFormat)
- {
- if (stream == null) throw new ArgumentNullException("stream");
- int bytesLength = (int)stream.Length;
- byte[] bytes = TextureUtil.BytesFromStream(stream);
-
- IImage image;
- uint hresult = ImageFactory.CreateImageFromBuffer(bytes, (uint)bytesLength, BufferDisposalFlag.None, out image);
- try
- {
- ImageInfo info = GetImageInfo(image);
- this.Size = new Size(info.Width, info.Height);
- Size imageSize = DetermineSize(info);
-
- if (textureFormat == TextureFormat.Automatic) textureFormat = GetTextureFormat(info);
- RawPixelFormat rawPixelFormat = TextureUtil.GetRawPixelFormatFromTextureFormat(textureFormat, (info.Flags & SinkFlags.HasAlpha) != 0);
-
- IBitmapImage bitmap;
- ImageFactory.CreateBitmapFromImage(image, (uint)imageSize.Width, (uint)imageSize.Height, rawPixelFormat, InterpolationHint.Default, out bitmap);
- try
- {
- Size textureSize;
- bitmap.GetSize(out textureSize);
- //StorageSize = textureSize;
- RECT rect = new RECT(0, 0, textureSize.Width, textureSize.Height);
- GlesPixelFormat glFormat = TextureUtil.GetGlFormatFromTextureFormat(textureFormat);
- glValueType valueType = TextureUtil.GetValueTypeFromTextureFormat(textureFormat);
-
- glImageLockMode lockMode = glImageLockMode.Read;
- BitmapImageData data = new BitmapImageData();
- bitmap.LockBits(ref rect, lockMode, rawPixelFormat, data);
- try
- {
- IntPtr scan0 = data.Scan0;
-
- ReformatRawData(textureFormat, data);
- LoadPixels(scan0, textureSize, glFormat, valueType);
- }
- finally
- {
- bitmap.UnlockBits(data);
- }
- }
- finally
- {
- Marshal.FinalReleaseComObject(bitmap);
- }
- }
- finally
- {
- Marshal.FinalReleaseComObject(image);
- }
- }
-
- private static ImageInfo GetImageInfo(IImage image)
- {
- ImageInfo info = new ImageInfo();
- image.GetImageInfo(info);
- return info;
- }
-
- private void ReformatRawData(TextureFormat textureFormat, BitmapImageData data)
- {
- RawPixelFormat pixelFormat = data.PixelFormat;
- switch (textureFormat)
- {
- case TextureFormat.Alpha:
- switch (pixelFormat)
- {
- case RawPixelFormat.Format16bppRGB565:
- TextureUtil.GenerateAlphaPlaneFromRgb565(data, data.Width, data.Height);
- break;
-
- case RawPixelFormat.Format32bppARGB:
- TextureUtil.GenerateAlphaPlaneFromARGB(data);
- break;
-
- default:
- throw new NotSupportedException();
- }
- break;
-
- case TextureFormat.RGB24:
- TextureUtil.SwapRedBluePixels(data, 3);
- break;
-
- case TextureFormat.RGBA4444:
- TextureUtil.SwapRedBluePixels(data, 4);
- break;
-
- case TextureFormat.RGBA5551:
- switch (pixelFormat)
- {
- case RawPixelFormat.Format16bppARGB1555: TextureUtil.Convert1555To5551(data); break;
- }
- break;
-
- case TextureFormat.LuminanceAlpha:
- TextureUtil.ConvertRGBAToLuminanceAlpha(data);
- break;
-
- case TextureFormat.Luminance:
- TextureUtil.ConvertRGBToLuminance(data);
- break;
-
- case TextureFormat.HiResAlpha:
- TextureUtil.ConvertRGBToLuminance(data);
- // TextureUtil.ConvertRGBAToAlpha(data);
- break;
-
- }
- }
-
-
- private static TextureFormat GetTextureFormat(ImageInfo info)
- {
- if ((info.Flags & SinkFlags.HasAlpha) != 0) return TextureFormat.RGBA5551;
- return TextureFormat.RGB565;
- }
-
-
-
- private static Size DetermineSize(ImageInfo info)
- {
- Size size = new Size(info.Width, info.Height);
-
- size.Width = TextureUtil.ConvertToValidTextureDimension(size.Width);
- size.Height = TextureUtil.ConvertToValidTextureDimension(size.Height);
-
- return size;
- }
-
-
- private void LoadPixels(IntPtr pixels, Size size, Format glFormat, ValueType glType)
- {
- gl.BindTexture(TextureTarget.Texture2D, Name);
- gl.TexParameterx(TextureTarget.Texture2D, TextureFilter.Minifying, TextureParam.Linear);
- gl.TexParameterx(TextureTarget.Texture2D, TextureFilter.Magnification, TextureParam.Linear);
- gl.TexParameterx(TextureTarget.Texture2D, TextureFilter.WrapS, TextureParam.Repeat);
- gl.TexParameterx(TextureTarget.Texture2D, TextureFilter.WrapT, TextureParam.Repeat);
- gl.GetError();
-
- //gl.PixelStorei(PixelStoreParam.UnpackAlignment, PixelStoreValue.EvenNumberedAlignment);
- //gl.GetError();
-
- gl.TexImage2D(TextureTarget.Texture2D, 0, glFormat, size.Width, size.Height, 0, glFormat, glType, pixels);
- gl.CheckError();
- this.StorageSize = size;
- this.Format = glFormat;
- this.ValueType = glType;
- }
-
- #endregion
- #region Methods
-
- public void PreLoad()
- {
- }
-
-
- /// <summary>
- /// Captures the specified clip from surface.
- /// </summary>
- /// <param name="clip">The clip rectangle to capture into this texture.</param>
- public void Capture(Rectangle clip)
- {
- Capture(clip, TextureUnit.Texture0);
- //this.ImageSize = this.Size = clip.Size;
- SetTextCoords();
-
- }
-
- /// <summary>
- /// Captures the specified clip from surface.
- /// </summary>
- /// <param name="clip">The clip rectangle to capture into this texture.</param>
- /// <param name="unit">A valid texture unit to use.</param>
- private void Capture(Rectangle clip, TextureUnit unit)
- {
- gl.ActiveTexture(unit);
- gl.ClientActiveTexture(unit);
- gl.BindTexture(TextureTarget.Texture2D, this.Name);
- Size defSize = new Size(TextureUtil.ConvertToValidTextureDimension(clip.Width), TextureUtil.ConvertToValidTextureDimension(clip.Height));
- short[] buffer = new short[defSize.Width * defSize.Height];
- if (StorageSize != clip.Size)
- {
- LoadPixels(IntPtr.Zero, defSize, GlesPixelFormat.RGB, glValueType.UnsignedShort565);
- }
- uint error2 = gl.GetError();
- if (error2 != 0) throw new OpenGlException("Capture:" + error2.ToString());
- // Note: CopyTexImage2D does not work when the width is larger than the screen width, but CopyTexSubImage2D does.
- //gl.CopyTexImage2D(TargetTexture.Texture2D, 0, GlesPixelFormat.RGB, clip.Left, clip.Top, clip.Width, clip.Height, 0);
- gl.CopyTexSubImage2D(TextureTarget.Texture2D, 0, 0, 0, clip.Left, clip.Top, clip.Width, clip.Height);
- uint error = gl.GetError();
- if (error != 0) throw new OpenGlException("Capture: " + error.ToString());
- this.Size = clip.Size;
- }
-
- private void SetTextCoords()
- {
- const int one = 65536;
-
- int w = StorageSize.Width;
- int h = StorageSize.Height;
-
- w = w > 0 ? one * Size.Width / w : 0;
- h = h > 0 ? one * (Size.Height - h) / h : 0;
-
- textCoords[0] = textCoords[2] = w;
- textCoords[1] = textCoords[5] = h;
- }
-
- public void Render()
- {
- gl.BindTexture(TextureTarget.Texture2D, Name);
- gl.TexCoordPointer(2, glValueType.Fixed, 0, textCoords);
- }
-
- public static Texture FromResource(string resource, TextureFormat format)
- {
- Stream stream = Assembly.GetCallingAssembly().GetManifestResourceStream(resource);
- if (stream == null) throw new SystemException("Resource " + resource + " not found.");
- Texture image = Texture.FromStream(stream, format);
-
- return image;
- }
-
- public static Texture FromResource(string resource, TextureFormat format, bool isSigned)
- {
- Stream stream = Assembly.GetCallingAssembly().GetManifestResourceStream(resource);
- if (stream == null) throw new SystemException("Resource " + resource + " not found.");
- Texture image = Texture.FromStream(stream, format);
- image.IsSigned = isSigned;
- return image;
- }
-
- internal unsafe void FromByteArray(byte[] array, TextureFormat textureFormat, Size size)
- {
- this.Size = size;
- glValueType valueType = TextureUtil.GetValueTypeFromTextureFormat(textureFormat);
- GlesPixelFormat glFormat = TextureUtil.GetGlFormatFromTextureFormat(textureFormat);
-
- fixed (byte* b = &array[0])
- {
- IntPtr ptr = new IntPtr(b);
- LoadPixels(ptr, size, glFormat, valueType);
- }
- }
-
- #endregion
-
- }
- }