Browse Source

* BitmapHandler thread-safe
* multi-threaded loading main graphics

Michał W. Urbańczyk 17 years ago
parent
commit
3988767329
8 changed files with 156 additions and 62 deletions
  1. 35 0
      CThreadHelper.cpp
  2. 38 0
      CThreadHelper.h
  3. 10 2
      client/CBitmapHandler.cpp
  4. 1 1
      client/CBitmapHandler.h
  5. 47 42
      client/Graphics.cpp
  6. 1 0
      client/Graphics.h
  7. 24 0
      client/VCMI_client.vcproj
  8. 0 17
      hch/CLodHandler.cpp

+ 35 - 0
CThreadHelper.cpp

@@ -0,0 +1,35 @@
+#include "CThreadHelper.h"
+#include <boost/thread.hpp>
+#include <boost/bind.hpp>
+CThreadHelper::CThreadHelper(std::vector<boost::function<void()> > *Tasks, int Threads)
+{
+	currentTask = 0; amount = Tasks->size();
+	tasks = Tasks;
+	threads = Threads;
+}
+void CThreadHelper::run()
+{
+	boost::thread_group grupa;
+	for(int i=0;i<threads;i++)
+		grupa.create_thread(boost::bind(&CThreadHelper::processTasks,this));
+	grupa.join_all();
+}
+void CThreadHelper::processTasks()
+{
+	int pom;
+	while(true)
+	{
+		rtinm.lock();
+		if((pom=currentTask) >= amount)
+		{
+			rtinm.unlock();
+			break;
+		}
+		else
+		{
+			++currentTask;
+			rtinm.unlock();
+			(*tasks)[pom]();
+		}
+	}
+}

+ 38 - 0
CThreadHelper.h

@@ -0,0 +1,38 @@
+#include "global.h"
+#include <boost/function.hpp>
+#include <boost/thread.hpp>
+typedef boost::function<void()> Task;
+
+class CThreadHelper
+{
+	boost::mutex rtinm;
+	int currentTask, amount, threads;
+	std::vector<Task> *tasks;
+
+
+	void processTasks();
+public:
+	CThreadHelper(std::vector<boost::function<void()> > *Tasks, int Threads);
+	void run();
+};
+
+template <typename T> inline void setData(T * data, boost::function<T()> func)
+{
+	*data = func();
+}
+
+
+#define GET_DATA(TYPE,DESTINATION,FUNCTION_TO_GET) \
+	(boost::bind(&setData<TYPE>,&DESTINATION,FUNCTION_TO_GET))
+#define GET_SURFACE(SUR_DESTINATION, SUR_NAME) \
+	(GET_DATA \
+		(SDL_Surface*,SUR_DESTINATION,\
+		boost::function<SDL_Surface*()>(boost::bind(&BitmapHandler::loadBitmap,SUR_NAME,true))))
+#define GET_DEF(DESTINATION, DEF_NAME) \
+	(GET_DATA \
+		(CDefHandler*,DESTINATION,\
+		boost::function<CDefHandler*()>(boost::bind(CDefHandler::giveDef,DEF_NAME,(CLodHandler*)NULL))))
+#define GET_DEF_ESS(DESTINATION, DEF_NAME) \
+	(GET_DATA \
+		(CDefEssential*,DESTINATION,\
+		boost::function<CDefEssential*()>(boost::bind(CDefHandler::giveDefEss,DEF_NAME,(CLodHandler*)NULL))))

+ 10 - 2
client/CBitmapHandler.cpp

@@ -5,6 +5,8 @@
 #include "../hch/CDefHandler.h"
 #include "../hch/CLodHandler.h"
 #include <sstream>
+#include <boost/thread.hpp>
+boost::mutex bitmap_handler_mx;
 int readNormalNr (int pos, int bytCon, unsigned char * str);
 CLodHandler * BitmapHandler::bitmaph = NULL;
 void BMPHeader::print(std::ostream & out)
@@ -253,7 +255,7 @@ SDL_Surface * CPCXConv::getSurface()
 	return ret;
 }
 
-SDL_Surface * BitmapHandler::loadBitmap(std::string fname)
+SDL_Surface * BitmapHandler::loadBitmap(std::string fname, bool setKey)
 {
 	if(!fname.size())
 		return NULL;
@@ -309,16 +311,19 @@ SDL_Surface * BitmapHandler::loadBitmap(std::string fname)
 			}
 		}
 	}
+	bitmap_handler_mx.lock();
 	fseek(bitmaph->FLOD, e->offset, 0);
 	if (e->size==0) //file is not compressed
 	{
 		pcx = new unsigned char[e->realSize];
 		fread((char*)pcx, 1, e->realSize, bitmaph->FLOD);
+		bitmap_handler_mx.unlock();
 	}
 	else 
 	{
 		unsigned char * pcd = new unsigned char[e->size];
 		fread((char*)pcd, 1, e->size, bitmaph->FLOD);
+		bitmap_handler_mx.unlock();
 		int res=bitmaph->infs2(pcd,e->size,e->realSize,pcx);
 		if(res!=0)
 		{
@@ -328,5 +333,8 @@ SDL_Surface * BitmapHandler::loadBitmap(std::string fname)
 	}
 	CPCXConv cp;
 	cp.openPCX((char*)pcx,e->realSize);
-	return cp.getSurface();
+	SDL_Surface * ret = cp.getSurface();
+	if(setKey)
+		SDL_SetColorKey(ret,SDL_SRCCOLORKEY,SDL_MapRGB(ret->format,0,255,255));
+	return ret;
 }

+ 1 - 1
client/CBitmapHandler.h

@@ -35,5 +35,5 @@ public:
 namespace BitmapHandler
 {
 	extern CLodHandler *bitmaph;
-	SDL_Surface * loadBitmap(std::string fname);
+	SDL_Surface * loadBitmap(std::string fname, bool setKey=false);
 };

+ 47 - 42
client/Graphics.cpp

@@ -8,7 +8,11 @@
 #include <sstream>
 #include <iomanip>
 #include <boost/thread.hpp>
+#include <boost/function.hpp>
 #include <boost/bind.hpp>
+#include <boost/assign/std/vector.hpp>
+#include "../CThreadHelper.h"
+using namespace boost::assign;
 using namespace CSDL_Ext;
 Graphics * graphics = NULL;
 SDL_Surface * Graphics::drawPrimarySkill(const CGHeroInstance *curh, SDL_Surface *ret, int from, int to)
@@ -80,11 +84,6 @@ SDL_Surface * Graphics::drawTownInfoWin(const CGTownInstance * curh)
 }
 Graphics::Graphics()
 {
-	artDefs = CDefHandler::giveDef("ARTIFACT.DEF");
-	hInfo = BitmapHandler::loadBitmap("HEROQVBK.bmp");
-	SDL_SetColorKey(hInfo,SDL_SRCCOLORKEY,SDL_MapRGB(hInfo->format,0,255,255));
-	tInfo = BitmapHandler::loadBitmap("TOWNQVBK.bmp");
-	SDL_SetColorKey(tInfo,SDL_SRCCOLORKEY,SDL_MapRGB(tInfo->format,0,255,255));
 	slotsPos.push_back(std::pair<int,int>(44,82));
 	slotsPos.push_back(std::pair<int,int>(80,82));
 	slotsPos.push_back(std::pair<int,int>(116,82));
@@ -93,45 +92,61 @@ Graphics::Graphics()
 	slotsPos.push_back(std::pair<int,int>(98,131));
 	slotsPos.push_back(std::pair<int,int>(134,131));
 
-	luck22 = CDefHandler::giveDefEss("ILCK22.DEF");
-	luck30 = CDefHandler::giveDefEss("ILCK30.DEF");
-	luck42 = CDefHandler::giveDefEss("ILCK42.DEF");
-	luck82 = CDefHandler::giveDefEss("ILCK82.DEF");
-	morale22 = CDefHandler::giveDefEss("IMRL22.DEF");
-	morale30 = CDefHandler::giveDefEss("IMRL30.DEF");
-	morale42 = CDefHandler::giveDefEss("IMRL42.DEF");
-	morale82 = CDefHandler::giveDefEss("IMRL82.DEF");
-	halls = CDefHandler::giveDefEss("ITMTLS.DEF");
-	forts = CDefHandler::giveDefEss("ITMCLS.DEF");
-	bigTownPic =  CDefHandler::giveDefEss("ITPT.DEF");
-	std::ifstream ifs;
-	ifs.open("config/cr_bgs.txt"); 
+	CDefHandler *smi, *smi2;
+
+	std::vector<Task> tasks; //preparing list of graphics to load
+	tasks += boost::bind(&Graphics::loadHeroFlags,this);
+	tasks += boost::bind(&Graphics::loadHeroPortraits,this);
+	tasks += GET_SURFACE(hInfo,"HEROQVBK.bmp");
+	tasks += GET_SURFACE(tInfo,"TOWNQVBK.bmp");
+	tasks += GET_DEF(artDefs,"ARTIFACT.DEF");
+	tasks += GET_DEF_ESS(forts,"ITMCLS.DEF");
+	tasks += GET_DEF_ESS(luck22,"ILCK22.DEF");
+	tasks += GET_DEF_ESS(luck30,"ILCK30.DEF");
+	tasks += GET_DEF_ESS(luck42,"ILCK42.DEF");
+	tasks += GET_DEF_ESS(luck82,"ILCK82.DEF");
+	tasks += GET_DEF_ESS(morale22,"IMRL22.DEF");
+	tasks += GET_DEF_ESS(morale30,"IMRL30.DEF");
+	tasks += GET_DEF_ESS(morale42,"IMRL42.DEF");
+	tasks += GET_DEF_ESS(morale82,"IMRL82.DEF");
+	tasks += GET_DEF_ESS(halls,"ITMTLS.DEF");
+	tasks += GET_DEF_ESS(bigTownPic,"ITPT.DEF");
+	tasks += GET_DEF(pskillsb,"PSKILL.DEF");
+	tasks += GET_DEF(resources,"RESOUR82.DEF");
+	tasks += GET_DEF(un44,"UN44.DEF");
+	tasks += GET_DEF(smallIcons,"ITPA.DEF");
+	tasks += GET_DEF(resources32,"RESOURCE.DEF");
+	tasks += GET_DEF(smi,"CPRSMALL.DEF");
+	tasks += GET_DEF(smi2,"TWCRPORT.DEF");
+
+	std::ifstream ifs("config/cr_bgs.txt"); 
+	int id;
+	std::string name;
 	while(!ifs.eof())
 	{
-		int id;
-		std::string name;
 		ifs >> id >> name;
-		backgrounds[id]=BitmapHandler::loadBitmap(name);
+		tasks += GET_SURFACE(backgrounds[id],name);
 	}
-	ifs.close();
-	ifs.clear();
 
-	//loading 32x32px imgs
-	CDefHandler *smi = CDefHandler::giveDef("CPRSMALL.DEF");
+	CThreadHelper th(&tasks,max(1,boost::thread::hardware_concurrency()));
+	th.run();
+
+	//handling 32x32px imgs
 	smi->notFreeImgs = true;
 	for (int i=0; i<smi->ourImages.size(); i++)
 	{
 		smallImgs[i-2] = smi->ourImages[i].bitmap;
 	}
 	delete smi;
-	smi = CDefHandler::giveDef("TWCRPORT.DEF");
-	smi->notFreeImgs = true;
-	for (int i=0; i<smi->ourImages.size(); i++)
+	smi2->notFreeImgs = true;
+	for (int i=0; i<smi2->ourImages.size(); i++)
 	{
-		bigImgs[i-2] = smi->ourImages[i].bitmap;
+		bigImgs[i-2] = smi2->ourImages[i].bitmap;
 	}
-	delete smi;
-
+	delete smi2;
+}
+void Graphics::loadHeroPortraits()
+{	
 	std::ifstream of("config/portrety.txt");
 	for (int j=0;j<HEROES_QUANTITY;j++)
 	{
@@ -140,8 +155,6 @@ Graphics::Graphics()
 		std::string path;
 		of>>path;
 		portraitSmall.push_back(BitmapHandler::loadBitmap(path));
-		//if (!heroes[ID]->portraitSmall)
-		//	std::cout<<"Can't read small portrait for "<<ID<<" ("<<path<<")\n";
 		for(int ff=0; ff<path.size(); ++ff) //size letter is usually third one, but there are exceptions an it should fix the problem
 		{
 			if(path[ff]=='S')
@@ -151,18 +164,10 @@ Graphics::Graphics()
 			}
 		}
 		portraitLarge.push_back(BitmapHandler::loadBitmap(path));
-		//if (!heroes[ID]->portraitLarge)
-		//	std::cout<<"Can't read large portrait for "<<ID<<" ("<<path<<")\n";	
 		SDL_SetColorKey(portraitLarge[portraitLarge.size()-1],SDL_SRCCOLORKEY,SDL_MapRGB(portraitLarge[portraitLarge.size()-1]->format,0,255,255));
 
 	}
 	of.close();
-	pskillsb = CDefHandler::giveDef("PSKILL.DEF");
-	resources = CDefHandler::giveDef("RESOUR82.DEF");
-	un44 = CDefHandler::giveDef("UN44.DEF");
-	smallIcons = CDefHandler::giveDef("ITPA.DEF");
-	resources32 = CDefHandler::giveDef("RESOURCE.DEF");
-	loadHeroFlags();
 }
 void Graphics::loadHeroAnim(std::vector<CDefHandler **> & anims)
 {
@@ -377,7 +382,7 @@ void Graphics::loadHeroFlags()
 	grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[1]),false));
 	grupa.create_thread(boost::bind(&Graphics::loadHeroFlags,this,boost::ref(pr[0]),false));
 	grupa.join_all();
-	std::cout << "Flagi: "<<th.getDif()<<std::endl;
+	std::cout << "Loading and transforming heroes' flags: "<<th.getDif()<<std::endl;
 }
 SDL_Surface * Graphics::getPic(int ID, bool fort, bool builded)
 {

+ 1 - 0
client/Graphics.h

@@ -34,6 +34,7 @@ public:
 	void loadHeroFlags();
 	void loadHeroFlags(std::pair<std::vector<CDefHandler *> Graphics::*, std::vector<const char *> > &pr, bool mode);
 	void loadHeroAnim(std::vector<CDefHandler **> & anims);
+	void loadHeroPortraits();
 	SDL_Surface * drawHeroInfoWin(const CGHeroInstance * curh);
 	SDL_Surface * drawPrimarySkill(const CGHeroInstance *curh, SDL_Surface *ret, int from=0, int to=PRIMARY_SKILLS);
 	SDL_Surface * drawTownInfoWin(const CGTownInstance * curh);

+ 24 - 0
client/VCMI_client.vcproj

@@ -376,6 +376,10 @@
 				RelativePath="..\hch\CSpellHandler.cpp"
 				>
 			</File>
+			<File
+				RelativePath="..\CThreadHelper.cpp"
+				>
+			</File>
 			<File
 				RelativePath=".\Graphics.cpp"
 				>
@@ -558,6 +562,10 @@
 				RelativePath="..\hch\CAmbarCendamo.h"
 				>
 			</File>
+			<File
+				RelativePath="..\hch\CArtHandler.h"
+				>
+			</File>
 			<File
 				RelativePath="..\CBattleInterface.h"
 				>
@@ -586,6 +594,10 @@
 				RelativePath=".\CCreatureAnimation.h"
 				>
 			</File>
+			<File
+				RelativePath="..\hch\CCreatureHandler.h"
+				>
+			</File>
 			<File
 				RelativePath="..\CCursorHandler.h"
 				>
@@ -610,6 +622,10 @@
 				RelativePath="..\hch\CGeneralTextHandler.h"
 				>
 			</File>
+			<File
+				RelativePath="..\hch\CHeroHandler.h"
+				>
+			</File>
 			<File
 				RelativePath="..\CHeroWindow.h"
 				>
@@ -630,6 +646,10 @@
 				RelativePath="..\hch\CMusicHandler.h"
 				>
 			</File>
+			<File
+				RelativePath="..\hch\CObjectHandler.h"
+				>
+			</File>
 			<File
 				RelativePath="..\CPathfinder.h"
 				>
@@ -658,6 +678,10 @@
 				RelativePath="..\hch\CSpellHandler.h"
 				>
 			</File>
+			<File
+				RelativePath="..\CThreadHelper.h"
+				>
+			</File>
 			<File
 				RelativePath="..\global.h"
 				>

+ 0 - 17
hch/CLodHandler.cpp

@@ -176,12 +176,6 @@ DLL_EXPORT int CLodHandler::infs2(unsigned char * in, int size, int realSize, un
 		}
 		++chunkNumber;
 		strm.avail_in = readBytes;
-		//strm.avail_in = fread(inx, 1, NLoadHandlerHelp::fCHUNK, source);
-		/*if (in.bad())
-		{
-			(void)inflateEnd(&strm);
-			return Z_ERRNO;
-		}*/
 		if (strm.avail_in == 0)
 			break;
 		strm.next_in = inx;
@@ -203,22 +197,11 @@ DLL_EXPORT int CLodHandler::infs2(unsigned char * in, int size, int realSize, un
 					return ret;
 			}
 			have = NLoadHandlerHelp::fCHUNK - strm.avail_out;
-			/*if (fwrite(out, 1, have, dest) != have || ferror(dest))
-			{
-				(void)inflateEnd(&strm);
-				return Z_ERRNO;
-			}*/
-			//out.write((char*)outx, have);
 			for(int oo=0; oo<have; ++oo)
 			{
 				out[latPosOut] = outx[oo];
 				++latPosOut;
 			}
-			/*if(out.bad())
-			{
-				(void)inflateEnd(&strm);
-				return Z_ERRNO;
-			}*/
 		} while (strm.avail_out == 0);
 
 		/* done when inflate() says it's done */