public Texture LoadTextureFromImage <T>(Image <T> image, string name = null, TextureLoadParameters?loadParams = null) where T : unmanaged, IPixel <T> { DebugTools.Assert(_mainThread == Thread.CurrentThread); var actualParams = loadParams ?? TextureLoadParameters.Default; var pixelType = typeof(T); // Flip image because OpenGL reads images upside down. var copy = FlipClone(image); var texture = new GLHandle((uint)GL.GenTexture()); GL.BindTexture(TextureTarget.Texture2D, texture.Handle); ApplySampleParameters(actualParams.SampleParameters); PixelInternalFormat internalFormat; PixelFormat pixelDataFormat; PixelType pixelDataType; if (pixelType == typeof(Rgba32)) { internalFormat = actualParams.Srgb ? PixelInternalFormat.Srgb8Alpha8 : PixelInternalFormat.Rgba8; pixelDataFormat = PixelFormat.Rgba; pixelDataType = PixelType.UnsignedByte; } else if (pixelType == typeof(Alpha8)) { if (image.Width % 4 != 0 || image.Height % 4 != 0) { throw new ArgumentException("Alpha8 images must have multiple of 4 sizes."); } internalFormat = PixelInternalFormat.R8; pixelDataFormat = PixelFormat.Red; pixelDataType = PixelType.UnsignedByte; // TODO: Does it make sense to default to 1 for RGB parameters? // It might make more sense to pass some options to change swizzling. var swizzle = new[] { (int)All.One, (int)All.One, (int)All.One, (int)All.Red }; GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle); } else if (pixelType == typeof(Gray8) && !actualParams.Srgb) { // Can only use R8 for Gray8 if sRGB is OFF. // Because OpenGL doesn't provide non-sRGB single/dual channel image formats. // Vulkan when? if (copy.Width % 4 != 0 || copy.Height % 4 != 0) { throw new ArgumentException("Gray8 non-sRGB images must have multiple of 4 sizes."); } internalFormat = PixelInternalFormat.R8; pixelDataFormat = PixelFormat.Red; pixelDataType = PixelType.UnsignedByte; var swizzle = new[] { (int)All.Red, (int)All.Red, (int)All.Red, (int)All.One }; GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle); } else { throw new NotImplementedException($"Unable to handle pixel type '{pixelType.Name}'"); } unsafe { var span = copy.GetPixelSpan(); fixed(T *ptr = span) { GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, copy.Width, copy.Height, 0, pixelDataFormat, pixelDataType, (IntPtr)ptr); } } return(GenTexture(texture, (copy.Width, copy.Height), name)); }
public Texture LoadTextureFromImage <T>(Image <T> image, string?name = null, TextureLoadParameters?loadParams = null) where T : unmanaged, IPixel <T> { DebugTools.Assert(_mainThread == Thread.CurrentThread); var actualParams = loadParams ?? TextureLoadParameters.Default; var pixelType = typeof(T); if (!_hasGLTextureSwizzle) { // If texture swizzle isn't available we have to pre-process the images to apply it ourselves // and then upload as RGBA8. // Yes this is inefficient but the alternative is modifying the shaders, // which I CBA to do. // Even 8 year old iGPUs support texture swizzle. if (pixelType == typeof(A8)) { // Disable sRGB so stuff doesn't get interpreter wrong. actualParams.Srgb = false; var img = ApplyA8Swizzle((Image <A8>)(object) image); return(LoadTextureFromImage(img, name, loadParams)); } if (pixelType == typeof(L8) && !actualParams.Srgb) { var img = ApplyL8Swizzle((Image <L8>)(object) image); return(LoadTextureFromImage(img, name, loadParams)); } } // Flip image because OpenGL reads images upside down. var copy = FlipClone(image); var texture = new GLHandle((uint)GL.GenTexture()); CheckGlError(); GL.BindTexture(TextureTarget.Texture2D, texture.Handle); CheckGlError(); ApplySampleParameters(actualParams.SampleParameters); PixelInternalFormat internalFormat; PixelFormat pixelDataFormat; PixelType pixelDataType; if (pixelType == typeof(Rgba32)) { internalFormat = actualParams.Srgb ? PixelInternalFormat.Srgb8Alpha8 : PixelInternalFormat.Rgba8; pixelDataFormat = PixelFormat.Rgba; pixelDataType = PixelType.UnsignedByte; } else if (pixelType == typeof(A8)) { if (image.Width % 4 != 0 || image.Height % 4 != 0) { throw new ArgumentException("Alpha8 images must have multiple of 4 sizes."); } internalFormat = PixelInternalFormat.R8; pixelDataFormat = PixelFormat.Red; pixelDataType = PixelType.UnsignedByte; unsafe { // TODO: Does it make sense to default to 1 for RGB parameters? // It might make more sense to pass some options to change swizzling. var swizzle = stackalloc[] { (int)All.One, (int)All.One, (int)All.One, (int)All.Red }; GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle); } } else if (pixelType == typeof(L8) && !actualParams.Srgb) { // Can only use R8 for L8 if sRGB is OFF. // Because OpenGL doesn't provide sRGB single/dual channel image formats. // Vulkan when? if (copy.Width % 4 != 0 || copy.Height % 4 != 0) { throw new ArgumentException("L8 non-sRGB images must have multiple of 4 sizes."); } internalFormat = PixelInternalFormat.R8; pixelDataFormat = PixelFormat.Red; pixelDataType = PixelType.UnsignedByte; unsafe { var swizzle = stackalloc[] { (int)All.Red, (int)All.Red, (int)All.Red, (int)All.One }; GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureSwizzleRgba, swizzle); } } else { throw new NotImplementedException($"Unable to handle pixel type '{pixelType.Name}'"); } unsafe { var span = copy.GetPixelSpan(); fixed(T *ptr = span) { GL.TexImage2D(TextureTarget.Texture2D, 0, internalFormat, copy.Width, copy.Height, 0, pixelDataFormat, pixelDataType, (IntPtr)ptr); CheckGlError(); } } var pressureEst = EstPixelSize(internalFormat) * copy.Width * copy.Height; return(GenTexture(texture, (copy.Width, copy.Height), name, pressureEst)); }