浏览代码

Moved all handling of image loading to render handler

Ivan Savenko 1 年之前
父节点
当前提交
600b06b74d

+ 6 - 3
client/battle/BattleFieldController.cpp

@@ -560,19 +560,22 @@ void BattleFieldController::flipRangeLimitImagesIntoPositions(std::shared_ptr<CA
 {
 	images->getImage(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();
 }
 

+ 31 - 124
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<IImage> 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<SDLImage>(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<SDLImage>(ImagePath::builtin("DEFAULT"), EImageBlitMode::ALPHA);
+		images[group][frame] = GH.renderHandler().loadImage(ImagePath::builtin("DEFAULT"), EImageBlitMode::OPAQUE);
+		return false;
 	}
-	else //load from separate file
+
+	if (!source[group][frame]["file"].isNull())
 	{
-		auto img = getFromExtraDef(source[group][frame]["file"].String());
-		if(!img)
-			img = std::make_shared<SDLImage>(source[group][frame], EImageBlitMode::ALPHA);
+		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<size_t, size_t> 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<EResType::JSON>();
-	auto configList = CResourceHandler::get()->getResourcesWithName(jsonResource);
-
-	for(auto & loader : configList)
-	{
-		auto stream = loader->load(jsonResource);
-		std::unique_ptr<ui8[]> textData(new ui8[stream->getSize()]);
-		stream->read(textData.get(), stream->getSize());
-
-		const JsonNode config(reinterpret_cast<const std::byte*>(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<size_t, std::vector <JsonNode> > 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<CDefFile>(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);

+ 1 - 11
client/render/CAnimation.h

@@ -35,27 +35,17 @@ private:
 
 	bool preloaded;
 
-	std::shared_ptr<CDefFile> 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<IImage> getFromExtraDef(std::string filename);
-
 public:
-	CAnimation(const AnimationPath & Name);
+	CAnimation(const AnimationPath & Name, std::map<size_t, std::vector <JsonNode> > layout);
 	CAnimation();
 	~CAnimation();
 

+ 0 - 1
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;

+ 1 - 2
client/render/IRenderHandler.h

@@ -25,7 +25,6 @@ public:
 	/// Loads image using given path
 	virtual std::shared_ptr<IImage> loadImage(const ImagePath & path) = 0;
 	virtual std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) = 0;
-
 	virtual std::shared_ptr<IImage> 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<CAnimation> loadAnimation(const AnimationPath & path) = 0;
 
-	/// Creates empty CAnimation
+	/// Creates empty CAnimation. Temporary compatibility method
 	virtual std::shared_ptr<CAnimation> createAnimation() = 0;
 };

+ 103 - 12
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<CDefFile> 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<CDefFile>(path);
+	if (!CResourceHandler::get()->existsResource(actualPath))
+	{
+		animationFiles[actualPath] = nullptr;
+		return nullptr;
+	}
+
+	auto result = std::make_shared<CDefFile>(actualPath);
 
-	animationFiles[path] = result;
+	animationFiles[actualPath] = result;
 	return result;
 }
 
-std::shared_ptr<JsonNode> RenderHandler::getJsonFile(const JsonPath & path)
+void RenderHandler::initFromJson(AnimationLayoutMap & source, 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;
+	}
+}
+
+const RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const AnimationPath & path)
 {
-	auto it = jsonFiles.find(path);
+	auto it = animationLayouts.find(path);
 
-	if (it != jsonFiles.end())
+	if (it != animationLayouts.end())
 		return it->second;
 
-	auto result = std::make_shared<JsonNode>(path);
+	AnimationLayoutMap result;
 
-	jsonFiles[path] = result;
-	return result;
+	auto defFile = getAnimationFile(path);
+	if(defFile)
+	{
+		const std::map<size_t, size_t> defEntries = defFile->getEntries();
+
+		for (auto & defEntry : defEntries)
+			result[defEntry.first].resize(defEntry.second);
+	}
+
+	auto jsonResource = path.toType<EResType::JSON>();
+	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<ui8[]> textData(new ui8[stream->getSize()]);
+		stream->read(textData.get(), stream->getSize());
+
+		const JsonNode config(reinterpret_cast<const std::byte*>(textData.get()), stream->getSize(), path.getOriginalName());
+
+		initFromJson(result, config);
+	}
+
+	animationLayouts[path] = result;
+	return animationLayouts[path];
 }
 
+//std::shared_ptr<JsonNode> RenderHandler::getJsonFile(const JsonPath & path)
+//{
+//	auto it = jsonFiles.find(path);
+//
+//	if (it != jsonFiles.end())
+//		return it->second;
+//
+//	auto result = std::make_shared<JsonNode>(path);
+//
+//	jsonFiles[path] = result;
+//	return result;
+//}
+
 std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group)
 {
 	AnimationLocator locator{path, frame, group};
@@ -78,7 +163,13 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path)
 
 std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
 {
-	return std::make_shared<SDLImage>(path, mode);
+	auto it = imageFiles.find(path);
+	if (it != imageFiles.end())
+		return it->second;
+
+	auto result = std::make_shared<SDLImage>(path, mode);
+	imageFiles[path] = result;
+	return result;
 }
 
 std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
@@ -88,7 +179,7 @@ std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
 
 std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path)
 {
-	return std::make_shared<CAnimation>(path);
+	return std::make_shared<CAnimation>(path, getAnimationLayout(path));
 }
 
 std::shared_ptr<CAnimation> RenderHandler::createAnimation()

+ 8 - 5
client/renderSDL/RenderHandler.h

@@ -15,6 +15,8 @@ class CDefFile;
 
 class RenderHandler : public IRenderHandler
 {
+	using AnimationLayoutMap = std::map<size_t, std::vector<JsonNode>>;
+
 	struct AnimationLocator
 	{
 		AnimationPath animation;
@@ -32,21 +34,22 @@ class RenderHandler : public IRenderHandler
 	};
 
 	std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
-	std::map<JsonPath, std::shared_ptr<JsonNode>> jsonFiles;
+	std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
 	std::map<ImagePath, std::shared_ptr<IImage>> imageFiles;
 	std::map<AnimationLocator, std::shared_ptr<IImage>> animationFrames;
 
 	std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
-	std::shared_ptr<JsonNode> getJsonFile(const JsonPath & path);
+	const AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
+	void initFromJson(AnimationLayoutMap & layout, const JsonNode & config);
 public:
+	// IRenderHandler implementation
+
 	std::shared_ptr<IImage> loadImage(const ImagePath & path) override;
 	std::shared_ptr<IImage> loadImage(const ImagePath & path, EImageBlitMode mode) override;
-
 	std::shared_ptr<IImage> loadImage(const AnimationPath & path, int frame, int group) override;
 
-	std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
-
 	std::shared_ptr<CAnimation> loadAnimation(const AnimationPath & path) override;
 
+	std::shared_ptr<IImage> createImage(SDL_Surface * source) override;
 	std::shared_ptr<CAnimation> createAnimation() override;
 };

+ 0 - 6
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()
 {

+ 0 - 1
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;