Konstantin Koch 55ab328f79 Updated BasicEffectSample, DualTextureSample, KeyboardSample and MultiRenderTarget. Also reduced the memory usage for multiple rendertargets
Also did some Refactoring for Classes that implement and use
INativeBuffer.
The memory usage reduction for rendertargets resulted in some
refactoring of the directx texture classes.
Also added DebugNames for some DirectX resources in case of a debug
build.
2015-09-30 21:31:15 +02:00

339 lines
8.6 KiB
C#

using System;
using System.IO;
using System.Runtime.InteropServices;
using ANX.Framework;
using ANX.Framework.Graphics;
using ANX.Framework.NonXNA.RenderSystem;
using ANX.RenderSystem.GL3.Helpers;
using OpenTK.Graphics.OpenGL;
// 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.RenderSystem.GL3
{
public class Texture2DGL3 : INativeTexture2D
{
#region Private
private PixelInternalFormat nativeFormat;
/// <summary>
/// [1-n]
/// </summary>
private int numberOfMipMaps;
private int width;
private int height;
private bool isCompressed;
internal bool IsDisposed;
private int uncompressedDataSize;
private byte[] texData;
private int maxSetDataSize;
#endregion
#region Public
protected internal int NativeHandle { get; protected set; }
#endregion
#region Constructor
internal Texture2DGL3()
{
GraphicsResourceManager.UpdateResource(this, true);
}
internal Texture2DGL3(SurfaceFormat surfaceFormat, int setWidth, int setHeight, int mipCount)
{
GraphicsResourceManager.UpdateResource(this, true);
width = setWidth;
height = setHeight;
numberOfMipMaps = mipCount;
nativeFormat = DatatypesMapping.SurfaceToPixelInternalFormat(surfaceFormat);
isCompressed = nativeFormat.ToString().StartsWith("Compressed");
uncompressedDataSize = GetUncompressedDataSize();
CreateTexture();
}
~Texture2DGL3()
{
GraphicsResourceManager.UpdateResource(this, false);
}
#endregion
#region CreateTexture
private void CreateTexture()
{
NativeHandle = GL.GenTexture();
GL.BindTexture(TextureTarget.Texture2D, NativeHandle);
int wrapMode = (int)All.ClampToEdge;
All minFilter = numberOfMipMaps > 1 ? All.LinearMipmapLinear : All.Linear;
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, wrapMode);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, wrapMode);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)All.Linear);
GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)minFilter);
#if DEBUG
ErrorHelper.Check("TexParameter");
#endif
}
#endregion
// TODO: offsetInBytes
// TODO: elementCount
#region SetData
public void SetData<T>(T[] data) where T : struct
{
SetData<T>(0, data, 0, data.Length);
}
public void SetData<T>(T[] data, int startIndex, int elementCount) where T : struct
{
SetData<T>(0, data, 0, data.Length);
}
public void SetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount) where T : struct
{
int size = Marshal.SizeOf(typeof(T)) * data.Length;
if (size > maxSetDataSize)
maxSetDataSize = size;
GL.BindTexture(TextureTarget.Texture2D, NativeHandle);
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
IntPtr dataPointer = handle.AddrOfPinnedObject();
// Go to the starting point.
dataPointer += startIndex;
int mipmapWidth = Math.Max(width >> level, 1);
int mipmapHeight = Math.Max(height >> level, 1);
if (isCompressed)
{
GL.CompressedTexImage2D(TextureTarget.Texture2D, level, nativeFormat, width, height, 0, data.Length,
dataPointer);
#if DEBUG
ErrorHelper.Check("CompressedTexImage2D Format=" + nativeFormat);
#endif
}
else
{
GL.TexImage2D(TextureTarget.Texture2D, level, nativeFormat, mipmapWidth, mipmapHeight, 0,
(PixelFormat)nativeFormat, PixelType.UnsignedByte, dataPointer);
#if DEBUG
ErrorHelper.Check("TexImage2D Format=" + nativeFormat);
#endif
}
}
finally
{
handle.Free();
}
}
public void SetData<T>(int offsetInBytes, T[] data, int startIndex, int elementCount) where T : struct
{
int size = Marshal.SizeOf(typeof(T)) * data.Length;
if (size > maxSetDataSize)
maxSetDataSize = size;
GL.BindTexture(TextureTarget.Texture2D, NativeHandle);
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
try
{
IntPtr dataPointer = handle.AddrOfPinnedObject();
dataPointer += startIndex;
if (isCompressed)
{
GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, nativeFormat, width, height, 0, data.Length, dataPointer);
#if DEBUG
ErrorHelper.Check("CompressedTexImage2D Format=" + nativeFormat);
#endif
}
else
{
GL.TexImage2D(TextureTarget.Texture2D, 0, nativeFormat, width, height, 0, (PixelFormat)nativeFormat,
PixelType.UnsignedByte, dataPointer);
#if DEBUG
ErrorHelper.Check("TexImage2D Format=" + nativeFormat);
#endif
}
}
finally
{
handle.Free();
}
}
#endregion
#region GetData (TODO)
public void GetData<T>(int level, Rectangle? rect, T[] data, int startIndex, int elementCount) where T : struct
{
throw new NotImplementedException();
}
#endregion
#region GetData
public void GetData<T>(T[] data) where T : struct
{
GetData(data, 0, data.Length);
}
#endregion
// TODO: compressed texture (see: http://www.bearisgaming.com/texture2d-getdata-and-dxt-compression/)
// TODO: elementCount
#region GetData
public void GetData<T>(T[] data, int startIndex, int elementCount) where T : struct
{
if (isCompressed)
throw new NotImplementedException("GetData is currently not implemented for compressed texture format " +
nativeFormat + ".");
if (data == null)
throw new ArgumentNullException("data");
int size = Marshal.SizeOf(typeof(T)) * data.Length;
if (size < uncompressedDataSize)
throw new InvalidDataException("The size of the data passed in is too large or too small for this resource.");
GCHandle handle = GCHandle.Alloc(data, GCHandleType.Pinned);
IntPtr ptr = handle.AddrOfPinnedObject();
ptr += startIndex;
GL.GetTexImage(TextureTarget.Texture2D, 0, (PixelFormat)nativeFormat, PixelType.UnsignedByte, ptr);
handle.Free();
}
#endregion
#region GetTextureData
private void GetTextureData()
{
GL.BindTexture(TextureTarget.Texture2D, NativeHandle);
if (isCompressed)
{
texData = new byte[maxSetDataSize];
GCHandle handle = GCHandle.Alloc(texData, GCHandleType.Pinned);
GL.GetCompressedTexImage(TextureTarget.Texture2D, 0, handle.AddrOfPinnedObject());
handle.Free();
}
else
{
texData = new byte[uncompressedDataSize];
GCHandle handle = GCHandle.Alloc(texData, GCHandleType.Pinned);
GL.GetTexImage(TextureTarget.Texture2D, 0, (PixelFormat)nativeFormat, PixelType.UnsignedByte,
handle.AddrOfPinnedObject());
handle.Free();
}
}
#endregion
#region RecreateData
internal void RecreateData()
{
CreateTexture();
SetData(texData);
texData = null;
}
#endregion
#region GetUncompressedDataSize
private int GetUncompressedDataSize()
{
int size = width * height;
switch (nativeFormat)
{
default:
case PixelInternalFormat.R32f:
case PixelInternalFormat.Rgb10A2:
case PixelInternalFormat.Rg16:
case PixelInternalFormat.Rgba:
size *= 4;
break;
case PixelInternalFormat.Rg32f:
case PixelInternalFormat.Rgba16f:
size *= 8;
break;
case PixelInternalFormat.R16f:
case PixelInternalFormat.Rgb5A1:
case PixelInternalFormat.Rgba4:
size *= 2;
break;
case PixelInternalFormat.Alpha8:
//size *= 1;
break;
case PixelInternalFormat.Rgba32f:
size *= 16;
break;
}
return size;
}
#endregion
#region SaveAsJpeg (TODO)
public void SaveAsJpeg(Stream stream, int width, int height)
{
throw new NotImplementedException();
}
#endregion
#region SaveAsPng (TODO)
public void SaveAsPng(Stream stream, int width, int height)
{
throw new NotImplementedException();
}
#endregion
#region Dispose
/// <summary>
/// Dispose the native OpenGL texture handle.
/// </summary>
public virtual void Dispose()
{
if (IsDisposed == false)
{
IsDisposed = true;
DisposeResource();
}
}
internal void DisposeResource()
{
if (IsDisposed == false)
{
GetTextureData();
}
if (NativeHandle != -1 &&
GraphicsDeviceWindowsGL3.IsContextCurrent)
{
GL.DeleteTexture(NativeHandle);
NativeHandle = -1;
#if DEBUG
ErrorHelper.Check("DeleteTexture");
#endif
}
}
#endregion
}
}