Files
glitchy-engine-beef/GlitchyEngine/src/Renderer/SamplerState.bf
T

329 lines
9.0 KiB
Beef

using System;
using GlitchyEngine.Math;
using System.Collections;
namespace GlitchyEngine.Renderer
{
/**
* Defines the filter function used when sampling from a texture.
*/
public enum FilterFunction
{
/// Use point filtering (nearest neighbor) for sampling.
Point,
/// Use linear interpolation for sampling.
Linear,
/// Use anisotropic interpolation for sampling.
Anisotropic
}
public enum FilterMode
{
/// Just sample the texture.
Default,
/// Sample the texture and compares it with a comparison value.
Comparison,
/// Return the minimum value of the fetched texels.
Minimum,
/// Return the maximum value of the fetched texels.
Maximum
}
public enum ComparisonFunction
{
/**
* Never pass the comparison.
*/
Never = 1,
/**
* If the source data is less than the destination data, the comparison passes.
*/
Less = 2,
/**
* If the source data is equal to the destination data, the comparison passes.
*/
Equal = 3,
/**
* If the source data is less than or equal to the destination data, the comparison passes.
*/
LessOrEqual = 4,
/**
* If the source data is greater than the destination data, the comparison passes.
*/
Greater = 5,
/**
* If the source data is not equal to the destination data, the comparison passes.
*/
NotEqual = 6,
/**
* If the source data is greater than or equal to the destination data, the comparison passes.
*/
GreaterOrEqual = 7,
/**
* Always pass the comparison.
*/
Always = 8
}
public enum TextureAddressMode
{
/// Tile the texture at every (u,v) integer junction.
Wrap = 1,
/*
* Tile the texture at every (u,v) integer junction. However it is flipped every other tile.
* Example
* Between 0 and 1 the texture is addressed normally.
* Between 1 and 2 the texture is flipped.
* Between 2 and 3 the texture is addressed normally.
*/
Mirror,
/**
* Texture coordinates outside the range [0.0, 1.0] are set to the texture color at 0.0 or 1.0, respectively.
*/
Clamp,
/**
* Texture coordinates outside the range [0.0, 1.0] are set to the border color.
*/
Border,
/**
* Like a combination of Mirror and Clamp.
* Sample using the absolute value and clamp to 1.0.
*/
MirrorOnce
}
public struct SamplerStateDescription : IHashable
{
public FilterFunction MinFilter = .Linear;
public FilterFunction MagFilter = .Linear;
public FilterFunction MipFilter = .Linear;
public FilterMode FilterMode = .Default;
/**
* The function that is used to compare the sampled data against the existing sampled data.
* Only applies if FilterMode is set to FilterMode.Comparison.
*/
public ComparisonFunction ComparisonFunction = .Never;
public TextureAddressMode AddressModeU = .Clamp;
public TextureAddressMode AddressModeV = .Clamp;
public TextureAddressMode AddressModeW = .Clamp;
/**
* Offset from the calculated mipmap level.
* For example, if Direct3D calculates that a texture should be sampled at mipmap level 3 and MipLODBias is 2, then the texture will be sampled at mipmap level 5.
*/
public float MipLODBias = 0;
/**
* Lower end of the mipmap range to clamp access to, where 0 is the largest and most detailed mipmap level and any level higher than that is less detailed.
*/
public float MipMinLOD = float.MinValue;
/**
* Upper end of the mipmap range to clamp access to, where 0 is the largest and most detailed mipmap level and any level higher than that is less detailed.
* This value must be greater than or equal to MinLOD. To have no upper limit on LOD set this to a large value such as float.MaxValue.
*/
public float MipMaxLOD = float.MaxValue;
/**
* Clamping value used if FilterMode.Anisotropic is specified in the Filters.
* Valid values are between 1 and 16.
*/
public uint8 MaxAnisotropy = 1; // TODO: we could use a smaller int
/**
* Border color to use if TextureAddressMode.Border is specified for AddressModeU, AddressModeV, or AddressModeW.
*/
public ColorRGBA BorderColor = .White;
public int GetHashCode()
{
// Put integers into one integer
int intHash = ((int)MinFilter) | ((int)MagFilter << 2) | ((int)MipFilter << 4) | ((int)FilterMode << 6) | ((int)ComparisonFunction << 8) |
((int)AddressModeU << 12) | ((int)AddressModeU << 15) | ((int)AddressModeU << 18) | ((int)(MaxAnisotropy & 0x1F) << 21); // (26 bit)
// Put BorderColor into hash.
int colorHash = ((BorderColor.R.GetHashCode() * 397 ^ BorderColor.G.GetHashCode()) * 397 ^ BorderColor.B.GetHashCode()) * 397 ^ BorderColor.A.GetHashCode();
return (((colorHash * 397 ^ MipLODBias.GetHashCode()) * 397 ^ MipMinLOD.GetHashCode()) * 397 ^ MipMaxLOD.GetHashCode()) * 397 ^ intHash;
}
}
public static class SamplerStateManager
{
static GraphicsContext _context;
static Dictionary<SamplerStateDescription, SamplerState> _samplers;
public static SamplerState PointClamp;
public static SamplerState PointWrap;
public static SamplerState LinearClamp;
public static SamplerState LinearWrap;
public static SamplerState AnisotropicClamp;
public static SamplerState AnisotropicWrap;
public static void Init(GraphicsContext context)
{
_context = context..AddRef();
_samplers = new .();
// Init point samplers
{
var clampDesc = SamplerStateDescription()
{
MinFilter = .Point,
MagFilter = .Point,
MipFilter = .Point
};
PointClamp = GetSampler(clampDesc);
var wrapDesc = SamplerStateDescription()
{
MinFilter = .Point,
MagFilter = .Point,
MipFilter = .Point,
AddressModeU = .Wrap,
AddressModeV = .Wrap,
AddressModeW = .Wrap
};
PointWrap = GetSampler(wrapDesc);
}
// Init linear samplers
{
// Default Sampler ist LinearClamp
var clampDesc = SamplerStateDescription();
LinearClamp = GetSampler(clampDesc);
var wrapDesc = SamplerStateDescription()
{
AddressModeU = .Wrap,
AddressModeV = .Wrap,
AddressModeW = .Wrap
};
LinearWrap = GetSampler(wrapDesc);
}
// Init anisotropic samplers
{
var clampDesc = SamplerStateDescription()
{
MinFilter = .Anisotropic,
MagFilter = .Anisotropic,
MipFilter = .Anisotropic,
MaxAnisotropy = 16
};
AnisotropicClamp = GetSampler(clampDesc);
var wrapDesc = SamplerStateDescription()
{
MinFilter = .Anisotropic,
MagFilter = .Anisotropic,
MipFilter = .Anisotropic,
MaxAnisotropy = 16,
AddressModeU = .Wrap,
AddressModeV = .Wrap,
AddressModeW = .Wrap
};
AnisotropicWrap = GetSampler(wrapDesc);
}
}
public static void Uninit()
{
PointClamp.ReleaseRef();
PointWrap.ReleaseRef();
LinearClamp.ReleaseRef();
LinearWrap.ReleaseRef();
AnisotropicClamp.ReleaseRef();
AnisotropicWrap.ReleaseRef();
_context?.ReleaseRef();
delete _samplers;
_samplers = null;
}
/**
* Returns a Sampler State that has the specified settings.
* @param desc The Struct containing the sampler state options.
* @returns A SamplerState with the given options.
* @remarks This Function increases the SamplerStates reference counter, so remember to release it.
*/
public static SamplerState GetSampler(SamplerStateDescription desc)
{
Log.EngineLogger.AssertDebug(_samplers != null, "SamplerStateManager was not initialized.");
if(_samplers.TryGetValue(desc, let sampler))
{
return sampler..AddRef();
}
SamplerState newState = new SamplerState(_context, desc);
ManageSampler(newState);
return newState;
}
public static void ManageSampler(SamplerState samplerState)
{
Log.EngineLogger.AssertDebug(_samplers != null, "SamplerStateManager was not initialized.");
_samplers.Add(samplerState.Description, samplerState);
}
/**
* Removes the given SamplerState from the manager.
* Only allows to remove samplerState with a reference count of 0.
*/
internal static void Remove(SamplerState samplerState)
{
Log.EngineLogger.AssertDebug(samplerState.RefCount == 0, "Tried to delete sampler with nonzero reference count.");
_samplers?.Remove(samplerState.Description);
}
}
public class SamplerState : RefCounted
{
protected GraphicsContext _context ~ _?.ReleaseRef();
protected SamplerStateDescription _desc;
[Inline]
public FilterFunction MinificationFilter => _desc.MinFilter;
[Inline]
public FilterFunction MagnificationFilter => _desc.MagFilter;
[Inline]
public FilterFunction MipFilter => _desc.MipFilter;
[Inline]
public FilterMode FilterMode => _desc.FilterMode;
[Inline]
public SamplerStateDescription Description => _desc;
protected this(GraphicsContext context)
{
_context = context..AddRef();
}
public this(GraphicsContext context, SamplerStateDescription desc) : this(context)
{
_desc = desc;
PlatformCreateSamplerState();
}
public ~this()
{
SamplerStateManager.[Friend]Remove(this);
}
/// Creates the platform specific Sampler State
protected extern void PlatformCreateSamplerState();
public extern void Bind(uint32 slot = 0);
}
}