瀏覽代碼

Use CAnimation for battle creature animation

AlexVinS 8 年之前
父節點
當前提交
05bb8b13e9
共有 4 個文件被更改,包括 75 次插入202 次删除
  1. 41 168
      client/battle/CCreatureAnimation.cpp
  2. 8 29
      client/battle/CCreatureAnimation.h
  3. 22 5
      client/gui/CAnimation.cpp
  4. 4 0
      client/gui/CAnimation.h

+ 41 - 168
client/battle/CCreatureAnimation.cpp

@@ -10,14 +10,10 @@
 #include "StdInc.h"
 #include "CCreatureAnimation.h"
 
-#include "../../lib/vcmi_endian.h"
 #include "../../lib/CConfigHandler.h"
 #include "../../lib/CCreatureHandler.h"
-#include "../../lib/filesystem/Filesystem.h"
-#include "../../lib/filesystem/CBinaryReader.h"
-#include "../../lib/filesystem/CMemoryStream.h"
 
-#include "../gui/SDL_Pixels.h"
+#include "../gui/SDL_Extensions.h"
 
 static const SDL_Color creatureBlueBorder = { 0, 255, 255, 255 };
 static const SDL_Color creatureGoldBorder = { 255, 255, 0, 255 };
@@ -143,60 +139,41 @@ void CCreatureAnimation::setType(CCreatureAnim::EAnimType type)
 }
 
 CCreatureAnimation::CCreatureAnimation(std::string name, TSpeedController controller)
-    : defName(name),
-      speed(0.1),
-      currentFrame(0),
-      elapsedTime(0),
+	: speed(0.1),
+	  currentFrame(0),
+	  elapsedTime(0),
 	  type(CCreatureAnim::HOLDING),
 	  border(CSDL_Ext::makeColor(0, 0, 0, 0)),
-      speedController(controller),
-      once(false)
+	  speedController(controller),
+	  once(false)
 {
-	// separate block to avoid accidental use of "data" after it was moved into "pixelData"
-	{
-		ResourceID resID(std::string("SPRITES/") + name, EResType::ANIMATION);
-
-		auto data = CResourceHandler::get()->load(resID)->readAll();
-
-		pixelData = std::move(data.first);
-		pixelDataSize = data.second;
-	}
-
-	CMemoryStream stm(pixelData.get(), pixelDataSize);
-
-	CBinaryReader reader(&stm);
+	forward = std::make_shared<CAnimation>(name);
+	reverse = std::make_shared<CAnimation>(name);
 
-	reader.readInt32(); // def type, unused
+	//todo: optimize
+	forward->preload();
+	reverse->preload();
+	reverse->verticalFlip();
 
-	fullWidth  = reader.readInt32();
-	fullHeight = reader.readInt32();
+	//TODO: get dimensions form CAnimation
+	IImage * first = forward->getImage(0, type, true);
 
-	int totalBlocks = reader.readInt32();
-
-	for (auto & elem : palette)
+	if(!first)
 	{
-		elem.r = reader.readUInt8();
-		elem.g = reader.readUInt8();
-		elem.b = reader.readUInt8();
-		elem.a = SDL_ALPHA_OPAQUE;
+		fullWidth = 0;
+		fullHeight = 0;
+		return;
 	}
+	fullWidth = first->width();
+	fullHeight = first->height();
 
-	for (int i=0; i<totalBlocks; i++)
+	// if necessary, add one frame into vcmi-only group DEAD
+	if(forward->size(CCreatureAnim::DEAD) == 0)
 	{
-		int groupID = reader.readInt32();
-
-		int totalInBlock = reader.readInt32();
-
-		reader.skip(4 + 4 + 13 * totalInBlock); // some unused data
-
-		for (int j=0; j<totalInBlock; j++)
-			dataOffsets[groupID].push_back(reader.readUInt32());
+		forward->duplicateImage(CCreatureAnim::DEATH, forward->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD);
+		reverse->duplicateImage(CCreatureAnim::DEATH, reverse->size(CCreatureAnim::DEATH)-1, CCreatureAnim::DEAD);
 	}
 
-	// if necessary, add one frame into vcmi-only group DEAD
-	if (dataOffsets.count(CCreatureAnim::DEAD) == 0)
-		dataOffsets[CCreatureAnim::DEAD].push_back(dataOffsets[CCreatureAnim::DEATH].back());
-
 	play();
 }
 
@@ -285,142 +262,38 @@ static SDL_Color addColors(const SDL_Color & base, const SDL_Color & over)
 			);
 }
 
-std::array<SDL_Color, 8> CCreatureAnimation::genSpecialPalette()
+void CCreatureAnimation::genBorderPalette(IImage::BorderPallete & target)
 {
-	std::array<SDL_Color, 8> ret;
-
-	ret[0] = genShadow(0);
-	ret[1] = genShadow(64);
-	ret[2] = genShadow(128);//unused
-	ret[3] = genShadow(128);//unused
-	ret[4] = genShadow(128);
-	ret[5] = genBorderColor(getBorderStrength(elapsedTime), border);
-	ret[6] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border));
-	ret[7] = addColors(genShadow(64),  genBorderColor(getBorderStrength(elapsedTime), border));
-
-	return ret;
+	target[0] = genBorderColor(getBorderStrength(elapsedTime), border);
+	target[1] = addColors(genShadow(128), genBorderColor(getBorderStrength(elapsedTime), border));
+	target[2] = addColors(genShadow(64),  genBorderColor(getBorderStrength(elapsedTime), border));
 }
 
-template<int bpp>
-void CCreatureAnimation::nextFrameT(SDL_Surface * dest, bool rotate)
-{
-	assert(dataOffsets.count(type) && dataOffsets.at(type).size() > size_t(currentFrame));
-
-	ui32 offset = dataOffsets.at(type).at(floor(currentFrame));
-
-	CMemoryStream stm(pixelData.get(), pixelDataSize);
 
-	CBinaryReader reader(&stm);
 
-	reader.getStream()->seek(offset);
+void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker)
+{
+	size_t frame = floor(currentFrame);
 
-	reader.readUInt32(); // unused, size of pixel data for this frame
-	const ui32 defType2 = reader.readUInt32();
-	const ui32 fullWidth = reader.readUInt32();
-	/*const ui32 fullHeight =*/ reader.readUInt32();
-	const ui32 spriteWidth = reader.readUInt32();
-	const ui32 spriteHeight = reader.readUInt32();
-	const int leftMargin = reader.readInt32();
-	const int topMargin = reader.readInt32();
+	IImage * image = nullptr;
 
-	const int rightMargin = fullWidth - spriteWidth - leftMargin;
-	//const int bottomMargin = fullHeight - spriteHeight - topMargin;
+	if(attacker)
+		image = forward->getImage(frame, type);
+	else
+		image = reverse->getImage(frame, type);
 
-	const size_t baseOffset = reader.getStream()->tell();
+	IImage::BorderPallete borderPallete;
+	genBorderPalette(borderPallete);
 
-	assert(defType2 == 1);
-	UNUSED(defType2);
+	image->setBorderPallete(borderPallete);
 
-	auto specialPalette = genSpecialPalette();
+	image->draw(dest, pos.x, pos.y);
 
-	for (ui32 i=0; i<spriteHeight; i++)
-	{
-		//NOTE: if this loop will be optimized to skip empty lines - recheck this read access
-		ui8 * lineData = pixelData.get() + baseOffset + reader.readUInt32();
-
-		size_t destX = pos.x;
-		if (rotate)
-			destX += rightMargin + spriteWidth - 1;
-		else
-			destX += leftMargin;
-
-		size_t destY = pos.y + topMargin + i;
-		size_t currentOffset = 0;
-		size_t totalRowLength = 0;
-
-		while (totalRowLength < spriteWidth)
-		{
-			ui8 type = lineData[currentOffset++];
-			ui32 length = lineData[currentOffset++] + 1;
-
-			if (type==0xFF)//Raw data
-			{
-				for (size_t j=0; j<length; j++)
-					putPixelAt<bpp>(dest, destX + (rotate?(-j):(j)), destY, lineData[currentOffset + j], specialPalette);
-
-				currentOffset += length;
-			}
-			else// RLE
-			{
-				if (type != 0) // transparency row, handle it here for speed
-				{
-					for (size_t j=0; j<length; j++)
-						putPixelAt<bpp>(dest, destX + (rotate?(-j):(j)), destY, type, specialPalette);
-				}
-			}
-
-			destX += rotate ? (-length) : (length);
-			totalRowLength += length;
-		}
-	}
-}
-
-void CCreatureAnimation::nextFrame(SDL_Surface *dest, bool attacker)
-{
-	// Note: please notice that attacker value is inversed when passed further.
-	// This is intended behavior because "attacker" actually does not needs rotation
-	switch(dest->format->BytesPerPixel)
-	{
-	case 2: return nextFrameT<2>(dest, !attacker);
-	case 3: return nextFrameT<3>(dest, !attacker);
-	case 4: return nextFrameT<4>(dest, !attacker);
-	default:
-		logGlobal->error("%d bpp is not supported!", (int)dest->format->BitsPerPixel);
-	}
 }
 
 int CCreatureAnimation::framesInGroup(CCreatureAnim::EAnimType group) const
 {
-	if(dataOffsets.count(group) == 0)
-		return 0;
-
-	return dataOffsets.at(group).size();
-}
-
-ui8 * CCreatureAnimation::getPixelAddr(SDL_Surface * dest, int X, int Y) const
-{
-	return (ui8*)dest->pixels + X * dest->format->BytesPerPixel + Y * dest->pitch;
-}
-
-template<int bpp>
-inline void CCreatureAnimation::putPixelAt(SDL_Surface * dest, int X, int Y, size_t index, const std::array<SDL_Color, 8> & special) const
-{
-	if ( X < pos.x + pos.w && Y < pos.y + pos.h && X >= 0 && Y >= 0)
-		putPixel<bpp>(getPixelAddr(dest, X, Y), palette[index], index, special);
-}
-
-template<int bpp>
-inline void CCreatureAnimation::putPixel(ui8 * dest, const SDL_Color & color, size_t index, const std::array<SDL_Color, 8> & special) const
-{
-	if((index <= 1) || (index >=4 && index < 8))
-	{
-		const SDL_Color & pal = special[index];
-		ColorPutter<bpp, 0>::PutColor(dest, pal.r, pal.g, pal.b, pal.a);
-	}
-	else
-	{
-		ColorPutter<bpp, 0>::PutColor(dest, color.r, color.g, color.b);
-	}
+	return forward->size(group);
 }
 
 bool CCreatureAnimation::isDead() const

+ 8 - 29
client/battle/CCreatureAnimation.h

@@ -10,8 +10,8 @@
 #pragma once
 
 #include "../../lib/FunctionList.h"
-#include "../gui/SDL_Extensions.h"
 #include "../widgets/Images.h"
+#include "../gui/CAnimation.h"
 
 class CIntObject;
 class CCreatureAnimation;
@@ -52,21 +52,11 @@ public:
 	typedef std::function<float(CCreatureAnimation *, size_t)> TSpeedController;
 
 private:
-	std::string defName;
+	std::shared_ptr<CAnimation> forward;
+	std::shared_ptr<CAnimation> reverse;
 
-	int fullWidth, fullHeight;
-
-	// palette, as read from def file
-	std::array<SDL_Color, 256> palette;
-
-	//key = id of group (note that some groups may be missing)
-	//value = offset of pixel data for each frame, vector size = number of frames in group
-	std::map<int, std::vector<unsigned int>> dataOffsets;
-
-	//animation raw data
-	//TODO: use vector instead?
-	std::unique_ptr<ui8[]> pixelData;
-	size_t pixelDataSize;
+	int fullWidth;
+	int fullHeight;
 
 	// speed of animation, measure in frames per second
 	float speed;
@@ -85,21 +75,10 @@ private:
 
 	bool once; // animation will be played once and the reset to idling
 
-	ui8 * getPixelAddr(SDL_Surface * dest, int ftcpX, int ftcpY) const;
-
-	template<int bpp>
-	void putPixelAt(SDL_Surface * dest, int X, int Y, size_t index, const std::array<SDL_Color, 8> & special) const;
-
-	template<int bpp>
-	void putPixel( ui8 * dest, const SDL_Color & color, size_t index, const std::array<SDL_Color, 8> & special) const;
-
-	template<int bpp>
-	void nextFrameT(SDL_Surface * dest, bool rotate);
-
 	void endAnimation();
 
-	/// creates 8 special colors for current frame
-	std::array<SDL_Color, 8> genSpecialPalette();
+
+	void genBorderPalette(IImage::BorderPallete & target);
 public:
 
 	// function(s) that will be called when animation ends, after reset to 1st frame
@@ -118,7 +97,7 @@ public:
 	void setType(CCreatureAnim::EAnimType type); //sets type of animation and cleares framecount
 	CCreatureAnim::EAnimType getType() const; //returns type of animation
 
-	void nextFrame(SDL_Surface * dest, bool rotate);
+	void nextFrame(SDL_Surface * dest, bool attacker);
 
 	// should be called every frame, return true when animation was reset to beginning
 	bool incrementFrame(float timePassed);

+ 22 - 5
client/gui/CAnimation.cpp

@@ -100,6 +100,8 @@ public:
 
 	void shiftPalette(int from, int howMany) override;
 
+	void setBorderPallete(const BorderPallete & borderPallete) override;
+
 	friend class SDLImageLoader;
 };
 
@@ -157,6 +159,7 @@ public:
 	void verticalFlip() override;
 
 	void shiftPalette(int from, int howMany) override;
+	void setBorderPallete(const BorderPallete & borderPallete) override;
 
 	friend class CompImageLoader;
 };
@@ -985,6 +988,15 @@ void SDLImage::shiftPalette(int from, int howMany)
 	}
 }
 
+void SDLImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
+{
+	if(surf->format->palette)
+	{
+		SDL_SetColors(surf, const_cast<SDL_Color *>(borderPallete.data()), 5, 3);
+	}
+}
+
+
 SDLImage::~SDLImage()
 {
 	SDL_FreeSurface(surf);
@@ -1238,22 +1250,27 @@ CompImage::~CompImage()
 
 void CompImage::horizontalFlip()
 {
-	logAnim->error("CompImage::horizontalFlip is not implemented");
+	logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
 }
 
 void CompImage::verticalFlip()
 {
-	logAnim->error("CompImage::verticalFlip is not implemented");
+	logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
 }
 
 void CompImage::shiftPalette(int from, int howMany)
 {
-	logAnim->error("CompImage::shiftPalette is not implemented");
+	logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
+}
+
+void CompImage::setBorderPallete(const IImage::BorderPallete & borderPallete)
+{
+	logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
 }
 
-void CompImage::exportBitmap(const boost::filesystem::path& path) const
+void CompImage::exportBitmap(const boost::filesystem::path & path) const
 {
-	logAnim->error("CompImage::exportBitmap is not implemented");
+	logAnim->error("%s is not implemented", BOOST_CURRENT_FUNCTION);
 }
 
 

+ 4 - 0
client/gui/CAnimation.h

@@ -24,6 +24,7 @@ class IImage
 {
 	int refCount;
 public:
+	using BorderPallete = std::array<SDL_Color, 3>;
 
 	//draws image on surface "where" at position
 	virtual void draw(SDL_Surface * where, int posX = 0, int posY = 0, Rect * src = nullptr, ui8 alpha = 255) const=0;
@@ -49,6 +50,9 @@ public:
 	//only indexed bitmaps, 16 colors maximum
 	virtual void shiftPalette(int from, int howMany) = 0;
 
+	//only indexed bitmaps, colors 5,6,7 must be special
+	virtual void setBorderPallete(const BorderPallete & borderPallete) = 0;
+
 	virtual void horizontalFlip() = 0;
 	virtual void verticalFlip() = 0;