using System;
using Silk.NET.OpenGL;
namespace AcDream.App.Rendering;
///
/// Two persistent GL sampler objects (Repeat + ClampToEdge) created once
/// per GL context. Renderers the appropriate
/// one to a texture unit instead of mutating per-texture
/// GL_TEXTURE_WRAP_S/T state — sampler state overrides the
/// texture's own wrap parameters, so two renderers can share the same
/// texture handle but sample it with different wrap modes safely.
///
///
/// Ported from
/// references/WorldBuilder/Chorizite.OpenGLSDLBackend/OpenGLGraphicsDevice.cs:115-132.
/// Filter modes match 's upload defaults
/// (Linear / Linear, no mipmaps) so binding either sampler doesn't
/// change the visual filtering behavior — only the wrap behavior at
/// UVs outside [0, 1].
///
///
///
/// Lifetime: created once at GL init, disposed with the GL context.
/// Anything that binds a sampler MUST unbind it (BindSampler(unit, 0))
/// before yielding to a renderer that doesn't use samplers, otherwise
/// the bound sampler's wrap mode will silently override that renderer's
/// per-texture wrap state.
///
///
public sealed class SamplerCache : IDisposable
{
private readonly GL _gl;
/// Sampler with WrapS = WrapT = Repeat. The default for textures uploaded by .
public uint Wrap { get; }
/// Sampler with WrapS = WrapT = ClampToEdge. Used by sky meshes whose authored UVs are strictly in [0, 1] to avoid bilinear-filter bleed at seam edges.
public uint Clamp { get; }
public SamplerCache(GL gl)
{
_gl = gl ?? throw new ArgumentNullException(nameof(gl));
Wrap = _gl.GenSampler();
_gl.SamplerParameter(Wrap, SamplerParameterI.WrapS, (int)TextureWrapMode.Repeat);
_gl.SamplerParameter(Wrap, SamplerParameterI.WrapT, (int)TextureWrapMode.Repeat);
_gl.SamplerParameter(Wrap, SamplerParameterI.MinFilter, (int)TextureMinFilter.Linear);
_gl.SamplerParameter(Wrap, SamplerParameterI.MagFilter, (int)TextureMagFilter.Linear);
Clamp = _gl.GenSampler();
_gl.SamplerParameter(Clamp, SamplerParameterI.WrapS, (int)TextureWrapMode.ClampToEdge);
_gl.SamplerParameter(Clamp, SamplerParameterI.WrapT, (int)TextureWrapMode.ClampToEdge);
_gl.SamplerParameter(Clamp, SamplerParameterI.MinFilter, (int)TextureMinFilter.Linear);
_gl.SamplerParameter(Clamp, SamplerParameterI.MagFilter, (int)TextureMagFilter.Linear);
}
public void Dispose()
{
if (Wrap != 0) _gl.DeleteSampler(Wrap);
if (Clamp != 0) _gl.DeleteSampler(Clamp);
}
}