From 48a9571609a8b0c2bedc96e08f89e6b93ebb7564 Mon Sep 17 00:00:00 2001 From: Leon Styhre Date: Sun, 28 Aug 2022 20:11:20 +0200 Subject: [PATCH] Refactored RatingComponent to improve rendering accuracy and performance. --- es-core/src/GuiComponent.h | 1 + es-core/src/components/ImageComponent.cpp | 19 +- es-core/src/components/ImageComponent.h | 16 +- es-core/src/components/RatingComponent.cpp | 224 +++++++++------------ es-core/src/components/RatingComponent.h | 23 +-- es-core/src/resources/TextureData.cpp | 12 +- es-core/src/resources/TextureData.h | 7 + es-core/src/resources/TextureResource.cpp | 24 ++- es-core/src/resources/TextureResource.h | 12 +- 9 files changed, 175 insertions(+), 163 deletions(-) diff --git a/es-core/src/GuiComponent.h b/es-core/src/GuiComponent.h index 06dd67847..edeb33e10 100644 --- a/es-core/src/GuiComponent.h +++ b/es-core/src/GuiComponent.h @@ -90,6 +90,7 @@ public: void setSize(const glm::vec2& size) { setSize(size.x, size.y); } void setSize(const float w, const float h); virtual void setResize(float width, float height) {} + virtual void setResize(float width, float height, bool rasterize) {} virtual void onSizeChanged() {} virtual glm::vec2 getRotationSize() const { return getSize(); } diff --git a/es-core/src/components/ImageComponent.cpp b/es-core/src/components/ImageComponent.cpp index 30759106a..80c6f9424 100644 --- a/es-core/src/components/ImageComponent.cpp +++ b/es-core/src/components/ImageComponent.cpp @@ -36,6 +36,8 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic) , mFlipY {false} , mTargetIsMax {false} , mTargetIsMin {false} + , mTileWidth {0.0f} + , mTileHeight {0.0f} , mColorShift {0xFFFFFFFF} , mColorShiftEnd {0xFFFFFFFF} , mColorGradientHorizontal {true} @@ -164,14 +166,15 @@ 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); + mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation, + false, 0, 0, mTileWidth, mTileHeight); if (isScalable) { resize(false); mTexture.reset(); - mTexture = - TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation, false, - static_cast(mSize.x), static_cast(mSize.y)); + mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation, + false, static_cast(mSize.x), + static_cast(mSize.y), mTileWidth, mTileHeight); mTexture->rasterizeAt(mSize.x, mSize.y); onSizeChanged(); } @@ -206,6 +209,14 @@ void ImageComponent::setResize(float width, float height) resize(); } +void ImageComponent::setResize(float width, float height, bool rasterize) +{ + mTargetSize = glm::vec2 {width, height}; + mTargetIsMax = false; + mTargetIsMin = false; + resize(rasterize); +} + void ImageComponent::setMaxSize(const float width, const float height) { mTargetSize = glm::vec2 {width, height}; diff --git a/es-core/src/components/ImageComponent.h b/es-core/src/components/ImageComponent.h index 429ecc480..ad59e52b0 100644 --- a/es-core/src/components/ImageComponent.h +++ b/es-core/src/components/ImageComponent.h @@ -30,6 +30,7 @@ public: // Use an already existing texture. void setImage(const std::shared_ptr& texture, bool resizeTexture = true); + void setDynamic(bool state) { mDynamic = state; } void onSizeChanged() override { updateVertices(); } // Resize the image to fit this size. If one axis is zero, scale that axis to maintain @@ -38,7 +39,11 @@ public: // Can be set before or after an image is loaded. // setMaxSize() and setResize() are mutually exclusive. void setResize(const float width, const float height) override; - void setResize(const glm::vec2& size) { setResize(size.x, size.y); } + void setResize(const glm::vec2& size, bool rasterize = true) + { + setResize(size.x, size.y, rasterize); + } + void setResize(const float width, const float height, bool rasterize) override; // Resize the image to be as large as possible but fit within a box of this size. // Can be set before or after an image is loaded. @@ -46,6 +51,12 @@ public: void setMaxSize(const float width, const float height); void setMaxSize(const glm::vec2& size) { setMaxSize(size.x, size.y); } + void setTileSize(const float width, const float height) + { + mTileWidth = width; + mTileHeight = height; + } + glm::vec2 getRotationSize() const override { return mRotateByTargetSize ? mTargetSize : mSize; } // Applied AFTER image positioning and sizing. @@ -108,6 +119,9 @@ private: bool mTargetIsMax; bool mTargetIsMin; + float mTileWidth; + float mTileHeight; + // Calculates the correct mSize from our resizing information (set by setResize/setMaxSize). // Used internally whenever the resizing parameters or texture change. This function also // initiates the SVG rasterization unless explicitly told not to. diff --git a/es-core/src/components/RatingComponent.cpp b/es-core/src/components/RatingComponent.cpp index 05daef9af..b7da7f1bd 100644 --- a/es-core/src/components/RatingComponent.cpp +++ b/es-core/src/components/RatingComponent.cpp @@ -19,15 +19,21 @@ RatingComponent::RatingComponent(bool colorizeChanges) , mColorChangedValue {DEFAULT_COLORSHIFT} , mColorShift {DEFAULT_COLORSHIFT} , mColorShiftEnd {DEFAULT_COLORSHIFT} - , mUnfilledColor {DEFAULT_COLORSHIFT} , mColorizeChanges {colorizeChanges} { - mFilledTexture = TextureResource::get(":/graphics/star_filled.svg", true); - mUnfilledTexture = TextureResource::get(":/graphics/star_unfilled.svg", true); + mSize = glm::vec2 {mRenderer->getScreenHeight() * 0.06f * NUM_RATING_STARS, + mRenderer->getScreenHeight() * 0.06f}; + + mIconFilled.setResize(mSize, false); + mIconFilled.setTileSize(mSize.y, mSize.y); + + mIconUnfilled.setResize(mSize, false); + mIconUnfilled.setTileSize(mSize.y, mSize.y); + + mIconFilled.setImage(std::string(":/graphics/star_filled.svg"), true); + mIconUnfilled.setImage(std::string(":/graphics/star_unfilled.svg"), true); + mValue = 0.5f; - mSize = glm::vec2 {64.0f * NUM_RATING_STARS, 64.0f}; - updateVertices(); - updateColors(); } void RatingComponent::setValue(const std::string& value) @@ -44,9 +50,9 @@ void RatingComponent::setValue(const std::string& value) // color shift accordingly. if (mColorizeChanges) { if (static_cast(mValue * 10.0f) == mOriginalValue) - setColorShift(mColorOriginalValue); + mIconFilled.setColorShift(mColorOriginalValue); else - setColorShift(mColorChangedValue); + mIconFilled.setColorShift(mColorChangedValue); } // For the special situation where there is a fractional rating in the gamelist.xml @@ -55,7 +61,7 @@ void RatingComponent::setValue(const std::string& value) // been manually edited. if (mColorizeChanges && mValue != stof(value)) { mOriginalValue = ICONCOLOR_USERMARKED; - setColorShift(0x449944FF); + mIconFilled.setColorShift(0x449944FF); } if (mValue > 1.0f) @@ -63,8 +69,6 @@ void RatingComponent::setValue(const std::string& value) else if (mValue < 0.0f) mValue = 0.0f; } - - updateVertices(); } std::string RatingComponent::getValue() const @@ -83,117 +87,55 @@ std::string RatingComponent::getRatingValue(const std::string& rating) return ss.str(); } -void RatingComponent::setOpacity(float opacity) -{ - mOpacity = opacity; - mColorShift = - (mColorShift >> 8 << 8) | static_cast(mOpacity * mThemeOpacity * 255.0f); - updateColors(); -} - void RatingComponent::setDimming(float dimming) { mDimming = dimming; - mVertices[0].dimming = mDimming; - mVertices[4].dimming = mDimming; -} - -void RatingComponent::setColorShift(unsigned int color) -{ - mColorShift = color; - mColorShiftEnd = color; - - // Grab the opacity from the color shift because we may need - // to apply it if fading in textures. - mOpacity = static_cast(color & 0xff) / 255.0f; - updateColors(); + mIconFilled.setDimming(dimming); + mIconUnfilled.setDimming(dimming); } void RatingComponent::onSizeChanged() { - // Make sure the size is not unreasonably large (which may be caused by a mistake in - // the theme configuration). - mSize.x = glm::clamp(mSize.x, 0.0f, mRenderer->getScreenWidth() / 2.0f); - mSize.y = glm::clamp(mSize.y, 0.0f, mRenderer->getScreenHeight() / 2.0f); + mSize = glm::round(mSize); - if (mSize.y == 0.0f) - mSize.y = mSize.x / NUM_RATING_STARS; - else if (mSize.x == 0.0f) + if (mSize.x == 0.0f) mSize.x = mSize.y * NUM_RATING_STARS; - if (mSize.y > 0.0f) { - if (mFilledTexture) - mFilledTexture->rasterizeAt(mSize.y, mSize.y); - if (mUnfilledTexture) - mUnfilledTexture->rasterizeAt(mSize.y, mSize.y); - } + mIconFilled.getTexture()->setSize(mSize.y, mSize.y); + mIconFilled.setResize(glm::vec2 {mSize.y * NUM_RATING_STARS, mSize.y}, true); - updateVertices(); -} - -void RatingComponent::updateVertices() -{ - const float numStars {NUM_RATING_STARS}; - const float h {getSize().y}; // Ss the same as a single star's width. - const float w {getSize().y * mValue * numStars}; - const float fw {getSize().y * numStars}; - - // clang-format off - mVertices[0] = {{0.0f, 0.0f}, {0.0f, 1.0f}, mColorShift}; - mVertices[1] = {{0.0f, h }, {0.0f, 0.0f}, mColorShift}; - mVertices[2] = {{w, 0.0f}, {mValue * numStars, 1.0f}, mColorShift}; - mVertices[3] = {{w, h }, {mValue * numStars, 0.0f}, mColorShift}; - - mVertices[4] = {{0.0f, 0.0f}, {0.0f, 1.0f}, mColorShift}; - mVertices[5] = {{0.0f, h }, {0.0f, 0.0f}, mColorShift}; - mVertices[6] = {{fw, 0.0f}, {numStars, 1.0f}, mColorShift}; - mVertices[7] = {{fw, h }, {numStars, 0.0f}, mColorShift}; - // clang-format on -} - -void RatingComponent::updateColors() -{ - for (int i = 0; i < 8; ++i) - mVertices[i].color = mColorShift; + mIconUnfilled.getTexture()->setSize(mSize.y, mSize.y); + mIconUnfilled.setResize(glm::vec2 {mSize.y * NUM_RATING_STARS, mSize.y}, true); } void RatingComponent::render(const glm::mat4& parentTrans) { - if (!isVisible() || mFilledTexture == nullptr || mUnfilledTexture == nullptr || - mThemeOpacity == 0.0f) + if (!isVisible() || mThemeOpacity == 0.0f || mOpacity == 0.0f) return; glm::mat4 trans {parentTrans * getTransform()}; - mRenderer->setMatrix(trans); - if (mOpacity > 0.0f) { - if (Settings::getInstance()->getBool("DebugImage")) { - mRenderer->drawRect(0.0f, 0.0f, mSize.y * NUM_RATING_STARS, mSize.y, 0xFF000033, - 0xFF000033); - } + mIconUnfilled.setOpacity(mOpacity * mThemeOpacity); + mIconUnfilled.render(trans); - if (mUnfilledTexture->bind()) { - if (mUnfilledColor != mColorShift) { - for (int i = 0; i < 8; ++i) - mVertices[i].color = - (mUnfilledColor & 0xFFFFFF00) + (mVertices[i].color & 0x000000FF); - } + // No need to render the filled texture if the value is zero. + if (mValue == 0.0f) + return; - mRenderer->drawTriangleStrips(&mVertices[4], 4); - mRenderer->bindTexture(0); + glm::ivec2 clipPos {static_cast(std::round(trans[3].x)), + static_cast(std::round(trans[3].y))}; + glm::vec3 dimScaled {}; + dimScaled.x = std::fabs(trans[3].x + mIconUnfilled.getSize().x); + dimScaled.y = std::fabs(trans[3].y + mIconUnfilled.getSize().y); - if (mUnfilledColor != mColorShift) - updateColors(); - } + glm::ivec2 clipDim {static_cast(std::round(dimScaled.x - std::round(trans[3].x)) * mValue), + static_cast(std::round(dimScaled.y - trans[3].y))}; - if (mFilledTexture->bind()) { - mRenderer->drawTriangleStrips(&mVertices[0], 4); - mRenderer->bindTexture(0); - } - } - - renderChildren(trans); + mIconFilled.setOpacity(mOpacity * mThemeOpacity); + mRenderer->pushClipRect(clipPos, clipDim); + mIconFilled.render(trans); + mRenderer->popClipRect(); } bool RatingComponent::input(InputConfig* config, Input input) @@ -207,11 +149,10 @@ bool RatingComponent::input(InputConfig* config, Input input) // set the color shift accordingly. if (mColorizeChanges) { if (static_cast(mValue * 10.0f) == mOriginalValue) - setColorShift(mColorOriginalValue); + mIconFilled.setColorShift(mColorOriginalValue); else - setColorShift(mColorChangedValue); + mIconFilled.setColorShift(mColorChangedValue); } - updateVertices(); } return GuiComponent::input(config, input); @@ -228,44 +169,65 @@ void RatingComponent::applyTheme(const std::shared_ptr& theme, if (!elem) return; - // Make sure the size is not unreasonably large (which may be caused by a mistake in - // the theme configuration). - mSize.x = glm::clamp(mSize.x, 0.0f, mRenderer->getScreenWidth() / 2.0f); - mSize.y = glm::clamp(mSize.y, 0.0f, mRenderer->getScreenHeight() / 2.0f); + GuiComponent::applyTheme(theme, view, element, properties ^ ThemeFlags::SIZE); - if (mSize.y == 0.0f) - mSize.y = mSize.x / NUM_RATING_STARS; - else if (mSize.x == 0.0f) - mSize.x = mSize.y * NUM_RATING_STARS; + glm::vec2 scale {getParent() ? + getParent()->getSize() : + glm::vec2(Renderer::getScreenWidth(), Renderer::getScreenHeight())}; - const size_t sizeY {static_cast(mSize.y)}; - - bool imgChanged {false}; - if (properties & PATH && elem->has("filledPath")) { - mFilledTexture = TextureResource::get(elem->get("filledPath"), true, false, - true, false, false, sizeY, sizeY); - imgChanged = true; + if (elem->has("size")) { + glm::vec2 ratingSize {elem->get("size")}; + if (ratingSize == glm::vec2 {0.0f, 0.0f}) { + LOG(LogWarning) << "RatingComponent: Invalid theme configuration, property " + "for element \"" + << element.substr(7) << "\" is set to zero"; + ratingSize.y = 0.01; + } + if (ratingSize.x > 0.0f) + ratingSize.x = glm::clamp(ratingSize.x, 0.01f, 1.0f); + if (ratingSize.y > 0.0f) + ratingSize.y = glm::clamp(ratingSize.y, 0.01f, 0.5f); + mSize = ratingSize * scale; + if (mSize.y == 0.0f) + mSize.y = mSize.x / NUM_RATING_STARS; + else + mSize.x = mSize.y * NUM_RATING_STARS; } + + mIconFilled.setTileSize(mSize.y, mSize.y); + mIconFilled.setResize(glm::vec2 {mSize}, false); + + if (properties & PATH && elem->has("filledPath")) { + mIconFilled.setDynamic(true); + mIconFilled.setImage(std::string(elem->get("filledPath")), true); + mIconFilled.getTexture()->setSize(mSize.y, mSize.y); + if (!mIconFilled.getTexture()->getScalable()) + mIconFilled.onSizeChanged(); + } + else { + mIconFilled.setImage(std::string(":/graphics/star_filled.svg"), true); + } + + mIconUnfilled.setTileSize(mSize.y, mSize.y); + mIconUnfilled.setResize(glm::vec2 {mSize}, false); + if (properties & PATH && elem->has("unfilledPath")) { - mUnfilledTexture = TextureResource::get(elem->get("unfilledPath"), true, false, - true, false, false, sizeY, sizeY); - imgChanged = true; + mIconUnfilled.setDynamic(true); + mIconUnfilled.setImage(std::string(elem->get("unfilledPath")), true); + mIconUnfilled.getTexture()->setSize(mSize.y, mSize.y); + if (!mIconUnfilled.getTexture()->getScalable()) + mIconUnfilled.onSizeChanged(); + } + else { + mIconUnfilled.setImage(std::string(":/graphics/star_unfilled.svg"), true); } if (properties & COLOR) { - if (elem->has("color")) - setColorShift(elem->get("color")); - - if (elem->has("unfilledColor")) - mUnfilledColor = elem->get("unfilledColor"); - else - mUnfilledColor = mColorShift; + if (elem->has("color")) { + mIconFilled.setColorShift(elem->get("color")); + mIconUnfilled.setColorShift(elem->get("color")); + } } - - GuiComponent::applyTheme(theme, view, element, properties); - - if (imgChanged) - onSizeChanged(); } std::vector RatingComponent::getHelpPrompts() diff --git a/es-core/src/components/RatingComponent.h b/es-core/src/components/RatingComponent.h index d7b5b2bf9..b7b5071f3 100644 --- a/es-core/src/components/RatingComponent.h +++ b/es-core/src/components/RatingComponent.h @@ -11,11 +11,12 @@ #define ES_APP_COMPONENTS_RATING_COMPONENT_H #include "GuiComponent.h" +#include "components/ImageComponent.h" #include "renderers/Renderer.h" class TextureResource; -#define NUM_RATING_STARS 5 +#define NUM_RATING_STARS 5.0f class RatingComponent : public GuiComponent { @@ -32,14 +33,8 @@ public: void render(const glm::mat4& parentTrans) override; void onSizeChanged() override; - - void setOpacity(float opacity) override; void setDimming(float dimming) override; - // Multiply all pixels in the image by this color when rendering. - void setColorShift(unsigned int color) override; - unsigned int getColorShift() const override { return mColorShift; } - void setOriginalColor(unsigned int color) override { mColorOriginalValue = color; } void setChangedColor(unsigned int color) override { mColorChangedValue = color; } @@ -51,23 +46,17 @@ public: std::vector getHelpPrompts() override; private: - void updateVertices(); - void updateColors(); - Renderer* mRenderer; + ImageComponent mIconFilled; + ImageComponent mIconUnfilled; + float mValue; int mOriginalValue; + unsigned int mColorOriginalValue; unsigned int mColorChangedValue; - - Renderer::Vertex mVertices[8]; - unsigned int mColorShift; unsigned int mColorShiftEnd; - unsigned int mUnfilledColor; - - std::shared_ptr mFilledTexture; - std::shared_ptr mUnfilledTexture; bool mColorizeChanges; }; diff --git a/es-core/src/resources/TextureData.cpp b/es-core/src/resources/TextureData.cpp index fbe240c44..b664c5609 100644 --- a/es-core/src/resources/TextureData.cpp +++ b/es-core/src/resources/TextureData.cpp @@ -30,6 +30,8 @@ TextureData::TextureData(bool tile) , mDataRGBA {} , mWidth {0} , mHeight {0} + , mTileWidth {0.0f} + , mTileHeight {0.0f} , mSourceWidth {0.0f} , mSourceHeight {0.0f} , mScalable {false} @@ -72,8 +74,14 @@ bool TextureData::initSVGFromMemory(const std::string& fileData) bool rasterize {true}; if (mTile) { - mSourceWidth = svgImage->width; - mSourceHeight = svgImage->height; + if (mTileWidth == 0.0f && mTileHeight == 0.0f) { + mSourceWidth = svgImage->width; + mSourceHeight = svgImage->height; + } + else { + mSourceWidth = static_cast(mTileWidth); + mSourceHeight = static_cast(mTileHeight); + } } // If there is no image size defined yet, then don't rasterize unless mForceRasterization has diff --git a/es-core/src/resources/TextureData.h b/es-core/src/resources/TextureData.h index 6a58d0aa9..b2023c796 100644 --- a/es-core/src/resources/TextureData.h +++ b/es-core/src/resources/TextureData.h @@ -57,6 +57,11 @@ public: float sourceWidth(); float sourceHeight(); void setSourceSize(float width, float height); + void setTileSize(float tileWidth, float tileHeight) + { + mTileWidth = tileWidth; + mTileHeight = tileHeight; + } glm::vec2 getSize() { return glm::vec2 {static_cast(mWidth), static_cast(mHeight)}; } // Whether to use linear filtering when magnifying the texture. @@ -82,6 +87,8 @@ private: std::vector mDataRGBA; std::atomic mWidth; std::atomic mHeight; + std::atomic mTileWidth; + std::atomic mTileHeight; std::atomic mSourceWidth; std::atomic mSourceHeight; std::atomic mScalable; diff --git a/es-core/src/resources/TextureResource.cpp b/es-core/src/resources/TextureResource.cpp index be70a3c80..8e904fd77 100644 --- a/es-core/src/resources/TextureResource.cpp +++ b/es-core/src/resources/TextureResource.cpp @@ -14,8 +14,14 @@ #define DEBUG_RASTER_CACHING false #define DEBUG_SVG_CACHING false -TextureResource::TextureResource( - const std::string& path, bool tile, bool dynamic, bool linearMagnify, bool forceRasterization) +TextureResource::TextureResource(const std::string& path, + float tileWidth, + float tileHeight, + bool tile, + bool dynamic, + bool linearMagnify, + bool scalable, + bool forceRasterization) : mTextureData {nullptr} , mForceLoad {false} { @@ -27,16 +33,17 @@ TextureResource::TextureResource( if (dynamic) { data = sTextureDataManager.add(this, tile); data->initFromPath(path); + data->setTileSize(tileWidth, tileHeight); data->setLinearMagnify(linearMagnify); data->setForceRasterization(forceRasterization); // Force the texture manager to load it using a blocking load. sTextureDataManager.load(data, true); } else { - mTextureData = std::shared_ptr(new TextureData(tile)); data = mTextureData; data->initFromPath(path); + data->setTileSize(tileWidth, tileHeight); data->setLinearMagnify(linearMagnify); data->setForceRasterization(forceRasterization); // Load it so we can read the width/height. @@ -151,12 +158,14 @@ std::shared_ptr TextureResource::get(const std::string& path, bool linearMagnify, bool forceRasterization, size_t width, - size_t height) + size_t height, + float tileWidth, + float tileHeight) { const std::string canonicalPath {Utils::FileSystem::getCanonicalPath(path)}; if (canonicalPath.empty()) { - std::shared_ptr tex( - new TextureResource("", tile, false, linearMagnify, forceRasterization)); + std::shared_ptr tex(new TextureResource( + "", tileWidth, tileHeight, tile, false, linearMagnify, false, forceRasterization)); // Make sure we get properly deinitialized even though we do nothing on reinitialization. ResourceManager::getInstance().addReloadable(tex); return tex; @@ -202,7 +211,8 @@ 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), tile, dynamic, linearMagnify, forceRasterization))}; + new TextureResource(std::get<0>(key), tileWidth, tileHeight, tile, dynamic, linearMagnify, + isScalable, forceRasterization))}; 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 7ee219f1e..4f5d70ec8 100644 --- a/es-core/src/resources/TextureResource.h +++ b/es-core/src/resources/TextureResource.h @@ -33,7 +33,9 @@ public: bool linearMagnify = false, bool forceRasterization = false, size_t width = 0, - size_t height = 0); + size_t height = 0, + float tileWidth = 0.0f, + float tileHeight = 0.0f); void initFromPixels(const unsigned char* dataRGBA, size_t width, size_t height); virtual void initFromMemory(const char* data, size_t length); static void manualUnload(const std::string& path, bool tile); @@ -63,6 +65,11 @@ public: virtual ~TextureResource(); bool isTiled() const; + void setSize(float width, float height) + { + mSize.x = static_cast(std::round(width)); + mSize.y = static_cast(std::round(height)); + } const glm::ivec2 getSize() const { return mSize; } bool bind(); @@ -74,9 +81,12 @@ public: protected: TextureResource(const std::string& path, + float tileWidth, + float tileHeight, bool tile, bool dynamic, bool linearMagnify, + bool scalable, bool forceRasterization); virtual void unload(ResourceManager& rm); virtual void reload(ResourceManager& rm);