mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2025-01-18 07:05:39 +00:00
Added a tileSize property to the image element so that the size of each individual image in tiled textures can be defined.
This commit is contained in:
parent
f4687e889e
commit
b4b709b589
|
@ -97,6 +97,7 @@ std::map<std::string, std::map<std::string, ThemeData::ElementPropertyType>>
|
||||||
{"metadataElement", BOOLEAN},
|
{"metadataElement", BOOLEAN},
|
||||||
{"gameselector", STRING},
|
{"gameselector", STRING},
|
||||||
{"tile", BOOLEAN},
|
{"tile", BOOLEAN},
|
||||||
|
{"tileSize", NORMALIZED_PAIR},
|
||||||
{"interpolation", STRING},
|
{"interpolation", STRING},
|
||||||
{"color", COLOR},
|
{"color", COLOR},
|
||||||
{"colorEnd", COLOR},
|
{"colorEnd", COLOR},
|
||||||
|
|
|
@ -21,7 +21,7 @@ glm::ivec2 ImageComponent::getTextureSize() const
|
||||||
if (mTexture)
|
if (mTexture)
|
||||||
return mTexture->getSize();
|
return mTexture->getSize();
|
||||||
else
|
else
|
||||||
return glm::ivec2 {};
|
return glm::ivec2 {0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec2 ImageComponent::getSize() const
|
glm::vec2 ImageComponent::getSize() const
|
||||||
|
@ -106,8 +106,8 @@ void ImageComponent::resize(bool rasterize)
|
||||||
|
|
||||||
// Make sure sub-pixel values are not rounded to zero and that the size is not unreasonably
|
// Make sure sub-pixel values are not rounded to zero and that the size is not unreasonably
|
||||||
// large (which may be caused by a mistake in the theme configuration).
|
// large (which may be caused by a mistake in the theme configuration).
|
||||||
mSize.x = glm::clamp(mSize.x, 1.0f, mRenderer->getScreenWidth() * 2.0f);
|
mSize.x = glm::clamp(mSize.x, 1.0f, mRenderer->getScreenWidth() * 3.0f);
|
||||||
mSize.y = glm::clamp(mSize.y, 1.0f, mRenderer->getScreenHeight() * 2.0f);
|
mSize.y = glm::clamp(mSize.y, 1.0f, mRenderer->getScreenHeight() * 3.0f);
|
||||||
|
|
||||||
if (rasterize) {
|
if (rasterize) {
|
||||||
mTexture->rasterizeAt(mSize.x, mSize.y);
|
mTexture->rasterizeAt(mSize.x, mSize.y);
|
||||||
|
@ -115,6 +115,21 @@ void ImageComponent::resize(bool rasterize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ImageComponent::setTileAxes()
|
||||||
|
{
|
||||||
|
if (mTileWidth == 0.0f && mTileHeight == 0.0f) {
|
||||||
|
mTileWidth = mTexture->getSize().x;
|
||||||
|
mTileHeight = mTexture->getSize().y;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const float ratio {mTexture->getSourceImageSize().x / mTexture->getSourceImageSize().y};
|
||||||
|
if (mTileWidth == 0.0f)
|
||||||
|
mTileWidth = std::round(mTileHeight * ratio);
|
||||||
|
else if (mTileHeight == 0.0f)
|
||||||
|
mTileHeight = std::round(mTileWidth / ratio);
|
||||||
|
}
|
||||||
|
|
||||||
void ImageComponent::setImage(const std::string& path, bool tile)
|
void ImageComponent::setImage(const std::string& path, bool tile)
|
||||||
{
|
{
|
||||||
// Always load bundled graphic resources statically, unless mForceLoad has been set.
|
// Always load bundled graphic resources statically, unless mForceLoad has been set.
|
||||||
|
@ -148,10 +163,11 @@ void ImageComponent::setImage(const std::string& path, bool tile)
|
||||||
// we perform the actual rasterization to have the cache entry updated with the proper
|
// 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
|
// 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).
|
// a call to setResize or setMaxSize (so the requested size is known upfront).
|
||||||
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
|
||||||
mMipmapping, 0, 0, 0.0f, 0.0f);
|
|
||||||
|
|
||||||
if (isScalable) {
|
if (isScalable) {
|
||||||
|
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
||||||
|
mMipmapping, 0, 0, 0.0f, 0.0f);
|
||||||
|
if (tile && (mTileWidth == 0.0f || mTileHeight == 0.0f))
|
||||||
|
setTileAxes();
|
||||||
resize(false);
|
resize(false);
|
||||||
mTexture.reset();
|
mTexture.reset();
|
||||||
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
||||||
|
@ -162,6 +178,10 @@ void ImageComponent::setImage(const std::string& path, bool tile)
|
||||||
onSizeChanged();
|
onSizeChanged();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
||||||
|
mMipmapping, 0, 0, mTileWidth, mTileHeight);
|
||||||
|
if (tile && (mTileWidth == 0.0f || mTileHeight == 0.0f))
|
||||||
|
setTileAxes();
|
||||||
resize(true);
|
resize(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,23 +400,35 @@ void ImageComponent::updateVertices()
|
||||||
if (!mTexture)
|
if (!mTexture)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 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 {0.0f, 0.0f};
|
const glm::vec2 topLeft {0.0f, 0.0f};
|
||||||
const glm::vec2 bottomRight {mSize};
|
const glm::vec2 bottomRight {mSize};
|
||||||
const float px {mTexture->isTiled() ? mSize.x / getTextureSize().x : 1.0f};
|
float px {1.0f};
|
||||||
const float py {mTexture->isTiled() ? mSize.y / getTextureSize().y : 1.0f};
|
float py {1.0f};
|
||||||
|
|
||||||
// clang-format off
|
if (mTileHeight == 0.0f) {
|
||||||
mVertices[0] = {{topLeft.x, topLeft.y }, {mTopLeftCrop.x, py - mTopLeftCrop.y }, 0};
|
// clang-format off
|
||||||
mVertices[1] = {{topLeft.x, bottomRight.y}, {mTopLeftCrop.x, 1.0f - mBottomRightCrop.y}, 0};
|
mVertices[0] = {{topLeft.x, topLeft.y }, {mTopLeftCrop.x, py - mTopLeftCrop.y }, 0};
|
||||||
mVertices[2] = {{bottomRight.x, topLeft.y }, {mBottomRightCrop.x * px, py - mTopLeftCrop.y }, 0};
|
mVertices[1] = {{topLeft.x, bottomRight.y}, {mTopLeftCrop.x, 1.0f - mBottomRightCrop.y}, 0};
|
||||||
mVertices[3] = {{bottomRight.x, bottomRight.y}, {mBottomRightCrop.x * px, 1.0f - mBottomRightCrop.y}, 0};
|
mVertices[2] = {{bottomRight.x, topLeft.y }, {mBottomRightCrop.x * px, py - mTopLeftCrop.y }, 0};
|
||||||
// clang-format on
|
mVertices[3] = {{bottomRight.x, bottomRight.y}, {mBottomRightCrop.x * px, 1.0f - mBottomRightCrop.y}, 0};
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Adjust the texture size as needed for tiled textures.
|
||||||
|
px = mSize.x / mTileWidth;
|
||||||
|
py = mSize.y / mTileHeight;
|
||||||
|
// clang-format off
|
||||||
|
mVertices[0] = {{topLeft.x, topLeft.y }, {mTopLeftCrop.x, py - mTopLeftCrop.y }, 0};
|
||||||
|
mVertices[1] = {{topLeft.x, bottomRight.y}, {mTopLeftCrop.x, 1.0f - mBottomRightCrop.y}, 0};
|
||||||
|
mVertices[2] = {{bottomRight.x, topLeft.y }, {mBottomRightCrop.x * px, py - mTopLeftCrop.y }, 0};
|
||||||
|
mVertices[3] = {{bottomRight.x, bottomRight.y}, {mBottomRightCrop.x * px, 1.0f - mBottomRightCrop.y}, 0};
|
||||||
|
// clang-format on
|
||||||
|
}
|
||||||
|
|
||||||
updateColors();
|
updateColors();
|
||||||
|
|
||||||
// Round vertices.
|
// We round the vertices already here in this component as we may otherwise end up with edge
|
||||||
|
// cases at sizes near 0.5.
|
||||||
for (int i = 0; i < 4; ++i)
|
for (int i = 0; i < 4; ++i)
|
||||||
mVertices[i].position = glm::round(mVertices[i].position);
|
mVertices[i].position = glm::round(mVertices[i].position);
|
||||||
|
|
||||||
|
@ -548,17 +580,17 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
imageSize = {0.001f, 0.001f};
|
imageSize = {0.001f, 0.001f};
|
||||||
}
|
}
|
||||||
if (imageSize.x > 0.0f)
|
if (imageSize.x > 0.0f)
|
||||||
imageSize.x = glm::clamp(imageSize.x, 0.001f, 2.0f);
|
imageSize.x = glm::clamp(imageSize.x, 0.001f, 3.0f);
|
||||||
if (imageSize.y > 0.0f)
|
if (imageSize.y > 0.0f)
|
||||||
imageSize.y = glm::clamp(imageSize.y, 0.001f, 2.0f);
|
imageSize.y = glm::clamp(imageSize.y, 0.001f, 3.0f);
|
||||||
setResize(imageSize * scale);
|
setResize(imageSize * scale);
|
||||||
if (imageSize.x != 0.0f && imageSize.y != 0.0f)
|
if (imageSize.x != 0.0f && imageSize.y != 0.0f)
|
||||||
noMax = true;
|
noMax = true;
|
||||||
}
|
}
|
||||||
else if (elem->has("maxSize")) {
|
else if (elem->has("maxSize")) {
|
||||||
glm::vec2 imageMaxSize {elem->get<glm::vec2>("maxSize")};
|
glm::vec2 imageMaxSize {elem->get<glm::vec2>("maxSize")};
|
||||||
imageMaxSize.x = glm::clamp(imageMaxSize.x, 0.001f, 2.0f);
|
imageMaxSize.x = glm::clamp(imageMaxSize.x, 0.001f, 3.0f);
|
||||||
imageMaxSize.y = glm::clamp(imageMaxSize.y, 0.001f, 2.0f);
|
imageMaxSize.y = glm::clamp(imageMaxSize.y, 0.001f, 3.0f);
|
||||||
setMaxSize(imageMaxSize * scale);
|
setMaxSize(imageMaxSize * scale);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -583,14 +615,33 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
||||||
setDefaultImage(elem->get<std::string>("default"));
|
setDefaultImage(elem->get<std::string>("default"));
|
||||||
|
|
||||||
if (properties & PATH && elem->has("path")) {
|
if (properties & PATH && elem->has("path")) {
|
||||||
const bool tile {elem->has("tile") && elem->get<bool>("tile")};
|
bool tile {elem->has("tile") && elem->get<bool>("tile")};
|
||||||
const std::string path {elem->get<std::string>("path")};
|
const std::string path {elem->get<std::string>("path")};
|
||||||
|
|
||||||
if (!theme->isLegacyTheme() && noMax && path.length() > 4 &&
|
if (!tile && !theme->isLegacyTheme() && noMax && path.length() > 4 &&
|
||||||
Utils::String::toLower(path.substr(path.size() - 4, std::string::npos)) == ".svg") {
|
Utils::String::toLower(path.substr(path.size() - 4, std::string::npos)) == ".svg") {
|
||||||
mScalableNonAspect = true;
|
mScalableNonAspect = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tile && elem->has("tileSize")) {
|
||||||
|
glm::vec2 tileSize {elem->get<glm::vec2>("tileSize")};
|
||||||
|
if (tileSize.x == 0.0f && tileSize.y == 0.0f) {
|
||||||
|
LOG(LogWarning)
|
||||||
|
<< "ImageComponent: Invalid theme configuration, property <tileSize> "
|
||||||
|
"for element \""
|
||||||
|
<< element.substr(6) << "\" is set to zero";
|
||||||
|
tile = false;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
tileSize.x = glm::clamp(tileSize.x, 0.0f, 1.0f);
|
||||||
|
tileSize.y = glm::clamp(tileSize.y, 0.0f, 1.0f);
|
||||||
|
mTileWidth = tileSize.x * scale.x;
|
||||||
|
mTileHeight = tileSize.y * scale.y;
|
||||||
|
if (mTileWidth != 0.0f && mTileHeight != 0.0f)
|
||||||
|
mScalableNonAspect = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
setImage(path, tile);
|
setImage(path, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -96,9 +96,8 @@ public:
|
||||||
void setMipmapping(bool state) { mMipmapping = state; }
|
void setMipmapping(bool state) { mMipmapping = state; }
|
||||||
|
|
||||||
// Returns the size of the current texture, or (0, 0) if none is loaded.
|
// Returns the size of the current texture, or (0, 0) if none is loaded.
|
||||||
// May be different than drawn size (use getSize() for that).
|
// This may be different than the rendered size so use getSize() for that.
|
||||||
glm::ivec2 getTextureSize() const;
|
glm::ivec2 getTextureSize() const;
|
||||||
|
|
||||||
glm::vec2 getSize() const override;
|
glm::vec2 getSize() const override;
|
||||||
|
|
||||||
bool hasImage() { return static_cast<bool>(mTexture); }
|
bool hasImage() { return static_cast<bool>(mTexture); }
|
||||||
|
@ -129,6 +128,8 @@ private:
|
||||||
// Used internally whenever the resizing parameters or texture change. This function also
|
// Used internally whenever the resizing parameters or texture change. This function also
|
||||||
// initiates the SVG rasterization unless explicitly told not to.
|
// initiates the SVG rasterization unless explicitly told not to.
|
||||||
void resize(bool rasterize = true);
|
void resize(bool rasterize = true);
|
||||||
|
// Set the axis values if it's a tiled image and either or both of the axes are set to zero.
|
||||||
|
void setTileAxes();
|
||||||
|
|
||||||
Renderer::Vertex mVertices[4];
|
Renderer::Vertex mVertices[4];
|
||||||
|
|
||||||
|
|
|
@ -79,7 +79,7 @@ public:
|
||||||
const bool getScalable() { return mScalable; }
|
const bool getScalable() { return mScalable; }
|
||||||
std::vector<unsigned char>& getRawRGBAData() { return mDataRGBA; }
|
std::vector<unsigned char>& getRawRGBAData() { return mDataRGBA; }
|
||||||
std::string getTextureFilePath() { return mPath; }
|
std::string getTextureFilePath() { return mPath; }
|
||||||
bool tiled() { return mTile; }
|
bool getTiled() { return mTile; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Renderer* mRenderer;
|
Renderer* mRenderer;
|
||||||
|
|
|
@ -136,9 +136,9 @@ std::string TextureResource::getTextureFilePath()
|
||||||
bool TextureResource::isTiled() const
|
bool TextureResource::isTiled() const
|
||||||
{
|
{
|
||||||
if (mTextureData != nullptr)
|
if (mTextureData != nullptr)
|
||||||
return mTextureData->tiled();
|
return mTextureData->getTiled();
|
||||||
std::shared_ptr<TextureData> data {sTextureDataManager.get(this)};
|
std::shared_ptr<TextureData> data {sTextureDataManager.get(this)};
|
||||||
return data->tiled();
|
return data->getTiled();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TextureResource::bind()
|
bool TextureResource::bind()
|
||||||
|
|
Loading…
Reference in a new issue