using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; using System.Runtime.CompilerServices; namespace SemiColinGames; public class Texture : IDisposable { public int Handle; public Vector2i Size; private static int maxHandle = -1; private bool disposedValue = false; public Texture(Image image) { Size = new Vector2i(image.Width, image.Height); byte[] pixelBytes = new byte[Size.X * Size.Y * Unsafe.SizeOf()]; image.CopyPixelDataTo(pixelBytes); Handle = GL.GenTexture(); if (Handle > maxHandle) { // Console.WriteLine("GL.GenTexture #" + Handle); maxHandle = Handle; } GL.ActiveTexture(TextureUnit.Texture0); GL.BindTexture(TextureTarget.Texture2D, Handle); GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, Size.X, Size.Y, 0, PixelFormat.Rgba, PixelType.UnsignedByte, pixelBytes); //GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.LinearMipmapLinear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int) TextureMinFilter.Linear); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int) TextureMagFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, (int) TextureWrapMode.ClampToBorder); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, (int) TextureWrapMode.ClampToBorder); float[] borderColor = { 0.0f, 0.0f, 0.0f, 1.0f }; GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureBorderColor, borderColor); // FIXME: should we use mipmaps? //GL.GenerateMipmap(GenerateMipmapTarget.Texture2D); } protected virtual void Dispose(bool disposing) { if (!disposedValue) { GL.DeleteTexture(Handle); disposedValue = true; } } ~Texture() { if (!disposedValue) { Console.WriteLine("~Texture(): resource leak? Dispose() should be called manually."); } } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } }