Added support for scaling SVG graphics files directly when loading them.

This commit is contained in:
Leon Styhre 2021-01-14 22:25:44 +01:00
parent 2995a0c7c5
commit 1148f941a9
5 changed files with 36 additions and 14 deletions

View file

@ -26,6 +26,7 @@ TextureData::TextureData(
: mTile(tile), : mTile(tile),
mTextureID(0), mTextureID(0),
mDataRGBA({}), mDataRGBA({}),
mScaleSVG(1.0f),
mScalable(false), mScalable(false),
mWidth(0), mWidth(0),
mHeight(0), mHeight(0),
@ -59,7 +60,7 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
NSVGimage* svgImage = nsvgParse(const_cast<char*>(fileData.c_str()), "px", DPI); NSVGimage* svgImage = nsvgParse(const_cast<char*>(fileData.c_str()), "px", DPI);
if (!svgImage) { if (!svgImage) {
LOG(LogError) << "Error parsing SVG image."; LOG(LogError) << "Couldn't parse SVG image";
return false; return false;
} }
@ -69,8 +70,9 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
mSourceWidth = svgImage->width; mSourceWidth = svgImage->width;
mSourceHeight = svgImage->height; mSourceHeight = svgImage->height;
} }
mWidth = static_cast<size_t>(std::round(mSourceWidth));
mHeight = static_cast<size_t>(std::round(mSourceHeight)); mWidth = static_cast<size_t>(std::round(mSourceWidth * mScaleSVG));
mHeight = static_cast<size_t>(std::round(mSourceHeight * mScaleSVG));
if (mWidth == 0) { if (mWidth == 0) {
// Auto scale width to keep aspect ratio. // Auto scale width to keep aspect ratio.

View file

@ -54,6 +54,9 @@ public:
float sourceHeight(); float sourceHeight();
void setSourceSize(float width, float height); void setSourceSize(float width, float height);
// Define a factor for scaling the SVG graphics when loading it (1.0f = no scaling).
void setScaleSVGDuringLoad(float scale) { mScaleSVG = scale; }
bool tiled() { return mTile; } bool tiled() { return mTile; }
private: private:
@ -66,6 +69,7 @@ private:
size_t mHeight; size_t mHeight;
float mSourceWidth; float mSourceWidth;
float mSourceHeight; float mSourceHeight;
float mScaleSVG;
bool mScalable; bool mScalable;
bool mReloadable; bool mReloadable;
}; };

View file

@ -17,7 +17,7 @@ TextureDataManager::TextureDataManager()
{ {
unsigned char data[5 * 5 * 4]; unsigned char data[5 * 5 * 4];
mBlank = std::shared_ptr<TextureData>(new TextureData(false)); mBlank = std::shared_ptr<TextureData>(new TextureData(false));
for (int i = 0; i < (5 * 5); ++i) { for (int i = 0; i < (5 * 5); i++) {
data[i*4] = (i % 2) * 255; data[i*4] = (i % 2) * 255;
data[i*4+1] = (i % 2) * 255; data[i*4+1] = (i % 2) * 255;
data[i*4+2] = (i % 2) * 255; data[i*4+2] = (i % 2) * 255;
@ -130,7 +130,7 @@ void TextureDataManager::load(std::shared_ptr<TextureData> tex, bool block)
size_t max_texture = settingVRAM * 1024 * 1024; size_t max_texture = settingVRAM * 1024 * 1024;
for (auto it = mTextures.crbegin(); it != mTextures.crend(); ++it) { for (auto it = mTextures.crbegin(); it != mTextures.crend(); it++) {
if (size < max_texture) if (size < max_texture)
break; break;
//size -= (*it)->getVRAMUsage(); //size -= (*it)->getVRAMUsage();

View file

@ -19,7 +19,8 @@ std::set<TextureResource*> TextureResource::sAllTextures;
TextureResource::TextureResource( TextureResource::TextureResource(
const std::string& path, const std::string& path,
bool tile, bool tile,
bool dynamic) bool dynamic,
float scaleSVG)
: mTextureData(nullptr), : mTextureData(nullptr),
mForceLoad(false) mForceLoad(false)
{ {
@ -31,6 +32,8 @@ TextureResource::TextureResource(
if (dynamic) { if (dynamic) {
data = sTextureDataManager.add(this, tile); data = sTextureDataManager.add(this, tile);
data->initFromPath(path); data->initFromPath(path);
if (scaleSVG != 1.0f)
data->setScaleSVGDuringLoad(scaleSVG);
// Force the texture manager to load it using a blocking load. // Force the texture manager to load it using a blocking load.
sTextureDataManager.load(data, true); sTextureDataManager.load(data, true);
} }
@ -38,6 +41,8 @@ TextureResource::TextureResource(
mTextureData = std::shared_ptr<TextureData>(new TextureData(tile)); mTextureData = std::shared_ptr<TextureData>(new TextureData(tile));
data = mTextureData; data = mTextureData;
data->initFromPath(path); data->initFromPath(path);
if (scaleSVG != 1.0f)
data->setScaleSVGDuringLoad(scaleSVG);
// Load it so we can read the width/height. // Load it so we can read the width/height.
data->load(); data->load();
} }
@ -124,14 +129,18 @@ bool TextureResource::bind()
} }
} }
std::shared_ptr<TextureResource> TextureResource::get(const std::string& path, bool tile, std::shared_ptr<TextureResource> TextureResource::get(
bool forceLoad, bool dynamic) const std::string& path,
bool tile,
bool forceLoad,
bool dynamic,
float scaleSVG)
{ {
std::shared_ptr<ResourceManager>& rm = ResourceManager::getInstance(); std::shared_ptr<ResourceManager>& rm = ResourceManager::getInstance();
const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(path); const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(path);
if (canonicalPath.empty()) { if (canonicalPath.empty()) {
std::shared_ptr<TextureResource> tex(new TextureResource("", tile, false)); std::shared_ptr<TextureResource> tex(new TextureResource("", tile, false, scaleSVG));
// Make sure we get properly deinitialized even though we do nothing on reinitialization. // Make sure we get properly deinitialized even though we do nothing on reinitialization.
rm->addReloadable(tex); rm->addReloadable(tex);
return tex; return tex;
@ -147,7 +156,7 @@ std::shared_ptr<TextureResource> TextureResource::get(const std::string& path, b
// Need to create it. // Need to create it.
std::shared_ptr<TextureResource> tex; std::shared_ptr<TextureResource> tex;
tex = std::shared_ptr<TextureResource>(new TextureResource(key.first, tile, dynamic)); tex = std::shared_ptr<TextureResource>(new TextureResource(key.first, tile, dynamic, scaleSVG));
std::shared_ptr<TextureData> data = sTextureDataManager.get(tex.get()); std::shared_ptr<TextureData> data = sTextureDataManager.get(tex.get());
// Is it an SVG? // Is it an SVG?

View file

@ -25,13 +25,20 @@ class TextureData;
class TextureResource : public IReloadable class TextureResource : public IReloadable
{ {
public: public:
static std::shared_ptr<TextureResource> get(const std::string& path, bool tile = false, static std::shared_ptr<TextureResource> get(
bool forceLoad = false, bool dynamic = true); const std::string& path,
bool tile = false,
bool forceLoad = false,
bool dynamic = true,
float scaleSVG = 1.0f);
void initFromPixels(const unsigned char* dataRGBA, size_t width, size_t height); void initFromPixels(const unsigned char* dataRGBA, size_t width, size_t height);
virtual void initFromMemory(const char* data, size_t length); virtual void initFromMemory(const char* data, size_t length);
static void manualUnload(std::string path, bool tile); static void manualUnload(std::string path, bool tile);
// For scalable source images in textures we want to set the resolution to rasterize at. // For SVG graphics this function effectively rescales the image to the defined size.
// It does unload and re-rasterize the texture though which may cause flickering in some
// situations. An alternative is to set a scaling factor directly when loading the texture
// using get(), by using the scaleSVG parameter.
void rasterizeAt(size_t width, size_t height); void rasterizeAt(size_t width, size_t height);
Vector2f getSourceImageSize() const; Vector2f getSourceImageSize() const;
@ -49,7 +56,7 @@ public:
static size_t getTotalTextureSize(); static size_t getTotalTextureSize();
protected: protected:
TextureResource(const std::string& path, bool tile, bool dynamic); TextureResource(const std::string& path, bool tile, bool dynamic, float scaleSVG);
virtual void unload(std::shared_ptr<ResourceManager>& rm); virtual void unload(std::shared_ptr<ResourceManager>& rm);
virtual void reload(std::shared_ptr<ResourceManager>& rm); virtual void reload(std::shared_ptr<ResourceManager>& rm);