/Graphics/OpenTK/OpenTKTexture.cs
C# | 355 lines | 249 code | 23 blank | 83 comment | 24 complexity | c707a99c88e30443d1c7245c6f9155bc MD5 | raw file
Possible License(s): Apache-2.0
- using System;
- using System.Runtime.InteropServices;
- using Delta.Graphics.BaseOpenGL;
- using Delta.Platforms.Windows;
- using Delta.Utilities;
- using Delta.Utilities.Datatypes;
- using Delta.Utilities.Graphics;
- using OpenTK.Graphics.OpenGL;
-
- namespace Delta.Graphics.OpenTK
- {
- /// <summary>
- /// OpenTK texture implementation. Helpful links:
- /// http://www.opentk.com/project/TexLib
- /// http://www.opentk.com/node/750
- /// http://www.opentk.com/node/1624
- /// http://people.mozilla.com/~vladimir/jsvec/WebGL-spec.html
- /// </summary>
- internal class OpenTKTexture : BaseOpenGLTexture
- {
- #region Constructors
- /// <summary>
- /// Creates a OpenGL Texture, all the magic happens in the Load methods
- /// </summary>
- /// <param name="setContentName">Content image name to load</param>
- protected OpenTKTexture(string setContentName)
- : base(setContentName)
- {
- }
-
- /// <summary>
- /// Create texture with given RGB data, this can be used to create
- /// textures programmatically (e.g. mini-maps). You can also use
- /// RenderToTexture to render onto textures, which can also be used in
- /// Materials and Shaders. RenderToTexture is much more efficient if you
- /// want to change the texture data and should always be used for post
- /// screen shaders. This constructor is only useful for static data.
- /// </summary>
- /// <param name="setRgbData">RGB data (24 bit per pixel, no alpha)</param>
- /// <param name="setSize">Size of the texture in pixels,
- /// Width * Height must match rgbData.Length / 3</param>
- /// <param name="setMode">Blend mode to use for this texture</param>
- /// <param name="setUseLinearFiltering">True if we want the normal linear
- /// filtering enabled or false for sharp blocky looking textures.</param>
- /// <param name="setIsRgba">
- /// Set true whether setByteData is RGBA or RGB.
- /// </param>
- protected OpenTKTexture(byte[] setRgbData, Size setSize,
- BlendMode setMode, bool setUseLinearFiltering, bool setIsRgba)
- : base(setRgbData, setSize, setMode, setUseLinearFiltering, setIsRgba)
- {
- }
- #endregion
-
- #region Methods (Private)
-
- #region SetTextureParameters
- /// <summary>
- /// Set texture parameters for wrap mode and texture filtering.
- /// </summary>
- protected override void SetTextureParameters(int wrapMode,
- int magFilterMode, int minFilterMode)
- {
- // Creating a texture without setting the filter states is problematic
- // in OpenGL (due to the default values
- // http://www.opengl.org/wiki/Common_Mistakes#Creating_a_Texture)
- // Since we cannot be sure when and how this constant is going to be
- // created, it is preferred to set the parameters explicitly here
- if (IsCubeMap)
- {
- GL.TexParameter(TextureTarget.TextureCubeMap,
- TextureParameterName.TextureWrapS, wrapMode);
- GL.TexParameter(TextureTarget.TextureCubeMap,
- TextureParameterName.TextureWrapT, wrapMode);
- GL.TexParameter(TextureTarget.TextureCubeMap,
- TextureParameterName.TextureMagFilter, magFilterMode);
- GL.TexParameter(TextureTarget.TextureCubeMap,
- TextureParameterName.TextureMinFilter, minFilterMode);
- }
- else
- {
- GL.TexParameter(TextureTarget.Texture2D,
- TextureParameterName.TextureWrapS, wrapMode);
- GL.TexParameter(TextureTarget.Texture2D,
- TextureParameterName.TextureWrapT, wrapMode);
- GL.TexParameter(TextureTarget.Texture2D,
- TextureParameterName.TextureMagFilter, magFilterMode);
- GL.TexParameter(TextureTarget.Texture2D,
- TextureParameterName.TextureMinFilter, minFilterMode);
- }
- }
- #endregion
-
- #region FillTextureData
- /// <summary>
- /// Fill texture data that has already been loaded in a specific format
- /// and upload it to the GPU for use in rendering.
- /// </summary>
- protected override bool FillTextureData(Size fullImageSize,
- byte[] imageData, int dataLengthPerTexture, int minimumMipmapByteSize,
- int numberOfMipmaps, bool isDxt1, bool isDxt3, bool isDxt5,
- bool isAtc, bool isAtcA, bool isAtcI,
- bool isRgba4Texture, bool isPvrTexture, bool isRgb5A1Texture)
- {
-
- ErrorCode error = GL.GetError();
- if (error != ErrorCode.NoError)
- {
- Log.Warning(
- "There was an OpenGL error before, you should " +
- "investigate: '" + error + "'. Trying to load a texture '" +
- this +
- "' here (and if anything fails with this fails we want to report " +
- "that error, not any previous error, which should be fixed " +
- "elsewhere).");
- }
- if (isPvrTexture)
- {
- Log.Warning(
- "Sorry, PVR textures are not supported in OpenTK: " +
- this +
- ". Please use the content system to generate texture files " +
- "that can be used here (usually DDS on Windows)");
- return false;
- }
- if (isAtc || isAtcA || isAtcI)
- {
- Log.Warning(
- "Sorry, ATC textures are not supported in OpenTK: " +
- this +
- ". Please use the content system to generate texture files " +
- "that can be used here (usually DDS on Windows)");
- return false;
- }
-
- // Check if power of two.
- //disabled because content is not using atlas yet.
- //if (MathHelper.IsPowerOfTwo(fullImageSize.Width) == false ||
- // MathHelper.IsPowerOfTwo(fullImageSize.Height) == false)
- //{
- // Log.Info("This texture is not power of two and might cause "+
- // "rendering problems, this platform supports non-power of "+
- // "two textures, but this can cause problems on other platforms. "+
- // "Please only create power of two textures! "+
- // "Image Size=" + fullImageSize);
- //}
-
- // Create the texture in OpenGL and use the textureHandle from now on.
- GL.GenTextures(1, out textureHandle);
-
- // By default the pixel format is Rgb for non alpha and Rgba for alpha
- // PixelInternalFormat: Rgba is 0x1908, Rgb is 0x1907.
- PixelInternalFormat formatUsed =
- HasAlpha
- ? PixelInternalFormat.Rgba
- : PixelInternalFormat.Rgb;
-
- int imageWidth = (int)fullImageSize.Width;
- int imageHeight = (int)fullImageSize.Height;
-
- // Bind the texture, which is usually a 2D texture (except for cube maps)
- if (IsCubeMap)
- {
- GL.BindTexture(TextureTarget.TextureCubeMap, textureHandle);
- GL.Enable(EnableCap.TextureCubeMap);
- }
- else
- {
- GL.BindTexture(TextureTarget.Texture2D, textureHandle);
- }
-
- // Note: We always force clamp to fully utilize atlas texturing
- // Use ClampToEdge or we get black lines at the edges.
- int wrapMode = (int)All.ClampToEdge;
- if (AllowTiling)
- {
- wrapMode = (int)All.Repeat;
- }
- // Note: Using just bilinear filtering, not trilinear for better
- // performance on slow devices. For additional information see:
- // http://www.ds.arch.tue.nl/joran/wup/Default.menu?menu=6
- // Note: on PC trilinear is the same speed as LinearMipmapNearest
- SetTextureParameters(wrapMode,
- UseLinearFiltering
- ? (int)All.Linear
- : (int)All.Nearest,
- UseLinearFiltering
- ? numberOfMipmaps > 1
- ? (int)All.LinearMipmapLinear
- : (int)All.Linear
- : numberOfMipmaps > 1
- ? (int)All.NearestMipmapNearest
- : (int)All.Nearest);
-
- // Use glTexImage2D instead of glCompressedTexImage2D for uncompressed
- // DDS files (RGB 888 or RGBA 8888)
- GCHandle handle = GCHandle.Alloc(imageData, GCHandleType.Pinned);
- try
- {
- IntPtr dataPointer = handle.AddrOfPinnedObject();
- if (isDxt1 || isDxt3 || isDxt5)
- {
- // Note: CompressedRgbS3tcDxt1Ext seems always to be the same as
- // CompressedRgbaS3tcDxt1Ext, if the image uses alpha is decided
- // by the dds, not by this flag.
- //PixelInternalFormat.CompressedRgbaS3tcDxt1Ext :
- formatUsed =
- isDxt1
- ? PixelInternalFormat.CompressedRgbS3tcDxt1Ext
- : isDxt3
- ? PixelInternalFormat.CompressedRgbaS3tcDxt3Ext
- : PixelInternalFormat.CompressedRgbaS3tcDxt5Ext;
-
- // Width and height must be multiple of 4x4. For more help see:
- // http://www.khronos.org/opengles/sdk/1.1/docs/man/glCompressedTexImage2D.xml
- int mipmapWidth = (imageWidth / 4) * 4;
- int mipmapHeight = (imageHeight / 4) * 4;
-
- if (IsCubeMap)
- {
- // For cube maps we need to load all 6 cube faces
- for (int face = 0; face < 6; face++)
- {
- GL.CompressedTexImage2D(
- TextureTarget.TextureCubeMapPositiveX + face, 0,
- formatUsed, mipmapWidth, mipmapHeight, 0,
- dataLengthPerTexture, dataPointer);
- dataPointer += dataLengthPerTexture;
- }
- }
- else
- {
- GL.CompressedTexImage2D(TextureTarget.Texture2D, 0, formatUsed,
- mipmapWidth, mipmapHeight, 0, dataLengthPerTexture,
- dataPointer);
-
- int mipmapByteSize = dataLengthPerTexture;
- for (int i = 1; i < numberOfMipmaps; i++)
- {
- // Move our data pointer along.
- dataPointer += mipmapByteSize;
- mipmapByteSize /= 4;
- mipmapWidth /= 2;
- mipmapHeight /= 2;
- if (mipmapByteSize < minimumMipmapByteSize)
- {
- mipmapByteSize = minimumMipmapByteSize;
- }
- if (mipmapWidth < 1)
- {
- mipmapWidth = 1;
- }
- if (mipmapHeight < 1)
- {
- mipmapHeight = 1;
- }
- GL.CompressedTexImage2D(TextureTarget.Texture2D, i, formatUsed,
- mipmapWidth, mipmapHeight, 0, mipmapByteSize, dataPointer);
- } // for
- } // else
- } // if (ddsFormat)
- else
- {
- PixelType pixelType =
- isRgb5A1Texture
- ? PixelType.UnsignedShort5551
- : isRgba4Texture
- ? PixelType.UnsignedShort4444
- : PixelType.UnsignedByte;
-
- GL.TexImage2D(TextureTarget.Texture2D, 0,
- // Use the same for internal format (Rgba or Rgb)
- formatUsed, imageWidth, imageHeight, 0,
- // And the same for the pixel format of the incoming data
- (PixelFormat)formatUsed, pixelType, dataPointer);
-
- int mipmapByteSize = dataLengthPerTexture;
- int mipmapWidth = imageWidth;
- int mipmapHeight = imageHeight;
- if (mipmapByteSize > 0 &&
- numberOfMipmaps > 1)
- {
- for (int i = 1; i < numberOfMipmaps; i++)
- {
- // Move our data pointer along.
- dataPointer += mipmapByteSize;
- mipmapByteSize /= 4;
- mipmapWidth /= 2;
- mipmapHeight /= 2;
- if (mipmapWidth < 1)
- {
- mipmapWidth = 1;
- }
- if (mipmapHeight < 1)
- {
- mipmapHeight = 1;
- }
-
- // Use the same for internal format (Rgba or Rgb)
- // And the same for the pixel format of the incoming data
- GL.TexImage2D(TextureTarget.Texture2D, i,
- formatUsed, mipmapWidth, mipmapHeight, 0,
- (PixelFormat)formatUsed, pixelType, dataPointer);
- } // for
- } // if
- } // else
- } // try
- finally
- {
- handle.Free();
- }
-
- return true;
- }
- #endregion
-
- #region LoadPngImageData
- /// <summary>
- /// Helper method to load png image data, which is not allowed on all
- /// platforms (only on Windows to be precise).
- /// </summary>
- /// <param name="filename">Filename to load the png from</param>
- /// <param name="totalImageSize">Total image size from the png data</param>
- /// <returns>The RGB or RGBA image data.</returns>
- protected override byte[] LoadPngImageData(string filename,
- out Size totalImageSize)
- {
- bool totalImageHasAlpha;
- byte[] data = BitmapHelper.GetRGBAImageData(filename,
- out totalImageSize, out totalImageHasAlpha);
- if (totalImageHasAlpha != HasAlpha)
- {
- Log.Info(
- "Loaded Png Image might cause problems '" + filename + "' has " +
- (totalImageHasAlpha
- ? "alpha"
- : "no alpha") + " (switching to " +
- "this), but the given blend mode '" + BlendMode + "' from the " +
- "content system says we have " +
- (HasAlpha
- ? "alpha"
- : "no alpha"));
- BlendMode =
- totalImageHasAlpha
- ? BlendMode.Translucency
- : BlendMode.Opaque;
- }
- return data;
- }
- #endregion
-
- #endregion
- }
- }
-