Selaa lähdekoodia

prescaled image support

Laserlicht 11 kuukautta sitten
vanhempi
sitoutus
11b437db62

+ 1 - 0
client/render/ImageLocator.cpp

@@ -71,6 +71,7 @@ ImageLocator ImageLocator::copyFile() const
 {
 	ImageLocator result;
 	result.scalingFactor = 1;
+	result.preScaledFactor = preScaledFactor;
 	result.image = image;
 	result.defFile = defFile;
 	result.defFrame = defFrame;

+ 1 - 0
client/render/ImageLocator.h

@@ -33,6 +33,7 @@ struct ImageLocator
 	bool verticalFlip = false;
 	bool horizontalFlip = false;
 	int8_t scalingFactor = 0; // 0 = auto / use default scaling
+	int8_t preScaledFactor = 1;
 	EImageLayer layer = EImageLayer::ALL;
 
 	ImageLocator() = default;

+ 69 - 6
client/renderSDL/RenderHandler.cpp

@@ -55,6 +55,58 @@ std::shared_ptr<CDefFile> RenderHandler::getAnimationFile(const AnimationPath &
 	return result;
 }
 
+std::optional<ResourcePath> RenderHandler::getPath(ResourcePath path)
+{
+	if(CResourceHandler::get()->existsResource(path))
+		return path;
+	if(path.getType() == EResType::IMAGE)
+	{
+		auto p = ImagePath::builtin(path.getName());
+		if(CResourceHandler::get()->existsResource(p.addPrefix("DATA/")))
+			return std::optional<ResourcePath>(p.addPrefix("DATA/"));
+		if(CResourceHandler::get()->existsResource(p.addPrefix("SPRITES/")))
+			return std::optional<ResourcePath>(p.addPrefix("SPRITES/"));
+	}
+	else
+	{
+		auto p = AnimationPath::builtin(path.getName());
+		auto pJson = p.toType<EResType::JSON>();
+		if(CResourceHandler::get()->existsResource(p.addPrefix("SPRITES/")))
+			return std::optional<ResourcePath>(p.addPrefix("SPRITES/"));
+		if(CResourceHandler::get()->existsResource(pJson))
+			return std::optional<ResourcePath>(p);
+		if(CResourceHandler::get()->existsResource(pJson.addPrefix("SPRITES/")))
+			return std::optional<ResourcePath>(p.addPrefix("SPRITES/"));
+	}
+
+	return std::nullopt;
+}
+
+std::pair<ResourcePath, int> RenderHandler::getScalePath(ResourcePath p)
+{
+	auto path = p;
+	auto name = p.getName();
+	int scaleFactor = 1;
+	if(getScalingFactor() > 1)
+	{
+		std::vector<int> factorsToCheck = {getScalingFactor(), 4, 3, 2};
+		for(auto factorToCheck : factorsToCheck)
+		{
+			ResourcePath scaledPath = ImagePath::builtin(name + "$" + std::to_string(factorToCheck));
+			if(p.getType() != EResType::IMAGE)
+				scaledPath = AnimationPath::builtin(name + "$" + std::to_string(factorToCheck));
+			if(getPath(scaledPath))
+			{
+				path = scaledPath;
+				scaleFactor = factorToCheck;
+				break;
+			}
+		}
+	}
+
+	return std::pair<ResourcePath, int>(path, scaleFactor);
+};
+
 void RenderHandler::initFromJson(AnimationLayoutMap & source, const JsonNode & config)
 {
 	std::string basepath;
@@ -177,13 +229,13 @@ std::shared_ptr<ISharedImage> RenderHandler::loadImageFromFileUncached(const Ima
 	if (locator.image)
 	{
 		// TODO: create EmptySharedImage class that will be instantiated if image does not exists or fails to load
-		return std::make_shared<SDLImageShared>(*locator.image);
+		return std::make_shared<SDLImageShared>(*locator.image, locator.preScaledFactor);
 	}
 
 	if (locator.defFile)
 	{
 		auto defFile = getAnimationFile(*locator.defFile);
-		return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup);
+		return std::make_shared<SDLImageShared>(defFile.get(), locator.defFrame, locator.defGroup, locator.preScaledFactor);
 	}
 
 	throw std::runtime_error("Invalid image locator received!");
@@ -247,7 +299,7 @@ std::shared_ptr<ISharedImage> RenderHandler::scaleImage(const ImageLocator & loc
 	if (locator.layer == EImageLayer::ALL && locator.playerColored != PlayerColor::CANNOT_DETERMINE)
 		handle->playerColored(locator.playerColored);
 
-	handle->scaleInteger(locator.scalingFactor);
+	handle->scaleInteger(locator.scalingFactor);	
 
 	// TODO: try to optimize image size (possibly even before scaling?) - trim image borders if they are completely transparent
 	auto result = handle->getSharedImage();
@@ -284,13 +336,17 @@ std::shared_ptr<IImage> RenderHandler::loadImage(const ImageLocator & locator, E
 
 std::shared_ptr<IImage> RenderHandler::loadImage(const AnimationPath & path, int frame, int group, EImageBlitMode mode)
 {
-	ImageLocator locator = getLocatorForAnimationFrame(path, frame, group);
+	auto tmp = getScalePath(path);
+	ImageLocator locator = getLocatorForAnimationFrame(AnimationPath::builtin(tmp.first.getName()), frame, group);
+	locator.preScaledFactor = tmp.second;
 	return loadImage(locator, mode);
 }
 
 std::shared_ptr<IImage> RenderHandler::loadImage(const ImagePath & path, EImageBlitMode mode)
 {
-	ImageLocator locator(path);
+	auto tmp = getScalePath(path);
+	ImageLocator locator(ImagePath::builtin(tmp.first.getName()));
+	locator.preScaledFactor = tmp.second;
 	return loadImage(locator, mode);
 }
 
@@ -301,7 +357,14 @@ std::shared_ptr<IImage> RenderHandler::createImage(SDL_Surface * source)
 
 std::shared_ptr<CAnimation> RenderHandler::loadAnimation(const AnimationPath & path, EImageBlitMode mode)
 {
-	return std::make_shared<CAnimation>(path, getAnimationLayout(path), mode);
+	auto tmp = getScalePath(path);
+	auto animPath = AnimationPath::builtin(tmp.first.getName());
+	auto layout = getAnimationLayout(animPath);
+	for(auto & g : layout)
+		for(auto & i : g.second)
+			i.preScaledFactor = tmp.second;
+
+	return std::make_shared<CAnimation>(animPath, layout, mode);
 }
 
 void RenderHandler::addImageListEntries(const EntityService * service)

+ 2 - 0
client/renderSDL/RenderHandler.h

@@ -29,6 +29,8 @@ class RenderHandler : public IRenderHandler
 	std::map<EFonts, std::shared_ptr<const IFont>> fonts;
 
 	std::shared_ptr<CDefFile> getAnimationFile(const AnimationPath & path);
+	std::optional<ResourcePath> getPath(ResourcePath path);
+	std::pair<ResourcePath, int> getScalePath(ResourcePath p);
 	AnimationLayoutMap & getAnimationLayout(const AnimationPath & path);
 	void initFromJson(AnimationLayoutMap & layout, const JsonNode & config);
 

+ 18 - 9
client/renderSDL/SDLImage.cpp

@@ -89,11 +89,12 @@ int IImage::height() const
 	return dimensions().y;
 }
 
-SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group)
+SDLImageShared::SDLImageShared(const CDefFile * data, size_t frame, size_t group, int scaleFactor)
 	: surf(nullptr),
 	margins(0, 0),
 	fullSize(0, 0),
-	originalPalette(nullptr)
+	originalPalette(nullptr),
+	scaleFactor(scaleFactor)
 {
 	SDLImageLoader loader(this);
 	data->loadFrame(frame, group, loader);
@@ -105,7 +106,8 @@ SDLImageShared::SDLImageShared(SDL_Surface * from)
 	: surf(nullptr),
 	margins(0, 0),
 	fullSize(0, 0),
-	originalPalette(nullptr)
+	originalPalette(nullptr),
+	scaleFactor(1)
 {
 	surf = from;
 	if (surf == nullptr)
@@ -118,11 +120,12 @@ SDLImageShared::SDLImageShared(SDL_Surface * from)
 	fullSize.y = surf->h;
 }
 
-SDLImageShared::SDLImageShared(const ImagePath & filename)
+SDLImageShared::SDLImageShared(const ImagePath & filename, int scaleFactor)
 	: surf(nullptr),
 	margins(0, 0),
 	fullSize(0, 0),
-	originalPalette(nullptr)
+	originalPalette(nullptr),
+	scaleFactor(scaleFactor)
 {
 	surf = BitmapHandler::loadBitmap(filename);
 
@@ -274,7 +277,13 @@ std::shared_ptr<ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palet
 	if (palette && surf && surf->format->palette)
 		SDL_SetSurfacePalette(surf, palette);
 
-	SDL_Surface * scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ);
+	SDL_Surface * scaled = nullptr;
+	if(scaleFactor == factor)
+		scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, 1, EScalingAlgorithm::NEAREST); // keep size
+	else if(scaleFactor == 1)
+		scaled = CSDL_Ext::scaleSurfaceIntegerFactor(surf, factor, EScalingAlgorithm::XBRZ);
+	else
+		scaled = CSDL_Ext::scaleSurface(surf, (surf->w / scaleFactor) * factor, (surf->h / scaleFactor) * factor);
 
 	auto ret = std::make_shared<SDLImageShared>(scaled);
 
@@ -296,8 +305,8 @@ std::shared_ptr<ISharedImage> SDLImageShared::scaleInteger(int factor, SDL_Palet
 
 std::shared_ptr<ISharedImage> SDLImageShared::scaleTo(const Point & size, SDL_Palette * palette) const
 {
-	float scaleX = float(size.x) / dimensions().x;
-	float scaleY = float(size.y) / dimensions().y;
+	float scaleX = float(size.x) / fullSize.x;
+	float scaleY = float(size.y) / fullSize.y;
 
 	if (palette && surf->format->palette)
 		SDL_SetSurfacePalette(surf, palette);
@@ -355,7 +364,7 @@ bool SDLImageShared::isTransparent(const Point & coords) const
 
 Point SDLImageShared::dimensions() const
 {
-	return fullSize;
+	return fullSize / scaleFactor;
 }
 
 std::shared_ptr<IImage> SDLImageShared::createImageReference(EImageBlitMode mode)

+ 5 - 2
client/renderSDL/SDLImage.h

@@ -35,6 +35,9 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
 	//total size including borders
 	Point fullSize;
 
+	//pre scaled image
+	int scaleFactor;
+
 	// Keep the original palette, in order to do color switching operation
 	void savePalette();
 
@@ -42,9 +45,9 @@ class SDLImageShared final : public ISharedImage, public std::enable_shared_from
 
 public:
 	//Load image from def file
-	SDLImageShared(const CDefFile *data, size_t frame, size_t group=0);
+	SDLImageShared(const CDefFile *data, size_t frame, size_t group=0, int scaleFactor=1);
 	//Load from bitmap file
-	SDLImageShared(const ImagePath & filename);
+	SDLImageShared(const ImagePath & filename, int scaleFactor=1);
 	//Create using existing surface, extraRef will increase refcount on SDL_Surface
 	SDLImageShared(SDL_Surface * from);
 	~SDLImageShared();