play smacker video with libsmacker instead of SMACKW32.DLL

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
This commit is contained in:
Marco Antonio J. Costa
2026-07-23 19:01:37 -03:00
committed by majcosta
parent 13c4be7382
commit 4ff2853b70
7 changed files with 400 additions and 831 deletions
+6 -1
View File
@@ -45,6 +45,7 @@ add_compile_definitions(CINTERFACE XML_STATIC VFS_STATIC VFS_WITH_SLF VFS_WITH_7
include_directories(
"${CMAKE_SOURCE_DIR}/Ja2"
"${CMAKE_SOURCE_DIR}/ext/VFS/include"
"${CMAKE_SOURCE_DIR}/ext/libsmacker"
"${CMAKE_SOURCE_DIR}/Utils"
"${CMAKE_SOURCE_DIR}/TileEngine"
"${CMAKE_SOURCE_DIR}/TacticalAI"
@@ -62,6 +63,7 @@ include_directories(
# external libraries
add_subdirectory("ext/libpng")
add_subdirectory("ext/libsmacker")
add_subdirectory("ext/zlib")
add_subdirectory("ext/VFS")
target_link_libraries(bfVFS PRIVATE 7z)
@@ -79,13 +81,13 @@ set(Ja2_Libraries
"${CMAKE_SOURCE_DIR}/libexpatMT.lib"
"${CMAKE_SOURCE_DIR}/lua51.lib"
"${CMAKE_SOURCE_DIR}/lua51.vc9.lib"
"${CMAKE_SOURCE_DIR}/SMACKW32.LIB"
"Dbghelp.lib"
"Winmm.lib"
"ws2_32.lib"
bfVFS
Lua
Multiplayer
smacker
wine
)
@@ -162,6 +164,9 @@ foreach(app IN LISTS ApplicationTargets)
target_link_libraries(${exe} PRIVATE ${app}_${lib})
endforeach()
# for Utils only
target_link_libraries(${app}_Utils PRIVATE smacker)
# for SGP only
target_link_libraries(${app}_sgp PRIVATE "ddraw.lib" "${PROJECT_SOURCE_DIR}/fmodvc.lib")
target_link_libraries(${app}_sgp PRIVATE libpng)
+1 -1
View File
@@ -38,7 +38,7 @@ public:
{
if(_type & VT_SMK)
{
SmkInitialize( ghWindow, SCREEN_WIDTH, SCREEN_HEIGHT);
SmkInitialize();
}
if(_type & VT_BINK)
{
BIN
View File
Binary file not shown.
-1
View File
@@ -10,7 +10,6 @@
#include "DEBUG.H"
#include "FileMan.h"
#include "SMACK.H"
#include "ddraw.h"
#include "Mss.h"
#include "DirectX Common.h"
+379 -329
View File
@@ -1,329 +1,379 @@
//----------------------------------------------------------------------------------
// Cinematics Module
//
//
// Stolen from Nemesis by Derek Beland.
// Originally by Derek Beland and Bret Rowden.
//
// ChangeLog:
// 10.12.2005 Lesh ripped everything that refers to MSS
// 15.12.2005 Lesh enabled sound in video
//----------------------------------------------------------------------------------
//#include "LocalCodeAll.h"
#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 "SMACK.H"
#include "ddraw.h"
#include "DirectX Common.h"
#include "DirectDraw Calls.h"
#include "Cinematics.h"
#include "soundman.h"
#include <vfs/Core/vfs.h>
#include <vfs/Core/vfs_file_raii.h>
#include "video.h"
#include "vsurface_private.h"
#include <crtdbg.h>
//-Structures----------------------------------------------------------------------
//-Flags-and-Symbols---------------------------------------------------------------
#define SMK_NUM_FLICS 4 // Maximum number of flics open
// SMKFLIC uiFlags
#define SMK_FLIC_OPEN 0x00000001 // Flic is open
#define SMK_FLIC_PLAYING 0x00000002 // Flic is playing
#define SMK_FLIC_LOOP 0x00000004 // Play flic in a loop
#define SMK_FLIC_AUTOCLOSE 0x00000008 // Close when done
//-Globals-------------------------------------------------------------------------
SMKFLIC SmkList[SMK_NUM_FLICS];
HWND hDisplayWindow = 0;
UINT32 uiDisplayHeight, uiDisplayWidth;
BOOLEAN fSuspendFlics = FALSE;
UINT32 uiFlicsPlaying = 0;
UINT32 guiSmackPixelFormat = SMACKBUFFER565;
LPDIRECTDRAWSURFACE lpVideoPlayback=NULL;
LPDIRECTDRAWSURFACE2 lpVideoPlayback2=NULL;
//-Function-Prototypes-------------------------------------------------------------
void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight);
void SmkShutdown(void);
SMKFLIC *SmkPlayFlic(CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fAutoClose);
BOOLEAN SmkPollFlics(void);
SMKFLIC *SmkOpenFlic(CHAR8 *cFilename);
void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop);
void SmkCloseFlic(SMKFLIC *pSmack);
SMKFLIC *SmkGetFreeFlic(void);
void SmkSetupVideo(void);
void SmkShutdownVideo(void);
BOOLEAN SmkPollFlics(void)
{
UINT32 uiCount;
BOOLEAN fFlicStatus = FALSE;
DDSURFACEDESC SurfaceDescription;
for(uiCount=0; uiCount < SMK_NUM_FLICS; uiCount++)
{
if(SmkList[uiCount].uiFlags & SMK_FLIC_PLAYING)
{
fFlicStatus=TRUE;
if(!fSuspendFlics)
{
if(!SmackWait(SmkList[uiCount].SmackHandle))
{
DDLockSurface(SmkList[uiCount].lpDDS, NULL, &SurfaceDescription, 0, NULL);
SmackToBuffer(SmkList[uiCount].SmackHandle,SmkList[uiCount].uiLeft,
SmkList[uiCount].uiTop,
SurfaceDescription.lPitch,
SmkList[uiCount].SmackHandle->Height,
SurfaceDescription.lpSurface,
guiSmackPixelFormat);
SmackDoFrame(SmkList[uiCount].SmackHandle);
DDUnlockSurface(SmkList[uiCount].lpDDS, SurfaceDescription.lpSurface);
// temp til I figure out what to do with it
//InvalidateRegion(0,0, 640, 480, FALSE);
// Check to see if the flic is done the last frame
if(SmkList[uiCount].SmackHandle->FrameNum==(SmkList[uiCount].SmackHandle->Frames-1))
{
// If flic is looping, reset frame to 0
if(SmkList[uiCount].uiFlags & SMK_FLIC_LOOP)
SmackGoto(SmkList[uiCount].SmackHandle, 0);
else if(SmkList[uiCount].uiFlags & SMK_FLIC_AUTOCLOSE)
SmkCloseFlic(&SmkList[uiCount]);
}
else
{
SmackNextFrame(SmkList[uiCount].SmackHandle);
}
}
}
}
}
if(!fFlicStatus)
SmkShutdownVideo();
return(fFlicStatus);
}
// Lesh changed this function only -----------------------------
void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight)
{
// Wipe the flic list clean
memset(SmkList, 0, sizeof(SMKFLIC)*SMK_NUM_FLICS);
// Set playback window properties
hDisplayWindow = hWindow;
uiDisplayWidth = uiWidth;
uiDisplayHeight= uiHeight;
// Use MMX acceleration, if available
SmackUseMMX(1);
//Get the sound Driver handle
void* pSoundDriver = SoundGetDriverHandle();
//if we got the sound handle, use sound during the intro
if( pSoundDriver )
SmackSoundUseDirectSound( pSoundDriver );
}
void SmkShutdown(void)
{
UINT32 uiCount;
// Close and deallocate any open flics
for(uiCount=0; uiCount < SMK_NUM_FLICS; uiCount++)
{
if(SmkList[uiCount].uiFlags & SMK_FLIC_OPEN)
SmkCloseFlic(&SmkList[uiCount]);
}
}
SMKFLIC *SmkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fClose)
{
SMKFLIC *pSmack;
// Open the flic
if((pSmack=SmkOpenFlic(cFilename))==NULL)
return(NULL);
// Set the blitting position on the screen
SmkSetBlitPosition(pSmack, uiLeft, uiTop);
// We're now playing, flag the flic for the poller to update
pSmack->uiFlags|=SMK_FLIC_PLAYING;
if(fClose)
pSmack->uiFlags|=SMK_FLIC_AUTOCLOSE;
return(pSmack);
}
SMKFLIC *SmkOpenFlic(const CHAR8 *cFilename)
{
SMKFLIC *pSmack;
// Get an available flic slot from the list
if(!(pSmack=SmkGetFreeFlic()))
{
ErrorMsg("SMK 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);
}
}
// Allocate a Smacker buffer for video decompression
if(!(pSmack->SmackBuffer=SmackBufferOpen(hDisplayWindow,SMACKAUTOBLIT,SCREEN_WIDTH,SCREEN_HEIGHT,0,0)))
{
ErrorMsg("SMK ERROR: Can't allocate a Smacker decompression buffer");
return(NULL);
}
// if(!(pSmack->SmackHandle=SmackOpen(cFilename, SMACKTRACKS, SMACKAUTOEXTRA)))
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(!(pSmack->SmackHandle=SmackOpen(tempfilename.to_string().c_str(), SMACKTRACKS, SMACKAUTOEXTRA)))
{
ErrorMsg("SMK ERROR: Smacker won't open the SMK file");
return(NULL);
}
// Make sure we have a video surface
SmkSetupVideo();
pSmack->cFilename=cFilename;
pSmack->lpDDS=lpVideoPlayback2;
pSmack->hWindow=hDisplayWindow;
// Smack flic is now open and ready to go
pSmack->uiFlags|=SMK_FLIC_OPEN;
return(pSmack);
}
void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop)
{
pSmack->uiLeft=uiLeft;
pSmack->uiTop=uiTop;
}
void SmkCloseFlic(SMKFLIC *pSmack)
{
// Attempt opening the filename
FileClose(pSmack->hFileHandle);
// Deallocate the smack buffers
SmackBufferClose(pSmack->SmackBuffer);
// Close the smack flic
SmackClose(pSmack->SmackHandle);
// Zero the memory, flags, etc.
memset(pSmack, 0, sizeof(SMKFLIC));
}
SMKFLIC *SmkGetFreeFlic(void)
{
UINT32 uiCount;
for(uiCount=0; uiCount < SMK_NUM_FLICS; uiCount++)
if(!(SmkList[uiCount].uiFlags & SMK_FLIC_OPEN))
return(&SmkList[uiCount]);
return(NULL);
}
void SmkSetupVideo(void)
{
// DEF:
// lpVideoPlayback2 = CinematicModeOn();
HVSURFACE hVSurface;
GetVideoSurface( &hVSurface, FRAME_BUFFER );
lpVideoPlayback2 = GetVideoSurfaceDDSurface( hVSurface );
DDSURFACEDESC SurfaceDescription;
ZEROMEM(SurfaceDescription);
SurfaceDescription.dwSize = sizeof (DDSURFACEDESC);
HRESULT ReturnCode = IDirectDrawSurface2_GetSurfaceDesc ( lpVideoPlayback2, &SurfaceDescription );
if (ReturnCode != DD_OK)
{
DirectXAttempt ( ReturnCode, __LINE__, __FILE__ );
return;
}
UINT16 usRed, usGreen, usBlue;
usRed = (UINT16) SurfaceDescription.ddpfPixelFormat.dwRBitMask;
usGreen = (UINT16) SurfaceDescription.ddpfPixelFormat.dwGBitMask;
usBlue = (UINT16) SurfaceDescription.ddpfPixelFormat.dwBBitMask;
if((usRed==0xf800) && (usGreen==0x07e0) && (usBlue==0x001f))
guiSmackPixelFormat=SMACKBUFFER565;
else
guiSmackPixelFormat=SMACKBUFFER555;
}
void SmkShutdownVideo(void)
{
//DEF:
// CinematicModeOff();
}
#include "types.h"
#include <algorithm>
#include <array>
#include <cstring>
#include <optional>
#include <vector>
extern "C"
{
#include "smacker.h"
}
#include "DEBUG.H"
#include "Cinematics.h"
#include "himage.h"
#include "local.h"
#include "soundman.h"
#include "vobject.h"
#include "vsurface.h"
#include <vfs/Core/vfs.h>
#include <vfs/Core/vfs_file_raii.h>
static constexpr UINT32 MAX_FLICS = 4; // How many flics can be open at once
static constexpr UINT32 NUM_AUDIO_TRACKS = 7; // Audio tracks an SMK file can carry
static constexpr UINT32 WAV_HEADER_SIZE = 44; // Header we prepend to the decoded audio
struct SMKFLIC {
// libsmacker decoder; null means the slot is free
smk decoder = nullptr;
bool playing = false;
// Close the flic once it has played to the end
bool autoClose = false;
// Where on the screen the flic is blitted
UINT32 left = 0, top = 0;
// Tick count the flic started playing at
UINT32 startTime = 0;
// Frame the decoder is on
UINT32 frame = 0;
double millisecondsPerFrame = 0.0;
// Last result of smk_first()/smk_next()
char status = SMK_DONE;
// WAV header followed by the decoded audio
std::array<std::vector<UINT8>, NUM_AUDIO_TRACKS> audio;
// SOUND_ERROR when the track isn't playing
std::array<UINT32, NUM_AUDIO_TRACKS> soundId;
};
static std::array<SMKFLIC, MAX_FLICS> flics;
static auto SmkGetFreeFlic() -> SMKFLIC*;
static auto SmkReadFile(const CHAR8 *filename) -> std::optional<std::vector<vfs::Byte>>;
static auto SmkDecodeAudio(SMKFLIC &flic) -> void;
static auto SmkStartAudio(SMKFLIC &flic, const CHAR8 *filename) -> void;
static auto SmkWriteWavHeader(UINT8 *wav, UINT32 pcmSize, UINT8 channels, UINT8 bitDepth, UINT32 rate) -> void;
static auto SmkAdvanceToCurrentFrame(SMKFLIC &flic) -> void;
static auto SmkBlitFrame(SMKFLIC &flic) -> void;
BOOLEAN SmkPollFlics()
{
bool anyPlaying = false;
for (SMKFLIC &flic : flics)
{
if (!flic.playing)
continue;
SmkAdvanceToCurrentFrame(flic);
if (flic.status == SMK_DONE || flic.status == SMK_ERROR)
{
if (flic.autoClose)
SmkCloseFlic(&flic);
else
flic.playing = false;
}
else
{
anyPlaying = true;
SmkBlitFrame(flic);
}
}
return anyPlaying;
}
void SmkInitialize()
{
for (SMKFLIC &flic : flics)
{
flic.decoder = nullptr;
flic.playing = false;
flic.autoClose = false;
flic.soundId.fill(SOUND_ERROR);
}
}
void SmkShutdown()
{
// Close and deallocate any open flics
for (SMKFLIC &flic : flics)
SmkCloseFlic(&flic);
}
SMKFLIC *SmkPlayFlic(const CHAR8 *filename, UINT32 left, UINT32 top, BOOLEAN autoClose)
{
SMKFLIC *flic = SmkGetFreeFlic();
if (flic == nullptr)
{
ErrorMsg("SMK ERROR: Out of flic slots, cannot open another");
return nullptr;
}
std::optional<std::vector<vfs::Byte>> fileData = SmkReadFile(filename);
if (!fileData)
return nullptr;
// libsmacker copies the compressed frames it needs out of the buffer, so
// fileData can go away again as soon as the file is open
flic->decoder = smk_open_memory(reinterpret_cast<const unsigned char *>(fileData->data()), static_cast<unsigned long>(fileData->size()));
if (flic->decoder == nullptr)
{
ErrorMsg("SMK ERROR: libsmacker won't open the SMK file");
return nullptr;
}
// The slot is now taken (decoder != nullptr) and ready to go
flic->left = left;
flic->top = top;
double microsecondsPerFrame = 0.0;
if (smk_info_all(flic->decoder, nullptr, nullptr, &microsecondsPerFrame) < 0 || microsecondsPerFrame <= 0.0)
{
ErrorMsg("SMK ERROR: Can't read the playback speed of the SMK file");
SmkCloseFlic(flic);
return nullptr;
}
// The video plays too slowly at microsecond resolution, speed it up by
// rounding down to milliseconds
flic->millisecondsPerFrame = microsecondsPerFrame / 1000.0;
SmkDecodeAudio(*flic);
// Rewind, this time to decode the picture
if (smk_enable_all(flic->decoder, SMK_VIDEO_TRACK) < 0)
{
ErrorMsg("SMK ERROR: Can't enable the video track of the SMK file");
SmkCloseFlic(flic);
return nullptr;
}
flic->status = smk_first(flic->decoder);
flic->frame = 0;
flic->startTime = GetTickCount();
SmkStartAudio(*flic, filename);
// We're now playing, flag the flic for the poller to update
flic->playing = true;
flic->autoClose = autoClose != FALSE;
return flic;
}
void SmkCloseFlic(SMKFLIC *flic)
{
// SmkPollFlics() closes flics that have played to the end by itself, so the
// caller may well be handing us a slot that is already free
if (flic->decoder == nullptr)
return;
for (UINT32 track = 0; track < NUM_AUDIO_TRACKS; ++track)
{
// The sound was streaming straight out of the audio buffer, so it has to
// be stopped before that buffer is released
if (flic->soundId[track] != SOUND_ERROR)
{
SoundStop(flic->soundId[track]);
flic->soundId[track] = SOUND_ERROR;
}
flic->audio[track] = {};
}
smk_close(flic->decoder);
flic->decoder = nullptr;
flic->playing = false;
flic->autoClose = false;
}
static SMKFLIC *SmkGetFreeFlic()
{
for (SMKFLIC &flic : flics)
if (flic.decoder == nullptr)
return &flic;
return nullptr;
}
// Reads a video file out of the VFS in one go. libsmacker can only read from a
// plain file or from memory, and the file may well be sitting inside an archive.
static std::optional<std::vector<vfs::Byte>> SmkReadFile(const CHAR8 *filename)
{
vfs::Path videoName(filename);
std::vector<vfs::Byte> data;
try
{
if (!getVFS()->fileExists(videoName))
return std::nullopt;
vfs::COpenReadFile file(videoName);
vfs::size_t size = file->getSize();
if (size == 0)
return std::nullopt;
data.resize(size);
file->read(data.data(), size);
}
catch (std::exception &ex)
{
SGP_RETHROW(_BS(L"Video file \"") << videoName << L"\" could not be read" << _BS::wget, ex);
}
return data;
}
// Decodes the audio of the whole file into flic.audio, each track preceded by a
// WAV header. Unlike SMACKW32.DLL, libsmacker hands out audio a frame at a time
// and leaves playing it to us, so it all has to be collected up front.
static void SmkDecodeAudio(SMKFLIC &flic)
{
unsigned char trackMask = 0;
std::array<unsigned char, NUM_AUDIO_TRACKS> channels{};
std::array<unsigned char, NUM_AUDIO_TRACKS> bitDepth{};
std::array<unsigned long, NUM_AUDIO_TRACKS> rate{};
if (smk_info_audio(flic.decoder, &trackMask, channels.data(), bitDepth.data(), rate.data()) < 0 || trackMask == 0)
return;
// Decoding the audio means running through the entire file. Leave the video
// track disabled so that this pass doesn't decode the picture as well.
if (smk_enable_all(flic.decoder, trackMask) < 0)
return;
// Leave room for the WAV header, which can only be written once the size of
// the track is known
for (UINT32 track = 0; track < NUM_AUDIO_TRACKS; ++track)
if (trackMask & (1 << track))
flic.audio[track].resize(WAV_HEADER_SIZE);
for (char status = smk_first(flic.decoder); status != SMK_DONE; status = smk_next(flic.decoder))
{
if (status == SMK_ERROR)
{
ErrorMsg("SMK ERROR: libsmacker failed to decode the audio of the SMK file");
break;
}
for (UINT32 track = 0; track < NUM_AUDIO_TRACKS; ++track)
{
if (!(trackMask & (1 << track)))
continue;
unsigned long size = smk_get_audio_size(flic.decoder, static_cast<unsigned char>(track));
if (size == 0)
continue;
const UINT8 *pcm = smk_get_audio(flic.decoder, static_cast<unsigned char>(track));
flic.audio[track].insert(flic.audio[track].end(), pcm, pcm + size);
}
}
for (UINT32 track = 0; track < NUM_AUDIO_TRACKS; ++track)
{
std::vector<UINT8> &trackAudio = flic.audio[track];
if (trackAudio.size() <= WAV_HEADER_SIZE)
{
// Track carries no audio after all
trackAudio = {};
continue;
}
SmkWriteWavHeader(trackAudio.data(), static_cast<UINT32>(trackAudio.size()) - WAV_HEADER_SIZE,
channels[track], bitDepth[track], static_cast<UINT32>(rate[track]));
}
}
static void SmkStartAudio(SMKFLIC &flic, const CHAR8 *filename)
{
SOUNDPARMS params;
memset(&params, 0xff, sizeof(params)); // 0xffffffff in every field means "use the default"
params.uiLoop = 1;
for (UINT32 track = 0; track < NUM_AUDIO_TRACKS; ++track)
{
if (flic.audio[track].empty())
continue;
flic.soundId[track] = SoundPlayFromBuffer(filename, flic.audio[track].data(),
static_cast<UINT32>(flic.audio[track].size()), &params);
}
}
// Writes a canonical 44 byte WAV header for uncompressed PCM, so that the audio
// we decoded can be handed to the sound module as if it came from a sound file.
static void SmkWriteWavHeader(UINT8 *wav, UINT32 pcmSize, UINT8 channels, UINT8 bitDepth, UINT32 rate)
{
const UINT16 blockAlign = static_cast<UINT16>(channels * (bitDepth / 8));
memcpy(wav + 0, "RIFF", 4);
*reinterpret_cast<UINT32 *>(wav + 4) = 36 + pcmSize; // size of everything after this field
memcpy(wav + 8, "WAVEfmt ", 8);
*reinterpret_cast<UINT32 *>(wav + 16) = 16; // size of the fmt chunk
*reinterpret_cast<UINT16 *>(wav + 20) = 1; // format: uncompressed PCM
*reinterpret_cast<UINT16 *>(wav + 22) = channels;
*reinterpret_cast<UINT32 *>(wav + 24) = rate;
*reinterpret_cast<UINT32 *>(wav + 28) = rate * blockAlign; // byte rate
*reinterpret_cast<UINT16 *>(wav + 32) = blockAlign;
*reinterpret_cast<UINT16 *>(wav + 34) = bitDepth;
memcpy(wav + 36, "data", 4);
*reinterpret_cast<UINT32 *>(wav + 40) = pcmSize;
}
// Decodes forward until the frame that should be on screen by now. SMACKW32.DLL
// kept the playback clock itself, libsmacker leaves that to the caller.
static void SmkAdvanceToCurrentFrame(SMKFLIC &flic)
{
UINT32 milliseconds = GetTickCount() - flic.startTime;
UINT32 targetFrame = static_cast<UINT32>(milliseconds / flic.millisecondsPerFrame);
while (flic.status != SMK_DONE && flic.status != SMK_ERROR && flic.frame != targetFrame)
{
flic.status = smk_next(flic.decoder);
++flic.frame;
}
}
static void SmkBlitFrame(SMKFLIC &flic)
{
// TODO: the Y scale modes (SMK_FLAG_Y_INTERLACE, SMK_FLAG_Y_DOUBLE) are not
// handled, none of the videos that ship with the game use them
const UINT8 *source = smk_get_video(flic.decoder);
if (source == nullptr)
return;
const UINT8 *sourcePalette = smk_get_palette(flic.decoder);
if (sourcePalette == nullptr)
return;
unsigned long sourceWidth, sourceHeight;
if (smk_info_video(flic.decoder, &sourceWidth, &sourceHeight, nullptr) < 0)
return;
UINT16 palette[256];
for (UINT32 i = 0; i < 256; ++i)
palette[i] = Get16BPPColor(FROMRGB(sourcePalette[i * 3], sourcePalette[i * 3 + 1], sourcePalette[i * 3 + 2]));
UINT32 destPitch;
UINT16 *dest = reinterpret_cast<UINT16 *>(LockVideoSurface(FRAME_BUFFER, &destPitch));
if (dest == nullptr)
return;
destPitch /= sizeof(UINT16); // pitch in pixels rather than bytes
// Blit the part of the frame that lands on the screen
// std::min is parenthesised to keep windows.h's min() macro off it
unsigned long columns = flic.left >= static_cast<UINT32>(SCREEN_WIDTH) ? 0 : (std::min)(sourceWidth, static_cast<unsigned long>(SCREEN_WIDTH - flic.left));
unsigned long rows = flic.top >= static_cast<UINT32>(SCREEN_HEIGHT) ? 0 : (std::min)(sourceHeight, static_cast<unsigned long>(SCREEN_HEIGHT - flic.top));
dest += flic.left + flic.top * destPitch;
for (unsigned long y = 0; y < rows; ++y)
{
for (unsigned long x = 0; x < columns; ++x)
dest[x] = palette[source[x]];
dest += destPitch;
source += sourceWidth;
}
UnLockVideoSurface(FRAME_BUFFER);
}
+14 -65
View File
@@ -1,65 +1,14 @@
#ifndef _CINEMATICS_H_
#define _CINEMATICS_H_
#include "SMACK.H"
struct SMKFLIC
{
const CHAR8 *cFilename;
// HFILE hFileHandle;
HWFILE hFileHandle;
Smack *SmackHandle;
SmackBuf *SmackBuffer;
UINT32 uiFlags;
LPDIRECTDRAWSURFACE2 lpDDS;
HWND hWindow;
UINT32 uiFrame;
UINT32 uiLeft, uiTop;
// LPDIRECTDRAW2 lpDD;
// UINT32 uiNumFrames;
// UINT8 *pAudioData;
// UINT8 *pCueData;
};
void SmkInitialize(HWND hWindow, UINT32 uiWidth, UINT32 uiHeight);
void SmkShutdown(void);
SMKFLIC *SmkPlayFlic(const CHAR8 *cFilename, UINT32 uiLeft, UINT32 uiTop, BOOLEAN fAutoClose);
BOOLEAN SmkPollFlics(void);
SMKFLIC *SmkOpenFlic(const CHAR8 *cFilename);
void SmkSetBlitPosition(SMKFLIC *pSmack, UINT32 uiLeft, UINT32 uiTop);
void SmkCloseFlic(SMKFLIC *pSmack);
SMKFLIC *SmkGetFreeFlic(void);
/*
//--------------------------------------------------------------------------
// Prototypes etc. for our functions that make use of the Smacker library.
//
// Written by Derek Beland, Jan 11, 1995
#define FLICSOUNDID "BLAH" // ID for smack flic w/ sound :)
typedef struct {
unsigned long offset;
unsigned long length;
} SMPLARRAY;
extern SmackBuf *sbuf;
extern Smack *smk;
extern int smktag;
extern HANDLE smkhandle;
extern int SmackFlicIsOpened;
extern int SmackFlicIsPlaying;
HANDLE OpenSmackFlic(char *fname,Smack **s,u32);
int GetNextCue(void);
void PlayCueSamples(void);
void InitFlicSamples(HANDLE fhandle);
void FreeFlicSamples(void);
int SmackPlayFlic(char *,u32);
void SmackShowNextFrame(void);
void CloseSmackFlic(void);
void InitPal(HWND wh);
*/
#endif
#ifndef _CINEMATICS_H_
#define _CINEMATICS_H_
#include "types.h"
struct SMKFLIC;
void SmkInitialize();
void SmkShutdown();
SMKFLIC *SmkPlayFlic(const CHAR8 *filename, UINT32 left, UINT32 top, BOOLEAN autoClose);
BOOLEAN SmkPollFlics();
void SmkCloseFlic(SMKFLIC *flic);
#endif
-434
View File
@@ -1,434 +0,0 @@
#ifndef SMACKH
#define SMACKH
#define SMACKVERSION "3.2f"
#ifndef __RADRES__
#include "RAD.H"
RADDEFSTART
typedef struct SmackTag {
u32 Version; // SMK2 only right now
u32 Width; // Width (1 based, 640 for example)
u32 Height; // Height (1 based, 480 for example)
u32 Frames; // Number of frames (1 based, 100 = 100 frames)
u32 MSPerFrame; // Frame Rate
u32 SmackerType; // bit 0 set=ring frame
u32 LargestInTrack[7]; // Largest single size for each track
u32 tablesize; // Size of the init tables
u32 codesize; // Compression info
u32 absize; // ditto
u32 detailsize; // ditto
u32 typesize; // ditto
u32 TrackType[7]; // high byte=0x80-Comp,0x40-PCM data,0x20-16 bit,0x10-stereo
u32 extra; // extra value (should be zero)
u32 NewPalette; // set to one if the palette changed
u8 Palette[772]; // palette data
u32 PalType; // type of palette
u32 FrameNum; // Frame Number to be displayed
u32 FrameSize; // The current frame's size in bytes
u32 SndSize; // The current frame sound tracks' size in bytes
s32 LastRectx; // Rect set in from SmackToBufferRect (X coord)
s32 LastRecty; // Rect set in from SmackToBufferRect (Y coord)
s32 LastRectw; // Rect set in from SmackToBufferRect (Width)
s32 LastRecth; // Rect set in from SmackToBufferRect (Height)
u32 OpenFlags; // flags used on open
u32 LeftOfs; // Left Offset used in SmackTo
u32 TopOfs; // Top Offset used in SmackTo
u32 LargestFrameSize; // Largest frame size
u32 Highest1SecRate; // Highest 1 sec data rate
u32 Highest1SecFrame; // Highest 1 sec data rate starting frame
u32 ReadError; // Set to non-zero if a read error has ocurred
u32 addr32; // translated address for 16 bit interface
} Smack;
#define SmackHeaderSize(smk) ((((u8*)&((smk)->extra))-((u8*)(smk)))+4)
typedef struct SmackSumTag {
u32 TotalTime; // total time
u32 MS100PerFrame; // MS*100 per frame (100000/MS100PerFrame=Frames/Sec)
u32 TotalOpenTime; // Time to open and prepare for decompression
u32 TotalFrames; // Total Frames displayed
u32 SkippedFrames; // Total number of skipped frames
u32 SoundSkips; // Total number of sound skips
u32 TotalBlitTime; // Total time spent blitting
u32 TotalReadTime; // Total time spent reading
u32 TotalDecompTime; // Total time spent decompressing
u32 TotalBackReadTime; // Total time spent reading in background
u32 TotalReadSpeed; // Total io speed (bytes/second)
u32 SlowestFrameTime; // Slowest single frame time
u32 Slowest2FrameTime; // Second slowest single frame time
u32 SlowestFrameNum; // Slowest single frame number
u32 Slowest2FrameNum; // Second slowest single frame number
u32 AverageFrameSize; // Average size of the frame
u32 HighestMemAmount; // Highest amount of memory allocated
u32 TotalExtraMemory; // Total extra memory allocated
u32 HighestExtraUsed; // Highest extra memory actually used
} SmackSum;
//=======================================================================
#define SMACKNEEDPAN 0x00020L // Will be setting the pan
#define SMACKNEEDVOLUME 0x00040L // Will be setting the volume
#define SMACKFRAMERATE 0x00080L // Override fr (call SmackFrameRate first)
#define SMACKLOADEXTRA 0x00100L // Load the extra buffer during SmackOpen
#define SMACKPRELOADALL 0x00200L // Preload the entire animation
#define SMACKNOSKIP 0x00400L // Don't skip frames if falling behind
#define SMACKSIMULATE 0x00800L // Simulate the speed (call SmackSim first)
#define SMACKFILEHANDLE 0x01000L // Use when passing in a file handle
#define SMACKTRACK1 0x02000L // Play audio track 1
#define SMACKTRACK2 0x04000L // Play audio track 2
#define SMACKTRACK3 0x08000L // Play audio track 3
#define SMACKTRACK4 0x10000L // Play audio track 4
#define SMACKTRACK5 0x20000L // Play audio track 5
#define SMACKTRACK6 0x40000L // Play audio track 6
#define SMACKTRACK7 0x80000L // Play audio track 7
#define SMACKTRACKS (SMACKTRACK1|SMACKTRACK2|SMACKTRACK3|SMACKTRACK4|SMACKTRACK5|SMACKTRACK6|SMACKTRACK7)
#define SMACKBUFFERREVERSED 0x00000001
#define SMACKBUFFER555 0x80000000
#define SMACKBUFFER565 0xc0000000
#define SMACKBUFFER16 (SMACKBUFFER555|SMACKBUFFER565)
#define SMACKYINTERLACE 0x100000L // Force interleaving Y scaling
#define SMACKYDOUBLE 0x200000L // Force doubling Y scaling
#define SMACKYNONE (SMACKYINTERLACE|SMACKYDOUBLE) // Force normal Y scaling
#define SMACKFILEISSMK 0x2000000L // Internal flag for 16 to 32 bit thunking
#define SMACKAUTOEXTRA 0xffffffffL // NOT A FLAG! - Use as extrabuf param
//=======================================================================
#define SMACKSURFACEFAST 0
#define SMACKSURFACESLOW 1
#define SMACKSURFACEDIRECT 2
RADEXPFUNC Smack PTR4* RADEXPLINK SmackOpen(const char PTR4* name,u32 flags,u32 extrabuf);
#ifdef __RADMAC__
#include <files.h>
RADEXPFUNC Smack PTR4* RADEXPLINK SmackMacOpen(FSSpec* fsp,u32 flags,u32 extrabuf);
#endif
RADEXPFUNC u32 RADEXPLINK SmackDoFrame(Smack PTR4* smk);
RADEXPFUNC void RADEXPLINK SmackNextFrame(Smack PTR4* smk);
RADEXPFUNC u32 RADEXPLINK SmackWait(Smack PTR4* smk);
RADEXPFUNC void RADEXPLINK SmackClose(Smack PTR4* smk);
RADEXPFUNC void RADEXPLINK SmackVolumePan(Smack PTR4* smk, u32 trackflag,u32 volume,u32 pan);
RADEXPFUNC void RADEXPLINK SmackSummary(Smack PTR4* smk,SmackSum PTR4* sum);
RADEXPFUNC u32 RADEXPLINK SmackSoundInTrack(Smack PTR4* smk,u32 trackflags);
RADEXPFUNC u32 RADEXPLINK SmackSoundOnOff(Smack PTR4* smk,u32 on);
#ifndef __RADMAC__
RADEXPFUNC void RADEXPLINK SmackToScreen(Smack PTR4* smk,u32 left,u32 top,u32 BytePS,const u16 PTR4* WinTbl,void* SetBank,u32 Flags);
#endif
RADEXPFUNC void RADEXPLINK SmackToBuffer(Smack PTR4* smk,u32 left,u32 top,u32 Pitch,u32 destheight,const void PTR4* buf,u32 Flags);
RADEXPFUNC u32 RADEXPLINK SmackToBufferRect(Smack PTR4* smk, u32 SmackSurface);
RADEXPFUNC void RADEXPLINK SmackGoto(Smack PTR4* smk,u32 frame);
RADEXPFUNC void RADEXPLINK SmackColorRemapWithTrans(Smack PTR4* smk,const void PTR4* remappal,u32 numcolors,u32 paltype,u32 transindex);
#define SmackColorRemap(smk,remappal,numcolors,paltype) SmackColorRemapWithTrans(smk,remappal,numcolors,paltype,1000)
RADEXPFUNC void RADEXPLINK SmackColorTrans(Smack PTR4* smk,const void PTR4* trans);
RADEXPFUNC void RADEXPLINK SmackFrameRate(u32 forcerate);
RADEXPFUNC void RADEXPLINK SmackSimulate(u32 sim);
RADEXPFUNC u32 RADEXPLINK SmackGetTrackData(Smack PTR4* smk,void PTR4* dest,u32 trackflag);
RADEXPFUNC void RADEXPLINK SmackSoundCheck(void);
//======================================================================
// the functions for the new SmackBlit API
typedef struct _SMACKBLIT PTR4* HSMACKBLIT;
typedef struct _SMACKBLIT {
u32 Flags;
u8 PTR4* Palette;
u32 PalType;
u16 PTR4* SmoothTable;
u16 PTR4* Conv8to16Table;
u32 whichmode;
u32 palindex;
u32 t16index;
u32 smoothindex;
u32 smoothtype;
u32 firstpalette;
} SMACKBLIT;
#define SMACKBLIT1X 1
#define SMACKBLIT2X 2
#define SMACKBLIT2XSMOOTHING 4
#define SMACKBLIT2XINTERLACE 8
RADEXPFUNC HSMACKBLIT RADEXPLINK SmackBlitOpen(u32 flags);
RADEXPFUNC void RADEXPLINK SmackBlitSetPalette(HSMACKBLIT sblit, void PTR4* Palette,u32 PalType);
RADEXPFUNC u32 RADEXPLINK SmackBlitSetFlags(HSMACKBLIT sblit,u32 flags);
RADEXPFUNC void RADEXPLINK SmackBlit(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch);
RADEXPFUNC void RADEXPLINK SmackBlitClear(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, u32 destw, u32 desth, s32 color);
RADEXPFUNC void RADEXPLINK SmackBlitClose(HSMACKBLIT sblit);
RADEXPFUNC void RADEXPLINK SmackBlitTrans(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch, u32 trans);
RADEXPFUNC void RADEXPLINK SmackBlitMask(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch, u32 trans,void PTR4* mask);
RADEXPFUNC void RADEXPLINK SmackBlitMerge(HSMACKBLIT sblit,void PTR4* dest, u32 destpitch, u32 destx, u32 desty, void PTR4* src, u32 srcpitch, u32 srcx, u32 srcy, u32 srcw, u32 srch, u32 trans,void PTR4* back);
RADEXPFUNC char PTR4* RADEXPLINK SmackBlitString(HSMACKBLIT sblit,char PTR4* dest);
#ifndef __RADMAC__
RADEXPFUNC u32 RADEXPLINK SmackUseMMX(u32 flag); //0=off, 1=on, 2=query current
#endif
//======================================================================
#ifdef __RADDOS__
#define SMACKSOUNDNONE -1
extern void* SmackTimerSetupAddr;
extern void* SmackTimerReadAddr;
extern void* SmackTimerDoneAddr;
typedef void RADEXPLINK (*SmackTimerSetupType)(void);
typedef u32 RADEXPLINK (*SmackTimerReadType)(void);
typedef void RADEXPLINK (*SmackTimerDoneType)(void);
#define SmackTimerSetup() ((SmackTimerSetupType)(SmackTimerSetupAddr))()
#define SmackTimerRead() ((SmackTimerReadType)(SmackTimerReadAddr))()
#define SmackTimerDone() ((SmackTimerDoneType)(SmackTimerDoneAddr))()
RADEXPFUNC u8 RADEXPLINK SmackSoundUseMSS(void* DigDriver);
#ifndef AIL_startup
#ifdef __SW_3R
extern s32 cdecl AIL_startup_reg(void);
#define AIL_startup AIL_startup_reg
#else
extern s32 cdecl AIL_startup_stack(void);
#define AIL_startup AIL_startup_stack
#endif
#endif
#define SmackSoundMSSLiteInit() SmackSoundMSSLiteInitWithStart(&AIL_startup);
RADEXPFUNC void RADEXPLINK SmackSoundMSSLiteInitWithStart(void* start);
RADEXPFUNC void RADEXPLINK SmackSoundMSSLiteDone(void);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS3r(u32 SOSDriver,u32 MaxTimerSpeed);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS3s(u32 SOSDriver,u32 MaxTimerSpeed);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS4r(u32 SOSDriver,u32 MaxTimerSpeed);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseSOS4s(u32 SOSDriver,u32 MaxTimerSpeed);
#ifdef __SW_3R
#define SmackSoundUseSOS3 SmackSoundUseSOS3r
#define SmackSoundUseSOS4 SmackSoundUseSOS4r
#else
#define SmackSoundUseSOS3 SmackSoundUseSOS3s
#define SmackSoundUseSOS4 SmackSoundUseSOS4s
#endif
#else
#define SMACKRESRESET 0
#define SMACKRES640X400 1
#define SMACKRES640X480 2
#define SMACKRES800X600 3
#define SMACKRES1024X768 4
RADEXPFUNC u32 RADEXPLINK SmackSetSystemRes(u32 mode); // use SMACKRES* values
#define SMACKNOCUSTOMBLIT 128
#define SMACKSMOOTHBLIT 256
#define SMACKINTERLACEBLIT 512
#ifdef __RADMAC__
#include <windows.h>
#include <palettes.h>
#include <qdoffscreen.h>
#define SmackTimerSetup()
#define SmackTimerDone()
RADEXPFUNC u32 RADEXPLINK SmackTimerRead(void);
RADEXPFUNC s32 RADEXPLINK SmackGDSurfaceType( GDHandle gd );
#define SMACKAUTOBLIT 0
#define SMACKDIRECTBLIT 1
#define SMACKGWORLDBLIT 2
typedef struct SmackBufTag {
u32 Reversed;
u32 SurfaceType; // SMACKSURFACExxxxxx
u32 BlitType; // SMACKxxxxxBLIT
u32 Width;
u32 Height;
u32 Pitch;
u32 Zoomed;
u32 ZWidth;
u32 ZHeight;
u32 DispColors; // colors on screen
u32 MaxPalColors;
u32 PalColorsInUse;
u32 StartPalColor;
u32 EndPalColor;
void* Buffer;
void* Palette;
u32 PalType;
u32 SoftwareCursor;
WindowPtr wp;
GWorldPtr gwp;
CTabHandle cth;
PaletteHandle palh;
GDHandle gd;
u32 gdSurfaceType;
HSMACKBLIT sblit;
void * ScreenAddr;
u32 ScreenPitch;
s32 manyblits;
s32 PTR4* blitrects;
s32 PTR4* rectsptr;
s32 maxrects;
s32 numrects;
} SmackBuf;
#else
#ifdef __RADWIN__
#define INCLUDE_MMSYSTEM_H
#include "windows.h"
#include "windowsx.h"
#ifdef __RADNT__ // to combat WIN32_LEAN_AND_MEAN
#include "mmsystem.h"
RADEXPFUNC s32 RADEXPLINK SmackDDSurfaceType(void* lpDDS);
#endif
#define SMACKAUTOBLIT 0
#define SMACKFULL320X240BLIT 1
#define SMACKFULL320X200BLIT 2
#define SMACKFULL320X200DIRECTBLIT 3
#define SMACKSTANDARDBLIT 4
#define SMACKWINGBLIT 5
#define SMACKDIBSECTIONBLIT 5
#define WM_SMACKACTIVATE WM_USER+0x5678
typedef struct SmackBufTag {
u32 Reversed; // 1 if the buffer is upside down
u32 SurfaceType; // SMACKSURFACExxxx defines
u32 BlitType; // SMACKxxxxBLIT defines
u32 FullScreen; // 1 if full-screen
u32 Width;
u32 Height;
u32 Pitch;
u32 Zoomed;
u32 ZWidth;
u32 ZHeight;
u32 DispColors; // colors on the screen
u32 MaxPalColors; // total possible colors in palette (usually 256)
u32 PalColorsInUse; // Used colors in palette (usually 236)
u32 StartPalColor; // first usable color index (usually 10)
u32 EndPalColor; // last usable color index (usually 246)
RGBQUAD Palette[256];
u32 PalType;
u32 forceredraw; // force a complete redraw on next blit (for >8bit)
u32 didapalette; // force an invalidate on the next palette change
void PTR4* Buffer;
void PTR4* DIBRestore;
u32 OurBitmap;
u32 OrigBitmap;
u32 OurPalette;
u32 WinGDC;
u32 FullFocused;
u32 ParentHwnd;
u32 OldParWndProc;
u32 OldDispWndProc;
u32 DispHwnd;
u32 WinGBufHandle;
void PTR4* lpDD;
void PTR4* lpDDSP;
u32 DDSurfaceType;
HSMACKBLIT DDblit;
s32 ddSoftwarecur;
s32 didaddblit;
s32 lastwasdd;
RECT ddscreen;
s32 manyblits;
s32 PTR4* blitrects;
s32 PTR4* rectsptr;
s32 maxrects;
s32 numrects;
HDC lastdc;
} SmackBuf;
RADEXPFUNC void RADEXPLINK SmackGet(Smack PTR4* smk,void PTR4* dest);
RADEXPFUNC void RADEXPLINK SmackBufferGet( SmackBuf PTR4* sbuf, void PTR4* dest);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseMSS(void PTR4* dd);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseDirectSound(void PTR4* dd); // NULL=Create
RADEXPFUNC void RADEXPLINK SmackSoundSetDirectSoundHWND(HWND hw);
RADEXPFUNC u8 RADEXPLINK SmackSoundUseDW(u32 openfreq, u32 openbits, u32 openchans);
#define SmackTimerSetup()
#define SmackTimerDone()
#define SmackTimerRead timeGetTime
#endif
#endif
#ifdef __RADMAC__
RADEXPFUNC SmackBuf PTR4* RADEXPLINK SmackBufferOpen( WindowPtr wp, u32 BlitType, u32 width, u32 height, u32 ZoomW, u32 ZoomH );
RADEXPFUNC u32 RADEXPLINK SmackBufferBlit( SmackBuf PTR4* sbuf, s32 hwndx, s32 hwndy, s32 subx, s32 suby, s32 subw, s32 subh );
RADEXPFUNC void RADEXPLINK SmackBufferFromScreen( SmackBuf PTR4* destbuf, s32 x, s32 y);
RADEXPFUNC s32 RADEXPLINK SmackIsSoftwareCursor(GDHandle gd);
RADEXPFUNC s32 RADEXPLINK SmackCheckCursor(WindowPtr wp,s32 x,s32 y,s32 w,s32 h);
RADEXPFUNC void RADEXPLINK SmackRestoreCursor(s32 checkcount);
#else
RADEXPFUNC SmackBuf PTR4* RADEXPLINK SmackBufferOpen( HWND wnd, u32 BlitType, u32 width, u32 height, u32 ZoomW, u32 ZoomH );
RADEXPFUNC u32 RADEXPLINK SmackBufferBlit( SmackBuf PTR4* sbuf, HDC dc, s32 hwndx, s32 hwndy, s32 subx, s32 suby, s32 subw, s32 subh );
RADEXPFUNC void RADEXPLINK SmackBufferFromScreen( SmackBuf PTR4* destbuf, HWND hw, s32 x, s32 y);
RADEXPFUNC s32 RADEXPLINK SmackIsSoftwareCursor(void* lpDDSP,HCURSOR cur);
RADEXPFUNC s32 RADEXPLINK SmackCheckCursor(HWND wnd,s32 x,s32 y,s32 w,s32 h);
RADEXPFUNC void RADEXPLINK SmackRestoreCursor(s32 checkcount);
#endif
RADEXPFUNC void RADEXPLINK SmackBufferStartMultipleBlits( SmackBuf PTR4* sbuf );
RADEXPFUNC void RADEXPLINK SmackBufferEndMultipleBlits( SmackBuf PTR4* sbuf );
RADEXPFUNC char PTR4* RADEXPLINK SmackBufferString(SmackBuf PTR4* sb,char PTR4* dest);
RADEXPFUNC void RADEXPLINK SmackBufferNewPalette( SmackBuf PTR4* sbuf, const void PTR4* pal, u32 paltype );
RADEXPFUNC u32 RADEXPLINK SmackBufferSetPalette( SmackBuf PTR4* sbuf );
RADEXPFUNC void RADEXPLINK SmackBufferClose( SmackBuf PTR4* sbuf );
RADEXPFUNC void RADEXPLINK SmackBufferClear( SmackBuf PTR4* destbuf, u32 color);
RADEXPFUNC void RADEXPLINK SmackBufferToBuffer( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh);
RADEXPFUNC void RADEXPLINK SmackBufferToBufferTrans( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh,u32 TransColor);
RADEXPFUNC void RADEXPLINK SmackBufferToBufferMask( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh,u32 TransColor,const SmackBuf PTR4* maskbuf);
RADEXPFUNC void RADEXPLINK SmackBufferToBufferMerge( SmackBuf PTR4* destbuf, s32 destx, s32 desty, const SmackBuf PTR4* sourcebuf,s32 sourcex,s32 sourcey,s32 sourcew,s32 sourceh,u32 TransColor,const SmackBuf PTR4* mergebuf);
RADEXPFUNC void RADEXPLINK SmackBufferCopyPalette( SmackBuf PTR4* destbuf, SmackBuf PTR4* sourcebuf, u32 remap);
RADEXPFUNC u32 RADEXPLINK SmackBufferFocused( SmackBuf PTR4* sbuf);
#endif
RADDEFEND
#endif
#endif