From 600b06b74d538ef5c4bec66e17bb06e450ad80ab Mon Sep 17 00:00:00 2001 From: Ivan Savenko Date: Sun, 2 Jun 2024 18:33:51 +0000 Subject: [PATCH] Moved all handling of image loading to render handler --- client/battle/BattleFieldController.cpp | 9 +- client/render/CAnimation.cpp | 157 +++++------------------- client/render/CAnimation.h | 12 +- client/render/IImage.h | 1 - client/render/IRenderHandler.h | 3 +- client/renderSDL/RenderHandler.cpp | 115 +++++++++++++++-- client/renderSDL/RenderHandler.h | 13 +- client/renderSDL/SDLImage.cpp | 6 - client/renderSDL/SDLImage.h | 1 - 9 files changed, 151 insertions(+), 166 deletions(-) diff --git a/client/battle/BattleFieldController.cpp b/client/battle/BattleFieldController.cpp index aeb4e2817..9df03805b 100644 --- a/client/battle/BattleFieldController.cpp +++ b/client/battle/BattleFieldController.cpp @@ -560,19 +560,22 @@ void BattleFieldController::flipRangeLimitImagesIntoPositions(std::shared_ptrgetImage(hexEdgeMaskToFrameIndex[HexMasks::topRight])->verticalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::right])->verticalFlip(); - images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRight])->doubleFlip(); + images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRight])->verticalFlip(); + images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRight])->horizontalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeft])->horizontalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottom])->horizontalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::topRightHalfCorner])->verticalFlip(); - images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner])->doubleFlip(); + images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner])->verticalFlip(); + images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner])->horizontalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftHalfCorner])->horizontalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::rightHalf])->verticalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::topRightCorner])->verticalFlip(); - images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner])->doubleFlip(); + images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner])->verticalFlip(); + images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner])->horizontalFlip(); images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftCorner])->horizontalFlip(); } diff --git a/client/render/CAnimation.cpp b/client/render/CAnimation.cpp index 39e373eb9..7ab38a01f 100644 --- a/client/render/CAnimation.cpp +++ b/client/render/CAnimation.cpp @@ -10,33 +10,12 @@ #include "StdInc.h" #include "CAnimation.h" -#include "CDefFile.h" +#include "../gui/CGuiHandler.h" +#include "../render/IImage.h" +#include "../render/IRenderHandler.h" #include "../../lib/filesystem/Filesystem.h" #include "../../lib/json/JsonUtils.h" -#include "../renderSDL/SDLImage.h" - -std::shared_ptr CAnimation::getFromExtraDef(std::string filename) -{ - size_t pos = filename.find(':'); - if (pos == -1) - return nullptr; - CAnimation anim(AnimationPath::builtinTODO(filename.substr(0, pos))); - pos++; - size_t frame = atoi(filename.c_str()+pos); - size_t group = 0; - pos = filename.find(':', pos); - if (pos != -1) - { - pos++; - group = frame; - frame = atoi(filename.c_str()+pos); - } - anim.load(frame ,group); - auto ret = anim.images[group][frame]; - anim.images.clear(); - return ret; -} bool CAnimation::loadFrame(size_t frame, size_t group) { @@ -46,8 +25,8 @@ bool CAnimation::loadFrame(size_t frame, size_t group) return false; } - auto image = getImage(frame, group, false); - if(image) + + if(auto image = getImage(frame, group, false)) { return true; } @@ -55,30 +34,38 @@ bool CAnimation::loadFrame(size_t frame, size_t group) //try to get image from def if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL) { - if(defFile) - { - auto frameList = defFile->getEntries(); + auto image = GH.renderHandler().loadImage(name, frame, group); - if(vstd::contains(frameList, group) && frameList.at(group) > frame) // frame is present - { - images[group][frame] = std::make_shared(defFile.get(), frame, group); - return true; - } + if(image) + { + images[group][frame] = image; + return true; } // still here? image is missing printError(frame, group, "LoadFrame"); - images[group][frame] = std::make_shared(ImagePath::builtin("DEFAULT"), EImageBlitMode::ALPHA); + images[group][frame] = GH.renderHandler().loadImage(ImagePath::builtin("DEFAULT"), EImageBlitMode::OPAQUE); + return false; } - else //load from separate file - { - auto img = getFromExtraDef(source[group][frame]["file"].String()); - if(!img) - img = std::make_shared(source[group][frame], EImageBlitMode::ALPHA); + if (!source[group][frame]["file"].isNull()) + { + auto img = GH.renderHandler().loadImage(ImagePath::fromJson(source[group][frame]["file"]), EImageBlitMode::ALPHA); images[group][frame] = img; return true; } + + if (!source[group][frame]["animation"].isNull()) + { + AnimationPath animationFile = AnimationPath::fromJson(source[group][frame]["animation"]); + int32_t animationGroup = source[group][frame]["sourceGroup"].Integer(); + int32_t animationFrame = source[group][frame]["sourceFrame"].Integer(); + + auto img = GH.renderHandler().loadImage(animationFile, animationFrame, animationGroup); + images[group][frame] = img; + return true; + } + return false; } @@ -96,45 +83,6 @@ bool CAnimation::unloadFrame(size_t frame, size_t group) return false; } -void CAnimation::initFromJson(const JsonNode & config) -{ - std::string basepath; - basepath = config["basepath"].String(); - - JsonNode base; - base["margins"] = config["margins"]; - base["width"] = config["width"]; - base["height"] = config["height"]; - - for(const JsonNode & group : config["sequences"].Vector()) - { - size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING) - source[groupID].clear(); - - for(const JsonNode & frame : group["frames"].Vector()) - { - JsonNode toAdd; - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + frame.String(); - source[groupID].push_back(toAdd); - } - } - - for(const JsonNode & node : config["images"].Vector()) - { - size_t group = node["group"].Integer(); - size_t frame = node["frame"].Integer(); - - if (source[group].size() <= frame) - source[group].resize(frame+1); - - JsonNode toAdd; - JsonUtils::inherit(toAdd, base); - toAdd["file"].String() = basepath + node["file"].String(); - source[group][frame] = toAdd; - } -} - void CAnimation::exportBitmaps(const boost::filesystem::path& path) const { if(images.empty()) @@ -168,57 +116,16 @@ void CAnimation::exportBitmaps(const boost::filesystem::path& path) const logGlobal->info("Exported %d frames to %s", counter, actualPath.string()); } -void CAnimation::init() -{ - if(defFile) - { - const std::map defEntries = defFile->getEntries(); - - for (auto & defEntry : defEntries) - source[defEntry.first].resize(defEntry.second); - } - -// if (vstd::contains(graphics->imageLists, name.getName())) -// initFromJson(graphics->imageLists[name.getName()]); - - auto jsonResource = name.toType(); - auto configList = CResourceHandler::get()->getResourcesWithName(jsonResource); - - for(auto & loader : configList) - { - auto stream = loader->load(jsonResource); - std::unique_ptr textData(new ui8[stream->getSize()]); - stream->read(textData.get(), stream->getSize()); - - const JsonNode config(reinterpret_cast(textData.get()), stream->getSize(), jsonResource.getName()); - - initFromJson(config); - } -} - void CAnimation::printError(size_t frame, size_t group, std::string type) const { logGlobal->error("%s error: Request for frame not present in CAnimation! File name: %s, Group: %d, Frame: %d", type, name.getOriginalName(), group, frame); } -CAnimation::CAnimation(const AnimationPath & Name): +CAnimation::CAnimation(const AnimationPath & Name, std::map > layout): name(boost::starts_with(Name.getName(), "SPRITES") ? Name : Name.addPrefix("SPRITES/")), + source(layout), preloaded(false) { - if(CResourceHandler::get()->existsResource(name)) - { - try - { - defFile = std::make_shared(name); - } - catch ( const std::runtime_error & e) - { - logAnim->error("Def file %s failed to load! Reason: %s", Name.getOriginalName(), e.what()); - } - } - - init(); - if(source.empty()) logAnim->error("Animation %s failed to load", Name.getOriginalName()); } @@ -226,7 +133,6 @@ CAnimation::CAnimation(const AnimationPath & Name): CAnimation::CAnimation(): preloaded(false) { - init(); } CAnimation::~CAnimation() = default; @@ -250,8 +156,9 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra if(clone.getType() == JsonNode::JsonType::DATA_NULL) { - std::string temp = name.getName()+":"+std::to_string(sourceGroup)+":"+std::to_string(sourceFrame); - clone["file"].String() = temp; + clone["animation"].String() = name.getName(); + clone["sourceGroup"].Integer() = sourceGroup; + clone["sourceFrame"].Integer() = sourceFrame; } source[targetGroup].push_back(clone); diff --git a/client/render/CAnimation.h b/client/render/CAnimation.h index efb66f602..2b2abfe86 100644 --- a/client/render/CAnimation.h +++ b/client/render/CAnimation.h @@ -35,27 +35,17 @@ private: bool preloaded; - std::shared_ptr defFile; - //loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded bool loadFrame(size_t frame, size_t group); //unloadFrame, returns true if image has been unloaded ( either deleted or decreased refCount) bool unloadFrame(size_t frame, size_t group); - //initialize animation from file - void initFromJson(const JsonNode & input); - void init(); - //to get rid of copy-pasting error message :] void printError(size_t frame, size_t group, std::string type) const; - //not a very nice method to get image from another def file - //TODO: remove after implementing resource manager - std::shared_ptr getFromExtraDef(std::string filename); - public: - CAnimation(const AnimationPath & Name); + CAnimation(const AnimationPath & Name, std::map > layout); CAnimation(); ~CAnimation(); diff --git a/client/render/IImage.h b/client/render/IImage.h index 2b8bf1d8d..abbb71583 100644 --- a/client/render/IImage.h +++ b/client/render/IImage.h @@ -80,7 +80,6 @@ public: virtual void horizontalFlip() = 0; virtual void verticalFlip() = 0; - virtual void doubleFlip() = 0; IImage() = default; virtual ~IImage() = default; diff --git a/client/render/IRenderHandler.h b/client/render/IRenderHandler.h index 551c61ea2..805d3ef67 100644 --- a/client/render/IRenderHandler.h +++ b/client/render/IRenderHandler.h @@ -25,7 +25,6 @@ public: /// Loads image using given path virtual std::shared_ptr loadImage(const ImagePath & path) = 0; virtual std::shared_ptr loadImage(const ImagePath & path, EImageBlitMode mode) = 0; - virtual std::shared_ptr loadImage(const AnimationPath & path, int frame, int group) = 0; /// temporary compatibility method. Creates IImage from existing SDL_Surface @@ -35,6 +34,6 @@ public: /// Loads animation using given path virtual std::shared_ptr loadAnimation(const AnimationPath & path) = 0; - /// Creates empty CAnimation + /// Creates empty CAnimation. Temporary compatibility method virtual std::shared_ptr createAnimation() = 0; }; diff --git a/client/renderSDL/RenderHandler.cpp b/client/renderSDL/RenderHandler.cpp index 98a3e680a..dc7126497 100644 --- a/client/renderSDL/RenderHandler.cpp +++ b/client/renderSDL/RenderHandler.cpp @@ -15,34 +15,119 @@ #include "../render/CAnimation.h" #include "../render/CDefFile.h" -#include "../../lib/json/JsonNode.h" +#include "../../lib/json/JsonUtils.h" +#include "../../lib/filesystem/Filesystem.h" std::shared_ptr RenderHandler::getAnimationFile(const AnimationPath & path) { - auto it = animationFiles.find(path); + AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/"); + + auto it = animationFiles.find(actualPath); if (it != animationFiles.end()) return it->second; - auto result = std::make_shared(path); + if (!CResourceHandler::get()->existsResource(actualPath)) + { + animationFiles[actualPath] = nullptr; + return nullptr; + } - animationFiles[path] = result; + auto result = std::make_shared(actualPath); + + animationFiles[actualPath] = result; return result; } -std::shared_ptr RenderHandler::getJsonFile(const JsonPath & path) +void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config) { - auto it = jsonFiles.find(path); + std::string basepath; + basepath = config["basepath"].String(); - if (it != jsonFiles.end()) + JsonNode base; + base["margins"] = config["margins"]; + base["width"] = config["width"]; + base["height"] = config["height"]; + + for(const JsonNode & group : config["sequences"].Vector()) + { + size_t groupID = group["group"].Integer();//TODO: string-to-value conversion("moving" -> MOVING) + source[groupID].clear(); + + for(const JsonNode & frame : group["frames"].Vector()) + { + JsonNode toAdd; + JsonUtils::inherit(toAdd, base); + toAdd["file"].String() = basepath + frame.String(); + source[groupID].push_back(toAdd); + } + } + + for(const JsonNode & node : config["images"].Vector()) + { + size_t group = node["group"].Integer(); + size_t frame = node["frame"].Integer(); + + if (source[group].size() <= frame) + source[group].resize(frame+1); + + JsonNode toAdd; + JsonUtils::inherit(toAdd, base); + toAdd["file"].String() = basepath + node["file"].String(); + source[group][frame] = toAdd; + } +} + +const RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const AnimationPath & path) +{ + auto it = animationLayouts.find(path); + + if (it != animationLayouts.end()) return it->second; - auto result = std::make_shared(path); + AnimationLayoutMap result; - jsonFiles[path] = result; - return result; + auto defFile = getAnimationFile(path); + if(defFile) + { + const std::map defEntries = defFile->getEntries(); + + for (auto & defEntry : defEntries) + result[defEntry.first].resize(defEntry.second); + } + + auto jsonResource = path.toType(); + JsonPath actualJsonPath = boost::starts_with(jsonResource.getName(), "SPRITES") ? jsonResource : jsonResource.addPrefix("SPRITES/");; + auto configList = CResourceHandler::get()->getResourcesWithName(actualJsonPath); + + for(auto & loader : configList) + { + auto stream = loader->load(actualJsonPath); + std::unique_ptr textData(new ui8[stream->getSize()]); + stream->read(textData.get(), stream->getSize()); + + const JsonNode config(reinterpret_cast(textData.get()), stream->getSize(), path.getOriginalName()); + + initFromJson(result, config); + } + + animationLayouts[path] = result; + return animationLayouts[path]; } +//std::shared_ptr RenderHandler::getJsonFile(const JsonPath & path) +//{ +// auto it = jsonFiles.find(path); +// +// if (it != jsonFiles.end()) +// return it->second; +// +// auto result = std::make_shared(path); +// +// jsonFiles[path] = result; +// return result; +//} + std::shared_ptr RenderHandler::loadImage(const AnimationPath & path, int frame, int group) { AnimationLocator locator{path, frame, group}; @@ -78,7 +163,13 @@ std::shared_ptr RenderHandler::loadImage(const ImagePath & path) std::shared_ptr RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode) { - return std::make_shared(path, mode); + auto it = imageFiles.find(path); + if (it != imageFiles.end()) + return it->second; + + auto result = std::make_shared(path, mode); + imageFiles[path] = result; + return result; } std::shared_ptr RenderHandler::createImage(SDL_Surface * source) @@ -88,7 +179,7 @@ std::shared_ptr RenderHandler::createImage(SDL_Surface * source) std::shared_ptr RenderHandler::loadAnimation(const AnimationPath & path) { - return std::make_shared(path); + return std::make_shared(path, getAnimationLayout(path)); } std::shared_ptr RenderHandler::createAnimation() diff --git a/client/renderSDL/RenderHandler.h b/client/renderSDL/RenderHandler.h index 1e6e7cc95..9ac90b926 100644 --- a/client/renderSDL/RenderHandler.h +++ b/client/renderSDL/RenderHandler.h @@ -15,6 +15,8 @@ class CDefFile; class RenderHandler : public IRenderHandler { + using AnimationLayoutMap = std::map>; + struct AnimationLocator { AnimationPath animation; @@ -32,21 +34,22 @@ class RenderHandler : public IRenderHandler }; std::map> animationFiles; - std::map> jsonFiles; + std::map animationLayouts; std::map> imageFiles; std::map> animationFrames; std::shared_ptr getAnimationFile(const AnimationPath & path); - std::shared_ptr getJsonFile(const JsonPath & path); + const AnimationLayoutMap & getAnimationLayout(const AnimationPath & path); + void initFromJson(AnimationLayoutMap & layout, const JsonNode & config); public: + // IRenderHandler implementation + std::shared_ptr loadImage(const ImagePath & path) override; std::shared_ptr loadImage(const ImagePath & path, EImageBlitMode mode) override; - std::shared_ptr loadImage(const AnimationPath & path, int frame, int group) override; - std::shared_ptr createImage(SDL_Surface * source) override; - std::shared_ptr loadAnimation(const AnimationPath & path) override; + std::shared_ptr createImage(SDL_Surface * source) override; std::shared_ptr createAnimation() override; }; diff --git a/client/renderSDL/SDLImage.cpp b/client/renderSDL/SDLImage.cpp index 2a1291c67..dddff02c3 100644 --- a/client/renderSDL/SDLImage.cpp +++ b/client/renderSDL/SDLImage.cpp @@ -266,12 +266,6 @@ void SDLImage::verticalFlip() surf = flipped; } -void SDLImage::doubleFlip() -{ - horizontalFlip(); - verticalFlip(); -} - // Keep the original palette, in order to do color switching operation void SDLImage::savePalette() { diff --git a/client/renderSDL/SDLImage.h b/client/renderSDL/SDLImage.h index 59487ff35..584667b03 100644 --- a/client/renderSDL/SDLImage.h +++ b/client/renderSDL/SDLImage.h @@ -64,7 +64,6 @@ public: void horizontalFlip() override; void verticalFlip() override; - void doubleFlip() override; void shiftPalette(uint32_t firstColorID, uint32_t colorsToMove, uint32_t distanceToMove) override; void adjustPalette(const ColorFilter & shifter, uint32_t colorsToSkipMask) override;