فهرست منبع

Finished BIK handler. Refactored CVideoPlayer. Added intro and main menu animation. (Win only).

Michał W. Urbańczyk 16 سال پیش
والد
کامیت
60f7048662
5فایلهای تغییر یافته به همراه455 افزوده شده و 293 حذف شده
  1. 93 69
      client/CMT.cpp
  2. 17 6
      client/CPreGame.cpp
  3. 51 18
      client/CSpellWindow.cpp
  4. 246 159
      hch/CVideoHandler.cpp
  5. 48 41
      hch/CVideoHandler.h

+ 93 - 69
client/CMT.cpp

@@ -70,6 +70,67 @@ TTF_Font * TNRB16, *TNR, *GEOR13, *GEORXX, *GEORM, *GEOR16;
 void processCommand(const std::string &message, CClient *&client);
 static void setScreenRes(int w, int h, int bpp, bool fullscreen);
 void dispose();
+void playIntro();
+
+void init()
+{
+	timeHandler tmh, pomtime;
+#if SDL_BYTEORDER == SDL_BIG_ENDIAN
+	int rmask = 0xff000000;int gmask = 0x00ff0000;int bmask = 0x0000ff00;int amask = 0x000000ff;
+#else
+	int rmask = 0x000000ff;	int gmask = 0x0000ff00;	int bmask = 0x00ff0000;	int amask = 0xff000000;
+#endif
+	CSDL_Ext::std32bppSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, rmask, gmask, bmask, amask);
+	tlog0 << "\tInitializing minors: " << pomtime.getDif() << std::endl;
+
+	TTF_Init();
+	atexit(TTF_Quit);
+	TNRB16 = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",16);
+	GEOR13 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",13);
+	GEOR16 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",16);
+	GEORXX = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",22);
+	GEORM = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",10);
+	if(! (TNRB16 && GEOR16 && GEORXX && GEORM))
+	{
+		tlog1 << "One of the fonts couldn't be loaded!\n";
+		exit(-1);
+	}
+	THC tlog0<<"\tInitializing fonts: "<<pomtime.getDif()<<std::endl;
+
+	//initializing audio
+	// Note: because of interface button range, volume can only be a
+	// multiple of 11, from 0 to 99.
+	CGI->soundh = new CSoundHandler;
+	CGI->soundh->init();
+	CGI->soundh->setVolume(88);
+	CGI->musich = new CMusicHandler;
+	CGI->musich->init();
+	CGI->musich->setVolume(88);
+	tlog0<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
+	tlog0<<"Initializing screen, fonts and sound handling: "<<tmh.getDif()<<std::endl;
+
+	initDLL(::console,logfile);
+	CGI->setFromLib();
+	CGI->soundh->initCreaturesSounds(CGI->creh->creatures);
+	CGI->soundh->initSpellsSounds(CGI->spellh->spells);
+	tlog0<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
+
+	pomtime.getDif();
+	CGI->curh = new CCursorHandler;
+	CGI->curh->initCursor();
+	CGI->curh->show();
+	tlog0<<"Screen handler: "<<pomtime.getDif()<<std::endl;
+	pomtime.getDif();
+	graphics = new Graphics();
+	graphics->loadHeroAnim();
+	tlog0<<"\tMain graphics: "<<tmh.getDif()<<std::endl;
+	tlog0<<"Initializing game graphics: "<<tmh.getDif()<<std::endl;
+
+	CMessage::init();
+	tlog0<<"Message handler: "<<tmh.getDif()<<std::endl;
+	CPG = new CPreGame(); //main menu and submenus
+	tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
+}
 
 #ifndef __GNUC__
 int _tmain(int argc, _TCHAR* argv[])
@@ -77,9 +138,8 @@ int _tmain(int argc, _TCHAR* argv[])
 int main(int argc, char** argv)
 #endif
 {
-
 	tlog0 << "Starting... " << std::endl;
-	THC timeHandler tmh, total, pomtime;
+	timeHandler total, pomtime;
 	CClient *client = NULL;
 	std::cout.flags(std::ios::unitbuf);
 	logfile = new std::ofstream("VCMI_Client_log.txt");
@@ -95,77 +155,29 @@ int main(int argc, char** argv)
 	srand ( time(NULL) );
 	CPG=NULL;
 	atexit(SDL_Quit);
-	CGameInfo * cgi = CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler itp.)
+	CGI = new CGameInfo; //contains all global informations about game (texts, lodHandlers, map handler itp.)
 	if(SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO)==0)
 	{
 		setScreenRes(800,600,conf.cc.bpp,conf.cc.fullscreen);
 		tlog0 <<"\tInitializing screen: "<<pomtime.getDif() << std::endl;
 
-		#if SDL_BYTEORDER == SDL_BIG_ENDIAN
-			int rmask = 0xff000000;int gmask = 0x00ff0000;int bmask = 0x0000ff00;int amask = 0x000000ff;
-		#else
-			int rmask = 0x000000ff;	int gmask = 0x0000ff00;	int bmask = 0x00ff0000;	int amask = 0xff000000;
-		#endif
-		CSDL_Ext::std32bppSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, 1, 1, 32, rmask, gmask, bmask, amask);
-		tlog0 << "\tInitializing minors: " << pomtime.getDif() << std::endl;
-
-		TTF_Init();
-		TNRB16 = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",16);
-		GEOR13 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",13);
-		GEOR16 = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",16);
-		GEORXX = TTF_OpenFont("Fonts" PATHSEPARATOR "tnrb.ttf",22);
-		GEORM = TTF_OpenFont("Fonts" PATHSEPARATOR "georgia.ttf",10);
-		if(! (TNRB16 && GEOR16 && GEORXX && GEORM))
-		{
-			tlog1 << "One of the fonts couldn't be loaded!\n";
-			throw "One of the fonts couldn't be loaded!\n";
-		}
-		atexit(TTF_Quit);
-		THC tlog0<<"\tInitializing fonts: "<<pomtime.getDif()<<std::endl;
-
-		//initializing audio
-		// Note: because of interface button range, volume can only be a
-		// multiple of 11, from 0 to 99.
-		cgi->soundh = new CSoundHandler;
-		cgi->soundh->init();
-		cgi->soundh->setVolume(88);
-		cgi->musich = new CMusicHandler;
-		cgi->musich->init();
-		cgi->musich->setVolume(88);
-		tlog0<<"\tInitializing sound: "<<pomtime.getDif()<<std::endl;
-
 		// Initialize video
-		cgi->videoh = new CVideoPlayer;
+		CGI->videoh = new CVideoPlayer;
 		tlog0<<"\tInitializing video: "<<pomtime.getDif()<<std::endl;
 
-		tlog0<<"Initializing screen, fonts and sound handling: "<<tmh.getDif()<<std::endl;
-		initDLL(::console,logfile);
-		CGI->setFromLib();
-		cgi->soundh->initCreaturesSounds(CGI->creh->creatures);
-		cgi->soundh->initSpellsSounds(CGI->spellh->spells);
-		tlog0<<"Initializing VCMI_Lib: "<<tmh.getDif()<<std::endl;
-
-		pomtime.getDif();
-		cgi->curh = new CCursorHandler;
-		cgi->curh->initCursor();
-		cgi->curh->show();
-		tlog0<<"Screen handler: "<<pomtime.getDif()<<std::endl;
-		pomtime.getDif();
-		graphics = new Graphics();
-		graphics->loadHeroAnim();
-		tlog0<<"\tMain graphics: "<<tmh.getDif()<<std::endl;
-		tlog0<<"Initializing game graphics: "<<tmh.getDif()<<std::endl;
-
-		CMessage::init();
-		tlog0<<"Message handler: "<<tmh.getDif()<<std::endl;
-		CPreGame * cpg = new CPreGame(); //main menu and submenus
-		tlog0<<"Initialization CPreGame (together): "<<tmh.getDif()<<std::endl;
+		//we can properly play intro only in the main thread, so we have to move loading to the separate thread
+		boost::thread loading(init);
+		playIntro();
+		SDL_FillRect(screen,NULL,0);
+		SDL_Flip(screen);
+		loading.join();
 		tlog0<<"Initialization of VCMI (together): "<<total.getDif()<<std::endl;
 
-		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
 
-		cgi->musich->playMusic(musicBase::mainMenu, -1);
-		StartInfo *options = new StartInfo(cpg->runLoop());
+		SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
+		CGI->musich->playMusic(musicBase::mainMenu, -1);
+		CPG->showMainMenu();
+		StartInfo *options = new StartInfo(CPG->runLoop());
 
 		if(screen->w != conf.cc.resx   ||   screen->h != conf.cc.resy)
 		{
@@ -174,19 +186,19 @@ int main(int argc, char** argv)
 		CClient cl;
 		if(options->mode == 0) //new game
 		{
-			tmh.getDif();
+			pomtime.getDif();
 			char portc[10];
 			SDL_itoa(conf.cc.port,portc,10);
 			CClient::runServer(portc);
-			tlog0<<"Preparing shared memory and starting server: "<<tmh.getDif()<<std::endl;
+			tlog0<<"Preparing shared memory and starting server: "<<pomtime.getDif()<<std::endl;
 
-			tmh.getDif();pomtime.getDif();//reset timers
+			pomtime.getDif();//reset timers
 
 			CConnection *c=NULL;
 			//wait until server is ready
 			tlog0<<"Waiting for server... ";
 			cl.waitForServer();
-			tlog0 << tmh.getDif()<<std::endl;
+			tlog0 << pomtime.getDif()<<std::endl;
 			while(!c)
 			{
 				try
@@ -200,10 +212,10 @@ int main(int argc, char** argv)
 					SDL_Delay(2000);
 				}
 			}
-			THC tlog0<<"\tConnecting to the server: "<<tmh.getDif()<<std::endl;
+			THC tlog0<<"\tConnecting to the server: "<<pomtime.getDif()<<std::endl;
 			cl.newGame(c,options);
 			client = &cl;
-			cgi->musich->stopMusic();
+			CGI->musich->stopMusic();
 			boost::thread t(boost::bind(&CClient::run,&cl));
 		}
 		else //load game
@@ -212,7 +224,7 @@ int main(int argc, char** argv)
 			boost::algorithm::erase_last(fname,".vlgm1");
 			cl.load(fname);
 			client = &cl;
-			cgi->musich->stopMusic();
+			CGI->musich->stopMusic();
 			boost::thread t(boost::bind(&CClient::run,&cl));
 		}
 
@@ -354,6 +366,18 @@ void processCommand(const std::string &message, CClient *&client)
 	}
 }
 
+
+//plays intro, ends when intro is over or button has been pressed (handles events)
+void playIntro()
+{
+#ifdef _WIN32
+	if(CGI->videoh->openAndPlayVideo("3DOLOGO.SMK", 60, 40, screen, true))
+	{
+		CGI->videoh->openAndPlayVideo("AZVS.SMK", 60, 80, screen, true);
+	}
+#endif
+}
+
 void dispose()
 {
 	delete logfile;

+ 17 - 6
client/CPreGame.cpp

@@ -23,6 +23,7 @@
 #include <cstdlib>
 #include "../lib/Connection.h"
 #include "../hch/CMusicHandler.h"
+#include "../hch/CVideoHandler.h"
 /*
  * CPreGame.cpp, part of VCMI engine
  *
@@ -1593,8 +1594,6 @@ CPreGame::CPreGame()
 	tlog0<<"\tCPreGame: scenario choice initialization: "<<tmh.getDif()<<std::endl;
 	initOptions();
 	tlog0<<"\tCPreGame: scenario options initialization: "<<tmh.getDif()<<std::endl;
-	showMainMenu();
-	tlog0<<"\tCPreGame: displaying main menu: "<<tmh.getDif()<<std::endl;
 	playerName="Player";
 }
 void CPreGame::initOptions()
@@ -1777,7 +1776,7 @@ void CPreGame::showNewMenu()
 	SDL_BlitSurface(ourNewMenu->credits->ourImages[0].bitmap,NULL,screen,&ourNewMenu->lCredits);
 	SDL_BlitSurface(ourNewMenu->quit->ourImages[0].bitmap,NULL,screen,&ourNewMenu->lQuit);
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 	first = true;
 }
 void CPreGame::initMainMenu()
@@ -1835,7 +1834,7 @@ void CPreGame::showMainMenu()
 	SDL_BlitSurface(ourMainMenu->credits->ourImages[0].bitmap,NULL,screen,&ourMainMenu->lCredits);
 	SDL_BlitSurface(ourMainMenu->quit->ourImages[0].bitmap,NULL,screen,&ourMainMenu->lQuit);
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 }
 void CPreGame::highlightButton(int which, int on)
 {
@@ -1870,7 +1869,7 @@ void CPreGame::highlightButton(int which, int on)
 		}
 	}
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 }
 void CPreGame::showCenBox (std::string data)
 {
@@ -2054,6 +2053,11 @@ StartInfo CPreGame::runLoop()
 	SDL_Event sEvent;
 	ret.turnTime = 0;
 
+#ifdef _WIN32
+	CGI->videoh->open("ACREDIT.SMK");
+	CGI->videoh->show(8, 105, screen, false);
+#endif
+
 	while(run)
 	{
 		try
@@ -2321,12 +2325,19 @@ StartInfo CPreGame::runLoop()
 			}
 		} HANDLE_EXCEPTION
 
+#ifdef _WIN32
+		if(currentItems())
+			CGI->videoh->update(8, 105, screen, true, false);
+#endif
+
 		CGI->curh->draw1();
 		SDL_Flip(screen);
 		CGI->curh->draw2();
 		SDL_Delay(20); //give time for other apps
 	}
 	ret.mode = (fromMenu==newGame) ? 0 : 1;
+	CGI->videoh->close();
+
 	return ret;
 }
 std::string CPreGame::buttonText(int which)
@@ -2454,7 +2465,7 @@ void CPreGame::showLoadMenu()
 	SDL_BlitSurface(ourLoadMenu->credits->ourImages[0].bitmap,NULL,screen,&ourLoadMenu->lCredits);
 	SDL_BlitSurface(ourLoadMenu->quit->ourImages[0].bitmap,NULL,screen,&ourLoadMenu->lQuit);
 	//SDL_Flip(screen);
-	CSDL_Ext::update(screen);
+	//CSDL_Ext::update(screen);
 	first = true;
 }
 

+ 51 - 18
client/CSpellWindow.cpp

@@ -639,43 +639,76 @@ void CSpellWindow::deactivate()
 void CSpellWindow::turnPageLeft()
 {
 	// Note: video decoders are different, and one is buggy.
-#ifdef _WIN32
-	const int y = pos.y+15;
-#else
-	const int y = pos.y+14;
-#endif	
 
-	if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, y)) {
-		while(CGI->videoh->nextFrame()) {
-			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 #ifndef _WIN32
+	if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, pos.y+14)) 
+	{
+		while(CGI->videoh->nextFrame()) 
+		{
+			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
-#endif
 		}
 		CGI->videoh->close();
 	}
+#else
+	CGI->videoh->openAndPlayVideo("PGTRNLFT.SMK", pos.x+13, pos.y+15, screen);
+#endif
+
+
+//#ifdef _WIN32
+//	const int y = pos.y+15;
+//
+//#endif	
+//
+//	if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, y)) {
+//		while(CGI->videoh->nextFrame()) {
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#ifndef _WIN32
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#endif
+//		}
+//		CGI->videoh->close();
+//	}
 }
 
 void CSpellWindow::turnPageRight()
 {
 	// Note: video decoders are different, and one is buggy.
-#ifdef _WIN32
-	const int y = pos.y+15;
-#else
-	const int y = pos.y+14;
-#endif	
 
-	if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, y)) {
-		while(CGI->videoh->nextFrame()) {
-			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+
 #ifndef _WIN32
+	if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, pos.y+14)) 
+	{
+		while(CGI->videoh->nextFrame()) 
+		{
+			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
 			SDL_framerateDelay(LOCPLINT->mainFPSmng);
-#endif
 		}
 		CGI->videoh->close();
 	}
+#else
+	CGI->videoh->openAndPlayVideo("PGTRNRGH.SMK", pos.x+13, pos.y+15, screen);
+#endif
+
+//#ifdef _WIN32
+//	const int y = pos.y+15;
+//#else
+//	const int y = pos.y+14;
+//#endif	
+//
+//	if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, y)) {
+//		while(CGI->videoh->nextFrame()) {
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#ifndef _WIN32
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//			SDL_framerateDelay(LOCPLINT->mainFPSmng);
+//#endif
+//		}
+//		CGI->videoh->close();
+//	}
 }
 
 CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner)

+ 246 - 159
hch/CVideoHandler.cpp

@@ -7,14 +7,53 @@
 #ifdef _WIN32
 
 #include "../client/SDL_Extensions.h"
+#include <boost/algorithm/string/predicate.hpp>
 
 
+void checkForError(bool throwing = true)
+{
+#ifdef _WIN32
+	int error = GetLastError();
+	if(!error)
+		return;
+
+
+	tlog1 << "Error " << error << " encountered!\n";
+	std::string msg;
+	char* pTemp = NULL;
+	FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
+		NULL, error,  MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT ), (LPSTR)&pTemp, 1, NULL );
+	tlog1 << "Error: " << pTemp << std::endl;
+	msg = pTemp;
+	LocalFree( pTemp );
+	pTemp = NULL;
+	if(throwing)
+		throw msg;
+#endif
+}
+
+void blitBuffer(char *buffer, int x, int y, int w, int h, SDL_Surface *dst)
+{
+	const int bpp = dst->format->BytesPerPixel;	
+	char *dest;
+	for(int i = h; i > 0; i--)
+	{
+		dest = (char*)dst->pixels + dst->pitch*(y+h-i) + x*dst->format->BytesPerPixel;
+		memcpy(dest, buffer, bpp*w);
+		buffer += bpp*w;
+	}
+}
 
 void DLLHandler::Instantiate(const char *filename)
 {
 	name = filename;
 #ifdef _WIN32
 	dll = LoadLibraryA(filename);
+	if(!dll)
+	{
+		tlog1 << "Failed loading " << filename << std::endl;
+		checkForError();
+	}
 #else
 	dll = dlopen(filename,RTLD_LOCAL | RTLD_LAZY);
 #endif
@@ -22,11 +61,18 @@ void DLLHandler::Instantiate(const char *filename)
 
 void *DLLHandler::FindAddress(const char *symbol)
 {
+	void *ret;
 #ifdef _WIN32
-	return (void*) GetProcAddress(dll,symbol);
+	ret = (void*) GetProcAddress(dll,symbol);
+	if(!ret)
+	{
+		tlog1 << "Failed to find " << symbol << " in " << name << std::endl;
+		checkForError();
+	}
 #else
-	return (void *)dlsym(dll, symbol);
+	ret = (void *)dlsym(dll, symbol);
 #endif
+	return ret;
 }
 
 DLLHandler::~DLLHandler()
@@ -34,7 +80,11 @@ DLLHandler::~DLLHandler()
 	if(dll)
 	{
 	#ifdef _WIN32
-		FreeLibrary(dll);
+		if(!FreeLibrary(dll))
+		{
+			tlog1 << "Failed to free " << name << std::endl;
+			checkForError();
+		}
 	#else
 		dlclose(dll);
 	#endif
@@ -46,29 +96,22 @@ DLLHandler::DLLHandler()
 	dll = NULL;
 }
 
-
-void checkForError()
-{
-#ifdef _WIN32
-	int error = GetLastError();
-	if(error)
-		tlog1 << "Error " << error << " encountered!\n";
-#endif
-}
-
-
 CBIKHandler::CBIKHandler()
 {
 	Instantiate("BINKW32.DLL");
 
-	binkGetError = FindAddress("_BinkGetError@0");
+	//binkGetError = FindAddress("_BinkGetError@0");
 	binkOpen = (BinkOpen)FindAddress("_BinkOpen@8");
 	binkSetSoundSystem = (BinkSetSoundSystem)FindAddress("_BinkSetSoundSystem@8");
-	getPalette = (BinkGetPalette)FindAddress("_BinkGetPalette@4");
+	//getPalette = (BinkGetPalette)FindAddress("_BinkGetPalette@4");
 	binkNextFrame = (BinkNextFrame)FindAddress("_BinkNextFrame@4");
 	binkDoFrame = (BinkDoFrame)FindAddress("_BinkDoFrame@4");
 	binkCopyToBuffer = (BinkCopyToBuffer)FindAddress("_BinkCopyToBuffer@28");
 	binkWait = (BinkWait)FindAddress("_BinkWait@4");
+	binkClose =  (BinkClose)FindAddress("_BinkClose@4");
+
+	hBinkFile = NULL;
+	hBink = NULL;
 }
 
 void CBIKHandler::open(std::string name)
@@ -86,36 +129,27 @@ void CBIKHandler::open(std::string name)
 
 	if(hBinkFile == INVALID_HANDLE_VALUE)
 	{
+		tlog1 << "BIK handler: failed to open " << name << std::endl;
 		checkForError();
-		return ;
+		return;
 	}
 
-	void *waveout = FindAddress("_BinkOpenWaveOut@4");
+	void *waveout = GetProcAddress(dll,"_BinkOpenWaveOut@4");
 	if(waveout)
 		binkSetSoundSystem(waveout,NULL);
 
 	hBink = binkOpen(hBinkFile, 0x8a800000);
-	width = hBink->width;
-	height = hBink->height;
-	buffer = new char[width * height * 3];
+	buffer = new char[hBink->width * hBink->width * 3];
 }
 
-void CBIKHandler::show( int x, int y, SDL_Surface *dst )
+void CBIKHandler::show( int x, int y, SDL_Surface *dst, bool update )
 {
 	int w = hBink->width, h = hBink->height;
-	//memset(buffer,0,w * h * 3);
 	binkDoFrame(hBink);
 	binkCopyToBuffer(hBink, buffer, w*3, h, 0, 0, 0);
-	char *src = buffer;
-	char *dest;
-	for(int i = h; i > 0; i--)
-	{
-		dest = (char*)dst->pixels + dst->pitch*(h-i) + x*dst->format->BytesPerPixel;
-		memcpy(dest,src,3*w);
-		src += 3*w;
-	}
-
-	SDL_UpdateRect(dst,x,y,hBink->width, hBink->height);
+	blitBuffer(buffer, x, y, w, h, dst);
+	if(update)
+		SDL_UpdateRect(dst, x, y, w, h);
 }
 
 void CBIKHandler::nextFrame()
@@ -125,6 +159,10 @@ void CBIKHandler::nextFrame()
 
 void CBIKHandler::close()
 {
+	binkClose(hBink);
+	hBink = NULL;
+	CloseHandle(hBinkFile);
+	hBinkFile = NULL;
 	delete [] buffer;
 }
 
@@ -133,80 +171,29 @@ bool CBIKHandler::wait()
 	return binkWait(hBink);
 }
 
-// Reference RSGrapics.RSGetPixelFormat
-PixelFormat getPixelFormat(TBitmap &b)
-{
-	DIBSECTION DS;
-	DS.dsBmih.biBitCount = 2;
-	DS.dsBmih.biCompression = 0; //not sure about that
-	PixelFormat result = b.pixelFormat;
-
-	  if ( (result!= pfCustom)
-		  || (b.handleType = bmDDB)
-		 // || (GetObject(b.Handle, SizeOf(DS), @DS) = 0) 
-		  )
-		  exit(0);
-
-	  switch (DS.dsBmih.biBitCount)
-	  {
-		case 16:
-			switch (DS.dsBmih.biCompression)
-			{
-				case BI_RGB:
-					result = pf15bit;
-					break;
-				case BI_BITFIELDS:
-					if ( DS.dsBitfields[1]==0x7E0 )
-						result = pf16bit;
-					if ( DS.dsBitfields[1]==0x7E0 )
-						result = pf15bit;
-					break;
-			}
-			break;
-		case 32:
-			switch (DS.dsBmih.biCompression)
-			{
-				case BI_RGB:
-					result = pf32bit;
-					break;
-				case BI_BITFIELDS:
-					if ( DS.dsBitfields[1]==0xFF0000 )
-						result = pf32bit;
-					break;
-			}
-			break;
-	  }
-	return result;
+int CBIKHandler::curFrame() const
+{
+	return hBink->currentFrame;
 }
 
-void CSmackPlayer::preparePic(TBitmap &b)
+int CBIKHandler::frameCount() const
 {
-	switch (getPixelFormat(b))
-	{
-	case pf15bit:
-	case pf16bit:
-		break;
-	default:
-		b.pixelFormat = pf16bit;
-	};
+	return hBink->frameCount;
 }
 
-
 void CSmackPlayer::nextFrame()
 {
 	ptrSmackNextFrame(data);
 }
 
-
 bool CSmackPlayer::wait()
 {
 	return ptrSmackWait(data);
 }
 
-void CSmackPlayer::init()
+CSmackPlayer::CSmackPlayer()
 {
 	Instantiate("smackw32.dll");
-	tlog0 << "smackw32.dll loaded" << std::endl;
 
 	ptrSmackNextFrame = (SmackNextFrame)FindAddress("_SmackNextFrame@4");
 	ptrSmackWait = (SmackWait)FindAddress("_SmackWait@4");
@@ -214,110 +201,210 @@ void CSmackPlayer::init()
 	ptrSmackToBuffer = (SmackToBuffer)FindAddress("_SmackToBuffer@28");
 	ptrSmackOpen = (SmackOpen)FindAddress("_SmackOpen@12");
 	ptrSmackSoundOnOff = (SmackSoundOnOff)FindAddress("_SmackSoundOnOff@8");
-	tlog0 << "Functions located" << std::endl;
+	ptrSmackClose = (SmackClose)FindAddress("_SmackClose@4");
+}
+
+CSmackPlayer::~CSmackPlayer()
+{
+	if(data)
+		close();
+}
+
+void CSmackPlayer::close()
+{
+	ptrSmackClose(data);
+	data = NULL;
+	delete [] buffer;
+	buffer = NULL;
+}
+
+void CSmackPlayer::open( std::string name )
+{
+	Uint32 flags[2] = {0xff400, 0xfe400};
+
+	data = ptrSmackOpen( (void*)name.c_str(), flags[1], -1);
+	if (!data) 
+	{
+		tlog1 << "Smack cannot open " << name << std::endl;
+		return;
+	}
+
+	buffer = new char[data->width*data->height*2];
+	buf = buffer+data->width*(data->height-1)*2;	// adjust pointer position for later use by 'SmackToBuffer'
+}
+
+void CSmackPlayer::show( int x, int y, SDL_Surface *dst, bool update)
+{
+	int w = data->width, h = data->height;
+	int stripe = (-w*2) & (~3);
+
+	//put frame to the buffer
+	ptrSmackToBuffer(data, 0, 0, stripe, w, buf, 0x80000000);
+	ptrSmackDoFrame(data);
+
+
+	/* Lock the screen for direct access to the pixels */
+	if ( SDL_MUSTLOCK(dst) ) 
+	{
+		if ( SDL_LockSurface(dst) < 0 ) 
+		{
+			fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
+			return;
+		}
+	}
+
+	// draw the frame
+	Uint16* addr = (Uint16*) (buffer+w*(h-1)*2-2);
+	for( int j=0; j<h-1; j++)	// why -1 ?
+	{
+		for ( int i=w-1; i>=0; i--)
+		{
+			Uint16 pixel = *addr;
+
+			Uint8 *p = (Uint8 *)dst->pixels + (j+y) * dst->pitch + (i + x) * dst->format->BytesPerPixel;
+			p[2] = ((pixel & 0x7c00) >> 10) * 8;
+			p[1] = ((pixel & 0x3e0) >> 5) * 8;
+			p[0] = ((pixel & 0x1F)) * 8;
+
+			addr--;
+		}
+	}
+
+	if ( SDL_MUSTLOCK(dst) ) 
+	{
+		SDL_UnlockSurface(dst);
+	}
+
+	if(update)
+		SDL_UpdateRect(dst, x, y, w, h);
+}
+
+int CSmackPlayer::curFrame() const
+{
+	return data->currentFrame;
+}
+
+int CSmackPlayer::frameCount() const
+{
+	return data->frameCount;
 }
 
 CVideoPlayer::CVideoPlayer()
 {
 	vidh = new CVidHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "VIDEO.VID"));
-	smkPlayer = new CSmackPlayer;
-	smkPlayer->init();
+	current = NULL;
 }
 
 CVideoPlayer::~CVideoPlayer()
 {
-	delete smkPlayer;
 	delete vidh;
 }
 
-bool CVideoPlayer::init()
+void CVideoPlayer::open(std::string name)
 {
-	return true;
-}
+	if(boost::algorithm::ends_with(name, ".BIK"))
+		current = &bikPlayer;
+	else
+		current = &smkPlayer;
 
-bool CVideoPlayer::open(std::string fname, int x, int y)
-{
-	vidh->extract(fname, fname);
+	fname = name;
 
-	Uint32 flags[2] = {0xff400, 0xfe400};
+	//extract video from video.vid so we can play it
+	vidh->extract(name, name);
+	current->open(name);
+}
 
-	smkPlayer->data = smkPlayer->ptrSmackOpen( (void*)fname.c_str(), flags[1], -1);
-	if (smkPlayer->data ==NULL) 
+void CVideoPlayer::close()
+{
+	if(!current)
 	{
-		tlog1<<"No "<<fname<<" file!"<<std::endl;
-		return false;
+		tlog2 << "Closing no opened player...?" << std::endl;
+		return;
 	}
 
-	buffer = new char[smkPlayer->data->width*smkPlayer->data->height*2];
-	buf = buffer+smkPlayer->data->width*(smkPlayer->data->height-1)*2;	// adjust pointer position for later use by 'SmackToBuffer'
-
-	xPos = x;
-	yPos = y;
-	frame = 0;
-
-	return true;
+	current->close();
+	current = NULL;
+	if(!DeleteFileA(fname.c_str()))
+	{
+		tlog1 << "Cannot remove temporarily extracted video file: " << fname;
+		checkForError(false);
+	}
+	fname.clear();
+}
+
+void CVideoPlayer::nextFrame()
+{
+	current->nextFrame();
+}
+
+void CVideoPlayer::show(int x, int y, SDL_Surface *dst, bool update)
+{
+	current->show(x, y, dst, update);
+}
+
+bool CVideoPlayer::wait()
+{
+	return current->wait();
 }
 
-void CVideoPlayer::close()
+int CVideoPlayer::curFrame() const
 {
-	delete [] buffer;
+	return current->curFrame();
 }
 
-bool CVideoPlayer::nextFrame()
+int CVideoPlayer::frameCount() const
 {
-	if(frame < smkPlayer->data->frameCount)
-	{
-		++frame;
+	return current->frameCount();
+}
 
-		int stripe = (-smkPlayer->data->width*2) & (~3);
-		Uint32 unknown = 0x80000000;
-		smkPlayer->ptrSmackToBuffer(smkPlayer->data , 0, 0, stripe, smkPlayer->data->width, buf, unknown);
-		smkPlayer->ptrSmackDoFrame(smkPlayer->data );
-		// now bitmap is in buffer
-		// but I don't know exactly how to parse these 15bit color and draw it onto 16bit screen
+bool CVideoPlayer::openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey)
+{
+	open(name);
+	bool ret = playVideo(x, y, dst, stopOnKey);
+	close();
+	return ret;
+}
 
+void CVideoPlayer::update( int x, int y, SDL_Surface *dst, bool redraw, bool update )
+{
+	bool w = wait(); //check if should keep current frame
 
-		/* Lock the screen for direct access to the pixels */
-		if ( SDL_MUSTLOCK(screen) ) 
-		{
-			if ( SDL_LockSurface(screen) < 0 ) 
-			{
-				fprintf(stderr, "Can't lock screen: %s\n", SDL_GetError());
-				return 0;
-			}
-		}
+	if(!w)
+		nextFrame();
 
-		// draw the frame!!
-		Uint16* addr = (Uint16*) (buffer+smkPlayer->data->width*(smkPlayer->data->height-1)*2-2);
-		for( int j=0; j<smkPlayer->data->height-1; j++)	// why -1 ?
-		{
-			for ( int i=smkPlayer->data->width-1; i>=0; i--)
-			{
-				Uint16 pixel = *addr;
+	if(!w || redraw) //redraw if changed frame or we was told to
+		show(x,y,dst,update);
+}
 
-				Uint8 *p = (Uint8 *)screen->pixels + (j+yPos) * screen->pitch + (i + xPos) * screen->format->BytesPerPixel;
-				p[2] = ((pixel & 0x7c00) >> 10) * 8;
-				p[1] = ((pixel & 0x3e0) >> 5) * 8;
-				p[0] = ((pixel & 0x1F)) * 8;
+//reads events and throws on key down
+bool keyDown()
+{
+	SDL_Event ev;
+	while(SDL_PollEvent(&ev))
+	{
+		if(ev.type == SDL_KEYDOWN || ev.type == SDL_MOUSEBUTTONDOWN)
+			return true;
+	}
+	return false;
+}
 
-				addr--;
-			}
-		}
+bool CVideoPlayer::playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey)
+{
+	int frame = 0;
+	while(frame < frameCount()) //play all frames
+	{
+		if(stopOnKey && keyDown())
+			return false;
 
-		if ( SDL_MUSTLOCK(screen) ) 
+		if(!wait())
 		{
-			SDL_UnlockSurface(screen);
+			show(x, y, dst);
+			nextFrame();
+			frame++;
 		}
-		/* Update just the part of the display that we've changed */
-		SDL_UpdateRect(screen, xPos, yPos, smkPlayer->data->width, smkPlayer->data->height);
-		SDL_Delay(50);
-		smkPlayer->ptrSmackWait(smkPlayer->data);
-		smkPlayer->ptrSmackNextFrame(smkPlayer->data);
-	}
-	else //end of video
-	{
-		return false;
+		SDL_Delay(20);
 	}
+
 	return true;
 }
 

+ 48 - 41
hch/CVideoHandler.h

@@ -50,57 +50,53 @@ public:
 
 typedef void*(__stdcall*  BinkSetSoundSystem)(void * soundfun, void*);
 typedef HBINK(__stdcall*  BinkOpen)(HANDLE bikfile, int flags);
-typedef si32(__stdcall*  BinkGetPalette)(HBINK);
+typedef void(__stdcall*  BinkClose)(HBINK);
+//typedef si32(__stdcall*  BinkGetPalette)(HBINK);
 typedef void(__stdcall*  BinkNextFrame)(HBINK);
 typedef void(__stdcall*  BinkDoFrame)(HBINK);
 typedef ui8(__stdcall*  BinkWait)(HBINK);
 typedef si32(__stdcall*  BinkCopyToBuffer)(HBINK, void* buffer, int stride, int height, int x, int y, int mode);
 
+
+class IVideoPlayer
+{
+public:
+	virtual void open(std::string name)=0;
+	virtual void close()=0;
+	virtual void nextFrame()=0;
+	virtual void show(int x, int y, SDL_Surface *dst, bool update = true)=0;
+	virtual bool wait()=0;
+	virtual int curFrame() const =0;
+	virtual int frameCount() const =0;
+};
 
-class CBIKHandler : public DLLHandler
+class CBIKHandler : public DLLHandler, public IVideoPlayer
 {
 public:
-	int newmode;
 	HANDLE hBinkFile;
 	HBINK hBink;
 	char * buffer;
 	BinkSetSoundSystem binkSetSoundSystem;
 	BinkOpen binkOpen;
-	BinkGetPalette getPalette;
+	//BinkGetPalette getPalette;
 	BinkNextFrame binkNextFrame;
 	BinkDoFrame binkDoFrame;
 	BinkCopyToBuffer binkCopyToBuffer;
 	BinkWait binkWait;
-
-	void * waveOutOpen, * binkGetError;
-
-	int width, height;
+	BinkClose binkClose;
 
 	CBIKHandler();
 	void open(std::string name);
 	void close();
 	void nextFrame();
-	void show(int x, int y, SDL_Surface *dst);
+	void show(int x, int y, SDL_Surface *dst, bool update = true);
 	bool wait();
+	int curFrame() const;
+	int frameCount() const;
 };
 
 //////////SMK Player ///////////////////////////////////////////////////////
 
-typedef enum { bmDIB, bmDDB} BitmapHandleType;
-typedef enum { pfDevice, pf1bit, pf4bit, pf8bit, pf15bit, pf16bit, pf24bit, pf32bit, pfCustom} PixelFormat;
-typedef enum {tmAuto, tmFixed} TransparentMode;
-
-class TBitmap
-{
-public:
-	ui32	width;
-	ui32 height;
-	PixelFormat pixelFormat;
-	BitmapHandleType handleType;
-	char* buffer;
-
-};
-
 struct SmackStruct
 {
     si32 version;
@@ -127,7 +123,7 @@ typedef void (__stdcall* SmackSoundOnOff) (SmackStruct*, bool);
 
 
 
-class CSmackPlayer: public DLLHandler
+class CSmackPlayer: public DLLHandler, public IVideoPlayer
 {
 public:
 	SmackOpen ptrSmackOpen;
@@ -136,39 +132,50 @@ public:
 	SmackNextFrame ptrSmackNextFrame;
 	SmackWait ptrSmackWait;
 	SmackSoundOnOff ptrSmackSoundOnOff;
+	SmackClose ptrSmackClose;
+
+	char *buffer, *buf;
 	SmackStruct* data;
 
-	void init();
-	void preparePic(TBitmap &b);
-	TBitmap extractFrame(TBitmap &b);
+	CSmackPlayer();
+	~CSmackPlayer();
+	void open(std::string name);
+	void close();
 	void nextFrame();
-	bool wait();
+	void show(int x, int y, SDL_Surface *dst, bool update = true);
+	bool wait();
+	int curFrame() const;
+	int frameCount() const;
 };
 
 class CVidHandler;
 
-class CVideoPlayer
+class CVideoPlayer : public IVideoPlayer
 {
 private:
 	CVidHandler * vidh; //.vid file handling
-	CSmackPlayer * smkPlayer;
-
-	int frame;
-	int xPos, yPos;
-	char * buffer;
-	char * buf;
 
+	CSmackPlayer smkPlayer; //for .SMK
+	CBIKHandler bikPlayer; //for .BIK
+	IVideoPlayer *current; //points to bik or smk player, appropriate to type of currently played video
 
 	std::string fname; //name of current video file (empty if idle)
-
 public:
 	CVideoPlayer(); //c-tor
 	~CVideoPlayer(); //d-tor
 
-	bool init();
-	bool open(std::string fname, int x, int y); //x, y -> position where animation should be displayed on the screen
-	void close();
-	bool nextFrame(); // display next frame
+
+	void open(std::string name);
+	void close();
+	void nextFrame(); //move animation to the next frame
+	void show(int x, int y, SDL_Surface *dst, bool update = true); //blit current frame
+	void update(int x, int y, SDL_Surface *dst, bool redraw, bool update = true); //moves to next frame if appropriate, and blits it or blits only if redraw paremeter is set true
+	bool wait(); //true if we should wait before displaying next frame (for keeping FPS)
+	int curFrame() const; //current frame number <1, framecount>
+	int frameCount() const;
+
+	bool openAndPlayVideo(std::string name, int x, int y, SDL_Surface *dst, bool stopOnKey = false); //opens video, calls playVideo, closes video; returns playVideo result (if whole video has been played)
+	bool playVideo(int x, int y, SDL_Surface *dst, bool stopOnKey = false); //plays whole opened video; returns: true when whole video has been shown, false when it has been interrupted
 };
 
 #else