From 3e7a180613856768fb0ad7666cef5b57078b5e5e Mon Sep 17 00:00:00 2001 From: mateuszb Date: Mon, 22 Jun 2009 11:12:40 +0000 Subject: [PATCH] * playing smk videos on Windows (currently only spellbook animation) --- client/CSpellWindow.cpp | 12 +- hch/CVideoHandler.cpp | 248 ++++++++++++++++++++++++++++++++++++++++ hch/CVideoHandler.h | 96 +++++++++++++++- 3 files changed, 346 insertions(+), 10 deletions(-) diff --git a/client/CSpellWindow.cpp b/client/CSpellWindow.cpp index cd7a6c3ab..90738079b 100644 --- a/client/CSpellWindow.cpp +++ b/client/CSpellWindow.cpp @@ -638,30 +638,30 @@ void CSpellWindow::deactivate() void CSpellWindow::turnPageLeft() { -#ifndef _WIN32 - if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, pos.y+14)) { + if (CGI->videoh->open("PGTRNLFT.SMK", pos.x+13, pos.y+15)) { while(CGI->videoh->nextFrame()) { SDL_framerateDelay(LOCPLINT->mainFPSmng); +#ifndef _WIN32 SDL_framerateDelay(LOCPLINT->mainFPSmng); SDL_framerateDelay(LOCPLINT->mainFPSmng); +#endif } CGI->videoh->close(); } -#endif } void CSpellWindow::turnPageRight() { -#ifndef _WIN32 - if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, pos.y+14)) { + if (CGI->videoh->open("PGTRNRGH.SMK", pos.x+13, pos.y+15)) { while(CGI->videoh->nextFrame()) { SDL_framerateDelay(LOCPLINT->mainFPSmng); +#ifndef _WIN32 SDL_framerateDelay(LOCPLINT->mainFPSmng); SDL_framerateDelay(LOCPLINT->mainFPSmng); +#endif } CGI->videoh->close(); } -#endif } CSpellWindow::SpellArea::SpellArea(SDL_Rect pos, CSpellWindow * owner) diff --git a/hch/CVideoHandler.cpp b/hch/CVideoHandler.cpp index 67977e0d6..ebbadf307 100644 --- a/hch/CVideoHandler.cpp +++ b/hch/CVideoHandler.cpp @@ -6,6 +6,8 @@ #ifdef _WIN32 +#include "../client/SDL_Extensions.h" + void DLLHandler::Instantiate(const char *filename) { #ifdef _WIN32 @@ -200,6 +202,252 @@ void CBIKHandler::open(std::string name) // //end; +//////////SMK Player - Windows /////////////////////////////////////////////////////// + +void CRADPlayer::loadProc(char* ptrFunc,char* procName) +{ + (FARPROC&)(*ptrFunc) = GetProcAddress(hinstLib, procName); +} + +// Reference RSGrapics.RSGetPixelFormat +PixelFormat CRADPlayer::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; +} + +void CSmackPlayer::preparePic(TBitmap b) +{ + switch (getPixelFormat(b)) + { + case pf15bit: + case pf16bit: + break; + default: + b.pixelFormat = pf16bit; + }; +} + + +void CSmackPlayer::nextFrame() +{ + loadProc((char*)&ptrSmackNextFrame, "_SmackNextFrame@4"); + ptrSmackNextFrame(data); +} + + +bool CSmackPlayer::wait() +{ + loadProc((char*)&ptrSmackWait, "_SmackWait@4"); + return ptrSmackWait(data); +} + + +TBitmap CSmackPlayer::extractFrame(TBitmap b) +{ + int i,j; + PixelFormat pf; + TBitmap result; + loadProc((char*)&ptrSmackDoFrame, "_SmackDoFrame@4"); + loadProc((char*)&ptrSmackToBuffer, "_SmackToBuffer@28"); + i=j=0; + /* + try { + pf = getPixelFormat(b); + i=j=0; + switch(pf){ + case pf8bit: i = 1; break; + case pf15bit: + case pf16bit: i=2; break; + default: + // assert(false) + break; + } + switch(pf) { + case pf8bit: + j = 0x10000000; + break; + case pf15bit: + // todo + break; + case pf16bit: + // todo + break; + default: + break; + } */ + int v = -b.width*i; + ptrSmackToBuffer(data, 0, 0, v, b.height, (char*)b.buffer, j); + ptrSmackDoFrame(data); + /* + } + + catch ( char * msg) { + + }*/ + result = b; + return result; + +} + +CVideoPlayer::CVideoPlayer() +{ + // Load DLL file + vidh = new CVidHandler(std::string(DATA_DIR "Data" PATHSEPARATOR "VIDEO.VID")); + + smkPlayer = new CSmackPlayer; + + smkPlayer->hinstLib = LoadLibrary(L"smackw32.dll"); + if (smkPlayer->hinstLib == NULL) { + tlog1<<"ERROR: unable to load DLL"<loadProc( (char*)&smkPlayer->ptrSmackOpen, "_SmackOpen@12"); + smkPlayer->loadProc((char*)&smkPlayer->ptrSmackDoFrame, "_SmackDoFrame@4"); + smkPlayer->loadProc((char*)&smkPlayer->ptrSmackToBuffer, "_SmackToBuffer@28"); + smkPlayer->loadProc((char*)&smkPlayer->ptrSmackToBuffer, "_SmackToBuffer@28"); + smkPlayer->loadProc((char*)&smkPlayer->ptrSmackSoundOnOff, "_SmackSoundOnOff@8"); + smkPlayer->loadProc((char*)&smkPlayer->ptrSmackWait, "_SmackWait@4"); + smkPlayer->loadProc((char*)&smkPlayer->ptrSmackNextFrame, "_SmackNextFrame@4"); +} + +CVideoPlayer::~CVideoPlayer() +{ + delete smkPlayer; + delete vidh; +} + +bool CVideoPlayer::init() +{ + return true; +} + +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 "<data->width*smkPlayer->data->height*2]; + buf = buffer+smkPlayer->data->width*(smkPlayer->data->height-1)*2; // adjust pointer postition for later use by 'SmackToBuffer' + + xPos = x; + yPos = y; + frame = 0; + + return true; +} + +void CVideoPlayer::close() +{ + delete buffer; +} + +bool CVideoPlayer::nextFrame() +{ + if(frame < smkPlayer->data->frameCount) + { + ++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 + + // draw the frame!! + Uint16* addr = (Uint16*) (buffer+smkPlayer->data->width*(smkPlayer->data->height-1)*2-2); + for( int j=0; jdata->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; + + /*Uint8 b = ((pixel & 0x7c00) >> 10) * 8; + Uint8 g = ((pixel & 0x3e0) >> 5) * 8; + Uint8 r = ((pixel & 0x1F)) * 8;*/ + + addr--; + /* 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; + } + } + //putpixel(screen, i,j, (Uint32)pixel); + 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); + } + else //end of video + { + return false; + } + return true; +} + #else #include "../client/SDL_Extensions.h" diff --git a/hch/CVideoHandler.h b/hch/CVideoHandler.h index 20aab2fb6..de9bef3e0 100644 --- a/hch/CVideoHandler.h +++ b/hch/CVideoHandler.h @@ -1,14 +1,12 @@ #ifndef __CVIDEOHANDLER_H__ #define __CVIDEOHANDLER_H__ +#include "../global.h" #ifdef _WIN32 #include -#ifdef _WIN32 #include -#else -#include -#endif +#include // #define BINKNOTHREADEDIO 0x00800000 @@ -150,8 +148,98 @@ public: void close(); }; +//////////SMK Player /////////////////////////////////////////////////////// + + +struct SmackStruct +{ + Sint32 version; // + Sint32 width; + Sint32 height; + Sint32 frameCount; + Sint32 mspf; + unsigned char unk1[88]; + unsigned char palette[776]; + Sint32 currentFrame; // Starting with 0 + + // 72 - иш? + // 1060 - interesting + // 1100 - Mute:Bool + + unsigned char unk[56]; + Uint32 fileHandle; // exact type is HANDLE in windows.h +}; + +// defines function pointer type +typedef SmackStruct* (__stdcall* SmackOpen)(void* , Uint32, Sint32 ); +// todo default value +typedef int (__stdcall* SmackDoFrame)( SmackStruct * ); +typedef void (__stdcall * SmackGoto )(SmackStruct *, int frameNumber); +typedef void (__stdcall* SmackNextFrame)(SmackStruct*); +typedef void (__stdcall* SmackClose)(SmackStruct*); +typedef void (__stdcall* SmackToBuffer) (SmackStruct*, int, int, int, int, char *, Uint32); +typedef bool (__stdcall* SmackWait)(SmackStruct*); +typedef void (__stdcall* SmackSoundOnOff) (SmackStruct*, bool); + + +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: + Uint32 width; + Uint32 height; + PixelFormat pixelFormat; + BitmapHandleType handleType; + char* buffer; + +}; + +class CRADPlayer +{ +public: + HINSTANCE hinstLib; + void loadProc(char* ptrFunc,char* procName); + PixelFormat getPixelFormat(TBitmap); +}; + +class CSmackPlayer: public CRADPlayer{ +public: + SmackOpen ptrSmackOpen; + SmackDoFrame ptrSmackDoFrame; + SmackToBuffer ptrSmackToBuffer; + SmackNextFrame ptrSmackNextFrame; + SmackWait ptrSmackWait; + SmackSoundOnOff ptrSmackSoundOnOff; + SmackStruct* data; + + void preparePic(TBitmap b); + TBitmap extractFrame(TBitmap b); + void nextFrame(); + bool wait(); +}; + +class CVidHandler; + class CVideoPlayer { +private: + CVidHandler * vidh; //.vid file handling + CSmackPlayer * smkPlayer; + int frame; + int xPos, yPos; + char * buffer; + char * buf; +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 }; #else