Pārlūkot izejas kodu

Flipped images are now tracked by RenderHandler

Ivan Savenko 1 gadu atpakaļ
vecāks
revīzija
b850b6339f

+ 15 - 19
client/battle/BattleFieldController.cpp

@@ -552,25 +552,21 @@ void BattleFieldController::calculateRangeLimitAndHighlightImages(uint8_t distan
 
 void BattleFieldController::flipRangeLimitImagesIntoPositions(std::shared_ptr<CAnimation> images)
 {
-	images->getImage(hexEdgeMaskToFrameIndex[HexMasks::topRight])->verticalFlip();
-	images->getImage(hexEdgeMaskToFrameIndex[HexMasks::right])->verticalFlip();
-	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])->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])->verticalFlip();
-	images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner])->horizontalFlip();
-	images->getImage(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftCorner])->horizontalFlip();
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::topRight]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::right]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRight]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRight]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomLeft]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottom]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::topRightHalfCorner]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightHalfCorner]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftHalfCorner]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::rightHalf]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::topRightCorner]);
+	images->verticalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomRightCorner]);
+	images->horizontalFlip(hexEdgeMaskToFrameIndex[HexMasks::bottomLeftCorner]);
 }
 
 void BattleFieldController::showHighlightedHexes(Canvas & canvas)

+ 1 - 2
client/mapView/MapRenderer.cpp

@@ -323,8 +323,7 @@ MapRendererFow::MapRendererFow()
 	for(const int rotation : rotations)
 	{
 		fogOfWarPartialHide->duplicateImage(0, rotation, 0);
-		auto image = fogOfWarPartialHide->getImage(size, 0);
-		image->verticalFlip();
+		fogOfWarPartialHide->verticalFlip(size, 0);
 		size++;
 	}
 }

+ 66 - 41
client/render/CAnimation.cpp

@@ -30,42 +30,26 @@ bool CAnimation::loadFrame(size_t frame, size_t group)
 		return true;
 	}
 
-	//try to get image from def
-	if(source[group][frame].getType() == JsonNode::JsonType::DATA_NULL)
-	{
-		auto image = GH.renderHandler().loadImage(name, frame, group);
-
-		if(image)
-		{
-			images[group][frame] = image;
-			return true;
-		}
-		// still here? image is missing
+	std::shared_ptr<IImage> image;
 
-		printError(frame, group, "LoadFrame");
-		images[group][frame] = GH.renderHandler().loadImage(ImagePath::builtin("DEFAULT"), EImageBlitMode::OPAQUE);
-		return false;
-	}
+	//try to get image from def
+	if(source[group][frame].isNull())
+		image = GH.renderHandler().loadImage(name, frame, group);
+	else
+		image = GH.renderHandler().loadImage(source[group][frame]);
 
-	if (!source[group][frame]["file"].isNull())
+	if(image)
 	{
-		auto img = GH.renderHandler().loadImage(ImagePath::fromJson(source[group][frame]["file"]), EImageBlitMode::ALPHA);
-		images[group][frame] = img;
+		images[group][frame] = image;
 		return true;
 	}
-
-	if (!source[group][frame]["animation"].isNull())
+	else
 	{
-		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;
+		// image is missing
+		printError(frame, group, "LoadFrame");
+		images[group][frame] = GH.renderHandler().loadImage(ImagePath::builtin("DEFAULT"), EImageBlitMode::OPAQUE);
+		return false;
 	}
-
-	return false;
 }
 
 bool CAnimation::unloadFrame(size_t frame, size_t group)
@@ -145,14 +129,13 @@ void CAnimation::duplicateImage(const size_t sourceGroup, const size_t sourceFra
 		return;
 	}
 
-	//todo: clone actual loaded Image object
 	JsonNode clone(source[sourceGroup][sourceFrame]);
 
 	if(clone.getType() == JsonNode::JsonType::DATA_NULL)
 	{
 		clone["animation"].String() = name.getName();
-		clone["sourceGroup"].Integer() = sourceGroup;
-		clone["sourceFrame"].Integer() = sourceFrame;
+		clone["group"].Integer() = sourceGroup;
+		clone["frame"].Integer() = sourceFrame;
 	}
 
 	source[targetGroup].push_back(clone);
@@ -197,16 +180,60 @@ size_t CAnimation::size(size_t group) const
 
 void CAnimation::horizontalFlip()
 {
-	for(auto & group : images)
-		for(auto & image : group.second)
-			image.second->horizontalFlip();
+	for(auto & group : source)
+		for(size_t i = 0; i < group.second.size(); ++i)
+			horizontalFlip(i, group.first);
 }
 
 void CAnimation::verticalFlip()
 {
-	for(auto & group : images)
-		for(auto & image : group.second)
-			image.second->verticalFlip();
+	for(auto & group : source)
+		for(size_t i = 0; i < group.second.size(); ++i)
+			verticalFlip(i, group.first);
+}
+
+void CAnimation::horizontalFlip(size_t frame, size_t group)
+{
+	try
+	{
+		images.at(group).at(frame) = nullptr;
+	}
+	catch (const std::out_of_range &)
+	{
+		// ignore - image not loaded
+	}
+
+	JsonNode & config = source.at(group).at(frame);
+	if (config.isNull())
+	{
+		config["animation"].String() = name.getName();
+		config["frame"].Integer() = frame;
+		config["group"].Integer() = group;
+	}
+
+	config["horizontalFlip"].Bool() = !config["horizontalFlip"].Bool();
+}
+
+void CAnimation::verticalFlip(size_t frame, size_t group)
+{
+	try
+	{
+		images.at(group).at(frame) = nullptr;
+	}
+	catch (const std::out_of_range &)
+	{
+		// ignore - image not loaded
+	}
+
+	JsonNode & config = source.at(group).at(frame);
+	if (config.isNull())
+	{
+		config["animation"].String() = name.getName();
+		config["frame"].Integer() = frame;
+		config["group"].Integer() = group;
+	}
+
+	config["verticalFlip"].Bool() = !config["verticalFlip"].Bool();
 }
 
 void CAnimation::playerColored(PlayerColor player)
@@ -221,8 +248,6 @@ void CAnimation::createFlippedGroup(const size_t sourceGroup, const size_t targe
 	for(size_t frame = 0; frame < size(sourceGroup); ++frame)
 	{
 		duplicateImage(sourceGroup, frame, targetGroup);
-
-		auto image = getImage(frame, targetGroup);
-		image->verticalFlip();
+		verticalFlip(frame, targetGroup);
 	}
 }

+ 2 - 0
client/render/CAnimation.h

@@ -62,6 +62,8 @@ public:
 	//total count of frames in group (including not loaded)
 	size_t size(size_t group=0) const;
 
+	void horizontalFlip(size_t frame, size_t group=0);
+	void verticalFlip(size_t frame, size_t group=0);
 	void horizontalFlip();
 	void verticalFlip();
 	void playerColored(PlayerColor player);

+ 4 - 3
client/render/IImage.h

@@ -75,9 +75,6 @@ public:
 	//only indexed bitmaps with 7 special colors
 	virtual void setSpecialPalette(const SpecialPalette & SpecialPalette, uint32_t colorsToSkipMask) = 0;
 
-	virtual void horizontalFlip() = 0;
-	virtual void verticalFlip() = 0;
-
 	virtual ~IImage() = default;
 };
 
@@ -90,5 +87,9 @@ public:
 
 	virtual std::shared_ptr<IImage> createImageReference() = 0;
 
+	virtual std::shared_ptr<IConstImage> horizontalFlip() const = 0;
+	virtual std::shared_ptr<IConstImage> verticalFlip() const = 0;
+
+
 	virtual ~IConstImage() = default;
 };

+ 1 - 0
client/render/IRenderHandler.h

@@ -30,6 +30,7 @@ public:
 	virtual void onLibraryLoadingFinished(const Services * services) = 0;
 
 	/// Loads image using given path
+	virtual std::shared_ptr<IImage> loadImage(const JsonNode & config) = 0;
 	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;

+ 98 - 21
client/renderSDL/RenderHandler.cpp

@@ -27,6 +27,43 @@
 #include <vcmi/SkillService.h>
 #include <vcmi/spells/Service.h>
 
+RenderHandler::ImageLocator::ImageLocator(const JsonNode & config)
+	: image(ImagePath::fromJson(config["file"]))
+	, animation(AnimationPath::fromJson(config["animation"]))
+	, frame(config["frame"].Integer())
+	, group(config["group"].Integer())
+	, verticalFlip(config["verticalFlip"].Bool())
+	, horizontalFlip(config["horizontalFlip"].Bool())
+{
+}
+
+RenderHandler::ImageLocator::ImageLocator(const ImagePath & path)
+	: image(path)
+{
+}
+
+RenderHandler::ImageLocator::ImageLocator(const AnimationPath & path, int frame, int group)
+	: animation(path)
+	, frame(frame)
+	, group(group)
+{
+}
+
+bool RenderHandler::ImageLocator::operator<(const ImageLocator & other) const
+{
+	if(image != other.image)
+		return image < other.image;
+	if(animation != other.animation)
+		return animation < other.animation;
+	if(group != other.group)
+		return group < other.group;
+	if(frame != other.frame)
+		return frame < other.frame;
+	if(verticalFlip != other.verticalFlip)
+		return verticalFlip < other.verticalFlip;
+	return horizontalFlip < other.horizontalFlip;
+}
+
 std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath & path)
 {
 	AnimationPath actualPath = boost::starts_with(path.getName(), "SPRITES") ? path : path.addPrefix("SPRITES/");
@@ -103,7 +140,7 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
 	{
 		const std::map<size_t, size_t> defEntries = defFile->getEntries();
 
-		for (auto & defEntry : defEntries)
+		for (const auto & defEntry : defEntries)
 			result[defEntry.first].resize(defEntry.second);
 	}
 
@@ -125,32 +162,78 @@ RenderHandler::AnimationLayoutMap & RenderHandler::getAnimationLayout(const Anim
 	return animationLayouts[actualPath];
 }
 
-std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group)
+std::shared_ptr<IConstImage> RenderHandler::loadImageFromSingleFile(const ImagePath & path)
 {
-	AnimationLocator locator{path, frame, group};
-
-	auto it = animationFrames.find(locator);
-	if (it != animationFrames.end())
-		return it->second->createImageReference();
+	auto result = std::make_shared<SDLImageConst>(path, EImageBlitMode::COLORKEY);
+	imageFiles[ImageLocator(path)] = result;
+	return result;
+}
 
+std::shared_ptr<IConstImage> RenderHandler::loadImageFromAnimationFileUncached(const AnimationPath & path, int frame, int group)
+{
 	const auto & layout = getAnimationLayout(path);
 	if (!layout.count(group))
-		return loadImage(ImagePath::builtin("DEFAULT"));
+		return loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
 
 	if (frame >= layout.at(group).size())
-		return loadImage(ImagePath::builtin("DEFAULT"));
+		return loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
 
 	const auto & config = layout.at(group).at(frame);
-
 	if (config.isNull())
 	{
 		auto defFile = getAnimationFile(path);
-		auto result = std::make_shared<SDLImageConst>(defFile.get(), frame, group);
-		animationFrames[locator] = result;
-		return result->createImageReference();
+		return std::make_shared<SDLImageConst>(defFile.get(), frame, group);
+	}
+	else
+	{
+		return loadImageImpl(ImageLocator(config));
 	}
+}
+
+std::shared_ptr<IConstImage> RenderHandler::loadImageFromAnimationFile(const AnimationPath & path, int frame, int group)
+{
+	auto result = loadImageFromAnimationFileUncached(path, frame, group);
+	imageFiles[ImageLocator(path, frame, group)] = result;
+	return result;
+}
+
+std::shared_ptr<IConstImage> RenderHandler::loadImageImpl(const ImageLocator & locator)
+{
+	auto it = imageFiles.find(locator);
+	if (it != imageFiles.end())
+		return it->second;
+
+	std::shared_ptr<IConstImage> result;
+
+	if (!locator.image.empty())
+		result = loadImageFromSingleFile(locator.image);
+	else if (!locator.animation.empty())
+		result = loadImageFromAnimationFile(locator.animation, locator.frame, locator.group);
+
+	if (!result)
+		result = loadImageFromSingleFile(ImagePath::builtin("DEFAULT"));
+
+	if (locator.verticalFlip)
+		result = result->verticalFlip();
 
-	return loadImage(ImagePath::builtin("DEFAULT"));
+	if (locator.horizontalFlip)
+		result = result->horizontalFlip();
+
+	imageFiles[locator] = result;
+	return result;
+}
+
+std::shared_ptr<IImage> RenderHandler::loadImage(const JsonNode & config)
+{
+	if (config.isString())
+		return loadImageImpl(ImageLocator(ImagePath::fromJson(config)))->createImageReference();
+	else
+		return loadImageImpl(ImageLocator(config))->createImageReference();
+}
+
+std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group)
+{
+	return loadImageImpl(ImageLocator(path, frame, group))->createImageReference();
 }
 
 std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path)
@@ -160,13 +243,7 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path)
 
 std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
 {
-	auto it = imageFiles.find(path);
-	if (it != imageFiles.end())
-		return it->second->createImageReference();
-
-	auto result = std::make_shared<SDLImageConst>(path, mode);
-	imageFiles[path] = result;
-	return result->createImageReference();
+	return loadImageImpl(ImageLocator(path))->createImageReference();
 }
 
 std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)

+ 16 - 11
client/renderSDL/RenderHandler.h

@@ -22,26 +22,25 @@ class RenderHandler : public IRenderHandler
 {
 	using AnimationLayoutMap = std::map<size_t, std::vector<JsonNode>>;
 
-	struct AnimationLocator
+	struct ImageLocator
 	{
+		ImagePath image;
 		AnimationPath animation;
 		int frame = -1;
 		int group = -1;
 
-		bool operator < (const AnimationLocator & other) const
-		{
-			if (animation != other.animation)
-				return animation < other.animation;
-			if (group != other.group)
-				return group < other.group;
-			return frame < other.frame;
-		}
+		bool verticalFlip = false;
+		bool horizontalFlip = false;
+
+		ImageLocator(const JsonNode & config);
+		ImageLocator(const ImagePath & path);
+		ImageLocator(const AnimationPath & path, int frame, int group);
+		bool operator < (const ImageLocator & other) const;
 	};
 
 	std::map<AnimationPath, std::shared_ptr<CDefFile>> animationFiles;
 	std::map<AnimationPath, AnimationLayoutMap> animationLayouts;
-	std::map<ImagePath, std::shared_ptr<IConstImage>> imageFiles;
-	std::map<AnimationLocator, std::shared_ptr<IConstImage>> animationFrames;
+	std::map<ImageLocator, std::shared_ptr<IConstImage>> imageFiles;
 
 	std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
 	AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
@@ -49,11 +48,17 @@ class RenderHandler : public IRenderHandler
 
 	void addImageListEntry(size_t index, size_t group, const std::string & listName, const std::string & imageName);
 	void addImageListEntries(const EntityService * service);
+
+	std::shared_ptr<IConstImage> loadImageFromSingleFile(const ImagePath & path);
+	std::shared_ptr<IConstImage> loadImageFromAnimationFileUncached(const AnimationPath & path, int frame, int group);
+	std::shared_ptr<IConstImage> loadImageFromAnimationFile(const AnimationPath & path, int frame, int group);
+	std::shared_ptr<IConstImage> loadImageImpl(const ImageLocator & config);
 public:
 
 	// IRenderHandler implementation
 	void onLibraryLoadingFinished(const Services * services) override;
 
+	std::shared_ptr<IImage> loadImage(const JsonNode & config) override;
 	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;

+ 2 - 12
client/renderSDL/SDLImage.cpp

@@ -202,7 +202,7 @@ std::shared_ptr<IImage> SDLImageConst::createImageReference()
 		return std::make_shared<SDLImageRGB>(shared_from_this());
 }
 
-std::shared_ptr<SDLImageConst> SDLImageConst::horizontalFlip() const
+std::shared_ptr<IConstImage> SDLImageConst::horizontalFlip() const
 {
 	SDL_Surface * flipped = CSDL_Ext::horizontalFlip(surf);
 	auto ret = std::make_shared<SDLImageConst>(flipped, EImageBlitMode::ALPHA);
@@ -214,7 +214,7 @@ std::shared_ptr<SDLImageConst> SDLImageConst::horizontalFlip() const
 	return ret;
 }
 
-std::shared_ptr<SDLImageConst> SDLImageConst::verticalFlip() const
+std::shared_ptr<IConstImage> SDLImageConst::verticalFlip() const
 {
 	SDL_Surface * flipped = CSDL_Ext::verticalFlip(surf);
 	auto ret = std::make_shared<SDLImageConst>(flipped, EImageBlitMode::ALPHA);
@@ -342,16 +342,6 @@ void SDLImageBase::setBlitMode(EImageBlitMode mode)
 	blitMode = mode;
 }
 
-void SDLImageBase::horizontalFlip()
-{
-	image = image->horizontalFlip();
-}
-
-void SDLImageBase::verticalFlip()
-{
-	image = image->verticalFlip();
-}
-
 void SDLImageRGB::setSpecialPallete(const SpecialPalette & SpecialPalette, uint32_t colorsToSkipMask)
 {}
 

+ 2 - 4
client/renderSDL/SDLImage.h

@@ -53,8 +53,8 @@ public:
 	Point dimensions() const override;
 	bool isTransparent(const Point & coords) const override;
 	std::shared_ptr<IImage> createImageReference() override;
-	std::shared_ptr<SDLImageConst> horizontalFlip() const;
-	std::shared_ptr<SDLImageConst> verticalFlip() const;
+	std::shared_ptr<IConstImage> horizontalFlip() const override;
+	std::shared_ptr<IConstImage> verticalFlip() const override;
 	std::shared_ptr<SDLImageConst> scaleFast(const Point & size) const;
 
 	const SDL_Palette * getPalette() const;
@@ -79,8 +79,6 @@ public:
 	Point dimensions() const override;
 	void setAlpha(uint8_t value) override;
 	void setBlitMode(EImageBlitMode mode) override;
-	void horizontalFlip() override;
-	void verticalFlip() override;
 };
 
 class SDLImageIndexed final : public SDLImageBase