mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-21 21:55:38 +00:00
Replaced the NanoSVG library with LunaSVG.
This commit is contained in:
parent
c35df18ad8
commit
bf5cce31c6
|
@ -380,6 +380,7 @@ endif()
|
|||
set(COMMON_INCLUDE_DIRS ${CURL_INCLUDE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/CImg
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/glm
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/lunasvg/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/nanosvg/src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/rapidjson/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/external/rlottie/inc
|
||||
|
@ -462,6 +463,7 @@ elseif(WIN32)
|
|||
${PROJECT_SOURCE_DIR}/glew32.lib
|
||||
${PROJECT_SOURCE_DIR}/libcurl-x64.lib
|
||||
${PROJECT_SOURCE_DIR}/freetype.lib
|
||||
${PROJECT_SOURCE_DIR}/lunasvg.lib
|
||||
${PROJECT_SOURCE_DIR}/pugixml.lib
|
||||
${PROJECT_SOURCE_DIR}/rlottie.lib
|
||||
${PROJECT_SOURCE_DIR}/SDL2main.lib
|
||||
|
@ -478,6 +480,7 @@ elseif(WIN32)
|
|||
${PROJECT_SOURCE_DIR}/glew32.dll
|
||||
${PROJECT_SOURCE_DIR}/libcurl-x64.dll
|
||||
${PROJECT_SOURCE_DIR}/libfreetype.dll
|
||||
${PROJECT_SOURCE_DIR}/liblunasvg.a
|
||||
${PROJECT_SOURCE_DIR}/libpugixml.dll
|
||||
${PROJECT_SOURCE_DIR}/libSDL2main.a
|
||||
${PROJECT_SOURCE_DIR}/librlottie.dll
|
||||
|
@ -527,8 +530,10 @@ else()
|
|||
${SDL2_LIBRARY})
|
||||
endif()
|
||||
|
||||
# Lottie animation library rlottie.
|
||||
if(NOT WIN32)
|
||||
# SVG rendering library LunaSVG.
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/liblunasvg.a)
|
||||
# Lottie animation library rlottie.
|
||||
set(COMMON_LIBRARIES ${COMMON_LIBRARIES} ${PROJECT_SOURCE_DIR}/librlottie.a)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -22,7 +22,6 @@ ImageComponent::ImageComponent(bool forceLoad, bool dynamic)
|
|||
, mFlipX {false}
|
||||
, mFlipY {false}
|
||||
, mTargetIsMax {false}
|
||||
, mScalableNonAspect {false}
|
||||
, mTileWidth {0.0f}
|
||||
, mTileHeight {0.0f}
|
||||
, mColorShift {0xFFFFFFFF}
|
||||
|
@ -88,7 +87,6 @@ void ImageComponent::setImage(const std::string& path, bool tile)
|
|||
mTexture = TextureResource::get(path, tile, mForceLoad, mDynamic, mLinearInterpolation,
|
||||
mMipmapping, static_cast<size_t>(mSize.x),
|
||||
static_cast<size_t>(mSize.y), mTileWidth, mTileHeight);
|
||||
mTexture->setScalableNonAspect(mScalableNonAspect);
|
||||
mTexture->rasterizeAt(mSize.x, mSize.y);
|
||||
onSizeChanged();
|
||||
}
|
||||
|
@ -404,8 +402,6 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
getParent()->getSize() :
|
||||
glm::vec2(Renderer::getScreenWidth(), Renderer::getScreenHeight())};
|
||||
|
||||
bool noMax {false};
|
||||
|
||||
if (properties & ThemeFlags::SIZE) {
|
||||
if (elem->has("size")) {
|
||||
glm::vec2 imageSize {elem->get<glm::vec2>("size")};
|
||||
|
@ -420,8 +416,6 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
if (imageSize.y > 0.0f)
|
||||
imageSize.y = glm::clamp(imageSize.y, 0.001f, 3.0f);
|
||||
setResize(imageSize * scale);
|
||||
if (imageSize.x != 0.0f && imageSize.y != 0.0f)
|
||||
noMax = true;
|
||||
}
|
||||
else if (elem->has("maxSize")) {
|
||||
glm::vec2 imageMaxSize {elem->get<glm::vec2>("maxSize")};
|
||||
|
@ -455,11 +449,6 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
if (properties & PATH && elem->has("path")) {
|
||||
const std::string path {elem->get<std::string>("path")};
|
||||
|
||||
if (!tile && !theme->isLegacyTheme() && noMax && path.length() > 4 &&
|
||||
Utils::String::toLower(path.substr(path.size() - 4, std::string::npos)) == ".svg") {
|
||||
mScalableNonAspect = true;
|
||||
}
|
||||
|
||||
if (tile && elem->has("tileSize")) {
|
||||
glm::vec2 tileSize {elem->get<glm::vec2>("tileSize")};
|
||||
if (tileSize.x == 0.0f && tileSize.y == 0.0f) {
|
||||
|
@ -474,8 +463,6 @@ void ImageComponent::applyTheme(const std::shared_ptr<ThemeData>& theme,
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -614,12 +601,8 @@ void ImageComponent::resize(bool rasterize)
|
|||
glm::vec2 resizeScale {mTargetSize.x / mSize.x, mTargetSize.y / mSize.y};
|
||||
|
||||
if (resizeScale.x < resizeScale.y) {
|
||||
// SVG rasterization is determined by height and rasterization is done in terms of
|
||||
// pixels. If rounding is off enough in the rasterization step (for images with
|
||||
// extreme aspect ratios), it can cause cutoff when the aspect ratio breaks.
|
||||
// So we always make sure to round accordingly to avoid such issues.
|
||||
mSize.x *= resizeScale.x;
|
||||
mSize.y = floorf(std::min(mSize.y * resizeScale.x, mTargetSize.y));
|
||||
mSize.y = std::min(mSize.y * resizeScale.x, mTargetSize.y);
|
||||
}
|
||||
else {
|
||||
// This will be mTargetSize.y(). We can't exceed it.
|
||||
|
|
|
@ -119,7 +119,6 @@ private:
|
|||
bool mFlipX;
|
||||
bool mFlipY;
|
||||
bool mTargetIsMax;
|
||||
bool mScalableNonAspect;
|
||||
|
||||
float mTileWidth;
|
||||
float mTileHeight;
|
||||
|
|
|
@ -6,9 +6,6 @@
|
|||
// Low-level texture data functions.
|
||||
//
|
||||
|
||||
#define NANOSVG_IMPLEMENTATION
|
||||
#define NANOSVGRAST_IMPLEMENTATION
|
||||
|
||||
#include "resources/TextureData.h"
|
||||
|
||||
#include "ImageIO.h"
|
||||
|
@ -16,13 +13,10 @@
|
|||
#include "resources/ResourceManager.h"
|
||||
#include "utils/StringUtil.h"
|
||||
|
||||
#include "nanosvg.h"
|
||||
#include "nanosvgrast.h"
|
||||
#include "lunasvg.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define DPI 96
|
||||
|
||||
TextureData::TextureData(bool tile)
|
||||
: mRenderer {Renderer::getInstance()}
|
||||
, mTile {tile}
|
||||
|
@ -34,10 +28,10 @@ TextureData::TextureData(bool tile)
|
|||
, mSourceWidth {0.0f}
|
||||
, mSourceHeight {0.0f}
|
||||
, mScalable {false}
|
||||
, mScalableNonAspect {false}
|
||||
, mHasRGBAData {false}
|
||||
, mPendingRasterization {false}
|
||||
, mMipmapping {false}
|
||||
, mInvalidSVGFile {false}
|
||||
, mLinearMagnify {false}
|
||||
{
|
||||
}
|
||||
|
@ -64,20 +58,23 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
|
|||
if (!mDataRGBA.empty() && !mPendingRasterization)
|
||||
return true;
|
||||
|
||||
NSVGimage* svgImage {nsvgParse(const_cast<char*>(fileData.c_str()), "px", DPI)};
|
||||
auto svgImage = lunasvg::Document::loadFromData(fileData);
|
||||
|
||||
if (!svgImage || svgImage->width == 0 || svgImage->height == 0) {
|
||||
LOG(LogError) << "Couldn't parse SVG image";
|
||||
if (svgImage == nullptr) {
|
||||
// LOG(LogError) << "Couldn't parse SVG image:" << mPath;
|
||||
mInvalidSVGFile = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
float svgWidth {static_cast<float>(svgImage->width())};
|
||||
float svgHeight {static_cast<float>(svgImage->height())};
|
||||
bool rasterize {true};
|
||||
|
||||
if (mTile) {
|
||||
if (mTileWidth == 0.0f && mTileHeight == 0.0f) {
|
||||
rasterize = false;
|
||||
mSourceWidth = svgImage->width;
|
||||
mSourceHeight = svgImage->height;
|
||||
mSourceWidth = svgWidth;
|
||||
mSourceHeight = svgHeight;
|
||||
}
|
||||
else {
|
||||
mSourceWidth = static_cast<float>(mTileWidth);
|
||||
|
@ -90,7 +87,7 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
|
|||
rasterize = false;
|
||||
// Set a small temporary size that maintains the image aspect ratio.
|
||||
mSourceWidth = 64.0f;
|
||||
mSourceHeight = 64.0f * (svgImage->height / svgImage->width);
|
||||
mSourceHeight = 64.0f * (svgHeight / svgWidth);
|
||||
}
|
||||
|
||||
mWidth = static_cast<int>(std::round(mSourceWidth));
|
||||
|
@ -98,38 +95,25 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
|
|||
|
||||
if (mWidth == 0) {
|
||||
// Auto scale width to keep aspect ratio.
|
||||
mWidth = static_cast<size_t>(
|
||||
std::round((static_cast<float>(mHeight) / svgImage->height) * svgImage->width));
|
||||
mWidth =
|
||||
static_cast<size_t>(std::round((static_cast<float>(mHeight) / svgHeight) * svgWidth));
|
||||
}
|
||||
else if (mHeight == 0) {
|
||||
// Auto scale height to keep aspect ratio.
|
||||
mHeight = static_cast<size_t>(
|
||||
std::round((static_cast<float>(mWidth) / svgImage->width) * svgImage->height));
|
||||
mHeight =
|
||||
static_cast<size_t>(std::round((static_cast<float>(mWidth) / svgWidth) * svgHeight));
|
||||
}
|
||||
|
||||
if (rasterize) {
|
||||
const float aspectW {svgImage->width / static_cast<float>(mWidth)};
|
||||
const float aspectH {svgImage->height / static_cast<float>(mHeight)};
|
||||
// For very short and wide images, make a slight scale adjustment to prevent pixels
|
||||
// to the right of the image from being cut off.
|
||||
if (svgWidth / svgHeight > 4.0f)
|
||||
svgImage->scale(0.998, 1.0);
|
||||
|
||||
// If the size property has been used to override the aspect ratio of the SVG image,
|
||||
// then we need to rasterize at a lower resolution and let the GPU scale the texture.
|
||||
// This is necessary as the rasterization always maintains the image aspect ratio.
|
||||
if (mScalableNonAspect && aspectW != aspectH)
|
||||
mWidth = static_cast<int>(std::round(svgImage->width / aspectH));
|
||||
|
||||
std::vector<unsigned char> tempVector;
|
||||
tempVector.reserve(mWidth * mHeight * 4);
|
||||
|
||||
NSVGrasterizer* rast {nsvgCreateRasterizer()};
|
||||
|
||||
nsvgRasterize(rast, svgImage, 0, 0, static_cast<float>(mHeight) / svgImage->height,
|
||||
tempVector.data(), mWidth, mHeight, mWidth * 4);
|
||||
|
||||
nsvgDeleteRasterizer(rast);
|
||||
|
||||
mDataRGBA.insert(mDataRGBA.begin(), std::make_move_iterator(tempVector.data()),
|
||||
std::make_move_iterator(tempVector.data() + (mWidth * mHeight * 4)));
|
||||
tempVector.erase(tempVector.begin(), tempVector.end());
|
||||
auto bitmap = svgImage->renderToBitmap(mWidth, mHeight);
|
||||
bitmap.convertToRGBA();
|
||||
mDataRGBA.insert(mDataRGBA.begin(), std::move(bitmap.data()),
|
||||
std::move(bitmap.data() + mWidth * mHeight * 4));
|
||||
|
||||
ImageIO::flipPixelsVert(mDataRGBA.data(), mWidth, mHeight);
|
||||
mPendingRasterization = false;
|
||||
|
@ -141,8 +125,6 @@ bool TextureData::initSVGFromMemory(const std::string& fileData)
|
|||
mPendingRasterization = true;
|
||||
}
|
||||
|
||||
nsvgDelete(svgImage);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -196,6 +178,9 @@ bool TextureData::initFromRGBA(const unsigned char* dataRGBA, size_t width, size
|
|||
|
||||
bool TextureData::load()
|
||||
{
|
||||
if (mInvalidSVGFile)
|
||||
return false;
|
||||
|
||||
bool retval {false};
|
||||
|
||||
// Need to load. See if there is a file.
|
||||
|
|
|
@ -64,10 +64,6 @@ public:
|
|||
}
|
||||
glm::vec2 getSize() { return glm::vec2 {static_cast<int>(mWidth), static_cast<int>(mHeight)}; }
|
||||
|
||||
// Whether to stretch or squash SVG images if the size property has been used to override
|
||||
// the aspect ratio (accomplished by rasterizing at a lower resolution and letting the GPU
|
||||
// scale the texture).
|
||||
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.
|
||||
|
@ -96,10 +92,10 @@ private:
|
|||
std::atomic<float> mSourceWidth;
|
||||
std::atomic<float> mSourceHeight;
|
||||
std::atomic<bool> mScalable;
|
||||
std::atomic<bool> mScalableNonAspect;
|
||||
std::atomic<bool> mHasRGBAData;
|
||||
std::atomic<bool> mPendingRasterization;
|
||||
std::atomic<bool> mMipmapping;
|
||||
std::atomic<bool> mInvalidSVGFile;
|
||||
bool mLinearMagnify;
|
||||
bool mReloadable;
|
||||
};
|
||||
|
|
|
@ -24,7 +24,6 @@ TextureResource::TextureResource(const std::string& path,
|
|||
bool scalable)
|
||||
: mTextureData {nullptr}
|
||||
, mForceLoad {false}
|
||||
, mScalableNonAspect {false}
|
||||
{
|
||||
// Create a texture data object for this texture.
|
||||
if (!path.empty()) {
|
||||
|
@ -251,8 +250,6 @@ void TextureResource::rasterizeAt(float width, float height)
|
|||
else
|
||||
data = sTextureDataManager.get(this);
|
||||
|
||||
data->setScalableNonAspect(mScalableNonAspect);
|
||||
|
||||
if (mTextureData && mTextureData.get()->getScalable())
|
||||
mSourceSize = glm::vec2 {static_cast<float>(width), static_cast<float>(height)};
|
||||
data->setSourceSize(static_cast<float>(width), static_cast<float>(height));
|
||||
|
|
|
@ -55,7 +55,6 @@ public:
|
|||
return (mTextureData != nullptr ? mTextureData->getScalable() : false);
|
||||
}
|
||||
|
||||
void setScalableNonAspect(bool state) { mScalableNonAspect = state; }
|
||||
void setLinearMagnify(bool state) { mTextureData->setLinearMagnify(state); }
|
||||
|
||||
std::string getTextureFilePath();
|
||||
|
@ -103,7 +102,6 @@ private:
|
|||
glm::ivec2 mSize;
|
||||
glm::vec2 mSourceSize;
|
||||
bool mForceLoad;
|
||||
bool mScalableNonAspect;
|
||||
|
||||
// File path, tile, linear interpolation, scalable/SVG, width, height.
|
||||
using TextureKeyType = std::tuple<std::string, bool, bool, bool, size_t, size_t>;
|
||||
|
|
25
external/CMakeLists.txt
vendored
25
external/CMakeLists.txt
vendored
|
@ -6,10 +6,8 @@
|
|||
# CMake configuration for bundled dependencies built in-tree.
|
||||
#
|
||||
|
||||
# On Windows, rlottie is built as a DLL file.
|
||||
if(NOT WIN32)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
# Always build the external libraries with optimizations enabled and without debug info.
|
||||
set (CMAKE_BUILD_TYPE "Release")
|
||||
|
||||
# Disabled threading support for rlottie as this functionality actually leads to far worse
|
||||
# performance. As well there is a bug on Windows that makes rlottie hang forever on application
|
||||
|
@ -18,12 +16,29 @@ option(LOTTIE_THREAD OFF)
|
|||
|
||||
option(LOTTIE_MODULE OFF)
|
||||
|
||||
# Only use the compiler and linker flags defined by rlottie.
|
||||
# Only use the compiler and linker flags defined by LunaSVG and rlottie.
|
||||
unset(CMAKE_CXX_FLAGS)
|
||||
unset(CMAKE_EXE_LINKER_FLAGS)
|
||||
|
||||
add_subdirectory(lunasvg)
|
||||
|
||||
# On Windows, rlottie is built as a DLL file.
|
||||
if(NOT WIN32)
|
||||
set(BUILD_SHARED_LIBS OFF)
|
||||
endif()
|
||||
|
||||
if(EMSCRIPTEN)
|
||||
set(CMAKE_CXX_FLAGS -pthread)
|
||||
endif()
|
||||
|
||||
# rlottie generates a lot of annoying compiler warnings that we don't need to show.
|
||||
if(CMAKE_CXX_COMPILER_ID MATCHES MSVC)
|
||||
set(CMAKE_CXX_FLAGS "/wd4244 /wd4251 /wd4267 /wd4530 /wd4996")
|
||||
else()
|
||||
set(CMAKE_CXX_FLAGS "-w")
|
||||
endif()
|
||||
|
||||
add_subdirectory(rlottie EXCLUDE_FROM_ALL)
|
||||
|
||||
# Build LunaSVG before rlottie.
|
||||
add_dependencies(rlottie lunasvg)
|
||||
|
|
Loading…
Reference in a new issue