diff --git a/src/CanvasComponents/ImageCanvasComponent.cpp b/src/CanvasComponents/ImageCanvasComponent.cpp index dcffa8d..77b4be3 100644 --- a/src/CanvasComponents/ImageCanvasComponent.cpp +++ b/src/CanvasComponents/ImageCanvasComponent.cpp @@ -124,6 +124,7 @@ void ImageCanvasComponent::update(DrawingProgram& drawP) { if(display) { if(display->update_draw()) drawP.invalidate_cache_at_component(&(*compContainer->objInfo)); + display->camera_view_update(compContainer->coords, compContainer->get_world_bounds(), drawP.world.drawData, rect_from_points(d.p1, d.p2)); } } diff --git a/src/ResourceDisplay/FileResourceDisplay.cpp b/src/ResourceDisplay/FileResourceDisplay.cpp index a220854..8368051 100644 --- a/src/ResourceDisplay/FileResourceDisplay.cpp +++ b/src/ResourceDisplay/FileResourceDisplay.cpp @@ -17,7 +17,7 @@ bool FileResourceDisplay::update_draw() const { void FileResourceDisplay::update(World& w) { } -bool FileResourceDisplay::load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) { +bool FileResourceDisplay::load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) { this->fileName = fileName; return true; } diff --git a/src/ResourceDisplay/FileResourceDisplay.hpp b/src/ResourceDisplay/FileResourceDisplay.hpp index 9ebf1ec..7d1f064 100644 --- a/src/ResourceDisplay/FileResourceDisplay.hpp +++ b/src/ResourceDisplay/FileResourceDisplay.hpp @@ -5,7 +5,7 @@ class FileResourceDisplay : public ResourceDisplay { public: virtual void update(World& w) override; - virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) override; + virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) override; virtual bool update_draw() const override; virtual void draw(SkCanvas* canvas, const DrawData& drawData, const SkRect& imRect) override; virtual Vector2f get_dimensions() const override; diff --git a/src/ResourceDisplay/ImageResourceDisplay.cpp b/src/ResourceDisplay/ImageResourceDisplay.cpp index fdeac95..89f5141 100644 --- a/src/ResourceDisplay/ImageResourceDisplay.cpp +++ b/src/ResourceDisplay/ImageResourceDisplay.cpp @@ -11,6 +11,8 @@ #include #include "../MainProgram.hpp" #include +#include +#include #ifdef USE_SKIA_BACKEND_GRAPHITE #include @@ -19,7 +21,7 @@ #include #endif -std::array decoders = { +std::array decoders2 = { SkBmpDecoder::Decoder(), SkGifDecoder::Decoder(), SkIcoDecoder::Decoder(), @@ -30,60 +32,50 @@ std::array decoders = { SkWebpDecoder::Decoder() }; -void ImageResourceDisplay::load_thread() { - for(int i = 0; i < totalFramesToLoad; i++) { - if(shutdownLoadThread) - break; - SkCodec::Options imageOptions; - imageOptions.fFrameIndex = i; - SkCodec::FrameInfo frameInfo; - float frameTime = -1.0f; - if(codec->getFrameInfo(i, &frameInfo)) - frameTime = frameInfo.fDuration; - auto decodeResult = codec->getImage(imageInfo, &imageOptions); - if(std::get<1>(decodeResult) == SkCodec::Result::kSuccess) - frames[i] = {std::get<0>(decodeResult), frameTime}; - else { - Logger::get().log("WORLDFATAL", "Could not decode image, got error code " + std::to_string(std::get<1>(decodeResult)) + ". Image has dimensions " + std::to_string(imageInfo.width()) + " " + std::to_string(imageInfo.height())); - break; - } - loadedFrames++; - } - imageRawData = nullptr; - codec = nullptr; -} +std::unordered_map, sk_sp> ImageResourceDisplay::screenshotCache; +std::atomic ImageResourceDisplay::imageLoadThreadCount = 0; + +#ifdef __EMSCRIPTEN__ + int ImageResourceDisplay::IMAGE_LOAD_THREAD_COUNT_MAX = 1; +#else + int ImageResourceDisplay::IMAGE_LOAD_THREAD_COUNT_MAX = 4; +#endif bool ImageResourceDisplay::update_draw() const { return mustUpdateDraw; } void ImageResourceDisplay::update(World& w) { - for(auto& frame : frames) { - std::erase_if(frame.mipmapLevels, [](const auto& mipmapPair) { - static constexpr std::chrono::duration TIME_TO_REMOVE_MIPMAP_CACHE = std::chrono::seconds(40); - return std::chrono::steady_clock::now() - mipmapPair.second.timeLastUsed > TIME_TO_REMOVE_MIPMAP_CACHE; - }); + screenshotCache.clear(); + + for(size_t mipmapLevel = 0; mipmapLevel < mipmapLevelsStatus.size(); mipmapLevel++) { + if(mipmapLevelsStatus[mipmapLevel] == MipmapLevelStatus::ALLOCATED_JUST_SET) + mipmapLevelsStatus[mipmapLevel] = MipmapLevelStatus::ALLOCATED_WILL_REMOVE; + else if(mipmapLevelsStatus[mipmapLevel] == MipmapLevelStatus::ALLOCATED_WILL_REMOVE) { + mipmapLevelsStatus[mipmapLevel] = MipmapLevelStatus::UNALLOCATED; + for(auto& frame : frames) + frame.mipmapLevels[mipmapLevel] = nullptr; + } } - mustUpdateDraw = false; - if(!loadedFirstFrame && loadedFrames >= 1) { + if(mustUpdateDrawLoadThread) { mustUpdateDraw = true; - loadedFirstFrame = true; + mustUpdateDrawLoadThread = false; } - if(loadedFrames <= 1) + else + mustUpdateDraw = false; + + if(frames.size() == 1) return; - currentTime += w.main.deltaTime * 1000.0; + + currentTime += w.main.deltaTime; for(;;) { if(currentTime >= frames[frameIndex].duration) { currentTime -= frames[frameIndex].duration; frameIndex++; - if(frameIndex >= loadedFrames) { - if(loadedFrames != totalFramesToLoad) // Dont loop the GIF if it's not completely loaded yet - frameIndex--; - else - frameIndex = 0; - } mustUpdateDraw = true; + if(frameIndex >= static_cast(frames.size())) + frameIndex = 0; } else return; @@ -92,64 +84,185 @@ void ImageResourceDisplay::update(World& w) { } } -bool ImageResourceDisplay::load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) { - imageRawData = SkData::MakeWithoutCopy(fileData.c_str(), fileData.size()); - codec = SkCodec::MakeFromData(imageRawData, decoders); +sk_sp ImageResourceDisplay::load_frame_with_codec(const std::unique_ptr& codec, unsigned width, unsigned height, unsigned frameIndexToLoad) { + SkCodec::Options imageOptions; + imageOptions.fFrameIndex = frameIndexToLoad; + auto decodeResult = codec->getImage(imageInfo, &imageOptions); + if(std::get<1>(decodeResult) != SkCodec::Result::kSuccess) + throw std::runtime_error("Could not decode image, got error code " + std::to_string(std::get<1>(decodeResult)) + ". Image decoded with dimensions " + std::to_string(imageInfo.width()) + " " + std::to_string(imageInfo.height())); + sk_sp ogImage = std::get<0>(decodeResult); + SkImageInfo scaledImageInfo = imageInfo.makeDimensions(SkISize(width, height)); + auto scaledImage = ogImage->makeScaled(scaledImageInfo, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + if(!scaledImage) + throw std::runtime_error("Could not scale image."); + return scaledImage; +} + +void ImageResourceDisplay::camera_view_update(const CoordSpaceHelper& compCoords, const SCollision::AABB& compAABB, const DrawData& drawData, const SkRect& imRect) { + if(!smallestMipmapLevelLoaded) + attempt_load_mipmap_in_separate_thread(get_smallest_mipmap_level()); + else { + if(SCollision::collide(compAABB, drawData.cam.viewingAreaGenerousCollider)) { + Vector2f transformedImRectDimensions; + transformedImRectDimensions.x() = drawData.cam.c.scalar_to_space(compCoords.scalar_from_space(imRect.width())); + transformedImRectDimensions.y() = drawData.cam.c.scalar_to_space(compCoords.scalar_from_space(imRect.height())); + int mipmapLevel = get_exact_mipmap_level_for_dimensions(transformedImRectDimensions.cast()); + if(mipmapLevel != get_smallest_mipmap_level()) { + if(mipmapLevelsStatus[mipmapLevel] == MipmapLevelStatus::UNALLOCATED) { + attempt_load_mipmap_in_separate_thread(mipmapLevel); + int nextBestMipmapLevel = get_best_allocated_mipmap_level(mipmapLevel); + if(nextBestMipmapLevel != get_smallest_mipmap_level()) + mipmapLevelsStatus[nextBestMipmapLevel] = MipmapLevelStatus::ALLOCATED_JUST_SET; + } + else + mipmapLevelsStatus[mipmapLevel] = MipmapLevelStatus::ALLOCATED_JUST_SET; + } + } + } +} + +bool ImageResourceDisplay::load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) { + this->fileData = fileData; + auto codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(this->fileData->c_str(), this->fileData->size()), decoders2); mustUpdateDraw = true; + mustUpdateDrawLoadThread = true; if(codec) { auto origin = codec->getOrigin(); bool rotate = (origin == kLeftTop_SkEncodedOrigin || origin == kRightTop_SkEncodedOrigin || origin == kRightBottom_SkEncodedOrigin || origin == kLeftBottom_SkEncodedOrigin); - totalFramesToLoad = codec->getFrameCount(); imageInfo = codec->getInfo(); - frames.resize(totalFramesToLoad); - loadedFrames = 0; + + mipmapLevelsStatus = std::vector>(calculate_smallest_mipmap_level()); + for(auto& mipmapLevelStatus : mipmapLevelsStatus) + mipmapLevelStatus = MipmapLevelStatus::UNALLOCATED; + + frames.resize(codec->getFrameCount()); + for(size_t i = 0; i < frames.size(); i++) { + auto& frame = frames[i]; + frame.mipmapLevels.resize(get_smallest_mipmap_level()); + SkCodec::FrameInfo frameInfo; + if(codec->getFrameInfo(i, &frameInfo)) + frame.duration = static_cast(frameInfo.fDuration) / 1000.0f; // get frametime in seconds + else + frame.duration = -1.0f; + } + if(rotate) { Logger::get().log("INFO", "Image loaded is rotated, so must rotate dimensions"); imageInfo = imageInfo.makeDimensions(SkISize(imageInfo.height(), imageInfo.width())); } - try{ - loadThread = std::make_unique(&ImageResourceDisplay::load_thread, this); - } - catch(...) { - Logger::get().log("INFO", "[ImageResourceDisplay::load] Failed to create load thread, loading on main thread"); - load_thread(); - } + codec = nullptr; + attempt_load_mipmap_in_separate_thread(get_smallest_mipmap_level()); return true; } return false; } +void ImageResourceDisplay::attempt_load_mipmap_in_separate_thread(int mipmapLevel) { + if(imageLoadThreadCount >= IMAGE_LOAD_THREAD_COUNT_MAX) + return; + if(!loadThread) { + shutdownLoadThread = false; + imageLoadThreadCount++; + loadThread = std::make_unique(&ImageResourceDisplay::load_thread_func, this, mipmapLevel); + } + else if(shutdownLoadThread) { + loadThread->join(); + shutdownLoadThread = false; + imageLoadThreadCount++; + loadThread = std::make_unique(&ImageResourceDisplay::load_thread_func, this, mipmapLevel); + } +} + +void ImageResourceDisplay::load_thread_func(int mipmapLevel) { + auto codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(this->fileData->c_str(), this->fileData->size()), decoders2); + Vector2i imDim = get_mipmap_level_image_dimensions(mipmapLevel); + for(size_t i = 0; i < frames.size(); i++) { + if(shutdownLoadThread) + return; + auto& frame = frames[i]; + auto& mipmapImage = (mipmapLevel == get_smallest_mipmap_level()) ? frame.smallestMipmapLevel : frame.mipmapLevels[mipmapLevel]; + mipmapImage = load_frame_with_codec(codec, imDim.x(), imDim.y(), i); + } + if(mipmapLevel == get_smallest_mipmap_level()) + smallestMipmapLevelLoaded = true; + else + mipmapLevelsStatus[mipmapLevel] = MipmapLevelStatus::ALLOCATED_JUST_SET; + mustUpdateDrawLoadThread = true; + imageLoadThreadCount--; + shutdownLoadThread = true; +} + void ImageResourceDisplay::draw(SkCanvas* canvas, const DrawData& drawData, const SkRect& imRect) { - if(loadedFrames == 0) + if(!smallestMipmapLevelLoaded) canvas->drawRect(imRect, SkPaint({0.5f, 0.5f, 0.5f, 0.5f})); else { SkRect imRectPixelSize = canvas->getLocalToDeviceAs3x3().mapRect(imRect); - float imWidth = std::max(imRectPixelSize.width(), 32.0f); - unsigned divisionLevel = imageInfo.width() / imWidth; + int mipmapLevel = get_exact_mipmap_level_for_dimensions({imRectPixelSize.width(), imRectPixelSize.height()}); auto& frame = frames[frameIndex]; - if(divisionLevel <= 1) - canvas->drawImageRect(frame.data, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); - else { - unsigned mipmapLevel = std::log2(divisionLevel); - auto mipmapIt = frame.mipmapLevels.find(mipmapLevel); - - if(mipmapIt == frame.mipmapLevels.end()) { - unsigned divideResolutionBy = std::exp2(mipmapLevel); - SkISize mipmapResolution(imageInfo.width() / divideResolutionBy, imageInfo.height() / divideResolutionBy); - - SkImageInfo mipmapImgInfo = imageInfo.makeDimensions(mipmapResolution); - sk_sp mipmapImage = frame.data->makeScaled(mipmapImgInfo, SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kNone)); - frame.mipmapLevels.emplace(mipmapLevel, MipmapLevelData{mipmapImage, std::chrono::steady_clock::now()}); - canvas->drawImageRect(mipmapImage, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + int closestMipmapLevel = get_best_allocated_mipmap_level(mipmapLevel); + if(drawData.main->takingScreenshot) { + if(closestMipmapLevel == mipmapLevel) { + if(closestMipmapLevel == get_smallest_mipmap_level()) + canvas->drawImageRect(frame.smallestMipmapLevel, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + else + canvas->drawImageRect(frame.mipmapLevels[closestMipmapLevel], imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); } else { - mipmapIt->second.timeLastUsed = std::chrono::steady_clock::now(); - canvas->drawImageRect(mipmapIt->second.imageData, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + if(screenshotCache.contains(fileData)) + canvas->drawImageRect(screenshotCache[fileData], imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + else { + auto codec = SkCodec::MakeFromData(SkData::MakeWithoutCopy(this->fileData->c_str(), this->fileData->size()), decoders2); + screenshotCache[fileData] = load_frame_with_codec(codec, imageInfo.width(), imageInfo.height(), frameIndex); + canvas->drawImageRect(screenshotCache[fileData], imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + } } } + else { + if(closestMipmapLevel == get_smallest_mipmap_level()) + canvas->drawImageRect(frame.smallestMipmapLevel, imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + else + canvas->drawImageRect(frame.mipmapLevels[closestMipmapLevel], imRect, {SkFilterMode::kLinear, SkMipmapMode::kNone}); + } } } +int ImageResourceDisplay::get_exact_mipmap_level_for_dimensions(const Vector2i& dim) { + int minimumImageDim = std::min(imageInfo.width(), imageInfo.height()); + int minimumRectDim = std::min(dim.x(), dim.y()); + int imDim = std::max(minimumRectDim, SMALLEST_MIPMAP_RESOLUTION); + int divisionLevel = minimumImageDim / imDim; + return (divisionLevel <= 1) ? 0 : std::log2(divisionLevel); +} + +int ImageResourceDisplay::get_best_allocated_mipmap_level(int mipmapLevel) { + if(mipmapLevel == get_smallest_mipmap_level()) + return mipmapLevel; + for(int i = mipmapLevel; i >= 0; i--) { + if(mipmapLevelsStatus[i] != MipmapLevelStatus::UNALLOCATED) + return i; + } + for(int i = mipmapLevel; i < get_smallest_mipmap_level(); i++) { + if(mipmapLevelsStatus[i] != MipmapLevelStatus::UNALLOCATED) + return i; + } + return get_smallest_mipmap_level(); +} + +int ImageResourceDisplay::calculate_smallest_mipmap_level() { + int minimumImageDim = std::min(imageInfo.width(), imageInfo.height()); + int divisionLevel = minimumImageDim / SMALLEST_MIPMAP_RESOLUTION; + return (divisionLevel <= 1) ? 0 : std::log2(divisionLevel); +} + +int ImageResourceDisplay::get_smallest_mipmap_level() const { + return mipmapLevelsStatus.size(); +} + +Vector2i ImageResourceDisplay::get_mipmap_level_image_dimensions(int mipmapLevel) const { + unsigned divideResolutionBy = std::exp2(mipmapLevel); + return {imageInfo.width() / divideResolutionBy, imageInfo.height() / divideResolutionBy}; +} + Vector2f ImageResourceDisplay::get_dimensions() const { return {imageInfo.width(), imageInfo.height()}; } diff --git a/src/ResourceDisplay/ImageResourceDisplay.hpp b/src/ResourceDisplay/ImageResourceDisplay.hpp index a8621be..3423bcb 100644 --- a/src/ResourceDisplay/ImageResourceDisplay.hpp +++ b/src/ResourceDisplay/ImageResourceDisplay.hpp @@ -4,42 +4,65 @@ #include #include #include +#include class ImageResourceDisplay : public ResourceDisplay { public: virtual void update(World& w) override; - virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) override; + virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) override; virtual bool update_draw() const override; virtual void draw(SkCanvas* canvas, const DrawData& drawData, const SkRect& imRect) override; virtual Vector2f get_dimensions() const override; virtual float get_dimension_scale() const override; virtual Type get_type() const override; + virtual void camera_view_update(const CoordSpaceHelper& compCoords, const SCollision::AABB& compAABB, const DrawData& drawData, const SkRect& imRect) override; virtual ~ImageResourceDisplay() override; + + static int IMAGE_LOAD_THREAD_COUNT_MAX; + private: - struct MipmapLevelData { - sk_sp imageData; - std::chrono::steady_clock::time_point timeLastUsed; - }; + static constexpr int SMALLEST_MIPMAP_RESOLUTION = 128; + struct FrameData { - sk_sp data; - float duration; - std::unordered_map mipmapLevels; + // Mipmap level calculation is done using the smaller dimension, not the bigger one, to ensure that the dimensions are never invalid + std::vector> mipmapLevels; + sk_sp smallestMipmapLevel; // Smaller dimension of this should be around SMALLEST_MIPMAP_RESOLUTION pixels. Is always allocated and used when cachedMipmapLevel is unavailable or when the image is viewed from far away + float duration = -1.0f; }; + + static std::unordered_map, sk_sp> screenshotCache; + + static std::atomic imageLoadThreadCount; + std::vector frames; + enum class MipmapLevelStatus { + UNALLOCATED, + ALLOCATED_JUST_SET, + ALLOCATED_WILL_REMOVE + }; + + std::vector> mipmapLevelsStatus; + std::atomic smallestMipmapLevelLoaded = false; + + std::shared_ptr fileData; SkImageInfo imageInfo; - void load_thread(); - - int totalFramesToLoad; - std::atomic loadedFrames = 0; - sk_sp imageRawData; - std::unique_ptr codec; - std::atomic shutdownLoadThread = false; - std::unique_ptr loadThread; - float currentTime = 0.0f; int frameIndex = 0; - bool mustUpdateDraw = false; bool loadedFirstFrame = false; + bool mustUpdateDraw = false; + + std::unique_ptr loadThread; + std::atomic shutdownLoadThread = false; + std::atomic mustUpdateDrawLoadThread = false; + + int get_exact_mipmap_level_for_dimensions(const Vector2i& dim); + int get_best_allocated_mipmap_level(int mipmapLevel); + int get_smallest_mipmap_level() const; + Vector2i get_mipmap_level_image_dimensions(int mipmapLevel) const; + int calculate_smallest_mipmap_level(); + void load_thread_func(int mipmapLevel); + void attempt_load_mipmap_in_separate_thread(int mipmapLevel); + sk_sp load_frame_with_codec(const std::unique_ptr& codec, unsigned width, unsigned height, unsigned frameIndexToLoad); }; diff --git a/src/ResourceDisplay/ResourceDisplay.cpp b/src/ResourceDisplay/ResourceDisplay.cpp index 1581b48..8d0b900 100644 --- a/src/ResourceDisplay/ResourceDisplay.cpp +++ b/src/ResourceDisplay/ResourceDisplay.cpp @@ -1,3 +1,6 @@ #include "ResourceDisplay.hpp" +void ResourceDisplay::camera_view_update(const CoordSpaceHelper& compCoords, const SCollision::AABB& compAABB, const DrawData& drawData, const SkRect& imRect) { +} + ResourceDisplay::~ResourceDisplay() {} diff --git a/src/ResourceDisplay/ResourceDisplay.hpp b/src/ResourceDisplay/ResourceDisplay.hpp index f89d18a..b5b9bc8 100644 --- a/src/ResourceDisplay/ResourceDisplay.hpp +++ b/src/ResourceDisplay/ResourceDisplay.hpp @@ -2,6 +2,9 @@ #include #include #include +#include "../SharedTypes.hpp" +#include +#include "../CoordSpaceHelper.hpp" using namespace Eigen; @@ -17,11 +20,12 @@ class ResourceDisplay { SVG }; virtual void update(World& w) = 0; - virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) = 0; + virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) = 0; virtual bool update_draw() const = 0; virtual void draw(SkCanvas* canvas, const DrawData& drawData, const SkRect& imRect) = 0; virtual Vector2f get_dimensions() const = 0; virtual float get_dimension_scale() const = 0; virtual Type get_type() const = 0; + virtual void camera_view_update(const CoordSpaceHelper& compCoords, const SCollision::AABB& compAABB, const DrawData& drawData, const SkRect& imRect); virtual ~ResourceDisplay(); }; diff --git a/src/ResourceDisplay/SvgResourceDisplay.cpp b/src/ResourceDisplay/SvgResourceDisplay.cpp index 7c0be3c..e1d86b0 100644 --- a/src/ResourceDisplay/SvgResourceDisplay.cpp +++ b/src/ResourceDisplay/SvgResourceDisplay.cpp @@ -12,8 +12,8 @@ void SvgResourceDisplay::update(World& w) { mustUpdateDraw = false; } -bool SvgResourceDisplay::load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) { - SkMemoryStream strm(fileData.c_str(), fileData.size()); +bool SvgResourceDisplay::load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) { + SkMemoryStream strm(fileData->c_str(), fileData->size()); svgDom = SkSVGDOM::Builder().make(strm); mustUpdateDraw = true; diff --git a/src/ResourceDisplay/SvgResourceDisplay.hpp b/src/ResourceDisplay/SvgResourceDisplay.hpp index d986294..6014618 100644 --- a/src/ResourceDisplay/SvgResourceDisplay.hpp +++ b/src/ResourceDisplay/SvgResourceDisplay.hpp @@ -7,7 +7,7 @@ class SvgResourceDisplay : public ResourceDisplay { public: virtual void update(World& w) override; - virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::string& fileData) override; + virtual bool load(ResourceManager& rMan, const std::string& fileName, const std::shared_ptr& fileData) override; virtual bool update_draw() const override; virtual void draw(SkCanvas* canvas, const DrawData& drawData, const SkRect& imRect) override; virtual Vector2f get_dimensions() const override; diff --git a/src/ResourceManager.cpp b/src/ResourceManager.cpp index 8e6366f..0c515af 100644 --- a/src/ResourceManager.cpp +++ b/src/ResourceManager.cpp @@ -151,19 +151,19 @@ ResourceDisplay* ResourceManager::get_display_data(const NetworkingObjects::NetO return nullptr; auto imgResource(std::make_unique()); - if(imgResource->load(*this, resourceData->name, *resourceData->data)) { + if(imgResource->load(*this, resourceData->name, resourceData->data)) { displays.emplace(fileID, std::move(imgResource)); return displays[fileID].get(); } auto svgResource(std::make_unique()); - if(svgResource->load(*this, resourceData->name, *resourceData->data)) { + if(svgResource->load(*this, resourceData->name, resourceData->data)) { displays.emplace(fileID, std::move(svgResource)); return displays[fileID].get(); } auto fileResource(std::make_unique()); - fileResource->load(*this, resourceData->name, *resourceData->data); + fileResource->load(*this, resourceData->name, resourceData->data); displays.emplace(fileID, std::move(fileResource)); return displays[fileID].get(); } diff --git a/src/Toolbar.cpp b/src/Toolbar.cpp index 0f0975c..da67694 100644 --- a/src/Toolbar.cpp +++ b/src/Toolbar.cpp @@ -10,6 +10,7 @@ #include "GUIStuff/Elements/Element.hpp" #include "GUIStuff/GUIManager.hpp" #include "InputManager.hpp" +#include "ResourceDisplay/ImageResourceDisplay.hpp" #include "VersionConstants.hpp" #include "World.hpp" #include @@ -282,6 +283,7 @@ nlohmann::json Toolbar::get_config_json() { debugJson["showPerformance"] = showPerformance; debugJson["fpsLimit"] = main.fpsLimit; debugJson["jumpTransitionEasing"] = jumpTransitionEasing; + debugJson["imageLoadMaxThreads"] = ImageResourceDisplay::IMAGE_LOAD_THREAD_COUNT_MAX; debugJson["cacheNodeResolution"] = DrawingProgramCache::CACHE_NODE_RESOLUTION; debugJson["maxCacheNodes"] = DrawingProgramCache::MAXIMUM_DRAW_CACHE_SURFACES; debugJson["maxComponentsInNode"] = DrawingProgramCache::MAXIMUM_COMPONENTS_IN_SINGLE_NODE; @@ -353,6 +355,7 @@ void Toolbar::set_config_json(const nlohmann::json& j, VersionNumber version) { try{j.at("debug").at("showPerformance").get_to(showPerformance);} catch(...) {} try{j.at("debug").at("fpsLimit").get_to(main.fpsLimit);} catch(...) {} try{j.at("debug").at("jumpTransitionEasing").get_to(jumpTransitionEasing);} catch(...) {} + try{j.at("debug").at("imageLoadMaxThreads").get_to(ImageResourceDisplay::IMAGE_LOAD_THREAD_COUNT_MAX);} catch(...) {} try{j.at("debug").at("cacheNodeResolution").get_to(DrawingProgramCache::CACHE_NODE_RESOLUTION);} catch(...) {} try{j.at("debug").at("maxCacheNodes").get_to(DrawingProgramCache::MAXIMUM_DRAW_CACHE_SURFACES);} catch(...) {} try{j.at("debug").at("maxComponentsInNode").get_to(DrawingProgramCache::MAXIMUM_COMPONENTS_IN_SINGLE_NODE);} catch(...) {} @@ -1856,6 +1859,7 @@ void Toolbar::options_menu() { #ifndef __EMSCRIPTEN__ gui.input_scalar_field("fps cap slider", "FPS cap", &main.fpsLimit, 3.0f, 10000.0f); #endif + gui.input_scalar_field("image load max threads", "Maximum image loading threads", &ImageResourceDisplay::IMAGE_LOAD_THREAD_COUNT_MAX, 1, 10000); gui.text_label_light("Cache related settings"); gui.input_scalar_field("cache node resolution", "Cache node resolution", &DrawingProgramCache::CACHE_NODE_RESOLUTION, 256, 8192); gui.input_scalar_field("max cache nodes", "Maximum cached nodes", &DrawingProgramCache::MAXIMUM_DRAW_CACHE_SURFACES, 2, 10000);