mirror of
https://github.com/1dot13/source.git
synced 2026-07-29 13:52:17 +02:00
Drops the last piece of the proprietary Smacker SDK: SMACKW32.LIB, its header sgp/SMACK.H, and with them the SMACKW32.DLL the game needed at runtime. Bink is untouched and still needs binkw32. The two libraries divide the work differently, so Cinematics.cpp changes more than the call names. SMACKW32.DLL played a file: it kept the playback clock (SmackWait), blitted converted 16bpp pixels into a surface we handed it (SmackToBuffer) and pushed the audio to DirectSound itself. libsmacker only decodes, so this module now: - keeps the clock. Frames are advanced against GetTickCount() from the moment the flic starts, skipping frames if the game fell behind, which is what SmackWait/SmackDoFrame did internally. - blits itself. Frames come out 8bpp palettised, so the palette is converted with Get16BPPColor() and the frame is written into the frame buffer, clipped to the screen. The Y-scaling flags are not handled; none of the videos shipping with the game set them. - plays the audio itself, through the SoundPlayFromBuffer() added earlier. libsmacker hands out audio a frame at a time, so the whole track is decoded up front, with the video track disabled to keep that pass cheap, and given a WAV header so the sound module can take it. libsmacker reads from memory, which lets the file be read straight out of the VFS. That removes the dance where the .smk was first copied to a real file under Temp/ because SmackOpen() could only open a path. SmkInitialize() loses its window and screen size arguments, which only existed for SmackBufferOpen(). SmkOpenFlic(), SmkSetBlitPosition() and SmkGetFreeFlic() are no longer declared in the header; nothing outside the module called them. SMKFLIC is now opaque, Intro.cpp only holds pointers. The unused SMACK.H include in Cinematics Bink.cpp goes away as well. Tested by running the Sirtech splash screen (SPLASHSCREEN.SMK, 640x480, 15 fps, one 44.1kHz 16 bit stereo track) under Wine: picture, palette, placement and playback speed are right. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> refactor
415 lines
9.1 KiB
C++
415 lines
9.1 KiB
C++
#include "types.h"
|
|
#include <stdio.h>
|
|
#include <io.h>
|
|
#include <string.h>
|
|
#include <fcntl.h>
|
|
#include <share.h>
|
|
#include <sys/stat.h>
|
|
#include <malloc.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "DEBUG.H"
|
|
#include "FileMan.h"
|
|
#include "ddraw.h"
|
|
#include "Mss.h"
|
|
#include "DirectX Common.h"
|
|
#include "DirectDraw Calls.h"
|
|
#include "soundman.h"
|
|
#include "video.h"
|
|
|
|
#include "Cinematics Bink.h"
|
|
|
|
#include "vsurface_private.h"
|
|
|
|
//#include "Intro.h"
|
|
#include <vfs/Core/vfs.h>
|
|
#include <vfs/Core/vfs_file_raii.h>
|
|
|
|
|
|
|
|
|
|
#include <crtdbg.h>
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// Local Defines
|
|
//
|
|
//*******************************************************************
|
|
|
|
|
|
#define BINK_NUM_FLICS 4 // Maximum number of flics open
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// Global Variables
|
|
//
|
|
//*******************************************************************
|
|
|
|
BINKFLIC BinkList[BINK_NUM_FLICS];
|
|
UINT32 guiBinkPixelFormat=0;
|
|
|
|
//LPDIRECTDRAWSURFACE lpBinkVideoPlayback=NULL;
|
|
LPDIRECTDRAWSURFACE2 lpBinkVideoPlayback2=NULL;
|
|
HWND hBinkDisplayWindow=0;
|
|
UINT32 guiHeight;
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// Function Prototypes
|
|
//
|
|
//*******************************************************************
|
|
|
|
void BinkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight);
|
|
void BinkShutdown(void);
|
|
BINKFLIC *BinkPlayFlic(CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, UINT32 uiFlags );
|
|
BOOLEAN BinkPollFlics(void);
|
|
BINKFLIC *BinkOpenFlic(const CHAR8 *cFilename);
|
|
void BinkSetBlitPosition(BINKFLIC *pBink, UINT32 uiLeft, UINT32 uiTop);
|
|
void BinkCloseFlic(BINKFLIC *pBink);
|
|
BINKFLIC *BinkGetFreeFlic(void);
|
|
void BinkSetupVideo(void);
|
|
void BinkShutdownVideo(void);
|
|
UINT16 GetNumberOfBits( UINT32 uiMask );
|
|
|
|
|
|
|
|
|
|
|
|
//*******************************************************************
|
|
//
|
|
// Functions
|
|
//
|
|
//*******************************************************************
|
|
|
|
|
|
|
|
void BinkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight)
|
|
{
|
|
//HDIGDRIVER pSoundDriver = NULL;
|
|
void* pSoundDriver = NULL;
|
|
|
|
|
|
//Get the sound Driver handle
|
|
pSoundDriver = SoundGetDriverHandle();
|
|
|
|
//if we got the sound handle, use sound during the intro
|
|
if( pSoundDriver )
|
|
{
|
|
BinkSoundUseDirectSound( pSoundDriver );
|
|
}
|
|
|
|
guiHeight = uiHeight;
|
|
}
|
|
|
|
|
|
void BinkShutdown(void)
|
|
{
|
|
UINT32 uiCount;
|
|
|
|
// Close and deallocate any open flics
|
|
for(uiCount=0; uiCount < BINK_NUM_FLICS; uiCount++)
|
|
{
|
|
//if the flic is currently open
|
|
if(BinkList[uiCount].uiFlags & BINK_FLIC_OPEN )
|
|
{
|
|
//close it
|
|
BinkCloseFlic( &BinkList[uiCount] );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
BINKFLIC *BinkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, UINT32 uiFlags )
|
|
{
|
|
BINKFLIC *pBink;
|
|
|
|
// Open the flic
|
|
if( ( pBink = BinkOpenFlic( cFilename ) ) == NULL )
|
|
{
|
|
return(NULL);
|
|
}
|
|
|
|
if( uiFlags & BINK_FLIC_CENTER_VERTICAL)
|
|
{
|
|
uiTop = ( guiHeight - pBink->BinkHandle->Height ) / 2;
|
|
}
|
|
|
|
// Set the blitting position on the screen
|
|
BinkSetBlitPosition( pBink, uiLeft, uiTop);
|
|
|
|
// We're now playing, flag the flic for the poller to update
|
|
pBink->uiFlags |= BINK_FLIC_PLAYING;
|
|
|
|
if( uiFlags & BINK_FLIC_AUTOCLOSE )
|
|
{
|
|
pBink->uiFlags |= BINK_FLIC_AUTOCLOSE;
|
|
}
|
|
else
|
|
{
|
|
pBink->uiFlags |= BINK_FLIC_LOOP;
|
|
}
|
|
|
|
|
|
return(pBink);
|
|
}
|
|
|
|
BINKFLIC *BinkOpenFlic( const CHAR8 *cFilename )
|
|
{
|
|
BINKFLIC *pBink;
|
|
|
|
// Get an available flic slot from the list
|
|
if( !( pBink = BinkGetFreeFlic() ) )
|
|
{
|
|
ErrorMsg("BINK ERROR: Out of flic slots, cannot open another");
|
|
return(NULL);
|
|
}
|
|
vfs::Path introname(cFilename);
|
|
vfs::Path dir,filename;
|
|
introname.splitLast(dir,filename);
|
|
vfs::Path tempfile = vfs::Path(L"Temp") + filename;
|
|
if(!getVFS()->fileExists(tempfile))
|
|
{
|
|
try
|
|
{
|
|
if(!getVFS()->fileExists(introname))
|
|
{
|
|
return NULL;
|
|
}
|
|
vfs::COpenReadFile rfile(introname);
|
|
vfs::size_t size = rfile->getSize();
|
|
std::vector<vfs::Byte> data(size);
|
|
rfile->read(&data[0],size);
|
|
|
|
vfs::COpenWriteFile wfile(tempfile,true);
|
|
wfile->write(&data[0],size);
|
|
}
|
|
catch(std::exception& ex)
|
|
{
|
|
SGP_RETHROW(_BS(L"Intro file \"") << filename << L"\" could not be extracted" << _BS::wget, ex);
|
|
}
|
|
}
|
|
|
|
vfs::Path tempfilename;
|
|
try
|
|
{
|
|
vfs::COpenWriteFile wfile(tempfile);
|
|
if(!wfile->_getRealPath(tempfilename))
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
catch(std::exception& ex)
|
|
{
|
|
SGP_RETHROW(L"Temporary intro file could not be read", ex);
|
|
}
|
|
if( !( pBink->BinkHandle = BinkOpen(tempfilename.to_string().c_str(), BINKNOTHREADEDIO /*BINKFILEHANDLE*/ ) ) ) //| SMACKTRACKS
|
|
{
|
|
ErrorMsg("BINK ERROR: Bink won't open the BINK file");
|
|
return(NULL);
|
|
}
|
|
|
|
// Make sure we have a video surface
|
|
BinkSetupVideo();
|
|
|
|
pBink->cFilename = cFilename;
|
|
|
|
pBink->lpDDS = lpBinkVideoPlayback2;
|
|
|
|
pBink->hWindow = hBinkDisplayWindow;
|
|
|
|
// Bink flic is now open and ready to go
|
|
pBink->uiFlags |= BINK_FLIC_OPEN;
|
|
|
|
return( pBink );
|
|
}
|
|
|
|
|
|
|
|
BINKFLIC *BinkGetFreeFlic()
|
|
{
|
|
UINT32 uiCount;
|
|
|
|
//loop through to get a free slot
|
|
for( uiCount=0; uiCount < BINK_NUM_FLICS; uiCount++ )
|
|
{
|
|
//if this slot is currently not in use
|
|
if( !( BinkList[uiCount].uiFlags & BINK_FLIC_OPEN ) )
|
|
{
|
|
return( &BinkList[ uiCount ] );
|
|
}
|
|
}
|
|
|
|
return( NULL );
|
|
}
|
|
|
|
|
|
void BinkSetBlitPosition( BINKFLIC *pBink, UINT32 uiLeft, UINT32 uiTop )
|
|
{
|
|
pBink->uiLeft = uiLeft;
|
|
pBink->uiTop = uiTop;
|
|
}
|
|
|
|
void BinkCloseFlic( BINKFLIC *pBink )
|
|
{
|
|
// Deallocate the smack buffers
|
|
// SmackBufferClose(pSmack->SmackBuffer);
|
|
|
|
// Close the smack flic
|
|
BinkClose(pBink->BinkHandle);
|
|
|
|
// Attempt opening the filename
|
|
FileClose(pBink->hFileHandle);
|
|
|
|
// Zero the memory, flags, etc.
|
|
memset( pBink, 0, sizeof(BINKFLIC) );
|
|
}
|
|
|
|
|
|
BOOLEAN BinkPollFlics(void)
|
|
{
|
|
UINT32 uiCount;
|
|
BOOLEAN fFlicStatus=FALSE;
|
|
DDSURFACEDESC SurfaceDescription;
|
|
BINKFLIC *pBink=NULL;
|
|
UINT32 uiCopyToBufferFlags = guiBinkPixelFormat;
|
|
|
|
//loop through all the open flics
|
|
for(uiCount=0; uiCount < BINK_NUM_FLICS; uiCount++)
|
|
{
|
|
pBink = &BinkList[uiCount];
|
|
|
|
if( pBink->uiFlags & BINK_FLIC_PLAYING )
|
|
{
|
|
fFlicStatus = TRUE;
|
|
|
|
//do we still have to wait for the frame to be finished being displayed
|
|
if( !( BinkWait( pBink->BinkHandle ) ) )
|
|
{
|
|
DDLockSurface( pBink->lpDDS, NULL, &SurfaceDescription, 0, NULL);
|
|
|
|
BinkDoFrame( pBink->BinkHandle );
|
|
|
|
BinkCopyToBuffer( pBink->BinkHandle,
|
|
SurfaceDescription.lpSurface,
|
|
SurfaceDescription.lPitch,
|
|
pBink->BinkHandle->Height,
|
|
pBink->uiLeft,
|
|
pBink->uiTop,
|
|
uiCopyToBufferFlags );
|
|
|
|
|
|
DDUnlockSurface( pBink->lpDDS, SurfaceDescription.lpSurface);
|
|
|
|
// Check to see if the flic is done the last frame
|
|
if( pBink->BinkHandle->FrameNum == ( pBink->BinkHandle->Frames-1 ) )
|
|
{
|
|
// If flic is looping, reset frame to 0
|
|
if( pBink->uiFlags & BINK_FLIC_LOOP)
|
|
{
|
|
BinkGoto( pBink->BinkHandle, 0, 0 );
|
|
}
|
|
else if( pBink->uiFlags & BINK_FLIC_AUTOCLOSE)
|
|
{
|
|
BinkCloseFlic( pBink );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
BinkNextFrame( BinkList[uiCount].BinkHandle );
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
return( fFlicStatus );
|
|
}
|
|
|
|
|
|
|
|
void BinkSetupVideo(void)
|
|
{
|
|
DDSURFACEDESC SurfaceDescription;
|
|
HRESULT ReturnCode;
|
|
UINT16 usRed, usGreen, usBlue;
|
|
HVSURFACE hVSurface;
|
|
|
|
GetVideoSurface( &hVSurface, FRAME_BUFFER );
|
|
|
|
lpBinkVideoPlayback2 = GetVideoSurfaceDDSurface( hVSurface );
|
|
|
|
ZEROMEM(SurfaceDescription);
|
|
SurfaceDescription.dwSize = sizeof (DDSURFACEDESC);
|
|
|
|
ReturnCode = IDirectDrawSurface2_GetSurfaceDesc ( lpBinkVideoPlayback2, &SurfaceDescription );
|
|
if (ReturnCode != DD_OK)
|
|
{
|
|
DirectXAttempt ( ReturnCode, __LINE__, __FILE__ );
|
|
return;
|
|
}
|
|
/*
|
|
usRed = (UINT16) SurfaceDescription.ddpfPixelFormat.dwRBitMask;
|
|
usGreen = (UINT16) SurfaceDescription.ddpfPixelFormat.dwGBitMask;
|
|
usBlue = (UINT16) SurfaceDescription.ddpfPixelFormat.dwBBitMask;
|
|
|
|
// SurfaceDescription.ddpfPixelFormat
|
|
|
|
if((usRed==0xf800) && (usGreen==0x07e0) && (usBlue==0x001f))
|
|
guiBinkPixelFormat = BINKSURFACE565;
|
|
else
|
|
guiBinkPixelFormat = BINKSURFACE555;
|
|
*/
|
|
//
|
|
// Get bit count for the RGB
|
|
//
|
|
usRed = GetNumberOfBits( SurfaceDescription.ddpfPixelFormat.dwRBitMask );
|
|
usGreen = GetNumberOfBits( SurfaceDescription.ddpfPixelFormat.dwGBitMask );
|
|
usBlue = GetNumberOfBits( SurfaceDescription.ddpfPixelFormat.dwBBitMask );
|
|
|
|
// 555
|
|
if( usRed == 5 && usGreen == 5 && usBlue == 5 )
|
|
{
|
|
guiBinkPixelFormat = BINKSURFACE555;
|
|
}
|
|
//565
|
|
else if( usRed == 5 && usGreen == 6 && usBlue == 5 )
|
|
{
|
|
guiBinkPixelFormat = BINKSURFACE565;
|
|
}
|
|
//655
|
|
else if( usRed == 6 && usGreen == 5 && usBlue == 5 )
|
|
{
|
|
guiBinkPixelFormat = BINKSURFACE655;
|
|
}
|
|
|
|
//dont know the format, wont get video
|
|
else
|
|
{
|
|
guiBinkPixelFormat = 0;
|
|
}
|
|
}
|
|
|
|
UINT16 GetNumberOfBits( UINT32 uiMask )
|
|
{
|
|
UINT16 usBits = 0;
|
|
|
|
while( uiMask )
|
|
{
|
|
uiMask = uiMask & ( uiMask - 1 );
|
|
usBits++;
|
|
}
|
|
return usBits;
|
|
}
|
|
|
|
|
|
void BinkShutdownVideo(void)
|
|
{
|
|
}
|