diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 4d60e162f..459248646 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -48,6 +48,7 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic) , mDynamic {dynamic} , mRotateByTargetSize {false} , mLinearInterpolation {false} + , mMipmapping {false} , mTopLeftCrop {0.0f, 0.0f} , mBottomRightCrop {1.0f, 1.0f} , mClipRegion {0.0f, 0.0f, 0.0f, 0.0f} @@ -137,7 +138,7 @@ void ImageComponent::setImage(const std::string& path, bool tile) mTexture.reset(); else mTexture = TextureResource::get(mDefaultPath, tile, mForceLoad, mDynamic, - mLinearInterpolation); + mLinearInterpolation, mMipmapping); resize(true); } else { @@ -147,14 +148,14 @@ void ImageComponent::setImage(const std::string& path, bool tile) // we perform the actual rasterization to have the cache entry updated with the proper // texture. For SVG images this requires that every call to setImage is made only after // a call to setResize or setMaxSize (so the requested size is known upfront). - mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation, 0, - 0, 0.0f, 0.0f); + mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation, + mMipmapping, 0, 0, 0.0f, 0.0f); if (isScalable) { resize(false); mTexture.reset(); mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation, - static_cast(mSize.x), + mMipmapping, static_cast(mSize.x), static_cast(mSize.y), mTileWidth, mTileHeight); mTexture->setScalableNonAspect(mScalableNonAspect); mTexture->rasterizeAt(mSize.x, mSize.y); diff --git a/es-core/src/components/ImageComponent.h b/es-core/src/components/ImageComponent.h index 122887a6b..9ba2c0c29 100644 --- a/es-core/src/components/ImageComponent.h +++ b/es-core/src/components/ImageComponent.h @@ -92,6 +92,8 @@ public: void setRotateByTargetSize(bool rotate) { mRotateByTargetSize = rotate; } // Whether to use smooth texture magnification by utilizing linear interpolation. void setLinearInterpolation(bool state) { mLinearInterpolation = state; } + // Whether to use mipmapping and trilinear filtering. + void setMipmapping(bool state) { mMipmapping = state; } // Returns the size of the current texture, or (0, 0) if none is loaded. // May be different than drawn size (use getSize() for that). @@ -152,6 +154,7 @@ private: bool mDynamic; bool mRotateByTargetSize; bool mLinearInterpolation; + bool mMipmapping; glm::vec2 mTopLeftCrop; glm::vec2 mBottomRightCrop; diff --git a/es-core/src/components/NinePatchComponent.cpp b/es-core/src/components/NinePatchComponent.cpp index 942bdecb2..39e438ac6 100644 --- a/es-core/src/components/NinePatchComponent.cpp +++ b/es-core/src/components/NinePatchComponent.cpp @@ -66,7 +66,7 @@ void NinePatchComponent::buildVertices() } glm::vec2 texSize {relCornerSize * 3.0f}; - mTexture = TextureResource::get(mPath, false, false, false, false, + mTexture = TextureResource::get(mPath, false, false, false, false, false, static_cast(texSize.x), static_cast(texSize.y)); mTexture->rasterizeAt(texSize.x, texSize.y); diff --git a/es-core/src/components/RatingComponent.cpp b/es-core/src/components/RatingComponent.cpp index 75308f189..71b2c8d7c 100644 --- a/es-core/src/components/RatingComponent.cpp +++ b/es-core/src/components/RatingComponent.cpp @@ -179,7 +179,7 @@ void RatingComponent::applyTheme(const std::shared_ptr& theme, std::string path {std::string(elem->get("filledPath"))}; if (Utils::FileSystem::isRegularFile(path) || Utils::FileSystem::isSymlink(path)) { auto tempImage = - TextureResource::get(path, false, false, false, false, 0, 0, 0.0f, 0.0f); + TextureResource::get(path, false, false, false, false, false, 0, 0, 0.0f, 0.0f); mImageRatio = static_cast(tempImage->getSize().x) / static_cast(tempImage->getSize().y); } diff --git a/es-core/src/components/primary/CarouselComponent.h b/es-core/src/components/primary/CarouselComponent.h index 41bdcbe6c..00f382ecb 100644 --- a/es-core/src/components/primary/CarouselComponent.h +++ b/es-core/src/components/primary/CarouselComponent.h @@ -210,6 +210,7 @@ void CarouselComponent::addEntry(Entry& entry, const std::shared_ptr(false, dynamic); item->setLinearInterpolation(mLinearInterpolation); + item->setMipmapping(true); item->setMaxSize(mItemSize * mItemScale); item->applyTheme(theme, "system", "image_logo", ThemeFlags::PATH | ThemeFlags::COLOR); @@ -223,6 +224,7 @@ void CarouselComponent::addEntry(Entry& entry, const std::shared_ptr(false, dynamic); item->setLinearInterpolation(mLinearInterpolation); + item->setMipmapping(true); item->setMaxSize(mItemSize * mItemScale); item->setImage(entry.data.itemPath); item->applyTheme(theme, "system", "", ThemeFlags::ALL); @@ -233,6 +235,7 @@ void CarouselComponent::addEntry(Entry& entry, const std::shared_ptr(false, dynamic); defaultItem->setLinearInterpolation(mLinearInterpolation); + defaultItem->setMipmapping(true); defaultItem->setMaxSize(mItemSize * mItemScale); defaultItem->setImage(entry.data.defaultItemPath); defaultItem->applyTheme(theme, "system", "", ThemeFlags::ALL); @@ -306,6 +309,7 @@ void CarouselComponent::updateEntry(Entry& entry, const std::shared_ptr(false, true); item->setLinearInterpolation(mLinearInterpolation); + item->setMipmapping(true); item->setMaxSize(mItemSize * mItemScale); item->setImage(entry.data.itemPath); item->applyTheme(theme, "system", "", ThemeFlags::ALL); diff --git a/es-core/src/renderers/Renderer.h b/es-core/src/renderers/Renderer.h index 082e42664..65fb533df 100644 --- a/es-core/src/renderers/Renderer.h +++ b/es-core/src/renderers/Renderer.h @@ -184,6 +184,7 @@ public: virtual unsigned int createTexture(const TextureType type, const bool linearMinify, const bool linearMagnify, + const bool mipmapping, const bool repeat, const unsigned int width, const unsigned int height, diff --git a/es-core/src/renderers/RendererOpenGL.cpp b/es-core/src/renderers/RendererOpenGL.cpp index 7f4741a48..182e01050 100644 --- a/es-core/src/renderers/RendererOpenGL.cpp +++ b/es-core/src/renderers/RendererOpenGL.cpp @@ -240,13 +240,13 @@ bool RendererOpenGL::createContext() GL_CHECK_ERROR(glBindVertexArray(mVertexBuffer2)); uint8_t data[4] {255, 255, 255, 255}; - mWhiteTexture = createTexture(TextureType::RGBA, false, false, true, 1, 1, data); + mWhiteTexture = createTexture(TextureType::RGBA, false, false, false, true, 1, 1, data); - mPostProcTexture1 = createTexture(TextureType::RGBA, false, false, false, + mPostProcTexture1 = createTexture(TextureType::RGBA, false, false, false, false, static_cast(getScreenWidth()), static_cast(getScreenHeight()), nullptr); - mPostProcTexture2 = createTexture(TextureType::RGBA, false, false, false, + mPostProcTexture2 = createTexture(TextureType::RGBA, false, false, false, false, static_cast(getScreenWidth()), static_cast(getScreenHeight()), nullptr); @@ -277,8 +277,8 @@ void RendererOpenGL::destroyContext() void RendererOpenGL::setMatrix(const glm::mat4& matrix) { - mTrans = matrix; - mTrans = getProjectionMatrix() * mTrans; + // Calculate the projection matrix. + mTrans = getProjectionMatrix() * matrix; } void RendererOpenGL::setScissor(const Rect& scissor) @@ -337,6 +337,7 @@ void RendererOpenGL::swapBuffers() unsigned int RendererOpenGL::createTexture(const TextureType type, const bool linearMinify, const bool linearMagnify, + const bool mipmapping, const bool repeat, const unsigned int width, const unsigned int height, @@ -354,15 +355,25 @@ unsigned int RendererOpenGL::createTexture(const TextureType type, GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, repeat ? static_cast(GL_REPEAT) : static_cast(GL_CLAMP_TO_EDGE))); - GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - linearMinify ? static_cast(GL_LINEAR) : - static_cast(GL_NEAREST))); + if (mipmapping) { + GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + static_cast(GL_LINEAR_MIPMAP_LINEAR))); + } + else { + GL_CHECK_ERROR(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + 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, textureType, width, height, 0, textureType, GL_UNSIGNED_BYTE, data)); + + if (mipmapping) + GL_CHECK_ERROR(glGenerateMipmap(GL_TEXTURE_2D)); + return texture; } diff --git a/es-core/src/renderers/RendererOpenGL.h b/es-core/src/renderers/RendererOpenGL.h index ec3a4d7ed..5cfaaa06a 100644 --- a/es-core/src/renderers/RendererOpenGL.h +++ b/es-core/src/renderers/RendererOpenGL.h @@ -46,6 +46,7 @@ public: unsigned int createTexture(const TextureType type, const bool linearMinify, const bool linearMagnify, + const bool mipmapping, const bool repeat, const unsigned int width, const unsigned int height, diff --git a/es-core/src/resources/TextureData.cpp b/es-core/src/resources/TextureData.cpp index a369bdb98..ce784acd6 100644 --- a/es-core/src/resources/TextureData.cpp +++ b/es-core/src/resources/TextureData.cpp @@ -39,6 +39,7 @@ TextureData::TextureData(bool tile) , mHasRGBAData {false} , mPendingRasterization {false} , mLinearMagnify {false} + , mMipmapping {false} { } @@ -240,8 +241,8 @@ bool TextureData::uploadAndBind() // Upload texture. mTextureID = - mRenderer->createTexture(Renderer::TextureType::RGBA, true, mLinearMagnify, mTile, - static_cast(mWidth), + mRenderer->createTexture(Renderer::TextureType::RGBA, true, mLinearMagnify, mMipmapping, + 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 ebe118a8e..c803c46d6 100644 --- a/es-core/src/resources/TextureData.h +++ b/es-core/src/resources/TextureData.h @@ -70,6 +70,8 @@ public: void setScalableNonAspect(bool state) { mScalableNonAspect = state; } // Whether to use linear filtering when magnifying the texture. void setLinearMagnify(bool state) { mLinearMagnify = state; } + // Whether to use mipmapping and trilinear filtering. + void setMipmapping(bool state) { mMipmapping = state; } // Has the image been loaded but not yet been rasterized as the size was not known? const bool getPendingRasterization() { return mPendingRasterization; } @@ -98,6 +100,7 @@ private: std::atomic mHasRGBAData; std::atomic mPendingRasterization; bool mLinearMagnify; + bool mMipmapping; bool mReloadable; }; diff --git a/es-core/src/resources/TextureResource.cpp b/es-core/src/resources/TextureResource.cpp index 95fb7e110..294f8401a 100644 --- a/es-core/src/resources/TextureResource.cpp +++ b/es-core/src/resources/TextureResource.cpp @@ -20,6 +20,7 @@ TextureResource::TextureResource(const std::string& path, bool tile, bool dynamic, bool linearMagnify, + bool mipmapping, bool scalable) : mTextureData {nullptr} , mForceLoad {false} @@ -35,6 +36,7 @@ TextureResource::TextureResource(const std::string& path, data->initFromPath(path); data->setTileSize(tileWidth, tileHeight); data->setLinearMagnify(linearMagnify); + data->setMipmapping(mipmapping); // Force the texture manager to load it using a blocking load. sTextureDataManager.load(data, true); } @@ -44,6 +46,7 @@ TextureResource::TextureResource(const std::string& path, data->initFromPath(path); data->setTileSize(tileWidth, tileHeight); data->setLinearMagnify(linearMagnify); + data->setMipmapping(mipmapping); // Load it so we can read the width/height. data->load(); } @@ -154,6 +157,7 @@ std::shared_ptr TextureResource::get(const std::string& path, bool forceLoad, bool dynamic, bool linearMagnify, + bool mipmapping, size_t width, size_t height, float tileWidth, @@ -161,8 +165,8 @@ std::shared_ptr TextureResource::get(const std::string& path, { const std::string canonicalPath {Utils::FileSystem::getCanonicalPath(path)}; if (canonicalPath.empty()) { - std::shared_ptr tex( - new TextureResource("", tileWidth, tileHeight, tile, false, linearMagnify, false)); + std::shared_ptr tex(new TextureResource( + "", tileWidth, tileHeight, tile, false, linearMagnify, mipmapping, false)); // Make sure we get properly deinitialized even though we do nothing on reinitialization. ResourceManager::getInstance().addReloadable(tex); return tex; @@ -207,8 +211,9 @@ std::shared_ptr TextureResource::get(const std::string& path, } // Need to create it. - std::shared_ptr tex {std::shared_ptr(new TextureResource( - std::get<0>(key), tileWidth, tileHeight, tile, dynamic, linearMagnify, isScalable))}; + std::shared_ptr tex {std::shared_ptr( + new TextureResource(std::get<0>(key), tileWidth, tileHeight, tile, dynamic, linearMagnify, + mipmapping, isScalable))}; std::shared_ptr data {sTextureDataManager.get(tex.get())}; if (!isScalable || (isScalable && width != 0.0f && height != 0.0f)) { diff --git a/es-core/src/resources/TextureResource.h b/es-core/src/resources/TextureResource.h index 77f07d944..5d2ca7a91 100644 --- a/es-core/src/resources/TextureResource.h +++ b/es-core/src/resources/TextureResource.h @@ -31,6 +31,7 @@ public: bool forceLoad = false, bool dynamic = true, bool linearMagnify = false, + bool mipmapping = false, size_t width = 0, size_t height = 0, float tileWidth = 0.0f, @@ -86,6 +87,7 @@ protected: bool tile, bool dynamic, bool linearMagnify, + bool mipmapping, bool scalable); virtual void unload(ResourceManager& rm); virtual void reload(ResourceManager& rm);