diff --git a/client/CMT.cpp b/client/CMT.cpp index 63cd3945f..f89abe0ae 100644 --- a/client/CMT.cpp +++ b/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; diff --git a/client/CPreGame.cpp b/client/CPreGame.cpp index 5b161b316..8f08be374 100644 --- a/client/CPreGame.cpp +++ b/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; } diff --git a/client/CSpellWindow.cpp b/client/CSpellWindow.cpp index 7d519abf0..edba1edf9 100644 --- a/client/CSpellWindow.cpp +++ b/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) diff --git a/hch/CVideoHandler.cpp b/hch/CVideoHandler.cpp index 30c7aad41..1aa863550 100644 --- a/hch/CVideoHandler.cpp +++ b/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) +int CBIKHandler::curFrame() const { - 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; + 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; + + fname = name; + + //extract video from video.vid so we can play it + vidh->extract(name, name); + current->open(name); } -bool CVideoPlayer::open(std::string fname, int x, int y) -{ - vidh->extract(fname, fname); - - Uint32 flags[2] = {0xff400, 0xfe400}; - - smkPlayer->data = smkPlayer->ptrSmackOpen( (void*)fname.c_str(), flags[1], -1); - if (smkPlayer->data ==NULL) - { - tlog1<<"No "<<fname<<" file!"<<std::endl; - return false; - } - - 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; -} - -void CVideoPlayer::close() -{ - delete [] buffer; -} - -bool CVideoPlayer::nextFrame() +void CVideoPlayer::close() { - if(frame < smkPlayer->data->frameCount) + if(!current) { - ++frame; - - 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 - - - /* 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; - } - } - - // 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; - - 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; - - addr--; - } - } - - if ( SDL_MUSTLOCK(screen) ) - { - SDL_UnlockSurface(screen); - } - /* 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); + tlog2 << "Closing no opened player...?" << std::endl; + return; } - else //end of video + + current->close(); + current = NULL; + if(!DeleteFileA(fname.c_str())) { - return false; + 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(); +} + +int CVideoPlayer::curFrame() const +{ + return current->curFrame(); +} + +int CVideoPlayer::frameCount() const +{ + return current->frameCount(); +} + +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 + + if(!w) + nextFrame(); + + if(!w || redraw) //redraw if changed frame or we was told to + show(x,y,dst,update); +} + +//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; +} + +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(!wait()) + { + show(x, y, dst); + nextFrame(); + frame++; + } + SDL_Delay(20); + } + return true; } diff --git a/hch/CVideoHandler.h b/hch/CVideoHandler.h index 9194d9197..864dd32c3 100644 --- a/hch/CVideoHandler.h +++ b/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