mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-22 06:05:38 +00:00
Added support for caching SVG images.
This commit is contained in:
parent
ebb099de5a
commit
5dae37f558
|
@ -313,7 +313,7 @@ void BadgeComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
ImageComponent badgeImage {false, false};
|
||||
badgeImage.setImage(mBadgeIcons[slot]);
|
||||
item.baseImage = badgeImage;
|
||||
item.overlayImage = ImageComponent {};
|
||||
item.overlayImage = ImageComponent {false, false};
|
||||
|
||||
if (slot == "folder") {
|
||||
if (elem->has("customFolderLinkIcon"))
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
ImageComponent baseImage;
|
||||
|
||||
// Optional overlay image that can be sized and positioned relative to the base image.
|
||||
ImageComponent overlayImage;
|
||||
ImageComponent overlayImage {false, false};
|
||||
glm::vec2 overlayPosition {0.5f, 0.5f};
|
||||
float overlaySize {0.5f};
|
||||
|
||||
|
|
|
@ -52,13 +52,13 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
|
|||
updateColors();
|
||||
}
|
||||
|
||||
void ImageComponent::resize()
|
||||
void ImageComponent::resize(bool rasterize)
|
||||
{
|
||||
if (!mTexture)
|
||||
return;
|
||||
|
||||
const glm::vec2 textureSize {mTexture->getSourceImageSize()};
|
||||
if (textureSize == glm::vec2 {})
|
||||
if (textureSize == glm::vec2 {0.0f, 0.0f})
|
||||
return;
|
||||
|
||||
if (mTexture->isTiled()) {
|
||||
|
@ -95,14 +95,14 @@ void ImageComponent::resize()
|
|||
mSize.x *= resizeScale.x;
|
||||
mSize.y *= resizeScale.x;
|
||||
|
||||
float cropPercent = (mSize.y - mTargetSize.y) / (mSize.y * 2.0f);
|
||||
float cropPercent {(mSize.y - mTargetSize.y) / (mSize.y * 2.0f)};
|
||||
crop(0.0f, cropPercent, 0.0f, cropPercent);
|
||||
}
|
||||
else {
|
||||
mSize.x *= resizeScale.y;
|
||||
mSize.y *= resizeScale.y;
|
||||
|
||||
float cropPercent = (mSize.x - mTargetSize.x) / (mSize.x * 2.0f);
|
||||
float cropPercent {(mSize.x - mTargetSize.x) / (mSize.x * 2.0f)};
|
||||
crop(cropPercent, 0.0f, cropPercent, 0.0f);
|
||||
}
|
||||
mSize.y = std::max(mSize.y, mTargetSize.y);
|
||||
|
@ -111,7 +111,7 @@ void ImageComponent::resize()
|
|||
else {
|
||||
// If both components are set, we just stretch.
|
||||
// If no components are set, we don't resize at all.
|
||||
mSize = mTargetSize == glm::vec2 {} ? textureSize : mTargetSize;
|
||||
mSize = mTargetSize == glm::vec2 {0.0f, 0.0f} ? textureSize : mTargetSize;
|
||||
|
||||
// If only one component is set, we resize in a way that maintains aspect ratio.
|
||||
if (!mTargetSize.x && mTargetSize.y) {
|
||||
|
@ -130,9 +130,10 @@ void ImageComponent::resize()
|
|||
mSize.x = glm::clamp(mSize.x, 1.0f, mRenderer->getScreenWidth() * 2.0f);
|
||||
mSize.y = glm::clamp(mSize.y, 1.0f, mRenderer->getScreenHeight() * 2.0f);
|
||||
|
||||
mTexture->rasterizeAt(mSize.x, mSize.y);
|
||||
|
||||
onSizeChanged();
|
||||
if (rasterize) {
|
||||
mTexture->rasterizeAt(mSize.x, mSize.y);
|
||||
onSizeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ImageComponent::setImage(const std::string& path, bool tile)
|
||||
|
@ -143,18 +144,40 @@ void ImageComponent::setImage(const std::string& path, bool tile)
|
|||
mDynamic = false;
|
||||
}
|
||||
|
||||
const bool isScalable {path != "" ? Utils::String::toLower(path.substr(
|
||||
path.size() - 4, std::string::npos)) == ".svg" :
|
||||
false};
|
||||
|
||||
// Create an initial blank texture if needed.
|
||||
if (path.empty() || !ResourceManager::getInstance().fileExists(path)) {
|
||||
if (mDefaultPath.empty() || !ResourceManager::getInstance().fileExists(mDefaultPath))
|
||||
mTexture.reset();
|
||||
else
|
||||
mTexture = TextureResource::get(mDefaultPath, tile, mForceLoad, mDynamic,
|
||||
mLinearInterpolation);
|
||||
resize(true);
|
||||
}
|
||||
else {
|
||||
// For raster images we just load and resize but for SVG images we first need to resize
|
||||
// without rasterizing in order to calculate the correct image size. Then we delete and
|
||||
// reload the texture at the requested size in order to add a valid cache entry. Finally
|
||||
// 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);
|
||||
}
|
||||
|
||||
resize();
|
||||
if (isScalable) {
|
||||
resize(false);
|
||||
mTexture.reset();
|
||||
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
||||
false, mSize.x, mSize.y);
|
||||
mTexture->rasterizeAt(mSize.x, mSize.y);
|
||||
onSizeChanged();
|
||||
}
|
||||
else {
|
||||
resize(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImageComponent::setImage(const char* data, size_t length, bool tile)
|
||||
|
@ -190,14 +213,6 @@ void ImageComponent::setMaxSize(const float width, const float height)
|
|||
resize();
|
||||
}
|
||||
|
||||
void ImageComponent::setMinSize(const float width, const float height)
|
||||
{
|
||||
mTargetSize = glm::vec2 {width, height};
|
||||
mTargetIsMax = false;
|
||||
mTargetIsMin = true;
|
||||
resize();
|
||||
}
|
||||
|
||||
void ImageComponent::cropLeft(const float percent)
|
||||
{
|
||||
assert(percent >= 0.0f && percent <= 1.0f);
|
||||
|
@ -238,10 +253,10 @@ void ImageComponent::uncrop()
|
|||
|
||||
void ImageComponent::cropTransparentPadding(const float maxSizeX, const float maxSizeY)
|
||||
{
|
||||
if (mSize == glm::vec2 {})
|
||||
if (mSize == glm::vec2 {0.0f, 0.0f})
|
||||
return;
|
||||
|
||||
std::vector<unsigned char> imageRGBA = mTexture.get()->getRawRGBAData();
|
||||
std::vector<unsigned char> imageRGBA {mTexture.get()->getRawRGBAData()};
|
||||
|
||||
if (imageRGBA.size() == 0)
|
||||
return;
|
||||
|
@ -273,7 +288,7 @@ void ImageComponent::cropTransparentPadding(const float maxSizeX, const float ma
|
|||
mSize.x -= mSize.x * (cropLeft + cropRight);
|
||||
mSize.y -= mSize.y * (cropTop + cropBottom);
|
||||
|
||||
float scaleFactor = originalSize.y / mSize.y;
|
||||
float scaleFactor {originalSize.y / mSize.y};
|
||||
|
||||
if (scaleFactor * mSize.x < maxSizeX)
|
||||
scaleFactor = maxSizeX / mSize.x;
|
||||
|
@ -347,7 +362,7 @@ void ImageComponent::updateVertices()
|
|||
|
||||
// We go through this mess to make sure everything is properly rounded.
|
||||
// If we just round vertices at the end, edge cases occur near sizes of 0.5.
|
||||
const glm::vec2 topLeft {};
|
||||
const glm::vec2 topLeft {0.0f, 0.0f};
|
||||
const glm::vec2 bottomRight {mSize};
|
||||
const float px {mTexture->isTiled() ? mSize.x / getTextureSize().x : 1.0f};
|
||||
const float py {mTexture->isTiled() ? mSize.y / getTextureSize().y : 1.0f};
|
||||
|
@ -492,7 +507,7 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
(properties ^ ThemeFlags::SIZE) |
|
||||
((properties & (ThemeFlags::SIZE | POSITION)) ? ORIGIN : 0));
|
||||
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "image");
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "image")};
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
|
@ -543,7 +558,7 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
setDefaultImage(elem->get<std::string>("default"));
|
||||
|
||||
if (properties & PATH && elem->has("path")) {
|
||||
bool tile = (elem->has("tile") && elem->get<bool>("tile"));
|
||||
bool tile {elem->has("tile") && elem->get<bool>("tile")};
|
||||
setImage(elem->get<std::string>("path"), tile);
|
||||
}
|
||||
|
||||
|
|
|
@ -46,9 +46,6 @@ public:
|
|||
void setMaxSize(const float width, const float height);
|
||||
void setMaxSize(const glm::vec2& size) { setMaxSize(size.x, size.y); }
|
||||
|
||||
void setMinSize(const float width, const float height);
|
||||
void setMinSize(const glm::vec2& size) { setMinSize(size.x, size.y); }
|
||||
|
||||
glm::vec2 getRotationSize() const override { return mRotateByTargetSize ? mTargetSize : mSize; }
|
||||
|
||||
// Applied AFTER image positioning and sizing.
|
||||
|
@ -113,8 +110,8 @@ private:
|
|||
|
||||
// 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.
|
||||
void resize();
|
||||
// initiates the SVG rasterization unless explicitly told not to.
|
||||
void resize(bool rasterize = true);
|
||||
|
||||
Renderer::Vertex mVertices[4];
|
||||
|
||||
|
|
|
@ -51,7 +51,7 @@ void NinePatchComponent::buildVertices()
|
|||
if (mVertices != nullptr)
|
||||
delete[] mVertices;
|
||||
|
||||
glm::vec2 relCornerSize {};
|
||||
glm::vec2 relCornerSize {0.0f, 0.0f};
|
||||
|
||||
// Don't scale the rasterized version of the frame as it would look bad.
|
||||
if (mPath.substr(mPath.size() - 4, std::string::npos) == ".png") {
|
||||
|
@ -65,8 +65,9 @@ void NinePatchComponent::buildVertices()
|
|||
(mSharpCorners == true ? 0.0568f : 0.09f) / 2.0f));
|
||||
}
|
||||
|
||||
mTexture = TextureResource::get(mPath, false, false, false);
|
||||
glm::vec2 texSize = relCornerSize * 3.0f;
|
||||
glm::vec2 texSize {relCornerSize * 3.0f};
|
||||
mTexture = TextureResource::get(mPath, false, false, false, false, false,
|
||||
static_cast<size_t>(texSize.x), static_cast<size_t>(texSize.y));
|
||||
|
||||
mTexture->rasterizeAt(texSize.x, texSize.y);
|
||||
|
||||
|
@ -86,11 +87,11 @@ void NinePatchComponent::buildVertices()
|
|||
// The "1 +" in posY and "-" in sizeY is to deal with texture coordinates having a bottom
|
||||
// left corner origin vs. verticies having a top left origin.
|
||||
// clang-format off
|
||||
const float texSizeX[3]{relCornerSize.x / texSize.x, (texSize.x - relCornerSize.x * 2.0f) / texSize.x, relCornerSize.x / texSize.x};
|
||||
const float texSizeY[3]{-relCornerSize.y / texSize.y, -(texSize.y - relCornerSize.y * 2.0f) / texSize.y, -relCornerSize.y / texSize.y};
|
||||
const float texSizeX[3] {relCornerSize.x / texSize.x, (texSize.x - relCornerSize.x * 2.0f) / texSize.x, relCornerSize.x / texSize.x};
|
||||
const float texSizeY[3] {-relCornerSize.y / texSize.y, -(texSize.y - relCornerSize.y * 2.0f) / texSize.y, -relCornerSize.y / texSize.y};
|
||||
|
||||
const float texPosX[3]{0.0f, texSizeX[0], texSizeX[0] + texSizeX[1]};
|
||||
const float texPosY[3]{1.0f, 1.0f + texSizeY[0], 1.0f + texSizeY[0] + texSizeY[1]};
|
||||
const float texPosX[3] {0.0f, texSizeX[0], texSizeX[0] + texSizeX[1]};
|
||||
const float texPosY[3] {1.0f, 1.0f + texSizeY[0], 1.0f + texSizeY[0] + texSizeY[1]};
|
||||
// clang-format on
|
||||
|
||||
int v = 0;
|
||||
|
@ -178,7 +179,7 @@ void NinePatchComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
GuiComponent::applyTheme(theme, view, element, properties);
|
||||
|
||||
using namespace ThemeFlags;
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "ninepatch");
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "ninepatch")};
|
||||
|
||||
if (!elem)
|
||||
return;
|
||||
|
|
|
@ -223,17 +223,30 @@ void RatingComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
unsigned int properties)
|
||||
{
|
||||
using namespace ThemeFlags;
|
||||
const ThemeData::ThemeElement* elem = theme->getElement(view, element, "rating");
|
||||
const ThemeData::ThemeElement* elem {theme->getElement(view, element, "rating")};
|
||||
|
||||
if (!elem)
|
||||
return;
|
||||
|
||||
bool imgChanged = false;
|
||||
// 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);
|
||||
|
||||
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;
|
||||
|
||||
bool imgChanged {false};
|
||||
if (properties & PATH && elem->has("filledPath")) {
|
||||
mFilledTexture = TextureResource::get(elem->get<std::string>("filledPath"), true);
|
||||
mFilledTexture = TextureResource::get(elem->get<std::string>("filledPath"), true, false,
|
||||
true, false, false, mSize.y, mSize.y);
|
||||
imgChanged = true;
|
||||
}
|
||||
if (properties & PATH && elem->has("unfilledPath")) {
|
||||
mUnfilledTexture = TextureResource::get(elem->get<std::string>("unfilledPath"), true);
|
||||
mUnfilledTexture = TextureResource::get(elem->get<std::string>("unfilledPath"), true, false,
|
||||
true, false, false, mSize.y, mSize.y);
|
||||
imgChanged = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -223,8 +223,8 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
ResourceManager::getInstance().fileExists(entry.data.itemPath)) {
|
||||
auto item = std::make_shared<ImageComponent>(false, dynamic);
|
||||
item->setLinearInterpolation(mLinearInterpolation);
|
||||
item->setImage(entry.data.itemPath);
|
||||
item->setMaxSize(mItemSize * mItemScale);
|
||||
item->setImage(entry.data.itemPath);
|
||||
item->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||
item->setRotateByTargetSize(true);
|
||||
entry.data.item = item;
|
||||
|
@ -233,8 +233,8 @@ void CarouselComponent<T>::addEntry(Entry& entry, const std::shared_ptr<ThemeDat
|
|||
ResourceManager::getInstance().fileExists(entry.data.defaultItemPath)) {
|
||||
auto defaultItem = std::make_shared<ImageComponent>(false, dynamic);
|
||||
defaultItem->setLinearInterpolation(mLinearInterpolation);
|
||||
defaultItem->setImage(entry.data.defaultItemPath);
|
||||
defaultItem->setMaxSize(mItemSize * mItemScale);
|
||||
defaultItem->setImage(entry.data.defaultItemPath);
|
||||
defaultItem->applyTheme(theme, "system", "", ThemeFlags::ALL);
|
||||
defaultItem->setRotateByTargetSize(true);
|
||||
entry.data.item = defaultItem;
|
||||
|
|
|
@ -36,7 +36,7 @@ TextureDataManager::~TextureDataManager()
|
|||
std::shared_ptr<TextureData> TextureDataManager::add(const TextureResource* key, bool tiled)
|
||||
{
|
||||
remove(key);
|
||||
std::shared_ptr<TextureData> data = std::make_shared<TextureData>(tiled);
|
||||
std::shared_ptr<TextureData> data {std::make_shared<TextureData>(tiled)};
|
||||
mTextures.push_front(data);
|
||||
mTextureLookup[key] = mTextures.cbegin();
|
||||
return data;
|
||||
|
@ -114,8 +114,8 @@ void TextureDataManager::load(std::shared_ptr<TextureData> tex, bool block)
|
|||
if (tex->isLoaded())
|
||||
return;
|
||||
// Not loaded. Make sure there is room.
|
||||
size_t size = TextureResource::getTotalMemUsage();
|
||||
size_t settingVRAM = static_cast<size_t>(Settings::getInstance()->getInt("MaxVRAM"));
|
||||
size_t size {TextureResource::getTotalMemUsage()};
|
||||
size_t settingVRAM {static_cast<size_t>(Settings::getInstance()->getInt("MaxVRAM"))};
|
||||
|
||||
if (settingVRAM < 80) {
|
||||
LOG(LogWarning) << "MaxVRAM is too low at " << settingVRAM
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// EmulationStation Desktop Edition
|
||||
// TextureResource.cpp
|
||||
//
|
||||
// Handles OpenGL textures.
|
||||
// Handles textures including loading, unloading and cache management.
|
||||
//
|
||||
|
||||
#include "resources/TextureResource.h"
|
||||
|
@ -11,6 +11,9 @@
|
|||
#include "utils/FileSystemUtil.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#define DEBUG_RASTER_CACHING false
|
||||
#define DEBUG_SVG_CACHING false
|
||||
|
||||
TextureResource::TextureResource(
|
||||
const std::string& path, bool tile, bool dynamic, bool linearMagnify, bool forceRasterization)
|
||||
: mTextureData {nullptr}
|
||||
|
@ -30,6 +33,7 @@ TextureResource::TextureResource(
|
|||
sTextureDataManager.load(data, true);
|
||||
}
|
||||
else {
|
||||
|
||||
mTextureData = std::shared_ptr<TextureData>(new TextureData(tile));
|
||||
data = mTextureData;
|
||||
data->initFromPath(path);
|
||||
|
@ -47,7 +51,7 @@ TextureResource::TextureResource(
|
|||
// loaded and unloaded. This would normally be a video texture, where the player
|
||||
// reserves a texture to later be used for the video rendering.
|
||||
mTextureData = std::shared_ptr<TextureData>(new TextureData(tile));
|
||||
mSize = glm::ivec2 {};
|
||||
mSize = glm::ivec2 {0.0f, 0.0f};
|
||||
}
|
||||
sAllTextures.insert(this);
|
||||
}
|
||||
|
@ -85,32 +89,25 @@ void TextureResource::initFromMemory(const char* data, size_t length)
|
|||
mSourceSize = glm::vec2 {mTextureData->sourceWidth(), mTextureData->sourceHeight()};
|
||||
}
|
||||
|
||||
void TextureResource::manualUnload(std::string path, bool tile)
|
||||
void TextureResource::manualUnload(const std::string& path, bool tile)
|
||||
{
|
||||
const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(path);
|
||||
const std::string canonicalPath {Utils::FileSystem::getCanonicalPath(path)};
|
||||
|
||||
// TODO: We always attempt to unload both the linear and nearest interpolation entries
|
||||
// which is a bit of a hack. Rewrite this to only unload the requested image.
|
||||
{
|
||||
TextureKeyType key {canonicalPath, tile, false};
|
||||
auto foundTexture = sTextureMap.find(key);
|
||||
|
||||
if (foundTexture != sTextureMap.cend())
|
||||
sTextureMap.erase(foundTexture);
|
||||
}
|
||||
|
||||
{
|
||||
TextureKeyType key {canonicalPath, tile, true};
|
||||
auto foundTexture = sTextureMap.find(key);
|
||||
|
||||
if (foundTexture != sTextureMap.cend())
|
||||
sTextureMap.erase(foundTexture);
|
||||
// TODO: We always attempt to unload both the linear and nearest interpolation entries.
|
||||
// Rewrite this to only unload the requested image.
|
||||
for (auto it = sTextureMap.begin(); it != sTextureMap.end();) {
|
||||
if (std::get<0>((*it).first) == canonicalPath && std::get<1>((*it).first) == tile) {
|
||||
sTextureMap.erase(it++);
|
||||
}
|
||||
else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<unsigned char> TextureResource::getRawRGBAData()
|
||||
{
|
||||
std::shared_ptr<TextureData> data = sTextureDataManager.get(this);
|
||||
std::shared_ptr<TextureData> data {sTextureDataManager.get(this)};
|
||||
|
||||
if (data)
|
||||
return data.get()->getRawRGBAData();
|
||||
|
@ -120,7 +117,7 @@ std::vector<unsigned char> TextureResource::getRawRGBAData()
|
|||
|
||||
std::string TextureResource::getTextureFilePath()
|
||||
{
|
||||
std::shared_ptr<TextureData> data = sTextureDataManager.get(this);
|
||||
std::shared_ptr<TextureData> data {sTextureDataManager.get(this)};
|
||||
|
||||
if (data)
|
||||
return data->getTextureFilePath();
|
||||
|
@ -132,7 +129,7 @@ bool TextureResource::isTiled() const
|
|||
{
|
||||
if (mTextureData != nullptr)
|
||||
return mTextureData->tiled();
|
||||
std::shared_ptr<TextureData> data = sTextureDataManager.get(this);
|
||||
std::shared_ptr<TextureData> data {sTextureDataManager.get(this)};
|
||||
return data->tiled();
|
||||
}
|
||||
|
||||
|
@ -152,9 +149,11 @@ std::shared_ptr<TextureResource> TextureResource::get(const std::string& path,
|
|||
bool forceLoad,
|
||||
bool dynamic,
|
||||
bool linearMagnify,
|
||||
bool forceRasterization)
|
||||
bool forceRasterization,
|
||||
size_t width,
|
||||
size_t height)
|
||||
{
|
||||
const std::string canonicalPath = Utils::FileSystem::getCanonicalPath(path);
|
||||
const std::string canonicalPath {Utils::FileSystem::getCanonicalPath(path)};
|
||||
if (canonicalPath.empty()) {
|
||||
std::shared_ptr<TextureResource> tex(
|
||||
new TextureResource("", tile, false, linearMagnify, forceRasterization));
|
||||
|
@ -163,25 +162,54 @@ std::shared_ptr<TextureResource> TextureResource::get(const std::string& path,
|
|||
return tex;
|
||||
}
|
||||
|
||||
TextureKeyType key {canonicalPath, tile, linearMagnify};
|
||||
const bool isScalable {Utils::String::toLower(canonicalPath.substr(
|
||||
canonicalPath.size() - 4, std::string::npos)) == ".svg"};
|
||||
|
||||
TextureKeyType key {canonicalPath, tile, linearMagnify, isScalable, width, height};
|
||||
auto foundTexture = sTextureMap.find(key);
|
||||
|
||||
std::string resolutionInfo;
|
||||
|
||||
if (DEBUG_SVG_CACHING && isScalable) {
|
||||
resolutionInfo.append(" (resolution ")
|
||||
.append(std::to_string(width))
|
||||
.append("x")
|
||||
.append(std::to_string(height))
|
||||
.append(")");
|
||||
}
|
||||
|
||||
if (foundTexture != sTextureMap.cend()) {
|
||||
if (!foundTexture->second.expired())
|
||||
if (!foundTexture->second.expired()) {
|
||||
if ((DEBUG_SVG_CACHING && isScalable) || (DEBUG_RASTER_CACHING && !isScalable)) {
|
||||
LOG(LogDebug) << "TextureResource::get(): Cache hit for "
|
||||
<< (isScalable ? "SVG" : "raster") << " image \"" << canonicalPath
|
||||
<< "\"" << resolutionInfo;
|
||||
}
|
||||
return foundTexture->second.lock();
|
||||
}
|
||||
else if ((DEBUG_SVG_CACHING && isScalable) || (DEBUG_RASTER_CACHING && !isScalable)) {
|
||||
LOG(LogDebug) << "TextureResource::get(): Cache expired for "
|
||||
<< (isScalable ? "SVG" : "raster") << " image \"" << canonicalPath << "\""
|
||||
<< resolutionInfo;
|
||||
}
|
||||
}
|
||||
else if ((DEBUG_SVG_CACHING && isScalable && width != 0.0f && height != 0.0f) ||
|
||||
(DEBUG_RASTER_CACHING && !isScalable)) {
|
||||
LOG(LogDebug) << "TextureResource::get(): Cache miss for "
|
||||
<< (isScalable ? "SVG" : "raster") << " image \"" << canonicalPath << "\""
|
||||
<< resolutionInfo;
|
||||
}
|
||||
|
||||
// Need to create it.
|
||||
std::shared_ptr<TextureResource> tex;
|
||||
tex = std::shared_ptr<TextureResource>(
|
||||
new TextureResource(std::get<0>(key), tile, dynamic, linearMagnify, forceRasterization));
|
||||
std::shared_ptr<TextureData> data = sTextureDataManager.get(tex.get());
|
||||
std::shared_ptr<TextureResource> tex {std::shared_ptr<TextureResource>(
|
||||
new TextureResource(std::get<0>(key), tile, dynamic, linearMagnify, forceRasterization))};
|
||||
std::shared_ptr<TextureData> data {sTextureDataManager.get(tex.get())};
|
||||
|
||||
// Is it an SVG?
|
||||
if (Utils::String::toLower(
|
||||
std::get<0>(key).substr(std::get<0>(key).size() - 4, std::string::npos)) != ".svg") {
|
||||
// Probably not. Add it to our map. We don't add SVGs because 2 SVGs might be
|
||||
// rasterized at different sizes.
|
||||
if (!isScalable || (isScalable && width != 0.0f && height != 0.0f)) {
|
||||
if ((DEBUG_SVG_CACHING && isScalable) || (DEBUG_RASTER_CACHING && !isScalable)) {
|
||||
LOG(LogDebug) << "TextureResource::get(): Adding " << (isScalable ? "SVG" : "raster")
|
||||
<< " image to cache: \"" << canonicalPath << "\"" << resolutionInfo;
|
||||
}
|
||||
sTextureMap[key] = std::weak_ptr<TextureResource>(tex);
|
||||
}
|
||||
|
||||
|
@ -200,7 +228,7 @@ std::shared_ptr<TextureResource> TextureResource::get(const std::string& path,
|
|||
void TextureResource::rasterizeAt(float width, float height)
|
||||
{
|
||||
if (mTextureData != nullptr) {
|
||||
glm::vec2 textureSize = mTextureData.get()->getSize();
|
||||
glm::vec2 textureSize {mTextureData.get()->getSize()};
|
||||
if (textureSize.x == width && textureSize.y == height &&
|
||||
!mTextureData.get()->getPendingRasterization())
|
||||
return;
|
||||
|
@ -221,7 +249,7 @@ void TextureResource::rasterizeAt(float width, float height)
|
|||
|
||||
size_t TextureResource::getTotalMemUsage()
|
||||
{
|
||||
size_t total = 0;
|
||||
size_t total {0};
|
||||
// Count up all textures that manage their own texture data.
|
||||
for (auto tex : sAllTextures) {
|
||||
if (tex->mTextureData != nullptr)
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
// EmulationStation Desktop Edition
|
||||
// TextureResource.h
|
||||
//
|
||||
// Handles OpenGL textures.
|
||||
// Handles textures including loading, unloading and cache management.
|
||||
//
|
||||
|
||||
#ifndef ES_CORE_RESOURCES_TEXTURE_RESOURCE_H
|
||||
|
@ -31,10 +31,12 @@ public:
|
|||
bool forceLoad = false,
|
||||
bool dynamic = true,
|
||||
bool linearMagnify = false,
|
||||
bool forceRasterization = false);
|
||||
bool forceRasterization = false,
|
||||
size_t width = 0,
|
||||
size_t height = 0);
|
||||
void initFromPixels(const unsigned char* dataRGBA, size_t width, size_t height);
|
||||
virtual void initFromMemory(const char* data, size_t length);
|
||||
static void manualUnload(std::string path, bool tile);
|
||||
static void manualUnload(const std::string& path, bool tile);
|
||||
static void manualUnloadAll() { sTextureMap.clear(); }
|
||||
|
||||
// Returns the raw pixel values.
|
||||
|
@ -91,7 +93,8 @@ private:
|
|||
glm::vec2 mSourceSize;
|
||||
bool mForceLoad;
|
||||
|
||||
using TextureKeyType = std::tuple<std::string, bool, bool>;
|
||||
// File path, tile, linear interpolation, scalable/SVG, width, height.
|
||||
using TextureKeyType = std::tuple<std::string, bool, bool, bool, size_t, size_t>;
|
||||
// Map of textures, used to prevent duplicate textures.
|
||||
static inline std::map<TextureKeyType, std::weak_ptr<TextureResource>> sTextureMap;
|
||||
// Set of all textures, used for memory management.
|
||||
|
|
Loading…
Reference in a new issue