diff --git a/src/modules/graphics/Canvas.cpp b/src/modules/graphics/Canvas.cpp index aeca38809..008851615 100644 --- a/src/modules/graphics/Canvas.cpp +++ b/src/modules/graphics/Canvas.cpp @@ -64,10 +64,7 @@ Canvas::Canvas(const Settings &settings) throw love::Exception("Non-readable and MSAA textures cannot have mipmaps."); if (settings.mipmaps != MIPMAPS_NONE) - { mipmapCount = getTotalMipmapCount(pixelWidth, pixelHeight, depth); - filter.mipmap = defaultMipmapFilter; - } auto gfx = Module::getInstance(Module::M_GRAPHICS); const Graphics::Capabilities &caps = gfx->getCapabilities(); diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index f94adaa05..df325dd73 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -47,18 +47,20 @@ int Font::fontCount = 0; const vertex::CommonFormat Font::vertexFormat = vertex::CommonFormat::XYf_STus_RGBAub; -Font::Font(love::font::Rasterizer *r, const Texture::Filter &f) +Font::Font(love::font::Rasterizer *r, const SamplerState &s) : rasterizers({r}) , height(r->getHeight()) , lineHeight(1) , textureWidth(128) , textureHeight(128) - , filter(f) + , samplerState() , dpiScale(r->getDPIScale()) , useSpacesAsTab(false) , textureCacheID(0) { - filter.mipmap = Texture::FILTER_NONE; + samplerState.minFilter = s.minFilter; + samplerState.magFilter = s.magFilter; + samplerState.maxAnisotropy = s.maxAnisotropy; // Try to find the best texture size match for the font size. default to the // largest texture size if no rough match is found. @@ -150,7 +152,7 @@ void Font::createTexture() Image::Settings settings; image = gfx->newImage(TEXTURE_2D, pixelFormat, size.width, size.height, 1, settings); - image->setFilter(filter); + image->setSamplerState(samplerState); { size_t bpp = getPixelFormatSize(pixelFormat); @@ -918,17 +920,19 @@ float Font::getLineHeight() const return lineHeight; } -void Font::setFilter(const Texture::Filter &f) +void Font::setSamplerState(const SamplerState &s) { - for (const auto &image : images) - image->setFilter(f); + samplerState.minFilter = s.minFilter; + samplerState.magFilter = s.magFilter; + samplerState.maxAnisotropy = s.maxAnisotropy; - filter = f; + for (const auto &image : images) + image->setSamplerState(samplerState); } -const Texture::Filter &Font::getFilter() const +const SamplerState &Font::getSamplerState() const { - return filter; + return samplerState; } int Font::getAscent() const diff --git a/src/modules/graphics/Font.h b/src/modules/graphics/Font.h index dbca1920c..20f5bc5c8 100644 --- a/src/modules/graphics/Font.h +++ b/src/modules/graphics/Font.h @@ -96,7 +96,7 @@ public: int vertexcount; }; - Font(love::font::Rasterizer *r, const Texture::Filter &filter); + Font(love::font::Rasterizer *r, const SamplerState &samplerState); virtual ~Font(); @@ -158,8 +158,8 @@ public: **/ float getLineHeight() const; - void setFilter(const Texture::Filter &f); - const Texture::Filter &getFilter() const; + void setSamplerState(const SamplerState &s); + const SamplerState &getSamplerState() const; // Extra font metrics int getAscent() const; @@ -227,7 +227,7 @@ private: PixelFormat pixelFormat; - Texture::Filter filter; + SamplerState samplerState; float dpiScale; diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index d3863cf33..fcdb70cee 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -184,19 +184,19 @@ Quad *Graphics::newQuad(Quad::Viewport v, double sw, double sh) return new Quad(v, sw, sh); } -Font *Graphics::newFont(love::font::Rasterizer *data, const Texture::Filter &filter) +Font *Graphics::newFont(love::font::Rasterizer *data) { - return new Font(data, filter); + return new Font(data, states.back().defaultSamplerState); } -Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting, const Texture::Filter &filter) +Font *Graphics::newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting) { auto fontmodule = Module::getInstance(M_FONT); if (!fontmodule) throw love::Exception("Font module has not been loaded."); StrongRef r(fontmodule->newTrueTypeRasterizer(size, hinting), Acquire::NORETAIN); - return newFont(r.get(), filter); + return newFont(r.get()); } Video *Graphics::newVideo(love::video::VideoStream *stream, float dpiscale) @@ -402,8 +402,7 @@ void Graphics::restoreState(const DisplayState &s) setColorMask(s.colorMask); setWireframe(s.wireframe); - setDefaultFilter(s.defaultFilter); - setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness); + setDefaultSamplerState(s.defaultSamplerState); } void Graphics::restoreStateChecked(const DisplayState &s) @@ -479,8 +478,7 @@ void Graphics::restoreStateChecked(const DisplayState &s) if (s.wireframe != cur.wireframe) setWireframe(s.wireframe); - setDefaultFilter(s.defaultFilter); - setDefaultMipmapFilter(s.defaultMipmapFilter, s.defaultMipmapSharpness); + setDefaultSamplerState(s.defaultSamplerState); } Colorf Graphics::getColor() const @@ -923,30 +921,14 @@ const BlendState &Graphics::getBlendState() const return states.back().blend; } -void Graphics::setDefaultFilter(const Texture::Filter &f) +void Graphics::setDefaultSamplerState(const SamplerState &s) { - Texture::defaultFilter = f; - states.back().defaultFilter = f; + states.back().defaultSamplerState = s; } -const Texture::Filter &Graphics::getDefaultFilter() const +const SamplerState &Graphics::getDefaultSamplerState() const { - return Texture::defaultFilter; -} - -void Graphics::setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness) -{ - Texture::defaultMipmapFilter = filter; - Texture::defaultMipmapSharpness = sharpness; - - states.back().defaultMipmapFilter = filter; - states.back().defaultMipmapSharpness = sharpness; -} - -void Graphics::getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const -{ - *filter = Texture::defaultMipmapFilter; - *sharpness = Texture::defaultMipmapSharpness; + return states.back().defaultSamplerState; } void Graphics::setLineWidth(float width) diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 155467885..151be6f08 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -433,8 +433,8 @@ public: virtual Image *newImage(TextureType textype, PixelFormat format, int width, int height, int slices, const Image::Settings &settings) = 0; Quad *newQuad(Quad::Viewport v, double sw, double sh); - Font *newFont(love::font::Rasterizer *data, const Texture::Filter &filter = Texture::defaultFilter); - Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting, const Texture::Filter &filter = Texture::defaultFilter); + Font *newFont(love::font::Rasterizer *data); + Font *newDefaultFont(int size, font::TrueTypeRasterizer::Hinting hinting); Video *newVideo(love::video::VideoStream *stream, float dpiscale); SpriteBatch *newSpriteBatch(Texture *texture, int size, vertex::Usage usage); @@ -620,20 +620,14 @@ public: const BlendState &getBlendState() const; /** - * Sets the default filter for images, canvases, and fonts. + * Sets the default sampler state for images, canvases, and fonts. **/ - void setDefaultFilter(const Texture::Filter &f); + void setDefaultSamplerState(const SamplerState &s); /** - * Gets the default filter for images, canvases, and fonts. + * Gets the default sampler state for images, canvases, and fonts. **/ - const Texture::Filter &getDefaultFilter() const; - - /** - * Default Image mipmap filter mode and sharpness values. - **/ - void setDefaultMipmapFilter(Texture::FilterMode filter, float sharpness); - void getDefaultMipmapFilter(Texture::FilterMode *filter, float *sharpness) const; + const SamplerState &getDefaultSamplerState() const; /** * Sets the line width. @@ -920,10 +914,7 @@ protected: bool wireframe = false; - Texture::Filter defaultFilter = Texture::Filter(); - - Texture::FilterMode defaultMipmapFilter = Texture::FILTER_LINEAR; - float defaultMipmapSharpness = 0.0f; + SamplerState defaultSamplerState = SamplerState(); }; struct StreamBufferState diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index bf19212dc..83d423dae 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -103,9 +103,6 @@ void Image::init(PixelFormat fmt, int w, int h, const Settings &settings) mipmapCount = mipmapsType == MIPMAPS_NONE ? 1 : getTotalMipmapCount(w, h, depth); - if (mipmapCount > 1) - filter.mipmap = defaultMipmapFilter; - initQuad(); ++imageCount; diff --git a/src/modules/graphics/Shader.cpp b/src/modules/graphics/Shader.cpp index 4692a82b3..f94b952f6 100644 --- a/src/modules/graphics/Shader.cpp +++ b/src/modules/graphics/Shader.cpp @@ -125,7 +125,7 @@ void Shader::checkMainTexture(Texture *tex) const if (!tex->isReadable()) throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader."); - checkMainTextureType(tex->getTextureType(), tex->getDepthSampleMode().hasValue); + checkMainTextureType(tex->getTextureType(), tex->getSamplerState().depthSampleMode.hasValue); } bool Shader::validate(ShaderStage *vertex, ShaderStage *pixel, std::string &err) diff --git a/src/modules/graphics/Texture.cpp b/src/modules/graphics/Texture.cpp index f54addfdb..1866aae50 100644 --- a/src/modules/graphics/Texture.cpp +++ b/src/modules/graphics/Texture.cpp @@ -33,11 +33,129 @@ namespace love namespace graphics { -love::Type Texture::type("Texture", &Drawable::type); +uint64 SamplerState::toKey() const +{ + union { float f; uint32 i; } conv; + conv.f = lodBias; -Texture::Filter Texture::defaultFilter; -Texture::FilterMode Texture::defaultMipmapFilter = Texture::FILTER_LINEAR; -float Texture::defaultMipmapSharpness = 0.0f; + return (minFilter << 0) | (magFilter << 1) | (mipmapFilter << 2) + | (wrapU << 4) | (wrapV << 7) | (wrapW << 10) + | (maxAnisotropy << 12) | (minLod << 16) | (maxLod << 20) + | (depthSampleMode.hasValue << 24) | (depthSampleMode.value << 25) + | ((uint64)conv.i << 32); +} + +SamplerState SamplerState::fromKey(uint64 key) +{ + const uint32 BITS_1 = 0x1; + const uint32 BITS_2 = 0x3; + const uint32 BITS_3 = 0x7; + const uint32 BITS_4 = 0xF; + + SamplerState s; + + s.minFilter = (FilterMode) ((key >> 0) & BITS_1); + s.magFilter = (FilterMode) ((key >> 1) & BITS_1); + s.mipmapFilter = (MipmapFilterMode) ((key >> 2) & BITS_2); + + s.wrapU = (WrapMode) ((key >> 4 ) & BITS_3); + s.wrapV = (WrapMode) ((key >> 7 ) & BITS_3); + s.wrapW = (WrapMode) ((key >> 10) & BITS_3); + + s.maxAnisotropy = (key >> 12) & BITS_4; + + s.minLod = (key >> 16) & BITS_4; + s.maxLod = (key >> 20) & BITS_4; + + s.depthSampleMode.hasValue = ((key >> 24) & BITS_1) != 0; + s.depthSampleMode.value = (CompareMode) ((key >> 25) & BITS_4); + + union { float f; uint32 i; } conv; + conv.i = (uint32) (key >> 32); + s.lodBias = conv.f; + + return s; +} + +bool SamplerState::isClampZeroOrOne(WrapMode w) +{ + return w == WRAP_CLAMP_ONE || w == WRAP_CLAMP_ZERO; +} + +static StringMap::Entry filterModeEntries[] = +{ + { "linear", SamplerState::FILTER_LINEAR }, + { "nearest", SamplerState::FILTER_NEAREST }, +}; + +static StringMap filterModes(filterModeEntries, sizeof(filterModeEntries)); + +static StringMap::Entry mipmapFilterModeEntries[] = +{ + { "none", SamplerState::MIPMAP_FILTER_NONE }, + { "linear", SamplerState::MIPMAP_FILTER_LINEAR }, + { "nearest", SamplerState::MIPMAP_FILTER_NEAREST }, +}; + +static StringMap mipmapFilterModes(mipmapFilterModeEntries, sizeof(mipmapFilterModeEntries)); + +static StringMap::Entry wrapModeEntries[] = +{ + { "clamp", SamplerState::WRAP_CLAMP }, + { "clampzero", SamplerState::WRAP_CLAMP_ZERO }, + { "clampone", SamplerState::WRAP_CLAMP_ONE }, + { "repeat", SamplerState::WRAP_REPEAT }, + { "mirroredrepeat", SamplerState::WRAP_MIRRORED_REPEAT }, +}; + +static StringMap wrapModes(wrapModeEntries, sizeof(wrapModeEntries)); + +bool SamplerState::getConstant(const char *in, FilterMode &out) +{ + return filterModes.find(in, out); +} + +bool SamplerState::getConstant(FilterMode in, const char *&out) +{ + return filterModes.find(in, out); +} + +std::vector SamplerState::getConstants(FilterMode) +{ + return filterModes.getNames(); +} + +bool SamplerState::getConstant(const char *in, MipmapFilterMode &out) +{ + return mipmapFilterModes.find(in, out); +} + +bool SamplerState::getConstant(MipmapFilterMode in, const char *&out) +{ + return mipmapFilterModes.find(in, out); +} + +std::vector SamplerState::getConstants(MipmapFilterMode) +{ + return mipmapFilterModes.getNames(); +} + +bool SamplerState::getConstant(const char *in, WrapMode &out) +{ + return wrapModes.find(in, out); +} + +bool SamplerState::getConstant(WrapMode in, const char *&out) +{ + return wrapModes.find(in, out); +} + +std::vector SamplerState::getConstants(WrapMode) +{ + return wrapModes.getNames(); +} + +love::Type Texture::type("Texture", &Drawable::type); int64 Texture::totalGraphicsMemory = 0; Texture::Texture(TextureType texType) @@ -51,11 +169,12 @@ Texture::Texture(TextureType texType) , mipmapCount(1) , pixelWidth(0) , pixelHeight(0) - , filter(defaultFilter) - , wrap() - , mipmapSharpness(defaultMipmapSharpness) + , samplerState() , graphicsMemorySize(0) { + auto gfx = Module::getInstance(Module::M_GRAPHICS); + if (gfx != nullptr) + samplerState = gfx->getDefaultSamplerState(); } Texture::~Texture() @@ -252,45 +371,25 @@ float Texture::getDPIScale() const return (float) pixelHeight / (float) height; } -void Texture::setFilter(const Filter &f) +void Texture::setSamplerState(const SamplerState &s) { - if (!validateFilter(f, getMipmapCount() > 1)) - { - if (f.mipmap != FILTER_NONE && getMipmapCount() == 1) - throw love::Exception("Non-mipmapped texture cannot have mipmap filtering."); - else - throw love::Exception("Invalid texture filter."); - } + if (s.depthSampleMode.hasValue && (!readable || !isPixelFormatDepthStencil(format))) + throw love::Exception("Only readable depth textures can have a depth sample compare mode."); Graphics::flushStreamDrawsGlobal(); - filter = f; + samplerState = s; + + if (samplerState.mipmapFilter != SamplerState::MIPMAP_FILTER_NONE && getMipmapCount() == 1) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + + if (texType == TEXTURE_CUBE) + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; } -const Texture::Filter &Texture::getFilter() const +const SamplerState &Texture::getSamplerState() const { - return filter; -} - -const Texture::Wrap &Texture::getWrap() const -{ - return wrap; -} - -float Texture::getMipmapSharpness() const -{ - return mipmapSharpness; -} - -void Texture::setDepthSampleMode(Optional mode) -{ - if (mode.hasValue && (!readable || !isPixelFormatDepthStencil(format))) - throw love::Exception("Only readable depth textures can have a depth sample compare mode."); -} - -Optional Texture::getDepthSampleMode() const -{ - return depthCompareMode; + return samplerState; } Quad *Texture::getQuad() const @@ -298,23 +397,6 @@ Quad *Texture::getQuad() const return quad; } -bool Texture::validateFilter(const Filter &f, bool mipmapsAllowed) -{ - if (!mipmapsAllowed && f.mipmap != FILTER_NONE) - return false; - - if (f.mag != FILTER_LINEAR && f.mag != FILTER_NEAREST) - return false; - - if (f.min != FILTER_LINEAR && f.min != FILTER_NEAREST) - return false; - - if (f.mipmap != FILTER_LINEAR && f.mipmap != FILTER_NEAREST && f.mipmap != FILTER_NONE) - return false; - - return true; -} - int Texture::getTotalMipmapCount(int w, int h) { return (int) log2(std::max(w, h)) + 1; @@ -556,36 +638,6 @@ std::vector Texture::getConstants(TextureType) return texTypes.getNames(); } -bool Texture::getConstant(const char *in, FilterMode &out) -{ - return filterModes.find(in, out); -} - -bool Texture::getConstant(FilterMode in, const char *&out) -{ - return filterModes.find(in, out); -} - -std::vector Texture::getConstants(FilterMode) -{ - return filterModes.getNames(); -} - -bool Texture::getConstant(const char *in, WrapMode &out) -{ - return wrapModes.find(in, out); -} - -bool Texture::getConstant(WrapMode in, const char *&out) -{ - return wrapModes.find(in, out); -} - -std::vector Texture::getConstants(WrapMode) -{ - return wrapModes.getNames(); -} - StringMap::Entry Texture::texTypeEntries[] = { { "2d", TEXTURE_2D }, @@ -596,25 +648,5 @@ StringMap::Entry Texture::texTypeEntries[] = StringMap Texture::texTypes(Texture::texTypeEntries, sizeof(Texture::texTypeEntries)); -StringMap::Entry Texture::filterModeEntries[] = -{ - { "linear", FILTER_LINEAR }, - { "nearest", FILTER_NEAREST }, - { "none", FILTER_NONE }, -}; - -StringMap Texture::filterModes(Texture::filterModeEntries, sizeof(Texture::filterModeEntries)); - -StringMap::Entry Texture::wrapModeEntries[] = -{ - { "clamp", WRAP_CLAMP }, - { "clampzero", WRAP_CLAMP_ZERO }, - { "clampone", WRAP_CLAMP_ONE }, - { "repeat", WRAP_REPEAT }, - { "mirroredrepeat", WRAP_MIRRORED_REPEAT }, -}; - -StringMap Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries)); - } // graphics } // love diff --git a/src/modules/graphics/Texture.h b/src/modules/graphics/Texture.h index 42239d3df..ee0c7c654 100644 --- a/src/modules/graphics/Texture.h +++ b/src/modules/graphics/Texture.h @@ -55,16 +55,8 @@ enum TextureType TEXTURE_MAX_ENUM }; -/** - * Base class for 2D textures. All textures can be drawn with Quads, have a - * width and height, and have filter and wrap modes. - **/ -class Texture : public Drawable, public Resource +struct SamplerState { -public: - - static love::Type type; - enum WrapMode { WRAP_CLAMP, @@ -77,26 +69,63 @@ public: enum FilterMode { - FILTER_NONE, FILTER_LINEAR, FILTER_NEAREST, FILTER_MAX_ENUM }; - struct Filter + enum MipmapFilterMode { - FilterMode min = FILTER_LINEAR; - FilterMode mag = FILTER_LINEAR; - FilterMode mipmap = FILTER_NONE; - float anisotropy = 1.0f; + MIPMAP_FILTER_NONE, + MIPMAP_FILTER_LINEAR, + MIPMAP_FILTER_NEAREST, + MIPMAP_FILTER_MAX_ENUM }; - struct Wrap - { - WrapMode s = WRAP_CLAMP; - WrapMode t = WRAP_CLAMP; - WrapMode r = WRAP_CLAMP; - }; + FilterMode minFilter = FILTER_LINEAR; + FilterMode magFilter = FILTER_LINEAR; + MipmapFilterMode mipmapFilter = MIPMAP_FILTER_NONE; + + WrapMode wrapU = WRAP_CLAMP; + WrapMode wrapV = WRAP_CLAMP; + WrapMode wrapW = WRAP_CLAMP; + + float lodBias = 0.0f; + + uint8 maxAnisotropy = 1; + + uint8 minLod = 0; + uint8 maxLod = LOVE_UINT8_MAX; + + Optional depthSampleMode; + + uint64 toKey() const; + static SamplerState fromKey(uint64 key); + + static bool isClampZeroOrOne(WrapMode w); + + static bool getConstant(const char *in, FilterMode &out); + static bool getConstant(FilterMode in, const char *&out); + static std::vector getConstants(FilterMode); + + static bool getConstant(const char *in, MipmapFilterMode &out); + static bool getConstant(MipmapFilterMode in, const char *&out); + static std::vector getConstants(MipmapFilterMode); + + static bool getConstant(const char *in, WrapMode &out); + static bool getConstant(WrapMode in, const char *&out); + static std::vector getConstants(WrapMode); +}; + +/** + * Base class for 2D textures. All textures can be drawn with Quads, have a + * width and height, and have filter and wrap modes. + **/ +class Texture : public Drawable, public Resource +{ +public: + + static love::Type type; enum MipmapsType { @@ -135,10 +164,6 @@ public: }; // Slices - static Filter defaultFilter; - static FilterMode defaultMipmapFilter; - static float defaultMipmapSharpness; - static int64 totalGraphicsMemory; Texture(TextureType texType); @@ -173,40 +198,18 @@ public: float getDPIScale() const; - virtual void setFilter(const Filter &f); - virtual const Filter &getFilter() const; - - virtual bool setWrap(const Wrap &w) = 0; - virtual const Wrap &getWrap() const; - - // Sets the mipmap texture LOD bias (sharpness) value. - virtual bool setMipmapSharpness(float sharpness) = 0; - float getMipmapSharpness() const; - - virtual void setDepthSampleMode(Optional mode = Optional()); - Optional getDepthSampleMode() const; + virtual void setSamplerState(const SamplerState &s); + const SamplerState &getSamplerState() const; Quad *getQuad() const; - static bool validateFilter(const Filter &f, bool mipmapsAllowed); - static int getTotalMipmapCount(int w, int h); static int getTotalMipmapCount(int w, int h, int d); - static bool isClampZeroOrOne(WrapMode w) { return w == WRAP_CLAMP_ZERO || w == WRAP_CLAMP_ONE; } - static bool getConstant(const char *in, TextureType &out); static bool getConstant(TextureType in, const char *&out); static std::vector getConstants(TextureType); - static bool getConstant(const char *in, FilterMode &out); - static bool getConstant(FilterMode in, const char *&out); - static std::vector getConstants(FilterMode); - - static bool getConstant(const char *in, WrapMode &out); - static bool getConstant(WrapMode in, const char *&out); - static std::vector getConstants(WrapMode); - protected: void initQuad(); @@ -229,12 +232,7 @@ protected: int pixelWidth; int pixelHeight; - Filter filter; - Wrap wrap; - - float mipmapSharpness; - - Optional depthCompareMode; + SamplerState samplerState; StrongRef quad; @@ -245,12 +243,6 @@ private: static StringMap::Entry texTypeEntries[]; static StringMap texTypes; - static StringMap::Entry filterModeEntries[]; - static StringMap filterModes; - - static StringMap::Entry wrapModeEntries[]; - static StringMap wrapModes; - }; // Texture } // graphics diff --git a/src/modules/graphics/Video.cpp b/src/modules/graphics/Video.cpp index 201670f6b..b27d3c856 100644 --- a/src/modules/graphics/Video.cpp +++ b/src/modules/graphics/Video.cpp @@ -35,9 +35,14 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) : stream(stream) , width(stream->getWidth() / dpiscale) , height(stream->getHeight() / dpiscale) - , filter(Texture::defaultFilter) + , samplerState() { - filter.mipmap = Texture::FILTER_NONE; + const SamplerState &defaultSampler = gfx->getDefaultSamplerState(); + samplerState.minFilter = defaultSampler.minFilter; + samplerState.magFilter = defaultSampler.magFilter; + samplerState.wrapU = defaultSampler.wrapU; + samplerState.wrapV = defaultSampler.wrapV; + samplerState.maxAnisotropy = defaultSampler.maxAnisotropy; stream->fillBackBuffer(); @@ -74,15 +79,13 @@ Video::Video(Graphics *gfx, love::video::VideoStream *stream, float dpiscale) const unsigned char *data[3] = {frame->yplane, frame->cbplane, frame->crplane}; - Texture::Wrap wrap; // Clamp wrap mode. Image::Settings settings; for (int i = 0; i < 3; i++) { Image *img = gfx->newImage(TEXTURE_2D, PIXELFORMAT_R8_UNORM, widths[i], heights[i], 1, settings); - img->setFilter(filter); - img->setWrap(wrap); + img->setSamplerState(samplerState); size_t bpp = getPixelFormatSize(PIXELFORMAT_R8_UNORM); size_t size = bpp * widths[i] * heights[i]; @@ -200,17 +203,21 @@ int Video::getPixelHeight() const return stream->getHeight(); } -void Video::setFilter(const Texture::Filter &f) +void Video::setSamplerState(const SamplerState &s) { - for (const auto &image : images) - image->setFilter(f); + samplerState.minFilter = s.minFilter; + samplerState.magFilter = s.magFilter; + samplerState.wrapU = s.wrapU; + samplerState.wrapV = s.wrapV; + samplerState.maxAnisotropy = s.maxAnisotropy; - filter = f; + for (const auto &image : images) + image->setSamplerState(samplerState); } -const Texture::Filter &Video::getFilter() const +const SamplerState &Video::getSamplerState() const { - return filter; + return samplerState; } } // graphics diff --git a/src/modules/graphics/Video.h b/src/modules/graphics/Video.h index d307d3e79..65db27c32 100644 --- a/src/modules/graphics/Video.h +++ b/src/modules/graphics/Video.h @@ -58,8 +58,8 @@ public: int getPixelWidth() const; int getPixelHeight() const; - void setFilter(const Texture::Filter &f); - const Texture::Filter &getFilter() const; + void setSamplerState(const SamplerState &s); + const SamplerState &getSamplerState() const; private: @@ -70,7 +70,7 @@ private: int width; int height; - Texture::Filter filter; + SamplerState samplerState; Vertex vertices[4]; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 029513261..f3555d1d9 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -239,10 +239,7 @@ bool Canvas::loadVolatile() if (GLAD_ANGLE_texture_usage) glTexParameteri(gltype, GL_TEXTURE_USAGE_ANGLE, GL_FRAMEBUFFER_ATTACHMENT_ANGLE); - setFilter(filter); - setWrap(wrap); - setMipmapSharpness(mipmapSharpness); - setDepthSampleMode(depthCompareMode); + setSamplerState(samplerState); while (glGetError() != GL_NO_ERROR) /* Clear the error buffer. */; @@ -320,113 +317,30 @@ void Canvas::unloadVolatile() setGraphicsMemorySize(0); } -void Canvas::setFilter(const Texture::Filter &f) +void Canvas::setSamplerState(const SamplerState &s) { - Texture::setFilter(f); + Texture::setSamplerState(s); + + if (samplerState.depthSampleMode.hasValue && !gl.isDepthCompareSampleSupported()) + throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) { - filter.mag = filter.min = FILTER_NEAREST; + samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - if (filter.mipmap == FILTER_LINEAR) - filter.mipmap = FILTER_NEAREST; + if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; } - gl.bindTextureToUnit(this, 0, false); - gl.setTextureFilter(texType, filter); -} - -bool Canvas::setWrap(const Texture::Wrap &w) -{ - Graphics::flushStreamDrawsGlobal(); - - bool success = true; - bool forceclamp = texType == TEXTURE_CUBE; - wrap = w; - // If we only have limited NPOT support then the wrap mode must be CLAMP. if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) { - forceclamp = true; - } - - if (forceclamp) - { - if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP || wrap.r != WRAP_CLAMP) - success = false; - - wrap.s = wrap.t = wrap.r = WRAP_CLAMP; - } - - if (!gl.isClampZeroOneTextureWrapSupported()) - { - if (isClampZeroOrOne(wrap.s)) wrap.s = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.t)) wrap.t = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.r)) wrap.r = WRAP_CLAMP; + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; } gl.bindTextureToUnit(this, 0, false); - gl.setTextureWrap(texType, wrap); - - return success; -} - -bool Canvas::setMipmapSharpness(float sharpness) -{ - if (!gl.isSamplerLODBiasSupported()) - return false; - - Graphics::flushStreamDrawsGlobal(); - - float maxbias = gl.getMaxLODBias(); - if (maxbias > 0.01f) - maxbias -= 0.0f; - - mipmapSharpness = std::min(std::max(sharpness, -maxbias), maxbias); - - gl.bindTextureToUnit(this, 0, false); - - // negative bias is sharper - glTexParameterf(gl.getGLTextureType(texType), GL_TEXTURE_LOD_BIAS, -mipmapSharpness); - - return true; -} - -void Canvas::setDepthSampleMode(Optional mode) -{ - Texture::setDepthSampleMode(mode); - - bool supported = gl.isDepthCompareSampleSupported(); - - if (mode.hasValue) - { - if (!supported) - throw love::Exception("Depth comparison sampling in shaders is not supported on this system."); - - Graphics::flushStreamDrawsGlobal(); - - gl.bindTextureToUnit(texType, texture, 0, false); - GLenum gltextype = OpenGL::getGLTextureType(texType); - - // See the comment in renderstate.h - GLenum glmode = OpenGL::getGLCompareMode(getReversedCompareMode(mode.value)); - - glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); - glTexParameteri(gltextype, GL_TEXTURE_COMPARE_FUNC, glmode); - - } - else if (isPixelFormatDepth(format) && supported) - { - Graphics::flushStreamDrawsGlobal(); - - gl.bindTextureToUnit(texType, texture, 0, false); - GLenum gltextype = OpenGL::getGLTextureType(texType); - - glTexParameteri(gltextype, GL_TEXTURE_COMPARE_MODE, GL_NONE); - } - - depthCompareMode = mode; + gl.setSamplerState(texType, samplerState); } ptrdiff_t Canvas::getHandle() const diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 8543c3503..bb45edf7b 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -47,10 +47,7 @@ public: void unloadVolatile() override; // Implements Texture. - void setFilter(const Texture::Filter &f) override; - bool setWrap(const Texture::Wrap &w) override; - bool setMipmapSharpness(float sharpness) override; - void setDepthSampleMode(Optional mode) override; + void setSamplerState(const SamplerState &s) override; ptrdiff_t getHandle() const override; love::image::ImageData *newImageData(love::image::Image *module, int slice, int mipmap, const Rect &rect) override; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index e7a821385..18b227e0a 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -1470,12 +1470,9 @@ bool Graphics::isPixelFormatSupported(PixelFormat format, bool rendertarget, boo glGenTextures(1, &texture); gl.bindTextureToUnit(TEXTURE_2D, texture, 0, false); - Texture::Filter f; - f.min = f.mag = Texture::FILTER_NEAREST; - gl.setTextureFilter(TEXTURE_2D, f); - - Texture::Wrap w; - gl.setTextureWrap(TEXTURE_2D, w); + SamplerState s; + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + gl.setSamplerState(TEXTURE_2D, s); gl.rawTexStorage(TEXTURE_2D, 1, format, sRGB, 1, 1); } diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index c9f4d93bf..ac5bdd50e 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -75,7 +75,7 @@ void Image::loadDefaultTexture() usingDefaultTexture = true; gl.bindTextureToUnit(this, 0, false); - setFilter(filter); + setSamplerState(samplerState); bool isSRGB = false; gl.rawTexStorage(texType, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 2, 2, 1); @@ -204,7 +204,7 @@ bool Image::loadVolatile() && mipmapsType != MIPMAPS_DATA) { mipmapsType = MIPMAPS_NONE; - filter.mipmap = FILTER_NONE; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; } } @@ -213,7 +213,7 @@ bool Image::loadVolatile() && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight))) { mipmapsType = MIPMAPS_NONE; - filter.mipmap = FILTER_NONE; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; } glGenTextures(1, &texture); @@ -226,9 +226,7 @@ bool Image::loadVolatile() return true; } - setFilter(filter); - setWrap(wrap); - setMipmapSharpness(mipmapSharpness); + setSamplerState(samplerState); GLenum gltextype = OpenGL::getGLTextureType(texType); @@ -282,85 +280,34 @@ ptrdiff_t Image::getHandle() const return texture; } -void Image::setFilter(const Texture::Filter &f) +void Image::setSamplerState(const SamplerState &s) { - Texture::setFilter(f); + Texture::setSamplerState(s); if (!OpenGL::hasTextureFilteringSupport(getPixelFormat())) { - filter.mag = filter.min = FILTER_NEAREST; + samplerState.magFilter = samplerState.minFilter = SamplerState::FILTER_NEAREST; - if (filter.mipmap == FILTER_LINEAR) - filter.mipmap = FILTER_NEAREST; + if (samplerState.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NEAREST; } // We don't want filtering or (attempted) mipmaps on the default texture. if (usingDefaultTexture) { - filter.mipmap = FILTER_NONE; - filter.min = filter.mag = FILTER_NEAREST; + samplerState.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; + samplerState.minFilter = samplerState.magFilter = SamplerState::FILTER_NEAREST; } - gl.bindTextureToUnit(this, 0, false); - gl.setTextureFilter(texType, filter); -} - -bool Image::setWrap(const Texture::Wrap &w) -{ - Graphics::flushStreamDrawsGlobal(); - - bool success = true; - bool forceclamp = texType == TEXTURE_CUBE; - wrap = w; - // If we only have limited NPOT support then the wrap mode must be CLAMP. if ((GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_texture_npot)) && (pixelWidth != nextP2(pixelWidth) || pixelHeight != nextP2(pixelHeight) || depth != nextP2(depth))) { - forceclamp = true; - } - - if (forceclamp) - { - if (wrap.s != WRAP_CLAMP || wrap.t != WRAP_CLAMP || wrap.r != WRAP_CLAMP) - success = false; - - wrap.s = wrap.t = wrap.r = WRAP_CLAMP; - } - - if (!gl.isClampZeroOneTextureWrapSupported()) - { - if (isClampZeroOrOne(wrap.s)) wrap.s = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.t)) wrap.t = WRAP_CLAMP; - if (isClampZeroOrOne(wrap.r)) wrap.r = WRAP_CLAMP; + samplerState.wrapU = samplerState.wrapV = samplerState.wrapW = SamplerState::WRAP_CLAMP; } gl.bindTextureToUnit(this, 0, false); - gl.setTextureWrap(texType, wrap); - - return success; -} - -bool Image::setMipmapSharpness(float sharpness) -{ - if (!gl.isSamplerLODBiasSupported()) - return false; - - Graphics::flushStreamDrawsGlobal(); - - float maxbias = gl.getMaxLODBias(); - - if (maxbias > 0.01f) - maxbias -= 0.01f; - - mipmapSharpness = std::min(std::max(sharpness, -maxbias), maxbias); - - gl.bindTextureToUnit(this, 0, false); - - // negative bias is sharper - glTexParameterf(gl.getGLTextureType(texType), GL_TEXTURE_LOD_BIAS, -mipmapSharpness); - - return true; + gl.setSamplerState(texType, samplerState); } } // opengl diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 1f6b853af..124e1bbf5 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -49,10 +49,7 @@ public: ptrdiff_t getHandle() const override; - void setFilter(const Texture::Filter &f) override; - bool setWrap(const Texture::Wrap &w) override; - - bool setMipmapSharpness(float sharpness) override; + void setSamplerState(const SamplerState &s) override; private: diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 28862602e..17dbb2860 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -502,11 +502,9 @@ void OpenGL::createDefaultTexture() // untextured primitives vs images. const GLubyte pix[] = {255, 255, 255, 255}; - Texture::Filter filter; - filter.min = filter.mag = Texture::FILTER_NEAREST; - - Texture::Wrap wrap; - wrap.s = wrap.t = wrap.r = Texture::WRAP_CLAMP; + SamplerState s; + s.minFilter = s.magFilter = SamplerState::FILTER_NEAREST; + s.wrapU = s.wrapV = s.wrapW = SamplerState::WRAP_CLAMP; for (int i = 0; i < TEXTURE_MAX_ENUM; i++) { @@ -522,8 +520,7 @@ void OpenGL::createDefaultTexture() glGenTextures(1, &state.defaultTexture[type]); bindTextureToUnit(type, state.defaultTexture[type], 0, false); - setTextureWrap(type, wrap); - setTextureFilter(type, filter); + setSamplerState(type, s); bool isSRGB = false; rawTexStorage(type, 1, PIXELFORMAT_RGBA8_UNORM, isSRGB, 1, 1); @@ -1050,52 +1047,19 @@ void OpenGL::deleteTexture(GLuint texture) glDeleteTextures(1, &texture); } -void OpenGL::setTextureFilter(TextureType target, graphics::Texture::Filter &f) -{ - GLint gmin = f.min == Texture::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; - GLint gmag = f.mag == Texture::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; - - if (f.mipmap != Texture::FILTER_NONE) - { - if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_NEAREST) - gmin = GL_NEAREST_MIPMAP_NEAREST; - else if (f.min == Texture::FILTER_NEAREST && f.mipmap == Texture::FILTER_LINEAR) - gmin = GL_NEAREST_MIPMAP_LINEAR; - else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_NEAREST) - gmin = GL_LINEAR_MIPMAP_NEAREST; - else if (f.min == Texture::FILTER_LINEAR && f.mipmap == Texture::FILTER_LINEAR) - gmin = GL_LINEAR_MIPMAP_LINEAR; - else - gmin = GL_LINEAR; - } - - GLenum gltarget = getGLTextureType(target); - - glTexParameteri(gltarget, GL_TEXTURE_MIN_FILTER, gmin); - glTexParameteri(gltarget, GL_TEXTURE_MAG_FILTER, gmag); - - if (GLAD_EXT_texture_filter_anisotropic) - { - f.anisotropy = std::min(std::max(f.anisotropy, 1.0f), maxAnisotropy); - glTexParameterf(gltarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, f.anisotropy); - } - else - f.anisotropy = 1.0f; -} - -GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode) +GLint OpenGL::getGLWrapMode(SamplerState::WrapMode wmode) { switch (wmode) { - case Texture::WRAP_CLAMP: + case SamplerState::WRAP_CLAMP: default: return GL_CLAMP_TO_EDGE; - case Texture::WRAP_CLAMP_ZERO: - case Texture::WRAP_CLAMP_ONE: + case SamplerState::WRAP_CLAMP_ZERO: + case SamplerState::WRAP_CLAMP_ONE: return GL_CLAMP_TO_BORDER; - case Texture::WRAP_REPEAT: + case SamplerState::WRAP_REPEAT: return GL_REPEAT; - case Texture::WRAP_MIRRORED_REPEAT: + case SamplerState::WRAP_MIRRORED_REPEAT: return GL_MIRRORED_REPEAT; } } @@ -1125,29 +1089,111 @@ GLint OpenGL::getGLCompareMode(CompareMode mode) } } -static bool isClampOne(Texture::WrapMode mode) +static bool isClampOne(SamplerState::WrapMode mode) { - return mode == Texture::WRAP_CLAMP_ONE; + return mode == SamplerState::WRAP_CLAMP_ONE; } -void OpenGL::setTextureWrap(TextureType target, const graphics::Texture::Wrap &w) +void OpenGL::setSamplerState(TextureType target, SamplerState &s) { - GLenum textype = getGLTextureType(target); + GLenum gltarget = getGLTextureType(target); - if (Texture::isClampZeroOrOne(w.s) || Texture::isClampZeroOrOne(w.t) || Texture::isClampZeroOrOne(w.r)) + GLint gmin = s.minFilter == SamplerState::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; + GLint gmag = s.magFilter == SamplerState::FILTER_NEAREST ? GL_NEAREST : GL_LINEAR; + + if (s.mipmapFilter != SamplerState::MIPMAP_FILTER_NONE) { - GLfloat c[] = {0.0f, 0.0f, 0.0f, 0.0f}; - if (isClampOne(w.s) || isClampOne(w.t) || isClampOne(w.r)) - c[0] = c[1] = c[2] = c[3] = 1.0f; - - glTexParameterfv(textype, GL_TEXTURE_BORDER_COLOR, c); + if (s.minFilter == SamplerState::FILTER_NEAREST && s.mipmapFilter == SamplerState::MIPMAP_FILTER_NEAREST) + gmin = GL_NEAREST_MIPMAP_NEAREST; + else if (s.minFilter == SamplerState::FILTER_NEAREST && s.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + gmin = GL_NEAREST_MIPMAP_LINEAR; + else if (s.minFilter == SamplerState::FILTER_LINEAR && s.mipmapFilter == SamplerState::MIPMAP_FILTER_NEAREST) + gmin = GL_LINEAR_MIPMAP_NEAREST; + else if (s.minFilter == SamplerState::FILTER_LINEAR && s.mipmapFilter == SamplerState::MIPMAP_FILTER_LINEAR) + gmin = GL_LINEAR_MIPMAP_LINEAR; } - glTexParameteri(textype, GL_TEXTURE_WRAP_S, getGLWrapMode(w.s)); - glTexParameteri(textype, GL_TEXTURE_WRAP_T, getGLWrapMode(w.t)); + glTexParameteri(gltarget, GL_TEXTURE_MIN_FILTER, gmin); + glTexParameteri(gltarget, GL_TEXTURE_MAG_FILTER, gmag); + + if (!isClampZeroOneTextureWrapSupported()) + { + if (SamplerState::isClampZeroOrOne(s.wrapU)) s.wrapU = SamplerState::WRAP_CLAMP; + if (SamplerState::isClampZeroOrOne(s.wrapV)) s.wrapV = SamplerState::WRAP_CLAMP; + if (SamplerState::isClampZeroOrOne(s.wrapW)) s.wrapW = SamplerState::WRAP_CLAMP; + } + + if (SamplerState::isClampZeroOrOne(s.wrapU) || SamplerState::isClampZeroOrOne(s.wrapV) || SamplerState::isClampZeroOrOne(s.wrapW)) + { + GLfloat c[] = {0.0f, 0.0f, 0.0f, 0.0f}; + if (isClampOne(s.wrapU) || isClampOne(s.wrapU) || isClampOne(s.wrapV)) + c[0] = c[1] = c[2] = c[3] = 1.0f; + + glTexParameterfv(gltarget, GL_TEXTURE_BORDER_COLOR, c); + } + + glTexParameteri(gltarget, GL_TEXTURE_WRAP_S, getGLWrapMode(s.wrapU)); + glTexParameteri(gltarget, GL_TEXTURE_WRAP_T, getGLWrapMode(s.wrapV)); if (target == TEXTURE_VOLUME) - glTexParameteri(textype, GL_TEXTURE_WRAP_R, getGLWrapMode(w.r)); + glTexParameteri(gltarget, GL_TEXTURE_WRAP_R, getGLWrapMode(s.wrapW)); + + if (isSamplerLODBiasSupported()) + { + float maxbias = getMaxLODBias(); + if (maxbias > 0.01f) + maxbias -= 0.01f; + + s.lodBias = std::min(std::max(s.lodBias, -maxbias), maxbias); + + glTexParameterf(gltarget, GL_TEXTURE_LOD_BIAS, s.lodBias); + } + else + { + s.lodBias = 0.0f; + } + + if (GLAD_EXT_texture_filter_anisotropic) + { + uint8 maxAniso = (uint8) std::min(maxAnisotropy, (float)LOVE_UINT8_MAX); + s.maxAnisotropy = std::min(std::max(s.maxAnisotropy, (uint8)1), maxAniso); + glTexParameteri(gltarget, GL_TEXTURE_MAX_ANISOTROPY_EXT, s.maxAnisotropy); + } + else + { + s.maxAnisotropy = 1; + } + + if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0) + { + glTexParameterf(gltarget, GL_TEXTURE_MIN_LOD, (float)s.minLod); + glTexParameterf(gltarget, GL_TEXTURE_MAX_LOD, (float)s.maxLod); + } + else + { + s.minLod = 0; + s.maxLod = LOVE_UINT8_MAX; + } + + if (isDepthCompareSampleSupported()) + { + if (s.depthSampleMode.hasValue) + { + // See the comment in renderstate.h + GLenum glmode = getGLCompareMode(getReversedCompareMode(s.depthSampleMode.value)); + + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_REF_TO_TEXTURE); + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_FUNC, glmode); + } + else + { + glTexParameteri(gltarget, GL_TEXTURE_COMPARE_MODE, GL_NONE); + } + } + else + { + s.depthSampleMode.hasValue = false; + } } bool OpenGL::rawTexStorage(TextureType target, int levels, PixelFormat pixelformat, bool &isSRGB, int width, int height, int depth) diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 8dd975cec..29b7da1ee 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -329,16 +329,9 @@ public: void deleteTexture(GLuint texture); /** - * Sets the texture filter mode for the currently bound texture. - * The anisotropy parameter of the argument is set to the actual amount of - * anisotropy that was used. + * Sets sampler state parameters for the currently bound texture. **/ - void setTextureFilter(TextureType target, graphics::Texture::Filter &f); - - /** - * Sets the texture wrap mode for the currently bound texture. - **/ - void setTextureWrap(TextureType target, const graphics::Texture::Wrap &w); + void setSamplerState(TextureType target, SamplerState &s); /** * Equivalent to glTexStorage2D/3D on platforms that support it. Equivalent @@ -407,7 +400,7 @@ public: static GLenum getGLVertexDataType(vertex::DataType type, GLboolean &normalized, bool &intformat); static GLenum getGLBufferUsage(vertex::Usage usage); static GLenum getGLTextureType(TextureType type); - static GLint getGLWrapMode(Texture::WrapMode wmode); + static GLint getGLWrapMode(SamplerState::WrapMode wmode); static GLint getGLCompareMode(CompareMode mode); static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB); diff --git a/src/modules/graphics/opengl/Shader.cpp b/src/modules/graphics/opengl/Shader.cpp index fca5e22c7..cb175e082 100644 --- a/src/modules/graphics/opengl/Shader.cpp +++ b/src/modules/graphics/opengl/Shader.cpp @@ -588,6 +588,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count if (tex != nullptr) { + const SamplerState &sampler = tex->getSamplerState(); if (!tex->isReadable()) { if (internalUpdate) @@ -595,7 +596,7 @@ void Shader::sendTextures(const UniformInfo *info, Texture **textures, int count else throw love::Exception("Textures with non-readable formats cannot be sampled from in a shader."); } - else if (info->isDepthSampler != tex->getDepthSampleMode().hasValue) + else if (info->isDepthSampler != sampler.depthSampleMode.hasValue) { if (internalUpdate) continue; diff --git a/src/modules/graphics/wrap_Font.cpp b/src/modules/graphics/wrap_Font.cpp index 115a84348..468d67fe2 100644 --- a/src/modules/graphics/wrap_Font.cpp +++ b/src/modules/graphics/wrap_Font.cpp @@ -139,33 +139,33 @@ int w_Font_getLineHeight(lua_State *L) int w_Font_setFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - Texture::Filter f = t->getFilter(); + SamplerState s = t->getSamplerState(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 4, 1.0)), LOVE_UINT8_MAX); - luax_catchexcept(L, [&](){ t->setFilter(f); }); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Font_getFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - const Texture::Filter f = t->getFilter(); + const SamplerState &s = t->getSamplerState(); const char *minstr; const char *magstr; - Texture::getConstant(f.min, minstr); - Texture::getConstant(f.mag, magstr); + SamplerState::getConstant(s.minFilter, minstr); + SamplerState::getConstant(s.magFilter, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 327ec5fe8..f262b9a0a 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -1102,7 +1102,7 @@ int w_newFont(lua_State *L) love::font::Rasterizer *rasterizer = luax_checktype(L, 1); luax_catchexcept(L, [&]() { - font = instance()->newFont(rasterizer, instance()->getDefaultFilter()); } + font = instance()->newFont(rasterizer); } ); // Push the type. @@ -1115,9 +1115,6 @@ int w_newImageFont(lua_State *L) { luax_checkgraphicscreated(L); - // filter for glyphs - Texture::Filter filter = instance()->getDefaultFilter(); - // Convert to Rasterizer if necessary. if (!luax_istype(L, 1, love::font::Rasterizer::type)) { @@ -1133,7 +1130,7 @@ int w_newImageFont(lua_State *L) love::font::Rasterizer *rasterizer = luax_checktype(L, 1); // Create the font. - Font *font = instance()->newFont(rasterizer, filter); + Font *font = instance()->newFont(rasterizer); // Push the type. luax_pushtype(L, font); @@ -1935,69 +1932,65 @@ int w_getBlendState(lua_State *L) int w_setDefaultFilter(lua_State *L) { - Texture::Filter f; + SamplerState s = instance()->getDefaultSamplerState(); const char *minstr = luaL_checkstring(L, 1); const char *magstr = luaL_optstring(L, 2, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 3, 1.0); - - instance()->setDefaultFilter(f); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 3, 1.0)), LOVE_UINT8_MAX); + instance()->setDefaultSamplerState(s); return 0; } int w_getDefaultFilter(lua_State *L) { - const Texture::Filter &f = instance()->getDefaultFilter(); + const SamplerState &s = instance()->getDefaultSamplerState(); const char *minstr; const char *magstr; - if (!Texture::getConstant(f.min, minstr)) + if (!SamplerState::getConstant(s.minFilter, minstr)) return luaL_error(L, "Unknown minification filter mode"); - if (!Texture::getConstant(f.mag, magstr)) + if (!SamplerState::getConstant(s.magFilter, magstr)) return luaL_error(L, "Unknown magnification filter mode"); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } int w_setDefaultMipmapFilter(lua_State *L) { - Texture::FilterMode filter = Texture::FILTER_NONE; + SamplerState s = instance()->getDefaultSamplerState(); + s.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; if (!lua_isnoneornil(L, 1)) { const char *str = luaL_checkstring(L, 1); - if (!Texture::getConstant(str, filter)) - return luax_enumerror(L, "filter mode", Texture::getConstants(filter), str); + if (!SamplerState::getConstant(str, s.mipmapFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.mipmapFilter), str); } - float sharpness = (float) luaL_optnumber(L, 2, 0); - - instance()->setDefaultMipmapFilter(filter, sharpness); + s.lodBias = -((float) luaL_optnumber(L, 2, 0.0)); + instance()->setDefaultSamplerState(s); return 0; } int w_getDefaultMipmapFilter(lua_State *L) { - Texture::FilterMode filter; - float sharpness; - - instance()->getDefaultMipmapFilter(&filter, &sharpness); + const SamplerState &s = instance()->getDefaultSamplerState(); const char *str; - if (Texture::getConstant(filter, str)) + if (SamplerState::getConstant(s.mipmapFilter, str)) lua_pushstring(L, str); else lua_pushnil(L); - lua_pushnumber(L, sharpness); + lua_pushnumber(L, -s.lodBias); return 2; } diff --git a/src/modules/graphics/wrap_Texture.cpp b/src/modules/graphics/wrap_Texture.cpp index a41af87c1..9189a3101 100644 --- a/src/modules/graphics/wrap_Texture.cpp +++ b/src/modules/graphics/wrap_Texture.cpp @@ -132,111 +132,111 @@ int w_Texture_getDPIScale(lua_State *L) int w_Texture_setFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Texture::Filter f = t->getFilter(); + SamplerState s = t->getSamplerState(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 4, 1.0)), LOVE_UINT8_MAX); - luax_catchexcept(L, [&](){ t->setFilter(f); }); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Texture_getFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - const Texture::Filter f = t->getFilter(); + const SamplerState &s = t->getSamplerState(); const char *minstr = nullptr; const char *magstr = nullptr; - if (!Texture::getConstant(f.min, minstr)) + if (!SamplerState::getConstant(s.minFilter, minstr)) return luaL_error(L, "Unknown filter mode."); - if (!Texture::getConstant(f.mag, magstr)) + if (!SamplerState::getConstant(s.magFilter, magstr)) return luaL_error(L, "Unknown filter mode."); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; } int w_Texture_setMipmapFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Texture::Filter f = t->getFilter(); + SamplerState s = t->getSamplerState(); + // Mipmapping is disabled if no argument is given. if (lua_isnoneornil(L, 2)) - f.mipmap = Texture::FILTER_NONE; // mipmapping is disabled if no argument is given + s.mipmapFilter = SamplerState::MIPMAP_FILTER_NONE; else { const char *mipmapstr = luaL_checkstring(L, 2); - if (!Texture::getConstant(mipmapstr, f.mipmap)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mipmap), mipmapstr); + if (!SamplerState::getConstant(mipmapstr, s.mipmapFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.mipmapFilter), mipmapstr); } - luax_catchexcept(L, [&](){ t->setFilter(f); }); - t->setMipmapSharpness((float) luaL_optnumber(L, 3, 0.0)); + s.lodBias = -((float) luaL_optnumber(L, 3, 0.0)); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Texture_getMipmapFilter(lua_State *L) { Texture *t = luax_checktexture(L, 1); - - const Texture::Filter &f = t->getFilter(); + const SamplerState &s = t->getSamplerState(); const char *mipmapstr; - if (Texture::getConstant(f.mipmap, mipmapstr)) + if (SamplerState::getConstant(s.mipmapFilter, mipmapstr)) lua_pushstring(L, mipmapstr); else lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled - lua_pushnumber(L, t->getMipmapSharpness()); + lua_pushnumber(L, -s.lodBias); return 2; } int w_Texture_setWrap(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Texture::Wrap w; + SamplerState s = t->getSamplerState(); const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); const char *rstr = luaL_optstring(L, 4, sstr); - if (!Texture::getConstant(sstr, w.s)) - return luax_enumerror(L, "wrap mode", Texture::getConstants(w.s), sstr); - if (!Texture::getConstant(tstr, w.t)) - return luax_enumerror(L, "wrap mode", Texture::getConstants(w.t), tstr); - if (!Texture::getConstant(rstr, w.r)) - return luax_enumerror(L, "wrap mode", Texture::getConstants(w.r), rstr); + if (!SamplerState::getConstant(sstr, s.wrapU)) + return luax_enumerror(L, "wrap mode", SamplerState::getConstants(s.wrapU), sstr); + if (!SamplerState::getConstant(tstr, s.wrapV)) + return luax_enumerror(L, "wrap mode", SamplerState::getConstants(s.wrapV), tstr); + if (!SamplerState::getConstant(rstr, s.wrapW)) + return luax_enumerror(L, "wrap mode", SamplerState::getConstants(s.wrapW), rstr); - luax_pushboolean(L, t->setWrap(w)); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 1; } int w_Texture_getWrap(lua_State *L) { Texture *t = luax_checktexture(L, 1); - const Texture::Wrap w = t->getWrap(); + const SamplerState &s = t->getSamplerState(); const char *sstr = nullptr; const char *tstr = nullptr; const char *rstr = nullptr; - if (!Texture::getConstant(w.s, sstr)) + if (!SamplerState::getConstant(s.wrapU, sstr)) return luaL_error(L, "Unknown wrap mode."); - if (!Texture::getConstant(w.t, tstr)) + if (!SamplerState::getConstant(s.wrapV, tstr)) return luaL_error(L, "Unknown wrap mode."); - if (!Texture::getConstant(w.r, rstr)) + if (!SamplerState::getConstant(s.wrapW, rstr)) return luaL_error(L, "Unknown wrap mode."); lua_pushstring(L, sstr); @@ -267,30 +267,31 @@ int w_Texture_isReadable(lua_State *L) int w_Texture_setDepthSampleMode(lua_State *L) { Texture *t = luax_checktexture(L, 1); + SamplerState s = t->getSamplerState(); - Optional mode; + s.depthSampleMode.hasValue = false; if (!lua_isnoneornil(L, 2)) { const char *str = luaL_checkstring(L, 2); - mode.hasValue = true; - if (!getConstant(str, mode.value)) - return luax_enumerror(L, "compare mode", getConstants(mode.value), str); + s.depthSampleMode.hasValue = true; + if (!getConstant(str, s.depthSampleMode.value)) + return luax_enumerror(L, "compare mode", getConstants(s.depthSampleMode.value), str); } - luax_catchexcept(L, [&]() { t->setDepthSampleMode(mode); }); + luax_catchexcept(L, [&](){ t->setSamplerState(s); }); return 0; } int w_Texture_getDepthSampleMode(lua_State *L) { Texture *t = luax_checktexture(L, 1); - Optional mode = t->getDepthSampleMode(); + const SamplerState &s = t->getSamplerState(); - if (mode.hasValue) + if (s.depthSampleMode.hasValue) { const char *str = nullptr; - if (!getConstant(mode.value, str)) + if (!getConstant(s.depthSampleMode.value, str)) return luaL_error(L, "Unknown compare mode."); lua_pushstring(L, str); } diff --git a/src/modules/graphics/wrap_Video.cpp b/src/modules/graphics/wrap_Video.cpp index 712330dbe..32d8b08ac 100644 --- a/src/modules/graphics/wrap_Video.cpp +++ b/src/modules/graphics/wrap_Video.cpp @@ -113,38 +113,38 @@ int w_Video_getPixelDimensions(lua_State *L) int w_Video_setFilter(lua_State *L) { Video *video = luax_checkvideo(L, 1); - Texture::Filter f = video->getFilter(); + SamplerState s = video->getSamplerState(); const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Texture::getConstant(minstr, f.min)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.min), minstr); - if (!Texture::getConstant(magstr, f.mag)) - return luax_enumerror(L, "filter mode", Texture::getConstants(f.mag), magstr); + if (!SamplerState::getConstant(minstr, s.minFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.minFilter), minstr); + if (!SamplerState::getConstant(magstr, s.magFilter)) + return luax_enumerror(L, "filter mode", SamplerState::getConstants(s.magFilter), magstr); - f.anisotropy = (float) luaL_optnumber(L, 4, 1.0); + s.maxAnisotropy = std::min(std::max(1, (int) luaL_optnumber(L, 4, 1.0)), LOVE_UINT8_MAX); - luax_catchexcept(L, [&](){ video->setFilter(f); }); + luax_catchexcept(L, [&](){ video->setSamplerState(s); }); return 0; } int w_Video_getFilter(lua_State *L) { Video *video = luax_checkvideo(L, 1); - const Texture::Filter f = video->getFilter(); + const SamplerState &s = video->getSamplerState(); const char *minstr = nullptr; const char *magstr = nullptr; - if (!Texture::getConstant(f.min, minstr)) + if (!SamplerState::getConstant(s.minFilter, minstr)) return luaL_error(L, "Unknown filter mode."); - if (!Texture::getConstant(f.mag, magstr)) + if (!SamplerState::getConstant(s.magFilter, magstr)) return luaL_error(L, "Unknown filter mode."); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - lua_pushnumber(L, f.anisotropy); + lua_pushnumber(L, s.maxAnisotropy); return 3; }