Browse Source

- New animation system:
-- New files: hch/CAnimation.h/cpp
-- Class CAnimation capable to load file partially and/or keep data in compressed state
-- Buttons now use CAnimation instead of CDefHandler

- build system regenerated to include new files
- fixed several gcc warnings
- updated README.linux

Ivan Savenko 15 years ago
parent
commit
c10dac929d

+ 9 - 5
README.linux

@@ -13,16 +13,20 @@ And then regenerate the build system with
 
 To compile, at least the following packages (and their development counterparts) are needed to build:
     * libstdc++ devel
-	* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org)
 	* SDL and SDL-devel
 	* SDL_mixer and SDL_mixer-devel
 	* SDL_image and SDL_image-devel
 	* SDL_ttf and SDL_ttf-devel
 	* zlib and zlib-devel
 	* the ffmpeg libraries (libavformat and libswscale). Their name could be libavformat-devel and libswscale-devel, or ffmpeg-libs-devel or similar names.
+	* boost c++ libraries v1.36+ (1.35 will not work) (www.boost.org):
+		- filesystem
+		- iostreams
+		- system
+		- thread
 
-On Ubuntu 9.04, run:
-  sudo apt-get install g++ libsdl1.2debian-all libsdl-image1.2-dev libsdl-ttf2.0-dev libsdl-mixer1.2-dev zlib1g-dev libavformat-dev libswscale-dev libboost1.37-dev
+On Ubuntu 9.04 or later, run:
+  sudo apt-get install g++ libsdl1.2debian-all libsdl-image1.2-dev libsdl-ttf2.0-dev libsdl-mixer1.2-dev zlib1g-dev libavformat-dev libswscale-dev libboost-dev libboost-filesystem-dev libboost-iostreams-dev libboost-system-dev libboost-thread-dev
 
 Create a directory /YOUR_INSTALL_PATH/vcmi (such as
 /usr/local/share/games/vcmi) that will contain the game data files. The /vcmi at the end is necessary.
@@ -47,7 +51,7 @@ That will generate vcmiclient, vcmiserver as well as 3 .so libraries.
 II. Installing Heroes of Might and Magic 3
 
 VCMI needs an installed version of Heroes III as well as WoG on top of
-it.  The version of Heroes needed is (I think!) either Shadow of Death
+it.  The version of Heroes needed is either Shadow of Death
 or Complete.
 
 Wog can be downloaded from: http://www.maps4heroes.com/heroes3/files/allinone_358f.zip
@@ -61,7 +65,7 @@ Install Heroes 3 and Wog. Then move all the installed files into
 Once both programs are installed, you can install VCMI.
 
 Download the windows VCMI release (at time of writing: 
-http://vcmi.antypika.aplus.pl/forum/dload.php?action=download&id=14)
+http://forum.vcmi.eu/dload.php?action=download&id=18)
 and extract it in a private directory. Populate /YOUR_INSTALL_PATH/vcmi:
 
   mv sprites /YOUR_INSTALL_PATH/vcmi/Sprites

+ 2 - 2
aclocal.m4

@@ -13,8 +13,8 @@
 
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
-m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],,
-[m4_warning([this file was generated for autoconf 2.65.
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.67],,
+[m4_warning([this file was generated for autoconf 2.67.
 You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically `autoreconf'.])])

+ 40 - 57
client/AdventureMapButton.cpp

@@ -1,7 +1,7 @@
 #include "AdventureMapButton.h"
+#include "../hch/CAnimation.h"
 #include "CAdvmapInterface.h"
 #include "SDL_Extensions.h"
-#include "../hch/CDefHandler.h"
 #include "CGameInfo.h"
 #include "../hch/CLodHandler.h"
 #include "../hch/CGeneralTextHandler.h"
@@ -14,7 +14,7 @@
 #include "CMessage.h"
 
 /*
- * AdevntureMapButton.cpp, part of VCMI engine
+ * AdventureMapButton.cpp, part of VCMI engine
  *
  * Authors: listed in file AUTHORS in main folder
  *
@@ -41,19 +41,19 @@ CButtonBase::~CButtonBase()
 	delete text;
 	if(notFreeButton)
 		return;
-	for(int i =0; i<imgs.size();i++)
-		for(int j=0;j<imgs[i].size();j++)
-			SDL_FreeSurface(imgs[i][j]);
+	for (size_t i = 0; i<imgs.size(); i++)
+		delete imgs[i];
+	imgs.clear();
 }
 
 void CButtonBase::show(SDL_Surface * to)
 {
-	int img = std::min(state+bitmapOffset,int(imgs[curimg].size()-1));
+	int img = std::min(state+bitmapOffset,int(imgs[curimg]->size()-1));
 	img = std::max(0, img);
 
 	if (abs)
 	{
-		blitAt(imgs[curimg][img],pos.x,pos.y,to);
+		blitAt(imgs[curimg]->image(img),pos.x,pos.y,to);
 		if(text)
 		{//using "state" instead of "state == 1" screwed up hoverable buttons with text
 			CSDL_Ext::printAt(text->text, text->x + pos.x + (state == 1), text->y + pos.y + (state == 1), text->font, text->color, to);
@@ -61,7 +61,7 @@ void CButtonBase::show(SDL_Surface * to)
 	}
 	else
 	{
-		blitAt(imgs[curimg][img],pos.x+ourObj->pos.x,pos.y+ourObj->pos.y,to);
+		blitAt(imgs[curimg]->image(img),pos.x+ourObj->pos.x,pos.y+ourObj->pos.y,to);
 	}
 }
 
@@ -221,28 +221,15 @@ void AdventureMapButton::init(const CFunctionList<void()> &Callback, const std::
 	setDef(defName, playerColoredButton);
 
 	if (add && add->size())
-	{
-		imgs.resize(imgs.size()+add->size());
 		for (size_t i=0; i<add->size();i++)
-		{
-			CDefHandler *temp = CDefHandler::giveDef((*add)[i]);
-			temp->notFreeImgs = true;
-			for (size_t j=0;j<temp->ourImages.size();j++)
-			{
-				imgs[i+1].push_back(temp->ourImages[j].bitmap);
-				if(playerColoredButton)
-				{
-					graphics->blueToPlayersAdv(imgs[1+i][j],LOCPLINT->playerID);
-				}
-			}
-			delete temp;
-		}
-		//delete add;
-	}
+			setDef((*add)[i], playerColoredButton);
+	if (playerColoredButton)
+		setPlayerColor(LOCPLINT->playerID);
+
 	pos.x += x;
 	pos.y += y;
-	pos.w = imgs[curimg][0]->w;
-	pos.h = imgs[curimg][0]->h  -1;
+	pos.w = imgs[curimg]->image(0)->w;
+	pos.h = imgs[curimg]->image(0)->h  -1;
 }
 
 void AdventureMapButton::block( ui8 on )
@@ -257,30 +244,22 @@ void AdventureMapButton::setDef(const std::string & defName, bool playerColoredB
 {
 	if (reset)
 	{
-		for (size_t i=0;i<imgs[0].size();i++)
-			SDL_FreeSurface(imgs[0][i]);
-		imgs[0].clear();
+		for (size_t i=0; i<imgs.size(); i++)
+			delete imgs[i];
+		imgs.clear();
 	}
 	
-	CDefHandler * temp = CDefHandler::giveDef(defName); 
-	temp->notFreeImgs = true;
-	for (size_t i=0;i<temp->ourImages.size();i++)
-	{
-		imgs.resize(1);
-		imgs[0].push_back(temp->ourImages[i].bitmap);
-		if(playerColoredButton)
-		{
-			graphics->blueToPlayersAdv(imgs[curimg][i],LOCPLINT->playerID);
-		}
-	}
-	delete temp;
+	imgs.push_back(new CAnimation(defName));
+	imgs.back()->load();
 }
 
 void AdventureMapButton::setPlayerColor(int player)
 {
-	for(int i =0; i<imgs.size();i++)
-		for(int j=0;j<imgs[i].size();j++)
-			graphics->blueToPlayersAdv(imgs[i][j],player);
+	for(size_t i =0; i<imgs.size();i++)
+		for(size_t j=0;j<imgs[i]->size();j++)
+		{
+			graphics->blueToPlayersAdv(imgs[i]->image(j),player);
+		}
 }
 
 void CHighlightableButton::select(bool on)
@@ -364,7 +343,7 @@ void CHighlightableButtonsGroup::addButton(const std::map<int,std::string> &tool
 }	
 
 CHighlightableButtonsGroup::CHighlightableButtonsGroup(const CFunctionList2<void(int)> &OnChange, bool musicLikeButtons)
-: musicLike(musicLikeButtons), onChange(OnChange)
+: onChange(OnChange), musicLike(musicLikeButtons)
 {}
 
 CHighlightableButtonsGroup::~CHighlightableButtonsGroup()
@@ -559,7 +538,7 @@ void CSlider::clickLeft(tribool down, bool previousState)
 
 CSlider::~CSlider()
 {
-	delete imgs;
+	
 }
 
 CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int Capacity, int Amount, int Value, bool Horizontal, int style)
@@ -609,19 +588,23 @@ CSlider::CSlider(int x, int y, int totalw, boost::function<void(int)> Moved, int
 
 	if(style == 0)
 	{
-		if (horizontal)
-			imgs = CDefHandler::giveDefEss("IGPCRDIV.DEF");
-		else
-			imgs = CDefHandler::giveDefEss("OVBUTN2.DEF");
-		left->imgs.resize(1); right->imgs.resize(1); slider->imgs.resize(1);
-		left->imgs[0].push_back(imgs->ourImages[0].bitmap); left->imgs[0].push_back(imgs->ourImages[1].bitmap);
-		right->imgs[0].push_back(imgs->ourImages[2].bitmap); right->imgs[0].push_back(imgs->ourImages[3].bitmap);
-		slider->imgs[0].push_back(imgs->ourImages[4].bitmap);
-		left->notFreeButton = right->notFreeButton = slider->notFreeButton = true;
+		CAnimation * pics = new CAnimation(horizontal?"IGPCRDIV.DEF":"OVBUTN2.DEF");
+		pics->load();
+		
+		left->imgs.push_back(new CAnimation());
+		right->imgs.push_back(new CAnimation());
+		slider->imgs.push_back(new CAnimation());
+		
+		left->imgs.back()->add(pics->image(0), true);
+		left->imgs.back()->add(pics->image(1), true);
+		right->imgs.back()->add(pics->image(2), true);
+		right->imgs.back()->add(pics->image(3), true);
+		slider->imgs.back()->add(pics->image(4), true);
+		
+		delete pics;
 	}
 	else
 	{
-		imgs = NULL;
 		left->setDef(horizontal ? "SCNRBLF.DEF" : "SCNRBUP.DEF", false);
 		right->setDef(horizontal ? "SCNRBRT.DEF" : "SCNRBDN.DEF", false);
 		slider->setDef("SCNRBSL.DEF", false);

+ 2 - 4
client/AdventureMapButton.h

@@ -17,7 +17,7 @@
 
 extern SDL_Color tytulowy, tlo, zwykly ;
 
-class CDefEssential;
+class CAnimation;
 
 namespace config{struct ButtonInfo;}
 
@@ -41,7 +41,7 @@ public:
 	bool notFreeButton; //TODO: comment me
 	CIntObject * ourObj; // "owner"
 	int state; //TODO: comment me
-	std::vector< std::vector<SDL_Surface*> > imgs; //images for this button
+	std::vector< CAnimation * > imgs; //images for this button
 	int curimg; //curently displayed image from imgs
 	virtual void show(SDL_Surface * to);
 	virtual void showAll(SDL_Surface * to);
@@ -129,8 +129,6 @@ public:
 	bool wheelScrolling;
 	bool keyScrolling;
 
-	CDefEssential *imgs ;
-
 	boost::function<void(int)> moved;
 
 	void redrawSlider(); 

+ 3 - 2
client/CBattleInterface.cpp

@@ -4,6 +4,7 @@
 #include "SDL_Extensions.h"
 #include "CAdvmapInterface.h"
 #include "AdventureMapButton.h"
+#include "../hch/CAnimation.h"
 #include "../hch/CObjectHandler.h"
 #include "../hch/CHeroHandler.h"
 #include "../hch/CDefHandler.h"
@@ -3914,9 +3915,9 @@ CBattleOptionsWindow::CBattleOptionsWindow(const SDL_Rect & position, CBattleInt
 	animSpeeds->onChange = boost::bind(&CBattleInterface::setAnimSpeed, owner, _1);
 
 	setToDefault = new AdventureMapButton (CGI->generaltexth->zelp[392].first, CGI->generaltexth->zelp[392].second, boost::bind(&CBattleOptionsWindow::bDefaultf,this), 405, 443, "codefaul.def");
-	std::swap(setToDefault->imgs[0][0], setToDefault->imgs[0][1]);
+	setToDefault->imgs[0]->fixButtonPos();
 	exit = new AdventureMapButton (CGI->generaltexth->zelp[393].first, CGI->generaltexth->zelp[393].second, boost::bind(&CBattleOptionsWindow::bExitf,this), 516, 443, "soretrn.def",SDLK_RETURN);
-	std::swap(exit->imgs[0][0], exit->imgs[0][1]);
+	exit->imgs[0]->fixButtonPos();
 
 	//printing texts to background
 	CSDL_Ext::printAtMiddle(CGI->generaltexth->allTexts[392], 242, 32, FONT_BIG, tytulowy, background); //window title

+ 2 - 3
client/CCastleInterface.cpp

@@ -1138,9 +1138,8 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
 	if(down)
 	{
 		CCastleInterface * ci=LOCPLINT->castleInt;
-		const CGTownInstance * town = ci->town;
 		std::set<si32> bld = ci->town->builtBuildings;
-		int summ=0, cnt=0;
+		int summ=0;
 		std::string descr=CGI->generaltexth->allTexts[589];//Growth of creature is number
 		boost::algorithm::replace_first(descr,"%s",CGI->creh->creatures[crid]->nameSing);
 		boost::algorithm::replace_first(descr,"%d", boost::lexical_cast<std::string>(ci->town->creatureGrowth(level)));
@@ -1174,7 +1173,7 @@ void CCastleInterface::CCreaInfo::clickRight(tribool down, bool previousState)
 				summ+=AddToString(CGI->buildh->buildings[ci->town->subID][24]->Name()+" %+d",descr,
 					CGI->creh->creatures[crid]->hordeGrowth);
 
-			cnt = 0;
+			int cnt = 0;
 
 			std::vector< const CGDwelling * > myDwellings = LOCPLINT->cb->getMyDwellings();
 			for (std::vector<const CGDwelling*>::const_iterator it = myDwellings.begin(); it != myDwellings.end(); ++it)

+ 7 - 3
client/CConfigHandler.cpp

@@ -2,14 +2,18 @@
 #include "CConfigHandler.h"
 #include <boost/bind.hpp>
 #include <boost/function.hpp>
+#include <boost/version.hpp>
+#include <fstream>
+using namespace config;
+
 #if BOOST_VERSION >= 103800
 #include <boost/spirit/include/classic.hpp>
+using namespace boost::spirit::classic;
 #else
 #include <boost/spirit.hpp>
-#endif
-#include <fstream>
-using namespace config;
 using namespace boost::spirit;
+#endif
+
 using namespace phoenix;
 
 /*

+ 4 - 3
client/CMessage.cpp

@@ -2,6 +2,7 @@
 #include "CMessage.h"
 #include "SDL_ttf.h"
 #include "../hch/CDefHandler.h"
+#include "../hch/CAnimation.h"
 #include "CGameInfo.h"
 #include "SDL_Extensions.h"
 #include "../hch/CLodHandler.h"
@@ -427,7 +428,7 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player)
 		// Compute total width of buttons
 		bw = 20*(ret->buttons.size()-1); // space between all buttons
 		for(size_t i=0; i<ret->buttons.size(); i++) //and add buttons width
-			bw+=ret->buttons[i]->imgs[0][0]->w; 
+			bw+=ret->buttons[i]->imgs[0]->image(0)->w; 
 		winSize.second += 20 + //before button
 		ok->ourImages[0].bitmap->h; //button	
 	}
@@ -464,13 +465,13 @@ void CMessage::drawIWindow(CInfoWindow * ret, std::string text, int player)
 	{
 		// Position the buttons at the bottom of the window
 		bw = (ret->bitmap->w/2) - (bw/2);
-		curh = ret->bitmap->h - SIDE_MARGIN - ret->buttons[0]->imgs[0][0]->h;
+		curh = ret->bitmap->h - SIDE_MARGIN - ret->buttons[0]->imgs[0]->image(0)->h;
 
 		for(size_t i=0; i<ret->buttons.size(); i++)
 		{
 			ret->buttons[i]->pos.x = bw + ret->pos.x;
 			ret->buttons[i]->pos.y = curh + ret->pos.y;
-			bw += ret->buttons[i]->imgs[0][0]->w + 20;
+			bw += ret->buttons[i]->imgs[0]->image(0)->w + 20;
 		}
 	}
 	for(size_t i=0; i<ret->components.size(); i++)

+ 8 - 7
client/CPreGame.cpp

@@ -9,6 +9,7 @@
 #include "SDL_Extensions.h"
 #include "CGameInfo.h"
 #include "CCursorHandler.h"
+#include "../hch/CAnimation.h"
 #include "../hch/CDefHandler.h"
 #include "../hch/CDefObjInfoHandler.h"
 #include "../hch/CGeneralTextHandler.h"
@@ -798,7 +799,7 @@ void SelectionTab::parseCampaigns( std::vector<FileInfo> & files )
 }
 
 SelectionTab::SelectionTab(CMenuScreen::EState Type, const boost::function<void(CMapInfo *)> &OnSelect, bool MultiPlayer)
-	:onSelect(OnSelect), bg(NULL)
+	:bg(NULL), onSelect(OnSelect)
 {
 	OBJ_CONSTRUCTION;
 	selectionPos = 0;
@@ -1239,7 +1240,7 @@ CChatBox::CChatBox(const Rect &rect)
 }
 
 InfoCard::InfoCard( CMenuScreen::EState Type, bool network )
-: difficulty(NULL), sizes(NULL), sFlags(NULL), bg(NULL), chatOn(false), chat(NULL)
+: bg(NULL), chatOn(false), chat(NULL), difficulty(NULL), sizes(NULL), sFlags(NULL)
 {
 	OBJ_CONSTRUCTION;
 	pos.x += 393;
@@ -2333,8 +2334,8 @@ void CHotSeatPlayers::enterSelectionScreen()
 }
 
 CBonusSelection::CBonusSelection( CCampaignState * _ourCampaign )
-: ourCampaign(_ourCampaign), highlightedRegion(NULL), ourHeader(NULL), bonuses(NULL),
-	diffLb(NULL), diffRb(NULL)
+: highlightedRegion(NULL), ourCampaign(_ourCampaign), ourHeader(NULL),
+	diffLb(NULL), diffRb(NULL), bonuses(NULL)
 {
 	OBJ_CONSTRUCTION_CAPTURING_ALL;
 	static const std::string bgNames [] = {"E1_BG.BMP", "G2_BG.BMP", "E2_BG.BMP", "G1_BG.BMP", "G3_BG.BMP", "N1_BG.BMP",
@@ -2765,9 +2766,9 @@ void CBonusSelection::updateBonusSelection()
 			blitAt(twcp->ourImages[1].bitmap, 0, 0, selected);
 
 			//moving surfaces into button
-			bonuses->buttons.back()->imgs[0].clear();
-			bonuses->buttons.back()->imgs[0].push_back(notSelected);
-			bonuses->buttons.back()->imgs[0].push_back(selected);
+			bonuses->buttons.back()->imgs[0]->unload();
+			bonuses->buttons.back()->imgs[0]->add(notSelected);
+			bonuses->buttons.back()->imgs[0]->add(selected);
 
 			//cleaning
 			delete de;

+ 5 - 4
client/GUIClasses.cpp

@@ -15,6 +15,7 @@
 #include "CConfigHandler.h"
 #include "CCreatureAnimation.h"
 #include "Graphics.h"
+#include "../hch/CAnimation.h"
 #include "../hch/CArtHandler.h"
 #include "../hch/CBuildingHandler.h"
 #include "../hch/CGeneralTextHandler.h"
@@ -3868,19 +3869,19 @@ CSystemOptionsWindow::CSystemOptionsWindow(const SDL_Rect &pos, CPlayerInterface
 	// std::swap(save->imgs[0][0], load->imgs[0][1]);
 
 	save = new AdventureMapButton (CGI->generaltexth->zelp[322].first, CGI->generaltexth->zelp[322].second, boost::bind(&CSystemOptionsWindow::bsavef, this), pos.x+357, pos.y+298, "SOSAVE.DEF", SDLK_s);
-	std::swap(save->imgs[0][0], save->imgs[0][1]);
+	save->imgs[0]->fixButtonPos();
 
 	// restart = new AdventureMapButton (CGI->generaltexth->zelp[323].first, CGI->generaltexth->zelp[323].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), pos.x+346, pos.y+357, "SORSTRT", SDLK_r);
 	// std::swap(save->imgs[0][0], restart->imgs[0][1]);
 
 	mainMenu = new AdventureMapButton (CGI->generaltexth->zelp[320].first, CGI->generaltexth->zelp[320].second, boost::bind(&CSystemOptionsWindow::bmainmenuf, this), pos.x+357, pos.y+357, "SOMAIN.DEF", SDLK_m);
-	std::swap(mainMenu->imgs[0][0], mainMenu->imgs[0][1]);
+	mainMenu->imgs[0]->fixButtonPos();
 
 	quitGame = new AdventureMapButton (CGI->generaltexth->zelp[324].first, CGI->generaltexth->zelp[324].second, boost::bind(&CSystemOptionsWindow::bquitf, this), pos.x+246, pos.y+415, "soquit.def", SDLK_q);
-	std::swap(quitGame->imgs[0][0], quitGame->imgs[0][1]);
+	quitGame->imgs[0]->fixButtonPos();
 
 	backToMap = new AdventureMapButton (CGI->generaltexth->zelp[325].first, CGI->generaltexth->zelp[325].second, boost::bind(&CSystemOptionsWindow::breturnf, this), pos.x+357, pos.y+415, "soretrn.def", SDLK_RETURN);
-	std::swap(backToMap->imgs[0][0], backToMap->imgs[0][1]);
+	backToMap->imgs[0]->fixButtonPos();
 	backToMap->assignedKeys.insert(SDLK_ESCAPE);
 
 	heroMoveSpeed = new CHighlightableButtonsGroup(0);

+ 2 - 1
client/Makefile.am

@@ -13,7 +13,8 @@ vcmiclient_SOURCES =  \
 	../CThreadHelper.h \
 	../StartInfo.h \
 	../global.h \
-	../hch/CAmbarCendamo.h \
+	../hch/CAnimation.h \
+	../hch/CAnimation.cpp \
 	../hch/CBuildingHandler.h \
 	../hch/CDefHandler.cpp \
 	../hch/CDefHandler.h \

+ 20 - 1
client/Makefile.in

@@ -59,6 +59,7 @@ PROGRAMS = $(bin_PROGRAMS)
 am_vcmiclient_OBJECTS = vcmiclient-CCallback.$(OBJEXT) \
 	vcmiclient-CGameInterface.$(OBJEXT) \
 	vcmiclient-CThreadHelper.$(OBJEXT) \
+	vcmiclient-CAnimation.$(OBJEXT) \
 	vcmiclient-CDefHandler.$(OBJEXT) \
 	vcmiclient-CMusicHandler.$(OBJEXT) \
 	vcmiclient-CSndHandler.$(OBJEXT) \
@@ -280,7 +281,8 @@ vcmiclient_SOURCES = \
 	../CThreadHelper.h \
 	../StartInfo.h \
 	../global.h \
-	../hch/CAmbarCendamo.h \
+	../hch/CAnimation.h \
+	../hch/CAnimation.cpp \
 	../hch/CBuildingHandler.h \
 	../hch/CDefHandler.cpp \
 	../hch/CDefHandler.h \
@@ -437,6 +439,7 @@ distclean-compile:
 
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmiclient-AdventureMapButton.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmiclient-CAdvmapInterface.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmiclient-CAnimation.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmiclient-CBattleInterface.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmiclient-CBitmapHandler.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/vcmiclient-CCallback.Po@am__quote@
@@ -539,6 +542,22 @@ vcmiclient-CThreadHelper.obj: ../CThreadHelper.cpp
 @AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vcmiclient_CXXFLAGS) $(CXXFLAGS) -c -o vcmiclient-CThreadHelper.obj `if test -f '../CThreadHelper.cpp'; then $(CYGPATH_W) '../CThreadHelper.cpp'; else $(CYGPATH_W) '$(srcdir)/../CThreadHelper.cpp'; fi`
 
+vcmiclient-CAnimation.o: ../hch/CAnimation.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vcmiclient_CXXFLAGS) $(CXXFLAGS) -MT vcmiclient-CAnimation.o -MD -MP -MF $(DEPDIR)/vcmiclient-CAnimation.Tpo -c -o vcmiclient-CAnimation.o `test -f '../hch/CAnimation.cpp' || echo '$(srcdir)/'`../hch/CAnimation.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/vcmiclient-CAnimation.Tpo $(DEPDIR)/vcmiclient-CAnimation.Po
+@am__fastdepCXX_FALSE@	$(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='../hch/CAnimation.cpp' object='vcmiclient-CAnimation.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vcmiclient_CXXFLAGS) $(CXXFLAGS) -c -o vcmiclient-CAnimation.o `test -f '../hch/CAnimation.cpp' || echo '$(srcdir)/'`../hch/CAnimation.cpp
+
+vcmiclient-CAnimation.obj: ../hch/CAnimation.cpp
+@am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vcmiclient_CXXFLAGS) $(CXXFLAGS) -MT vcmiclient-CAnimation.obj -MD -MP -MF $(DEPDIR)/vcmiclient-CAnimation.Tpo -c -o vcmiclient-CAnimation.obj `if test -f '../hch/CAnimation.cpp'; then $(CYGPATH_W) '../hch/CAnimation.cpp'; else $(CYGPATH_W) '$(srcdir)/../hch/CAnimation.cpp'; fi`
+@am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/vcmiclient-CAnimation.Tpo $(DEPDIR)/vcmiclient-CAnimation.Po
+@am__fastdepCXX_FALSE@	$(AM_V_CXX) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	source='../hch/CAnimation.cpp' object='vcmiclient-CAnimation.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@	DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@	$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vcmiclient_CXXFLAGS) $(CXXFLAGS) -c -o vcmiclient-CAnimation.obj `if test -f '../hch/CAnimation.cpp'; then $(CYGPATH_W) '../hch/CAnimation.cpp'; else $(CYGPATH_W) '$(srcdir)/../hch/CAnimation.cpp'; fi`
+
 vcmiclient-CDefHandler.o: ../hch/CDefHandler.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_CXX)$(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(vcmiclient_CXXFLAGS) $(CXXFLAGS) -MT vcmiclient-CDefHandler.o -MD -MP -MF $(DEPDIR)/vcmiclient-CDefHandler.Tpo -c -o vcmiclient-CDefHandler.o `test -f '../hch/CDefHandler.cpp' || echo '$(srcdir)/'`../hch/CDefHandler.cpp
 @am__fastdepCXX_TRUE@	$(AM_V_at)$(am__mv) $(DEPDIR)/vcmiclient-CDefHandler.Tpo $(DEPDIR)/vcmiclient-CDefHandler.Po

+ 3 - 3
client/SDL_Extensions.cpp

@@ -61,9 +61,9 @@ STRONG_INLINE void ColorPutter<bpp, incrementPtr>::PutColorAlphaSwitch(Uint8 *&p
 template<int bpp, int incrementPtr>
 STRONG_INLINE void ColorPutter<bpp, incrementPtr>::PutColor(Uint8 *&ptr, const Uint8 & R, const Uint8 & G, const Uint8 & B, const Uint8 & A)
 {
-	PutColor(ptr,	(((Uint32)ptr[2]-(Uint32)R)*(Uint32)A) >> 8 + (Uint32)R, 
-		(((Uint32)ptr[1]-(Uint32)G)*(Uint32)A) >> 8 + (Uint32)G, 
-		(((Uint32)ptr[0]-(Uint32)B)*(Uint32)A) >> 8 + (Uint32)B);
+	PutColor(ptr,	(((Uint32)ptr[2]-(Uint32)R)*(Uint32)A) >> (8 + (Uint32)R), 
+		(((Uint32)ptr[1]-(Uint32)G)*(Uint32)A) >> (8 + (Uint32)G), 
+		(((Uint32)ptr[0]-(Uint32)B)*(Uint32)A) >> (8 + (Uint32)B));
 }
 
 

File diff suppressed because it is too large
+ 155 - 153
configure


+ 1 - 1
configure.ac

@@ -29,7 +29,7 @@ if test "x$GXX" = "xyes" -a "x$enable_debug" = "xyes" ; then
 fi
 
 if test "x$GXX" = "xyes" ; then
-   CXXFLAGS="$CXXFLAGS -Wall -Wno-switch-enum -Wno-sign-compare -Wcast-align -Wpointer-arith"
+   CXXFLAGS="$CXXFLAGS -Wall -Wno-switch -Wno-sign-compare -Wcast-align -Wpointer-arith"
 fi
 
 CXXFLAGS="$CXXFLAGS -DDATA_DIR=\\\"\$(pkgdatadir)\\\" -DBIN_DIR=\\\"\$(bindir)\\\" -DLIB_DIR=\\\"\$(pkglibdir)\\\""

+ 689 - 0
hch/CAnimation.cpp

@@ -0,0 +1,689 @@
+#include <iostream>
+#include <sstream>
+#include <boost/foreach.hpp>
+
+#include "SDL.h"
+#include "SDL_image.h"
+
+#include "../client/CBitmapHandler.h"
+#include "CAnimation.h"
+#include "CLodHandler.h"
+
+/*
+ * CAnimation.cpp, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+
+extern DLL_EXPORT CLodHandler *spriteh;
+
+/*************************************************************************
+ *  DefFile, class used for def loading                                  *
+ *************************************************************************/
+
+bool CDefFile::haveFrame(size_t frame, size_t group) const
+{
+	if (offset.size() > group)
+		if (offset[group].size() > frame)
+			return true;
+
+	return false;
+}
+
+SDL_Surface *  CDefFile::loadFrame(size_t frame, size_t group) const
+{
+	if (haveFrame(frame, group))
+		return loadFrame(( unsigned char * )data+offset[group][frame], colors);
+	return NULL;
+}
+
+SDL_Surface * CDefFile::loadFrame (const unsigned char * FDef, const BMPPalette * palette)
+{
+	SDL_Surface * ret=NULL;
+
+	unsigned int BaseOffset,
+	         SpriteWidth, SpriteHeight, //format of sprite
+	         TotalRowLength,			// length of read segment
+	         add, FullHeight,FullWidth,
+	         RowAdd,
+	         prSize,
+	         defType2;
+	int LeftMargin, RightMargin, TopMargin, BottomMargin;
+
+
+	unsigned char SegmentType;
+
+	BaseOffset = 0;
+	SSpriteDef sd = * reinterpret_cast<const SSpriteDef *>(FDef + BaseOffset);
+
+	prSize = SDL_SwapLE32(sd.prSize);
+	defType2 = SDL_SwapLE32(sd.defType2);
+	FullWidth = SDL_SwapLE32(sd.FullWidth);
+	FullHeight = SDL_SwapLE32(sd.FullHeight);
+	SpriteWidth = SDL_SwapLE32(sd.SpriteWidth);
+	SpriteHeight = SDL_SwapLE32(sd.SpriteHeight);
+	LeftMargin = SDL_SwapLE32(sd.LeftMargin);
+	TopMargin = SDL_SwapLE32(sd.TopMargin);
+	RightMargin = FullWidth - SpriteWidth - LeftMargin;
+	BottomMargin = FullHeight - SpriteHeight - TopMargin;
+
+	//if(LeftMargin + RightMargin < 0)
+	//	SpriteWidth += LeftMargin + RightMargin; //ugly construction... TODO: check how to do it nicer
+	if (LeftMargin<0)
+		SpriteWidth+=LeftMargin;
+	if (RightMargin<0)
+		SpriteWidth+=RightMargin;
+
+	// Note: this looks bogus because we allocate only FullWidth, not FullWidth+add
+	add = 4 - FullWidth%4;
+	if (add==4)
+		add=0;
+
+	ret = SDL_CreateRGBSurface(SDL_SWSURFACE, FullWidth, FullHeight, 8, 0, 0, 0, 0);
+	//int tempee2 = readNormalNr(0,4,((unsigned char *)tempee.c_str()));
+
+	BaseOffset += sizeof(SSpriteDef);
+	int BaseOffsetor = BaseOffset;
+
+	for (int i=0; i<256; ++i)
+	{
+		SDL_Color pr;
+		pr.r = palette[i].R;
+		pr.g = palette[i].G;
+		pr.b = palette[i].B;
+		pr.unused = palette[i].F;
+		(*(ret->format->palette->colors+i))=pr;
+	}
+
+	int ftcp=0;
+
+	// If there's a margin anywhere, just blank out the whole surface.
+	if (TopMargin > 0 || BottomMargin > 0 || LeftMargin > 0 || RightMargin > 0)
+	{
+		memset( reinterpret_cast<char*>(ret->pixels), 0, FullHeight*FullWidth);
+	}
+
+	// Skip top margin
+	if (TopMargin > 0)
+		ftcp += TopMargin*(FullWidth+add);
+
+	switch (defType2)
+	{
+	case 0:
+		{
+			for (unsigned int i=0; i<SpriteHeight; i++)
+			{
+				if (LeftMargin>0)
+					ftcp += LeftMargin;
+
+				memcpy(reinterpret_cast<char*>(ret->pixels)+ftcp, &FDef[BaseOffset], SpriteWidth);
+				ftcp += SpriteWidth;
+				BaseOffset += SpriteWidth;
+
+				if (RightMargin>0)
+					ftcp += RightMargin;
+			}
+		}
+		break;
+
+	case 1:
+		{
+			const unsigned int * RWEntriesLoc = reinterpret_cast<const unsigned int *>(FDef+BaseOffset);
+			BaseOffset += sizeof(int) * SpriteHeight;
+			for (unsigned int i=0; i<SpriteHeight; i++)
+			{
+				BaseOffset=BaseOffsetor + SDL_SwapLE32(read_unaligned_u32(RWEntriesLoc + i));
+				if (LeftMargin>0)
+					ftcp += LeftMargin;
+
+				TotalRowLength=0;
+				do
+				{
+					unsigned int SegmentLength;
+
+					SegmentType=FDef[BaseOffset++];
+					SegmentLength=FDef[BaseOffset++] + 1;
+
+					if (SegmentType==0xFF)
+					{
+						memcpy(reinterpret_cast<char*>(ret->pixels)+ftcp, FDef + BaseOffset, SegmentLength);
+						BaseOffset+=SegmentLength;
+					}
+					else
+					{
+						memset(reinterpret_cast<char*>(ret->pixels)+ftcp, SegmentType, SegmentLength);
+					}
+					ftcp += SegmentLength;
+					TotalRowLength += SegmentLength;
+				}
+				while (TotalRowLength<SpriteWidth);
+
+				RowAdd=SpriteWidth-TotalRowLength;
+
+				if (RightMargin>0)
+					ftcp += RightMargin;
+
+				if (add>0)
+					ftcp += add+RowAdd;
+			}
+		}
+		break;
+
+	case 2:
+		{
+			BaseOffset = BaseOffsetor + SDL_SwapLE16(read_unaligned_u16(FDef + BaseOffsetor));
+
+			for (unsigned int i=0; i<SpriteHeight; i++)
+			{
+				//BaseOffset = BaseOffsetor+RWEntries[i];
+				if (LeftMargin>0)
+					ftcp += LeftMargin;
+
+				TotalRowLength=0;
+
+				do
+				{
+					SegmentType=FDef[BaseOffset++];
+					unsigned char code = SegmentType / 32;
+					unsigned char value = (SegmentType & 31) + 1;
+					if (code==7)
+					{
+						memcpy(reinterpret_cast<char*>(ret->pixels)+ftcp, &FDef[BaseOffset], value);
+						ftcp += value;
+						BaseOffset += value;
+					}
+					else
+					{
+						memset(reinterpret_cast<char*>(ret->pixels)+ftcp, code, value);
+						ftcp += value;
+					}
+					TotalRowLength+=value;
+				}
+				while (TotalRowLength<SpriteWidth);
+
+				if (RightMargin>0)
+					ftcp += RightMargin;
+
+				RowAdd=SpriteWidth-TotalRowLength;
+
+				if (add>0)
+					ftcp += add+RowAdd;
+			}
+		}
+		break;
+
+	case 3:
+		{
+			for (unsigned int i=0; i<SpriteHeight; i++)
+			{
+				BaseOffset = BaseOffsetor + SDL_SwapLE16(read_unaligned_u16(FDef + BaseOffsetor+i*2*(SpriteWidth/32)));
+				if (LeftMargin>0)
+					ftcp += LeftMargin;
+
+				TotalRowLength=0;
+
+				do
+				{
+					SegmentType=FDef[BaseOffset++];
+					unsigned char code = SegmentType / 32;
+					unsigned char value = (SegmentType & 31) + 1;
+
+					int len = std::min<unsigned int>(value, SpriteWidth - TotalRowLength) - std::max(0, -LeftMargin);
+					amax(len, 0);
+
+					if (code==7)
+					{
+						memcpy((ui8*)ret->pixels + ftcp, FDef + BaseOffset, len);
+						ftcp += len;
+						BaseOffset += len;
+					}
+					else
+					{
+						memset((ui8*)ret->pixels + ftcp, code, len);
+						ftcp += len;
+					}
+					TotalRowLength+=( LeftMargin>=0 ? value : value+LeftMargin );
+				}
+				while (TotalRowLength<SpriteWidth);
+
+				if (RightMargin>0)
+					ftcp += RightMargin;
+
+				RowAdd=SpriteWidth-TotalRowLength;
+
+				if (add>0)
+					ftcp += add+RowAdd;
+			}
+		}
+		break;
+
+	default:
+		throw std::string("Unknown sprite format.");
+		break;
+	}
+
+	SDL_Color ttcol = ret->format->palette->colors[0];
+	Uint32 keycol = SDL_MapRGBA(ret->format, ttcol.r, ttcol.b, ttcol.g, ttcol.unused);
+	SDL_SetColorKey(ret, SDL_SRCCOLORKEY, keycol);
+	return ret;
+};
+
+BMPPalette * CDefFile::getPalette()
+{
+	BMPPalette * ret = new BMPPalette[256];
+	memcpy(ret, colors, sizeof(BMPPalette)*256);
+	return ret;
+}
+
+CDefFile::CDefFile(std::string Name):data(NULL),colors(NULL)
+{
+	data = spriteh->giveFile(Name, &datasize);
+	if (!data)
+	{
+		tlog0<<"Error: file "<< Name <<" not found\n";
+		return;
+	}
+
+	colors = new BMPPalette[256];
+	int it = 0;
+
+	//int type   = readNormalNr(data, it); it+=4;
+	//int width  = readNormalNr(data, it); it+=4;//not used
+	//int height = readNormalNr(data, it); it+=4;
+	it+=12;
+	unsigned int totalBlocks = readNormalNr(data, it);
+	it+=4;
+
+	for (unsigned int i=0; i<256; i++)
+	{
+		colors[i].R = data[it++];
+		colors[i].G = data[it++];
+		colors[i].B = data[it++];
+		colors[i].F = 0;
+	}
+
+	offset.resize(totalBlocks);
+	offList.insert(datasize);
+
+	for (unsigned int i=0; i<totalBlocks; i++)
+	{
+		it+=4;
+		unsigned int totalEntries = readNormalNr(data, it);
+		it+=12;
+
+		//13 bytes for name of every frame in this block - not used, skipping
+		it+= 13 * totalEntries;
+
+		for (unsigned int j=0; j<totalEntries; j++)
+		{
+			size_t currOffset = readNormalNr(data, it);
+			offset[i].push_back(currOffset);
+			offList.insert(currOffset);
+			it += 4;
+		}
+	}
+}
+unsigned char * CDefFile::getFrame(size_t frame, size_t group) const
+{
+	if (offset.size() > group)
+	{
+		if (offset[group].size() > frame)
+		{
+			size_t offs = offset[group][frame];
+
+			std::set<size_t>::iterator it = offList.find(offs);
+
+			if (it == offList.end() || ++it == offList.end())
+				tlog0<<"Error: offset not found!\n";
+
+			size_t size = *it - offs;
+
+			unsigned char * ret = new unsigned char[size];
+			memcpy(ret, data+offs, size);
+			return ret;
+		}
+	}
+	return NULL;
+}
+
+CDefFile::~CDefFile()
+{
+	delete[] data;
+	delete[] colors;
+}
+
+bool CDefFile::loaded() const
+{
+	return data != NULL;
+}
+
+/*************************************************************************
+ *  CAnimation for animations handling, can load part of file if needed  *
+ *************************************************************************/
+
+CAnimation::AnimEntry::AnimEntry():
+	surf(NULL),
+	source(0),
+	refCount(0),
+	data(NULL),
+	dataSize(0)
+{
+
+}
+
+bool CAnimation::loadFrame(CDefFile * file, size_t frame, size_t group)
+{
+	if (groupSize(group) <= frame)
+		return false;
+	AnimEntry &e = entries[group][frame];
+
+	if (e.surf || e.data)
+	{
+		e.refCount++;
+		return true;
+	}
+
+	if (e.source & 6)//load frame with SDL_Image
+	{
+		int size;
+		unsigned char * pic = NULL;
+
+		std::ostringstream str;
+		if ( e.source & 2 )
+			str << name << '#' << (group+1) << '#' << (frame+1); // file#12#34.*
+		else
+			str << name << '#' << (frame+1);//file#34.*
+
+		pic = spriteh->giveFile(str.str(), &size);
+		if (pic)
+		{
+			if (compressed)
+			{
+				e.data = pic;
+				e.dataSize = size;
+			}
+			else
+			{
+				e.surf = IMG_Load_RW( SDL_RWFromMem((void*)pic, size), 1);
+				delete pic;
+			}
+		}
+	}
+	else if (file && e.source & 1)//try to get image from def
+	{
+		if (compressed)
+			e.data = file->getFrame(frame, group);
+		else
+			e.surf = file->loadFrame(frame, group);
+	}
+
+	if (!(e.surf || e.data))
+		return false;//failed to load
+
+	e.refCount++;
+	return true;
+}
+
+bool CAnimation::unloadFrame(size_t frame, size_t group)
+{
+	if (groupSize(group) > frame && entries[group][frame].refCount)
+	{
+		AnimEntry &e = entries[group][frame];
+		if (--e.refCount)//not last ref
+			return true;
+
+		SDL_FreeSurface(e.surf);
+		delete e.data;
+
+		e.surf = NULL;
+		e.data = NULL;
+		return true;
+	}
+	return false;
+}
+
+void CAnimation::decompress(AnimEntry &entry)
+{
+	if (entry.source & 6)//load frame with SDL_Image
+		entry.surf = IMG_Load_RW( SDL_RWFromMem((void*)entry.data, entry.dataSize), 1);
+
+	else if (entry.source & 1)
+		entry.surf = CDefFile::loadFrame(entry.data, defPalette);
+}
+
+void CAnimation::init(CDefFile * file)
+{
+	if (compressed)
+		defPalette = file->getPalette();
+
+	for (size_t group = 0; ; group++)
+	{
+		std::vector<AnimEntry> toAdd;
+
+		for (size_t frame = 0; ; frame++)
+		{
+			unsigned char res=0;
+
+			{
+				std::ostringstream str;
+				str << name << '#' << (group+1) << '#' << (frame+1); // format: file#12#34.*
+				if (spriteh->haveFile(str.str()))
+					res |= 2;
+			}
+
+			if (group == 0)
+			{
+				std::ostringstream str;
+				str << name << '#' << (frame+1);// format: file#34.*
+				if ( spriteh->haveFile(str.str()))
+					res |=4;
+			}
+
+			if (file)//we have def too. try to get image from def
+			{
+				if (file->haveFrame(frame, group))
+					res |=1;
+			}
+
+			if (res)
+			{
+				toAdd.push_back(AnimEntry());
+				toAdd.back().source = res;
+			}
+			else
+				break;
+		}
+		if (!toAdd.empty())
+		{
+			entries.push_back(toAdd);
+			break;
+		}
+	}
+}
+
+CDefFile * CAnimation::getFile() const
+{
+	CDefFile * file = new CDefFile(name);
+	if (!file->loaded())
+	{
+		delete file;
+		return NULL;
+	}
+	return file;
+}
+
+void CAnimation::printError(size_t frame, size_t group, std::string type) const
+{
+	tlog0 << type <<" error: Request for frame not present in CAnimation!\n"
+	      <<"\tFile name: "<<name<<" Group: "<<group<<" Frame: "<<frame<<"\n";
+}
+
+CAnimation::CAnimation(std::string Name, bool Compressed):
+	name(Name),
+	compressed(Compressed),
+	defPalette(NULL)
+{
+	std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper);
+	int dotPos = name.find_last_of('.');
+	if ( dotPos != -1 )
+		name.erase(dotPos);
+
+	CDefFile * file = getFile();
+	init(file);
+	delete file;
+}
+
+CAnimation::CAnimation():
+	name(""),
+	compressed(false),
+	defPalette(NULL)
+{
+
+}
+
+CAnimation::~CAnimation()
+{
+	delete defPalette;
+
+	for (size_t i = 0; i < entries.size(); i++)
+		for (size_t j = 0; j < entries.at(i).size(); j++)
+		{
+			delete entries[i][j].data;
+			if (entries[i][j].surf)
+				SDL_FreeSurface(entries[i][j].surf);
+		}
+}
+
+void CAnimation::add(SDL_Surface * surf, bool shared, size_t group)
+{
+	if (!surf)
+		return;
+
+	if (entries.size() <= group)
+		entries.resize(group+1);
+
+	if (shared)
+		surf->refcount++;
+
+	entries[group].push_back(AnimEntry());
+	entries[group].back().refCount = 1;
+	entries[group].back().surf = surf;
+}
+
+void CAnimation::purgeCompressed()
+{
+	for (size_t group; group < entries.size(); group++)
+		for (size_t frame; frame < entries[group].size(); frame++)
+			if (entries[group][frame].surf)
+				SDL_FreeSurface(entries[group][frame].surf);
+}
+
+SDL_Surface * CAnimation::image(size_t frame)
+{
+	size_t group=0;
+	for (; group<entries.size() && frame > entries[group].size(); group++)
+		frame -= entries[group].size();
+
+	return image(frame, group);
+}
+
+SDL_Surface * CAnimation::image(size_t frame, size_t group)
+{
+	if ( groupSize(group) > frame )
+	{
+		AnimEntry &e = entries[group][frame];
+		if (!e.surf && e.data)
+			decompress(e);
+		return e.surf;
+	}
+
+	printError(frame, group, "GetImage");
+	return NULL;
+}
+
+void CAnimation::load()
+{
+	CDefFile * file = getFile();
+
+	for (size_t group = 0; group<entries.size(); group++)
+		for (size_t frame = 0; frame<entries[group].size(); frame++)
+			loadFrame(file, frame, group);
+
+	delete file;
+}
+
+void CAnimation::unload()
+{
+	for (size_t group = 0; group<entries.size(); group++)
+		for (size_t frame = 0; frame<entries[group].size(); frame++)
+			unloadFrame(frame, group);
+}
+
+void CAnimation::loadGroup(size_t group)
+{
+	CDefFile * file = getFile();
+
+	for (size_t frame = 0; frame<entries[group].size(); frame++)
+		loadFrame(file, frame, group);
+}
+
+void CAnimation::unloadGroup(size_t group)
+{
+	for (size_t frame = 0; frame<entries[group].size(); frame++)
+		unloadFrame(frame, group);
+}
+
+void CAnimation::load(size_t frame, size_t group)
+{
+	CDefFile * file = getFile();
+	loadFrame(file, frame, group);
+	delete file;
+}
+
+void CAnimation::unload(size_t frame, size_t group)
+{
+	unloadFrame(frame, group);
+}
+
+void CAnimation::load(std::vector <std::pair <size_t, size_t> > frames)
+{
+	CDefFile * file = getFile();
+	for (size_t i=0; i<frames.size(); i++)
+		loadFrame(file, frames[i].second, frames[i].first);
+	delete file;
+}
+
+void CAnimation::unload(std::vector <std::pair <size_t, size_t> > frames)
+{
+	for (size_t i=0; i<frames.size(); i++)
+		unloadFrame(frames[i].second, frames[i].first);
+}
+
+void CAnimation::fixButtonPos()
+{
+	if ( groupSize(0) > 1 )
+		std::swap(entries[0][1].surf, entries[0][0].surf);
+}
+
+size_t CAnimation::groupSize(size_t group) const
+{
+	if (entries.size() > group)
+		return entries[group].size();
+
+	return 0;
+}
+
+size_t CAnimation::size() const
+{
+	size_t ret=0;
+	for (size_t i=0; i<entries.size(); i++)
+	{
+		ret += entries[i].size();
+	}
+	return ret;
+}

+ 177 - 0
hch/CAnimation.h

@@ -0,0 +1,177 @@
+#ifndef __CANIMATION_H__
+#define __CANIMATION_H__
+
+#include <vector>
+#include <string>
+#include <set>
+#include "../global.h"
+
+/*
+ * CAnimation.h, part of VCMI engine
+ *
+ * Authors: listed in file AUTHORS in main folder
+ *
+ * License: GNU General Public License v2.0 or later
+ * Full text of license available in license.txt file, in main folder
+ *
+ */
+
+struct SDL_Surface;
+struct BMPPalette;
+
+//class for def loading, methods are based on CDefHandler
+//after loading will store general info (palette and frame offsets) and pointer to file itself
+class CDefFile
+{
+private:
+
+	struct SSpriteDef
+	{
+		ui32 prSize;
+		ui32 defType2;
+		ui32 FullWidth;
+		ui32 FullHeight;
+		ui32 SpriteWidth;
+		ui32 SpriteHeight;
+		ui32 LeftMargin;
+		ui32 TopMargin;
+	};
+
+	unsigned char * data;
+	int datasize;
+	BMPPalette * colors;
+
+	//offset[group][frame] - offset of frame data in file
+	std::vector< std::vector <size_t> > offset;
+
+	//sorted list of offsets used to determine size
+	std::set <size_t> offList;
+
+
+public:
+	CDefFile(std::string Name);
+	~CDefFile();
+
+	//true if file was opened correctly
+	bool loaded() const;
+
+	//get copy of palette to unpack compressed animation
+	BMPPalette * getPalette();
+
+	//true if frame is present in it
+	bool haveFrame(size_t frame, size_t group) const;
+
+	//get copy of binary data
+	unsigned char * getFrame(size_t frame, size_t group) const;
+
+	//load frame as SDL_Surface
+	SDL_Surface * loadFrame(size_t frame, size_t group) const ;
+
+	//static version of previous one for calling from compressed anim
+	static SDL_Surface * loadFrame(const unsigned char * FDef, const BMPPalette * palette);
+};
+
+// Class for handling animation.
+class CAnimation
+{
+private:
+
+	//internal structure to hold all data of specific frame
+	struct AnimEntry
+	{
+		//surface for this entry
+		SDL_Surface * surf;
+
+		//bitfield, location of image data: 1 - def, 2 - file#9.*, 4 - file#9#2.*
+		unsigned char source;
+
+		//reference count, changed by loadFrame \ unloadFrame
+		size_t refCount;
+
+		//data for CompressedAnim
+		unsigned char * data;
+
+		//size of compressed data, unused for def files
+		size_t dataSize;
+
+		AnimEntry();
+	};
+
+	//animation file name
+	std::string name;
+
+	//if true all frames will be stored in compressed state
+	const bool compressed;
+
+	//palette from def file, used only for compressed anim
+	BMPPalette * defPalette;
+
+	//entries[group][position], store all info regarding frames
+	std::vector< std::vector <AnimEntry> > entries;
+
+	//loader, will be called by load(), require opened def file for loading from it. Returns true if image is loaded
+	bool loadFrame(CDefFile * file, 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);
+
+	//decompress entry data
+	void decompress(AnimEntry &entry);
+
+	//initialize animation from file
+	void init(CDefFile * file);
+
+	//try to open def file
+	CDefFile * getFile() const;
+
+	//to get rid of copy-pasting error message :]
+	void printError(size_t frame, size_t group, std::string type) const;
+
+public:
+
+	CAnimation(std::string Name, bool Compressed = false);
+	CAnimation();
+	~CAnimation();
+
+	//add custom surface to the end of specific group. If shared==true surface needs to be deleted
+	//somewhere outside of CAnim as well (SDL_Surface::refcount will be increased)
+	void add(SDL_Surface * surf, bool shared=false, size_t group=0);
+
+	//removes all surfaces which have compressed data
+	void purgeCompressed();
+
+	//get pointer to surface, this function ignores groups (like ourImages in DefHandler)
+	SDL_Surface * image (size_t frame);
+
+	//get pointer to surface, from specific group
+	SDL_Surface * image(size_t frame, size_t group);
+
+	//all available frames
+	void load  ();
+	void unload();
+
+	//all frames from group
+	void loadGroup  (size_t group);
+	void unloadGroup(size_t group);
+
+	//single image
+	void load  (size_t frame, size_t group=0);
+	void unload(size_t frame, size_t group=0);
+
+	//list of frames (first = group ID, second = frame ID)
+	void load  (std::vector <std::pair <size_t, size_t> > frames);
+	void unload(std::vector <std::pair <size_t, size_t> > frames);
+
+	//helper to fix frame order on some buttons
+	void fixButtonPos();
+
+	//size of specific group, 0 if not present
+	size_t groupSize(size_t group) const;
+
+	//total count of frames in whole anim
+	size_t size() const;
+
+
+};
+
+#endif // __CANIMATIONHANDLER_H__

+ 29 - 12
hch/CLodHandler.cpp

@@ -119,6 +119,17 @@ unsigned char * CLodHandler::giveFile(std::string defName, int * length)
 	return NULL;
 }
 
+bool CLodHandler::haveFile(std::string name)
+{
+	std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper);
+	int dotPos = name.find_last_of('.');
+	if ( dotPos != -1 )
+		name.erase(dotPos);
+		
+	Entry * ourEntry = entries.znajdz(Entry(name));
+	return ourEntry != NULL;
+}
+
 DLL_EXPORT int CLodHandler::infs2(unsigned char * in, int size, int realSize, unsigned char *& out, int wBits)
 {
 	int ret;
@@ -232,12 +243,15 @@ void CLodHandler::init(std::string lodFile, std::string dirName)
 		std::transform(entry.nameStr.begin(), entry.nameStr.end(), 
 					   entry.nameStr.begin(), toupper);
 					   
-		int dotPos = entry.nameStr.find_last_of('.');
-		std::string ext = entry.nameStr.substr(dotPos);
-		if (ext == ".MSK" || ext == ".MSG")
-			entry.nameStr[dotPos] = '#';//this files have same name as def - rename to defName#msk
-		else
-			entry.nameStr.erase(dotPos);//filename.ext becomes filename
+		size_t dotPos = entry.nameStr.find_last_of('.');
+		if ( dotPos < entry.nameStr.size() )
+		{
+			std::string ext = entry.nameStr.substr(dotPos);
+			if (ext == ".MSK" || ext == ".MSG")
+				entry.nameStr[dotPos] = '#';//this files have same name as def - rename to defName#msk
+			else
+				entry.nameStr.erase(dotPos);//filename.ext becomes filename
+		}
 
 		entry.offset= SDL_SwapLE32(lodEntries[i].offset);
 		entry.realSize = SDL_SwapLE32(lodEntries[i].uncompressedSize);
@@ -259,12 +273,15 @@ void CLodHandler::init(std::string lodFile, std::string dirName)
 				std::string realname = name;
 				std::transform(name.begin(), name.end(), name.begin(), (int(*)(int))toupper);
 				
-				int dotPos = name.find_last_of('.');
-				std::string ext = name.substr(dotPos);
-				if (ext == ".MSK" || ext == ".MSG")
-					name[dotPos] = '#';//this files have same name as def - rename to defName#msk
-				else
-					name.erase(dotPos);//filename.ext becomes filename
+				size_t dotPos = name.find_last_of('.');
+				if ( dotPos < name.size() )
+				{
+					std::string ext = name.substr(dotPos);
+					if (ext == ".MSK" || ext == ".MSG")
+						name[dotPos] = '#';//this files have same name as def - rename to defName#msk
+					else
+						name.erase(dotPos);//filename.ext becomes filename
+				}
 				
 				Entry * e = entries.znajdz(name);
 				if(e) //file present in .lod - overwrite its entry

+ 1 - 0
hch/CLodHandler.h

@@ -77,6 +77,7 @@ public:
 	~CLodHandler();
 	int infs2(unsigned char * in, int size, int realSize, unsigned char*& out, int wBits=15); //zlib fast handler
 	unsigned char * giveFile(std::string defName, int * length=NULL); //returns pointer to the decompressed data - it must be deleted when no longer needed!
+	bool haveFile(std::string name);//check if file is present in lod
 	std::string getTextFile(std::string name); //extracts one file
 	void extractFile(std::string FName, std::string name); //extracts a specific file
 	void init(std::string lodFile, std::string dirName);

+ 6 - 6
lib/Connection.h

@@ -283,10 +283,10 @@ public:
 	}
 
 	template <typename T>
-	T* getVectorItemFromId(const VectorisedObjectInfo<T> &oInfo, si32 id) const
+	T* getVectorItemFromId(const VectorisedObjectInfo<T> &oInfo, ui32 id) const
 	{
-		if(id < 0)
-			return NULL;
+	/*	if(id < 0)
+			return NULL;*/
 
 		assert(oInfo.vector);
 		assert(oInfo.vector->size() > id);
@@ -673,14 +673,14 @@ public:
 			typedef typename VectorisedTypeFor<TObjectType>::type VType;									 //eg: CGHeroInstance -> CGobjectInstance
 			if(const VectorisedObjectInfo<VType> *info = getVectorisedTypeInfo<VType>())
 			{
-				si32 id;
+				ui32 id;
 				*this >> id;
 				data = static_cast<T>(getVectorItemFromId(*info, id));
 				return;
 			}
 		}
 
-		ui32 pid = -1; //pointer id (or maybe rather pointee id) 
+		ui32 pid = 0xffffffff; //pointer id (or maybe rather pointee id) 
 		if(smartPointerSerialization)
 		{
 			*this >> pid; //get the id
@@ -721,7 +721,7 @@ public:
 	template <typename T>
 	void ptrAllocated(const T *ptr, ui32 pid)
 	{
-		if(smartPointerSerialization && pid != -1)
+		if(smartPointerSerialization && pid != 0xffffffff)
 			loadedPointers[pid] = (void*)ptr; //add loaded pointer to our lookup map; cast is to avoid errors with const T* pt
 	}
 

Some files were not shown because too many files changed in this diff