mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-13 21:31:53 +00:00
TINSEL: Initial work on the Saturn version of DW1
This version is using the same graphics format as the PSX version, with differences in resource endianess, but features digital music with a different track structure and has a different sound sample format Pending issues: - Font rendering is wrong - this is evident in the text and menus in the game title screen - Cursor sprite and trails are wrong - can be seen in the menu of the game title screen - Digital music is not supported yet - seems that a different track structure is used - The sound sample format is different than the PC version - looks to be raw, but isn't - The game crashes at the first room after watching Rincewind's waking up cutscene
This commit is contained in:
parent
11dbe3ca3d
commit
4f1676e38b
@ -157,7 +157,11 @@ bool GotoCD() {
|
||||
|
||||
bool TinselFile::_warningShown = false;
|
||||
|
||||
TinselFile::TinselFile() : ReadStreamEndian(TinselV1Mac) {
|
||||
TinselFile::TinselFile() : ReadStreamEndian(TinselV1Saturn) {
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
TinselFile::TinselFile(bool bigEndian) : ReadStreamEndian(bigEndian) {
|
||||
_stream = nullptr;
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,9 @@ private:
|
||||
Common::SeekableReadStream *_stream;
|
||||
bool openInternal(const Common::String &filename);
|
||||
public:
|
||||
// This constructor is only used for _sampleStream inside sound.h
|
||||
TinselFile();
|
||||
TinselFile(bool bigEndian);
|
||||
~TinselFile() override;
|
||||
bool open(const Common::String &filename);
|
||||
void close();
|
||||
|
@ -56,11 +56,11 @@ static inline uint16 t3getColor(uint8 r, uint8 g, uint8 b) {
|
||||
}
|
||||
|
||||
/**
|
||||
* PSX Block list unwinder.
|
||||
* PSX/Saturn Block list unwinder.
|
||||
* Chunk type 0x0003 (CHUNK_CHARPTR) in PSX version of DW 1 & 2 is compressed (original code
|
||||
* calls the compression PJCRLE), thus we need to decompress it before passing data to drawing functions
|
||||
*/
|
||||
uint8* psxPJCRLEUnwinder(uint16 imageWidth, uint16 imageHeight, uint8 *srcIdx) {
|
||||
uint8* psxSaturnPJCRLEUnwinder(uint16 imageWidth, uint16 imageHeight, uint8 *srcIdx) {
|
||||
uint32 remainingBlocks = 0;
|
||||
|
||||
uint16 compressionType = 0; // Kind of decompression to apply
|
||||
@ -84,7 +84,7 @@ uint8* psxPJCRLEUnwinder(uint16 imageWidth, uint16 imageHeight, uint8 *srcIdx) {
|
||||
|
||||
while (remainingBlocks) { // Repeat until all blocks are decompressed
|
||||
if (!controlBits) {
|
||||
controlData = READ_16(srcIdx);
|
||||
controlData = READ_LE_UINT16(srcIdx);
|
||||
srcIdx += 2;
|
||||
|
||||
// If bit 15 of controlData is enabled, compression data is type 1.
|
||||
@ -103,7 +103,7 @@ uint8* psxPJCRLEUnwinder(uint16 imageWidth, uint16 imageHeight, uint8 *srcIdx) {
|
||||
// If there is compression, we need to fetch an index
|
||||
// to be treated as "base" for compression.
|
||||
if (compressionType != 0) {
|
||||
controlData = READ_16(srcIdx);
|
||||
controlData = READ_LE_UINT16(srcIdx);
|
||||
srcIdx += 2;
|
||||
baseIndex = controlData;
|
||||
}
|
||||
@ -125,7 +125,7 @@ uint8* psxPJCRLEUnwinder(uint16 imageWidth, uint16 imageHeight, uint8 *srcIdx) {
|
||||
switch (compressionType) {
|
||||
case 0: // No compression, plain copy of indexes
|
||||
while (decremTiles) {
|
||||
WRITE_LE_UINT16(dstIdx, READ_16(srcIdx));
|
||||
WRITE_LE_UINT16(dstIdx, READ_LE_UINT16(srcIdx));
|
||||
srcIdx += 2;
|
||||
dstIdx += 2;
|
||||
decremTiles--;
|
||||
@ -301,9 +301,9 @@ static void MacDrawTiles(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool apply
|
||||
|
||||
|
||||
/**
|
||||
* Straight rendering with transparency support, PSX variant supporting also 4-BIT clut data
|
||||
* Straight rendering with transparency support, PSX/Saturn variant supporting also 4-BIT clut data for PSX
|
||||
*/
|
||||
static void PsxDrawTiles(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping, bool fourBitClut, uint32 psxSkipBytes, byte *psxMapperTable, bool transparency) {
|
||||
static void psxSaturnDrawTiles(DRAWOBJECT *pObj, uint8 *srcP, uint8 *destP, bool applyClipping, bool fourBitClut, uint32 psxSkipBytes, byte *psxMapperTable, bool transparency) {
|
||||
// Set up the offset between destination blocks
|
||||
int rightClip = applyClipping ? pObj->rightClip : 0;
|
||||
Common::Rect boxBounds;
|
||||
@ -1066,7 +1066,7 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
byte psxMapperTable[16];
|
||||
|
||||
bool psxFourBitClut = false; // Used by Tinsel PSX, true if an image using a 4bit CLUT is rendered
|
||||
bool psxRLEindex = false; // Used by Tinsel PSX, true if an image is using PJCRLE compressed indexes
|
||||
bool psxSaturnRLEindex = false; // Used by Tinsel PSX/Saturn, true if an image is using PJCRLE compressed indexes
|
||||
uint32 psxSkipBytes = 0; // Used by Tinsel PSX, number of bytes to skip before counting indexes for image tiles
|
||||
|
||||
if ((pObj->width <= 0) || (pObj->height <= 0))
|
||||
@ -1083,29 +1083,30 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
byte *p = (byte *)_vm->_handle->LockMem(pObj->hBits & HANDLEMASK);
|
||||
|
||||
srcPtr = p + (pObj->hBits & OFFSETMASK);
|
||||
pObj->charBase = (char *)p + READ_LE_UINT32(p + 0x10);
|
||||
pObj->transOffset = READ_LE_UINT32(p + 0x14);
|
||||
pObj->charBase = (char *)p + READ_32(p + 0x10);
|
||||
pObj->transOffset = READ_32(p + 0x14);
|
||||
|
||||
// Decompress block indexes for Discworld PSX
|
||||
if (TinselV1PSX) {
|
||||
uint8 paletteType = *(srcPtr); // if 0x88 we are using an 8bit palette type, if 0x44 we are using a 4 bit PSX CLUT
|
||||
uint8 indexType = *(srcPtr + 1); // if 0xCC indexes for this image are compressed with PCJRLE, if 0xDD indexes are not compressed
|
||||
// Decompress block indexes for Discworld PSX/Saturn
|
||||
if (TinselV1PSX || TinselV1Saturn) {
|
||||
uint8 paletteType = TinselV1PSX ? *(srcPtr) : *(srcPtr + 1); // if 0x88 we are using an 8bit palette type, if 0x44 we are using a 4 bit PSX CLUT
|
||||
uint8 indexType = TinselV1PSX ? *(srcPtr + 1) : *(srcPtr); // if 0xCC indexes for this image are compressed with PCJRLE, if 0xDD indexes are not compressed
|
||||
|
||||
switch (paletteType) {
|
||||
case 0x88: // Normal 8-bit palette
|
||||
case 0x00: // Normal 8-bit palette (Saturn)
|
||||
case 0x88: // Normal 8-bit palette (PSX)
|
||||
psxFourBitClut = false;
|
||||
psxSkipBytes = 0;
|
||||
switch (indexType) {
|
||||
case 0xDD: // Normal uncompressed indexes
|
||||
psxRLEindex = false;
|
||||
psxSaturnRLEindex = false;
|
||||
srcPtr += sizeof(uint16); // Get to the beginning of index data
|
||||
break;
|
||||
case 0xCC: // PJCRLE compressed indexes
|
||||
psxRLEindex = true;
|
||||
srcPtr = psxPJCRLEUnwinder(pObj->width, pObj->height, srcPtr + sizeof(uint16));
|
||||
psxSaturnRLEindex = true;
|
||||
srcPtr = psxSaturnPJCRLEUnwinder(pObj->width, pObj->height, srcPtr + sizeof(uint16));
|
||||
break;
|
||||
default:
|
||||
error("Unknown PSX index type 0x%.2X", indexType);
|
||||
error("Unknown PSX/Saturn index type 0x%.2X", indexType);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
@ -1113,15 +1114,15 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
psxPaletteMapper(pObj->pPal, srcPtr + sizeof(uint16), psxMapperTable);
|
||||
|
||||
psxFourBitClut = true;
|
||||
psxSkipBytes = READ_LE_UINT32(p + sizeof(uint32) * 5) << 4; // Fetch number of bytes we have to skip
|
||||
psxSkipBytes = READ_32(p + sizeof(uint32) * 5) << 4; // Fetch number of bytes we have to skip
|
||||
switch (indexType) {
|
||||
case 0xDD: // Normal uncompressed indexes
|
||||
psxRLEindex = false;
|
||||
psxSaturnRLEindex = false;
|
||||
srcPtr += sizeof(uint16) * 17; // Skip image type and clut, and get to beginning of index data
|
||||
break;
|
||||
case 0xCC: // PJCRLE compressed indexes
|
||||
psxRLEindex = true;
|
||||
srcPtr = psxPJCRLEUnwinder(pObj->width, pObj->height, srcPtr + sizeof(uint16) * 17);
|
||||
psxSaturnRLEindex = true;
|
||||
srcPtr = psxSaturnPJCRLEUnwinder(pObj->width, pObj->height, srcPtr + sizeof(uint16) * 17);
|
||||
break;
|
||||
default:
|
||||
error("Unknown PSX index type 0x%.2X", indexType);
|
||||
@ -1129,7 +1130,7 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error("Unknown PSX palette type 0x%.2X", paletteType);
|
||||
error("Unknown PSX/Saturn palette type 0x%.2X", paletteType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1169,8 +1170,8 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
t3WrtNonZero(pObj, srcPtr, destPtr);
|
||||
else if (TinselV2)
|
||||
t2WrtNonZero(pObj, srcPtr, destPtr, (typeId & DMA_CLIP) != 0, (typeId & DMA_FLIPH) != 0);
|
||||
else if (TinselV1PSX)
|
||||
PsxDrawTiles(pObj, srcPtr, destPtr, typeId == 0x41, psxFourBitClut, psxSkipBytes, psxMapperTable, true);
|
||||
else if (TinselV1PSX || TinselV1Saturn)
|
||||
psxSaturnDrawTiles(pObj, srcPtr, destPtr, typeId == 0x41, psxFourBitClut, psxSkipBytes, psxMapperTable, true);
|
||||
else if (TinselV1Mac)
|
||||
MacDrawTiles(pObj, srcPtr, destPtr, typeId == 0x41);
|
||||
else if (TinselV1)
|
||||
@ -1184,8 +1185,8 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
t3WrtAll(pObj, srcPtr, destPtr);
|
||||
else if (TinselV2 || TinselV1Mac || TinselV0)
|
||||
WrtAll(pObj, srcPtr, destPtr, typeId == 0x48);
|
||||
else if (TinselV1PSX)
|
||||
PsxDrawTiles(pObj, srcPtr, destPtr, typeId == 0x48, psxFourBitClut, psxSkipBytes, psxMapperTable, false);
|
||||
else if (TinselV1PSX || TinselV1Saturn)
|
||||
psxSaturnDrawTiles(pObj, srcPtr, destPtr, typeId == 0x48, psxFourBitClut, psxSkipBytes, psxMapperTable, false);
|
||||
else if (TinselV1)
|
||||
WrtNonZero(pObj, srcPtr, destPtr, typeId == 0x48);
|
||||
break;
|
||||
@ -1214,9 +1215,9 @@ void DrawObject(DRAWOBJECT *pObj) {
|
||||
}
|
||||
}
|
||||
|
||||
// If we were using Discworld PSX, free the memory allocated
|
||||
// If we were using Discworld PSX/Saturn, free the memory allocated
|
||||
// for decompressed block indexes.
|
||||
if (TinselV1PSX && psxRLEindex)
|
||||
if ((TinselV1PSX || TinselV1Saturn) && psxSaturnRLEindex)
|
||||
free(srcPtr);
|
||||
}
|
||||
|
||||
|
@ -83,7 +83,7 @@ void Handle::SetupHandleTable() {
|
||||
int len;
|
||||
uint i;
|
||||
MEMHANDLE *pH;
|
||||
TinselFile f;
|
||||
TinselFile f(TinselV1Mac || TinselV1Saturn);
|
||||
|
||||
const char *indexFileName = TinselV1PSX ? PSX_INDEX_FILENAME : INDEX_FILENAME;
|
||||
|
||||
|
@ -176,6 +176,8 @@ bool Music::PlayMidiSequence(uint32 dwFileOffset, bool bLoop) {
|
||||
// The Macintosh version of DW1 uses raw PCM for music
|
||||
dwSeqLen = midiStream.readUint32BE();
|
||||
_vm->_sound->playDW1MacMusic(midiStream, dwSeqLen);
|
||||
} else if (TinselV1Saturn) {
|
||||
// TODO: Music format for the Saturn version
|
||||
} else {
|
||||
dwSeqLen = midiStream.readUint32LE();
|
||||
|
||||
@ -298,6 +300,10 @@ void Music::OpenMidiFiles() {
|
||||
}
|
||||
|
||||
midiStream.close();
|
||||
} else if (TinselV1Saturn) {
|
||||
// The Saturn version has digital music with a different track structure
|
||||
// TODO
|
||||
warning("Music support for Discworld 1 Saturn");
|
||||
} else {
|
||||
if (_midiBuffer.pDat)
|
||||
// already allocated
|
||||
|
@ -192,9 +192,8 @@ static void SceneTinselProcess(CORO_PARAM, const void *param) {
|
||||
|
||||
// The following myEscape value setting is used for enabling title screen skipping in DW1
|
||||
if (TinselV1 && (g_sceneCtr == 1)) g_initialMyEscape = GetEscEvents();
|
||||
// DW1 PSX has its own scene skipping script code for scenes 2 and 3 (bug #6094).
|
||||
// Same goes for DW1 Mac.
|
||||
_ctx->myEscape = (TinselV1 && (g_sceneCtr < ((TinselV1PSX || TinselV1Mac) ? 2 : 4))) ? g_initialMyEscape : 0;
|
||||
// DW1 PSX, Saturn and Mac has its own scene skipping script code for scenes 2 and 3 (bug #6094).
|
||||
_ctx->myEscape = (TinselV1 && (g_sceneCtr < ((TinselV1PSX || TinselV1Saturn || TinselV1Mac) ? 2 : 4))) ? g_initialMyEscape : 0;
|
||||
|
||||
// get the stuff copied to process when it was created
|
||||
_ctx->pInit = (const TP_INIT *)param;
|
||||
|
@ -100,7 +100,7 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
||||
error(FILE_IS_CORRUPT, _vm->getSampleFile(g_sampleLanguage));
|
||||
|
||||
// read the length of the sample
|
||||
uint32 sampleLen = _sampleStream.readUint32LE();
|
||||
uint32 sampleLen = _sampleStream.readUint32();
|
||||
if (_sampleStream.eos() || _sampleStream.err())
|
||||
error(FILE_IS_CORRUPT, _vm->getSampleFile(g_sampleLanguage));
|
||||
|
||||
@ -115,6 +115,8 @@ bool SoundManager::playSample(int id, Audio::Mixer::SoundType type, Audio::Sound
|
||||
|
||||
// Play the audio stream
|
||||
_vm->_mixer->playStream(type, &curChan.handle, xaStream);
|
||||
} else if (TinselV1Saturn) {
|
||||
// TODO: Sound format for the Saturn version - looks to be raw, but isn't
|
||||
} else {
|
||||
// allocate a buffer
|
||||
byte *sampleBuf = (byte *)malloc(sampleLen);
|
||||
@ -499,7 +501,7 @@ void SoundManager::openSampleFiles() {
|
||||
if (TinselV0 || (TinselV1 && !_vm->isV1CD()))
|
||||
return;
|
||||
|
||||
TinselFile f;
|
||||
TinselFile f(TinselV1Saturn);
|
||||
|
||||
if (_sampleIndex)
|
||||
// already allocated
|
||||
@ -518,7 +520,7 @@ void SoundManager::openSampleFiles() {
|
||||
|
||||
// Load data
|
||||
for (int i = 0; i < _sampleIndexLen; ++i) {
|
||||
_sampleIndex[i] = f.readUint32LE();
|
||||
_sampleIndex[i] = f.readUint32();
|
||||
if (f.err()) {
|
||||
showSoundError(FILE_READ_ERROR, _vm->getSampleIndex(g_sampleLanguage));
|
||||
}
|
||||
|
@ -88,7 +88,7 @@ void ResetVarsStrRes() {
|
||||
* @param newLang The new language
|
||||
*/
|
||||
void ChangeLanguage(LANGUAGE newLang) {
|
||||
TinselFile f;
|
||||
TinselFile f(TinselV1Mac || TinselV1Saturn);
|
||||
uint32 textLen = 0; // length of buffer
|
||||
|
||||
g_textLanguage = newLang;
|
||||
|
@ -107,12 +107,13 @@ typedef bool (*KEYFPTR)(const Common::KeyState &);
|
||||
#define TinselV2Demo (TinselVersion == TINSEL_V2 && _vm->getIsADGFDemo())
|
||||
#define TinselV1PSX (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformPSX)
|
||||
#define TinselV1Mac (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformMacintosh)
|
||||
#define TinselV1Saturn (TinselVersion == TINSEL_V1 && _vm->getPlatform() == Common::kPlatformSaturn)
|
||||
|
||||
#define READ_16(v) (TinselV1Mac ? READ_BE_UINT16(v) : READ_LE_UINT16(v))
|
||||
#define READ_32(v) (TinselV1Mac ? READ_BE_UINT32(v) : READ_LE_UINT32(v))
|
||||
#define FROM_16(v) (TinselV1Mac ? FROM_BE_16(v) : FROM_LE_16(v))
|
||||
#define FROM_32(v) (TinselV1Mac ? FROM_BE_32(v) : FROM_LE_32(v))
|
||||
#define TO_32(v) (TinselV1Mac ? TO_BE_32(v) : TO_LE_32(v))
|
||||
#define READ_16(v) (TinselV1Mac || TinselV1Saturn ? READ_BE_UINT16(v) : READ_LE_UINT16(v))
|
||||
#define READ_32(v) (TinselV1Mac || TinselV1Saturn ? READ_BE_UINT32(v) : READ_LE_UINT32(v))
|
||||
#define FROM_16(v) (TinselV1Mac || TinselV1Saturn ? FROM_BE_16(v) : FROM_LE_16(v))
|
||||
#define FROM_32(v) (TinselV1Mac || TinselV1Saturn ? FROM_BE_32(v) : FROM_LE_32(v))
|
||||
#define TO_32(v) (TinselV1Mac || TinselV1Saturn ? TO_BE_32(v) : TO_LE_32(v))
|
||||
|
||||
// Global reference to the TinselEngine object
|
||||
extern TinselEngine *_vm;
|
||||
|
Loading…
Reference in New Issue
Block a user