From 6e882dd56456bd78c996c47eac536a42bf04af07 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Thu, 19 Aug 2021 20:16:42 +0200 Subject: [PATCH] Added support for upscaling bitmap images using linear filtering. --- es-core/src/components/ImageComponent.cpp | 7 ++-- es-core/src/components/ImageComponent.h | 2 +- es-core/src/components/NinePatchComponent.cpp | 2 +- es-core/src/renderers/Renderer.h | 13 +++--- es-core/src/renderers/Renderer_GL21.cpp | 40 ++++++++++--------- es-core/src/renderers/Renderer_GLES10.cpp | 30 +++++++------- es-core/src/resources/Font.cpp | 4 +- es-core/src/resources/TextureData.cpp | 8 ++-- es-core/src/resources/TextureData.h | 3 ++ es-core/src/resources/TextureResource.cpp | 21 ++++++---- es-core/src/resources/TextureResource.h | 7 +++- 11 files changed, 80 insertions(+), 57 deletions(-) diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 88fb97f19..e292f180a 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -138,7 +138,7 @@ void ImageComponent::resize() onSizeChanged(); } -void ImageComponent::setImage(std::string path, bool tile) +void ImageComponent::setImage(std::string path, bool tile, bool linearMagnify) { // Always load bundled graphic resources statically, unless mForceLoad has been set. // This eliminates annoying texture pop-in problems that would otherwise occur. @@ -150,10 +150,11 @@ void ImageComponent::setImage(std::string path, bool tile) if (mDefaultPath.empty() || !ResourceManager::getInstance()->fileExists(mDefaultPath)) mTexture.reset(); else - mTexture = TextureResource::get(mDefaultPath, tile, mForceLoad, mDynamic); + mTexture = + TextureResource::get(mDefaultPath, tile, mForceLoad, mDynamic, linearMagnify); } else { - mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic); + mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, linearMagnify); } resize(); diff --git a/es-core/src/components/ImageComponent.h b/es-core/src/components/ImageComponent.h index 56f45acf3..15f2c27f7 100644 --- a/es-core/src/components/ImageComponent.h +++ b/es-core/src/components/ImageComponent.h @@ -24,7 +24,7 @@ public: // Loads the image at the given filepath. Will tile if tile is true (retrieves texture // as tiling, creates vertices accordingly). - void setImage(std::string path, bool tile = false); + void setImage(std::string path, bool tile = false, bool linearMagnify = false); // Loads an image from memory. void setImage(const char* data, size_t length, bool tile = false); // Use an already existing texture. diff --git a/es-core/src/components/NinePatchComponent.cpp b/es-core/src/components/NinePatchComponent.cpp index a90d52cb1..4de95d9f7 100644 --- a/es-core/src/components/NinePatchComponent.cpp +++ b/es-core/src/components/NinePatchComponent.cpp @@ -59,7 +59,7 @@ void NinePatchComponent::buildVertices() else scaleFactor = glm::clamp(Renderer::getScreenWidthModifier(), 0.4f, 3.0f); - mTexture = TextureResource::get(mPath, false, false, true, scaleFactor); + mTexture = TextureResource::get(mPath, false, false, true, true, scaleFactor); if (mTexture->getSize() == glm::ivec2{}) { mVertices = nullptr; diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index f02531a35..ba17823b7 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -167,12 +167,13 @@ namespace Renderer void setupWindow(); bool createContext(); void destroyContext(); - unsigned int createTexture(const Texture::Type _type, - const bool _linear, - const bool _repeat, - const unsigned int _width, - const unsigned int _height, - void* _data); + unsigned int createTexture(const Texture::Type type, + const bool linearMinify, + const bool linearMagnify, + const bool repeat, + const unsigned int width, + const unsigned int height, + void* data); void destroyTexture(const unsigned int _texture); void updateTexture(const unsigned int _texture, const Texture::Type _type, diff --git a/es-core/src/renderers/Renderer_GL21.cpp b/es-core/src/renderers/Renderer_GL21.cpp index 130393e46..79d9a9350 100644 --- a/es-core/src/renderers/Renderer_GL21.cpp +++ b/es-core/src/renderers/Renderer_GL21.cpp @@ -138,7 +138,7 @@ namespace Renderer } uint8_t data[4] = {255, 255, 255, 255}; - whiteTexture = createTexture(Texture::RGBA, false, true, 1, 1, data); + whiteTexture = createTexture(Texture::RGBA, false, false, true, 1, 1, data); GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL_CHECK_ERROR(glEnable(GL_TEXTURE_2D)); @@ -162,32 +162,35 @@ namespace Renderer sdlContext = nullptr; } - unsigned int createTexture(const Texture::Type _type, - const bool _linear, - const bool _repeat, - const unsigned int _width, - const unsigned int _height, - void* _data) + unsigned int createTexture(const Texture::Type type, + const bool linearMinify, + const bool linearMagnify, + const bool repeat, + const unsigned int width, + const unsigned int height, + void* data) { - const GLenum type = convertTextureType(_type); + const GLenum textureType = convertTextureType(type); unsigned int texture; GL_CHECK_ERROR(glGenTextures(1, &texture)); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - _repeat ? static_cast(GL_REPEAT) : - static_cast(GL_CLAMP_TO_EDGE))); + repeat ? static_cast(GL_REPEAT) : + static_cast(GL_CLAMP_TO_EDGE))); GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - _repeat ? static_cast(GL_REPEAT) : - static_cast(GL_CLAMP_TO_EDGE))); + repeat ? static_cast(GL_REPEAT) : + static_cast(GL_CLAMP_TO_EDGE))); GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - _linear ? static_cast(GL_LINEAR) : - static_cast(GL_NEAREST))); - GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + linearMinify ? static_cast(GL_LINEAR) : + static_cast(GL_NEAREST))); + GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + linearMagnify ? static_cast(GL_LINEAR) : + static_cast(GL_NEAREST))); - GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, type, _width, _height, 0, type, - GL_UNSIGNED_BYTE, _data)); + GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, + GL_UNSIGNED_BYTE, data)); return texture; } @@ -448,7 +451,8 @@ namespace Renderer vertices[0].saturation = parameters.fragmentSaturation; setMatrix(getIdentity()); - GLuint screenTexture = createTexture(Texture::RGBA, false, false, width, height, nullptr); + GLuint screenTexture = + createTexture(Texture::RGBA, false, false, false, width, height, nullptr); GL_CHECK_ERROR(glBindFramebuffer(GL_READ_FRAMEBUFFER, 0)); diff --git a/es-core/src/renderers/Renderer_GLES10.cpp b/es-core/src/renderers/Renderer_GLES10.cpp index 7e36ea094..f8c846372 100644 --- a/es-core/src/renderers/Renderer_GLES10.cpp +++ b/es-core/src/renderers/Renderer_GLES10.cpp @@ -91,7 +91,7 @@ namespace Renderer "MISSING"); uint8_t data[4] = {255, 255, 255, 255}; - whiteTexture = createTexture(Texture::RGBA, false, true, 1, 1, data); + whiteTexture = createTexture(Texture::RGBA, false, false, true, 1, 1, data); GL_CHECK_ERROR(glClearColor(0.0f, 0.0f, 0.0f, 1.0f)); GL_CHECK_ERROR(glEnable(GL_TEXTURE_2D)); @@ -111,29 +111,31 @@ namespace Renderer sdlContext = nullptr; } - unsigned int createTexture(const Texture::Type _type, - const bool _linear, - const bool _repeat, - const unsigned int _width, - const unsigned int _height, - void* _data) + unsigned int createTexture(const Texture::Type type, + const bool linearMinify, + const bool linearMagnify, + const bool repeat, + const unsigned int width, + const unsigned int height, + void* data) { - const GLenum type = convertTextureType(_type); + const GLenum textureType = convertTextureType(type); unsigned int texture; GL_CHECK_ERROR(glGenTextures(1, &texture)); GL_CHECK_ERROR(glBindTexture(GL_TEXTURE_2D, texture)); GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, - _repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE)); + repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE)); GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, - _repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE)); + repeat ? GL_REPEAT : GL_CLAMP_TO_EDGE)); GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - _linear ? GL_LINEAR : GL_NEAREST)); - GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)); + linearMinify ? GL_LINEAR : GL_NEAREST)); + GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, + linearMagnify ? GL_LINEAR : GL_NEAREST)); - GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, type, _width, _height, 0, type, - GL_UNSIGNED_BYTE, _data)); + GL_CHECK_ERROR(glTexImage2D(GL_TEXTURE_2D, 0, textureType, width, height, 0, textureType, + GL_UNSIGNED_BYTE, data)); return texture; } diff --git a/es-core/src/resources/Font.cpp b/es-core/src/resources/Font.cpp index e92b4d651..4d5ff1c8f 100644 --- a/es-core/src/resources/Font.cpp +++ b/es-core/src/resources/Font.cpp @@ -179,8 +179,8 @@ bool Font::FontTexture::findEmpty(const glm::ivec2& size, glm::ivec2& cursor_out void Font::FontTexture::initTexture() { assert(textureId == 0); - textureId = Renderer::createTexture(Renderer::Texture::ALPHA, false, false, textureSize.x, - textureSize.y, nullptr); + textureId = Renderer::createTexture(Renderer::Texture::ALPHA, false, false, false, + textureSize.x, textureSize.y, nullptr); } void Font::FontTexture::deinitTexture() diff --git a/es-core/src/resources/TextureData.cpp b/es-core/src/resources/TextureData.cpp index 32a301a15..65e715512 100644 --- a/es-core/src/resources/TextureData.cpp +++ b/es-core/src/resources/TextureData.cpp @@ -28,6 +28,7 @@ TextureData::TextureData(bool tile) , mDataRGBA({}) , mScaleDuringLoad(1.0f) , mScalable(false) + , mLinearMagnify(false) , mWidth(0) , mHeight(0) , mSourceWidth(0.0f) @@ -196,9 +197,10 @@ bool TextureData::uploadAndBind() return false; // Upload texture. - mTextureID = Renderer::createTexture( - Renderer::Texture::RGBA, true, mTile, static_cast(mWidth), - static_cast(mHeight), mDataRGBA.data()); + mTextureID = + Renderer::createTexture(Renderer::Texture::RGBA, true, mLinearMagnify, mTile, + static_cast(mWidth), + static_cast(mHeight), mDataRGBA.data()); } return true; } diff --git a/es-core/src/resources/TextureData.h b/es-core/src/resources/TextureData.h index d038f0123..ebb27b3e8 100644 --- a/es-core/src/resources/TextureData.h +++ b/es-core/src/resources/TextureData.h @@ -56,6 +56,8 @@ public: // Define a factor for scaling the file when loading it (1.0f = no scaling). void setScaleDuringLoad(float scale) { mScaleDuringLoad = scale; } + // Whether to use linear filtering when magnifying the texture. + void setLinearMagnify(bool setting) { mLinearMagnify = setting; } std::vector getRawRGBAData() { return mDataRGBA; } std::string getTextureFilePath() { return mPath; } @@ -73,6 +75,7 @@ private: float mSourceHeight; float mScaleDuringLoad; bool mScalable; + bool mLinearMagnify; bool mReloadable; }; diff --git a/es-core/src/resources/TextureResource.cpp b/es-core/src/resources/TextureResource.cpp index ff2281044..33fec7e8a 100644 --- a/es-core/src/resources/TextureResource.cpp +++ b/es-core/src/resources/TextureResource.cpp @@ -16,10 +16,8 @@ std::map> TextureResource::sTextureMap; std::set TextureResource::sAllTextures; -TextureResource::TextureResource(const std::string& path, - bool tile, - bool dynamic, - float scaleDuringLoad) +TextureResource::TextureResource( + const std::string& path, bool tile, bool dynamic, bool linearMagnify, float scaleDuringLoad) : mTextureData(nullptr) , mForceLoad(false) { @@ -33,6 +31,7 @@ TextureResource::TextureResource(const std::string& path, data->initFromPath(path); if (scaleDuringLoad != 1.0f) data->setScaleDuringLoad(scaleDuringLoad); + data->setLinearMagnify(linearMagnify); // Force the texture manager to load it using a blocking load. sTextureDataManager.load(data, true); } @@ -42,6 +41,7 @@ TextureResource::TextureResource(const std::string& path, data->initFromPath(path); if (scaleDuringLoad != 1.0f) data->setScaleDuringLoad(scaleDuringLoad); + data->setLinearMagnify(linearMagnify); // Load it so we can read the width/height. data->load(); } @@ -143,14 +143,19 @@ bool TextureResource::bind() } } -std::shared_ptr TextureResource::get( - const std::string& path, bool tile, bool forceLoad, bool dynamic, float scaleDuringLoad) +std::shared_ptr TextureResource::get(const std::string& path, + bool tile, + bool forceLoad, + bool dynamic, + bool linearMagnify, + float scaleDuringLoad) { std::shared_ptr& rm = ResourceManager::getInstance(); const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(path); if (canonicalPath.empty()) { - std::shared_ptr tex(new TextureResource("", tile, false, scaleDuringLoad)); + std::shared_ptr tex( + new TextureResource("", tile, false, linearMagnify, scaleDuringLoad)); // Make sure we get properly deinitialized even though we do nothing on reinitialization. rm->addReloadable(tex); return tex; @@ -167,7 +172,7 @@ std::shared_ptr TextureResource::get( // Need to create it. std::shared_ptr tex; tex = std::shared_ptr( - new TextureResource(key.first, tile, dynamic, scaleDuringLoad)); + new TextureResource(key.first, tile, dynamic, linearMagnify, scaleDuringLoad)); std::shared_ptr data = sTextureDataManager.get(tex.get()); // Is it an SVG? diff --git a/es-core/src/resources/TextureResource.h b/es-core/src/resources/TextureResource.h index f3f5ae34b..223d60fcc 100644 --- a/es-core/src/resources/TextureResource.h +++ b/es-core/src/resources/TextureResource.h @@ -29,6 +29,7 @@ public: bool tile = false, bool forceLoad = false, bool dynamic = true, + bool linearMagnify = false, float scaleDuringLoad = 1.0f); void initFromPixels(const unsigned char* dataRGBA, size_t width, size_t height); virtual void initFromMemory(const char* data, size_t length); @@ -60,7 +61,11 @@ public: static size_t getTotalTextureSize(); protected: - TextureResource(const std::string& path, bool tile, bool dynamic, float scaleDuringLoad); + TextureResource(const std::string& path, + bool tile, + bool dynamic, + bool linearMagnify, + float scaleDuringLoad); virtual void unload(std::shared_ptr& rm); virtual void reload(std::shared_ptr& rm);