using System; using System.Collections.Generic; using System.IO; using gaemstone.ECS; using Silk.NET.OpenGL; using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using Size = System.Drawing.Size; namespace gaemstone.Client; public static class TextureManager { private static readonly Dictionary _byTexture = new(); private static readonly Dictionary _bySourceFile = new(); public static void Initialize(Universe universe) { var GL = universe.Lookup().Get().GL; // Upload single-pixel white texture into texture slot 0, so when // "no" texture is bound, we can still use the texture sampler. GL.BindTexture(TextureTarget.Texture2D, 0); Span pixel = stackalloc byte[4]; pixel.Fill(255); GL.TexImage2D(TextureTarget.Texture2D, 0, InternalFormat.Rgba, 1, 1, 0, PixelFormat.Rgba, PixelType.UnsignedByte, in pixel[0]); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); } public static Texture Load(Universe universe, string name) { using var stream = Resources.GetStream(name); return CreateFromStream(universe, stream, name); } public static Texture CreateFromStream(Universe universe, Stream stream, string? sourceFile = null) { var GL = universe.Lookup().Get().GL; var texture = new Texture(TextureTarget.Texture2D, GL.GenTexture()); GL.BindTexture(texture.Target, texture.Handle); var image = Image.Load(stream); ref var origin = ref image.Frames[0].PixelBuffer[0, 0]; GL.TexImage2D(texture.Target, 0, (int)PixelFormat.Rgba, (uint)image.Width, (uint)image.Height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, origin); GL.TexParameter(texture.Target, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Nearest); GL.TexParameter(texture.Target, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Nearest); var info = new TextureInfo(texture, sourceFile, new(image.Width, image.Height)); _byTexture.Add(texture, info); if (sourceFile != null) _bySourceFile.Add(sourceFile, info); GL.BindTexture(texture.Target, 0); return texture; } public static TextureInfo? Lookup(Texture texture) => _byTexture.TryGetValue(texture, out var value) ? value : null; public static TextureInfo? Lookup(string sourceFile) => _bySourceFile.TryGetValue(sourceFile, out var value) ? value : null; } public class TextureInfo { public Texture Texture { get; } public string? SourceFile { get; } public Size Size { get; } public TextureInfo(Texture texture, string? sourceFile, Size size) => (Texture, SourceFile, Size) = (texture, sourceFile, size); }