aboutsummaryrefslogtreecommitdiff
path: root/engines/tinsel/handle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/tinsel/handle.cpp')
-rw-r--r--engines/tinsel/handle.cpp213
1 files changed, 201 insertions, 12 deletions
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 11623516ec..41774a9c88 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -28,6 +28,7 @@
#include "common/file.h"
+#include "tinsel/drives.h"
#include "tinsel/dw.h"
#include "tinsel/scn.h" // name of "index" file
#include "tinsel/handle.h"
@@ -41,6 +42,8 @@
#include "tinsel/object.h"
#include "tinsel/palette.h"
#include "tinsel/text.h"
+#include "tinsel/timers.h"
+#include "tinsel/tinsel.h"
#include "tinsel/scene.h"
namespace Tinsel {
@@ -58,6 +61,7 @@ struct MEMHANDLE {
char szName[12]; //!< 00 - file name of graphics file
int32 filesize; //!< 12 - file size and flags
MEM_NODE *pNode; //!< 16 - memory node for the graphics
+ uint32 flags2;
};
@@ -72,7 +76,6 @@ enum {
};
#define FSIZE_MASK 0x00FFFFFFL //!< mask to isolate the filesize
#define MALLOC_MASK 0xFF000000L //!< mask to isolate the memory allocation flags
-#define OFFSETMASK 0x007fffffL //!< get offset of address
//#define HANDLEMASK 0xFF800000L //!< get handle of address
//----------------- LOCAL GLOBAL DATA --------------------
@@ -83,6 +86,13 @@ static MEMHANDLE *handleTable = 0;
// number of handles in the handle table
static uint numHandles = 0;
+static uint32 cdPlayHandle = (uint32)-1;
+
+static int cdPlayFileNum, cdPlaySceneNum;
+static SCNHANDLE cdBaseHandle = 0, cdTopHandle = 0;
+static Common::File cdGraphStream;
+
+static char szCdPlayFile[100];
//----------------- FORWARD REFERENCES --------------------
@@ -94,7 +104,8 @@ static void LoadFile(MEMHANDLE *pH, bool bWarn); // load a memory block as a fil
* permanent graphics etc.
*/
void SetupHandleTable(void) {
- enum { RECORD_SIZE = 20 };
+ bool t2Flag = (TinselVersion == TINSEL_V2);
+ int RECORD_SIZE = t2Flag ? 24 : 20;
int len;
uint i;
@@ -108,7 +119,7 @@ void SetupHandleTable(void) {
if (len > 0) {
if ((len % RECORD_SIZE) != 0) {
// index file is corrupt
- error("File %s is corrupt", INDEX_FILENAME);
+ error(FILE_IS_CORRUPT, INDEX_FILENAME);
}
// calc number of handles
@@ -128,31 +139,36 @@ void SetupHandleTable(void) {
// need to read that from the file.
handleTable[i].pNode = NULL;
f.seek(4, SEEK_CUR);
+ // For Discworld 2, read in the flags2 field
+ handleTable[i].flags2 = t2Flag ? f.readUint32LE() : 0;
}
if (f.ioFailed()) {
// index file is corrupt
- error("File %s is corrupt", INDEX_FILENAME);
+ error(FILE_IS_CORRUPT, INDEX_FILENAME);
}
// close the file
f.close();
} else { // index file is corrupt
- error("File %s is corrupt", INDEX_FILENAME);
+ error(FILE_IS_CORRUPT, INDEX_FILENAME);
}
} else { // cannot find the index file
- error("Cannot find file %s", INDEX_FILENAME);
+ error(CANNOT_FIND_FILE, INDEX_FILENAME);
}
// allocate memory nodes and load all permanent graphics
for (i = 0, pH = handleTable; i < numHandles; i++, pH++) {
if (pH->filesize & fPreload) {
// allocate a fixed memory node for permanent files
- pH->pNode = MemoryAlloc(DWM_FIXED, pH->filesize & FSIZE_MASK);
+ pH->pNode = MemoryAlloc(DWM_FIXED, sizeof(MEM_NODE) + (pH->filesize & FSIZE_MASK));
// make sure memory allocated
assert(pH->pNode);
+ // Initialise the MEM_NODE structure
+ memset(pH->pNode, 0, sizeof(MEM_NODE));
+
// load the data
LoadFile(pH, true);
}
@@ -178,9 +194,102 @@ void FreeHandleTable(void) {
free(handleTable);
handleTable = NULL;
}
+ if (cdGraphStream.isOpen())
+ cdGraphStream.close();
+}
+
+/**
+ * Loads a memory block as a file.
+ */
+void OpenCDGraphFile(void) {
+ if (cdGraphStream.isOpen())
+ cdGraphStream.close();
+
+ // As the theory goes, the right CD will be in there!
+
+ cdGraphStream.clearIOFailed();
+ cdGraphStream.open(szCdPlayFile);
+ if (cdGraphStream.ioFailed())
+ error(CANNOT_FIND_FILE, szCdPlayFile);
+}
+
+void LoadCDGraphData(MEMHANDLE *pH) {
+ // read the data
+ uint bytes;
+ byte *addr;
+ int retries = 0;
+
+ assert(!(pH->filesize & fCompressed));
+
+ // Can't be preloaded
+ assert(!(pH->filesize & fPreload));
+
+ // discardable - lock the memory
+ addr = (byte *)MemoryLock(pH->pNode);
+
+ // make sure address is valid
+ assert(addr);
+
+ // Move to correct place in file and load the required data
+ cdGraphStream.seek(cdBaseHandle & OFFSETMASK, SEEK_SET);
+ bytes = cdGraphStream.read(addr, (cdTopHandle - cdBaseHandle) & OFFSETMASK);
+
+ // New code to try and handle CD read failures 24/2/97
+ while (bytes != ((cdTopHandle - cdBaseHandle) & OFFSETMASK) && retries++ < MAX_READ_RETRIES) {
+ // Try again
+ cdGraphStream.seek(cdBaseHandle & OFFSETMASK, SEEK_SET);
+ bytes = cdGraphStream.read(addr, (cdTopHandle - cdBaseHandle) & OFFSETMASK);
+ }
+
+ // discardable - unlock the memory
+ MemoryUnlock(pH->pNode);
+
+ // set the loaded flag
+ pH->filesize |= fLoaded;
+
+ // clear the loading flag
+// pH->filesize &= ~fLoading;
+
+ if (bytes != ((cdTopHandle-cdBaseHandle) & OFFSETMASK))
+ // file is corrupt
+ error(FILE_READ_ERROR, "CD play file");
}
/**
+ * Called immediatly preceding a CDplay().
+ * Prepares the ground so that when LockMem() is called, the
+ * appropriate section of the extra scene file is loaded.
+ * @param start Handle of start of range
+ * @param next Handle of end of range + 1
+ */
+void LoadExtraGraphData(SCNHANDLE start, SCNHANDLE next) {
+ if (cdPlayFileNum == cdPlaySceneNum && start == cdBaseHandle)
+ return;
+
+ OpenCDGraphFile();
+
+ if ((handleTable + cdPlayHandle)->pNode->pBaseAddr != NULL)
+ MemoryDiscard((handleTable + cdPlayHandle)->pNode); // Free it
+
+ // It must always be the same
+ assert(cdPlayHandle == (start >> SCNHANDLE_SHIFT));
+ assert(cdPlayHandle == (next >> SCNHANDLE_SHIFT));
+
+ cdBaseHandle = start;
+ cdTopHandle = next;
+}
+
+void SetCdPlaySceneDetails(int fileNum, const char *fileName) {
+ cdPlaySceneNum = fileNum;
+ strcpy(szCdPlayFile, fileName);
+}
+
+void SetCdPlayHandle(int fileNum) {
+ cdPlayHandle = fileNum;
+}
+
+
+/**
* Loads a memory block as a file.
* @param pH Memory block pointer
* @param bWarn If set, treat warnings as errors
@@ -204,7 +313,7 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) {
if (pH->filesize & fPreload)
// preload - no need to lock the memory
- addr = (uint8 *)pH->pNode;
+ addr = (uint8 *)pH->pNode + sizeof(MEM_NODE);
else {
// discardable - lock the memory
addr = (uint8 *)MemoryLock(pH->pNode);
@@ -243,12 +352,12 @@ void LoadFile(MEMHANDLE *pH, bool bWarn) {
if (bWarn)
// file is corrupt
- error("File %s is corrupt", szFilename);
+ error(FILE_IS_CORRUPT, szFilename);
}
if (bWarn)
// cannot find file
- error("Cannot find file %s", szFilename);
+ error(CANNOT_FIND_FILE, szFilename);
}
/**
@@ -265,8 +374,39 @@ uint8 *LockMem(SCNHANDLE offset) {
pH = handleTable + handle;
if (pH->filesize & fPreload) {
+ if (TinselV2)
+ // update the LRU time (new in this file)
+ pH->pNode->lruTime = DwGetCurrentTime();
+
// permanent files are already loaded
- return (uint8 *)pH->pNode + (offset & OFFSETMASK);
+ return (uint8 *)pH->pNode + sizeof(MEM_NODE) + (offset & OFFSETMASK);
+ } else if (handle == cdPlayHandle) {
+ // Must be in currently loaded/loadable range
+ if(offset < cdBaseHandle || offset >= cdTopHandle)
+ error("Overlapping (in time) CD-plays!");
+
+ if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded))
+ // already allocated and loaded
+ return pH->pNode->pBaseAddr + ((offset - cdBaseHandle) & OFFSETMASK);
+
+ if (pH->pNode->pBaseAddr == NULL)
+ // must have been discarded - reallocate the memory
+ MemoryReAlloc(pH->pNode, cdTopHandle-cdBaseHandle,
+ DWM_MOVEABLE | DWM_DISCARDABLE);
+
+ if(pH->pNode->pBaseAddr == NULL)
+ error("Out of memory");
+
+ LoadCDGraphData(pH);
+
+ // make sure address is valid
+ assert(pH->pNode->pBaseAddr);
+
+ // update the LRU time (new in this file)
+ pH->pNode->lruTime = DwGetCurrentTime();
+
+ return pH->pNode->pBaseAddr + ((offset - cdBaseHandle) & OFFSETMASK);
+
} else {
if (pH->pNode->pBaseAddr && (pH->filesize & fLoaded))
// already allocated and loaded
@@ -312,7 +452,10 @@ void LockScene(SCNHANDLE offset) {
if ((pH->filesize & fPreload) == 0) {
// change the flags for the node
- MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, DWM_MOVEABLE);
+ // WORKAROUND: The original didn't include the DWM_LOCKED flag. It's being
+ // included because the method is 'LockScene' so it's presumed that the
+ // point of this was that the scene's memory block be locked
+ MemoryReAlloc(pH->pNode, pH->filesize & FSIZE_MASK, DWM_MOVEABLE | DWM_LOCKED);
#ifdef DEBUG
bLockedScene = true;
#endif
@@ -363,4 +506,50 @@ bool ValidHandle(SCNHANDLE offset) {
}
#endif
+/**
+ * TouchMem
+ * @param offset Handle and offset to data
+ */
+void TouchMem(SCNHANDLE offset) {
+ MEMHANDLE *pH; // points to table entry
+ uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use
+
+ if (offset != 0) {
+ pH = handleTable + handle;
+
+ // update the LRU time whether its loaded or not!
+ pH->pNode->lruTime = DwGetCurrentTime();
+ }
+}
+
+/**
+ * Returns true if the given handle is into the cd graph data
+ * @param offset Handle and offset to data
+ */
+bool IsCdPlayHandle(SCNHANDLE offset) {
+ uint32 handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use
+
+ // range check the memory handle
+ assert(handle < numHandles);
+
+ return (handle == cdPlayHandle);
+}
+
+/**
+ * Returns the CD for a given scene handle
+ */
+int CdNumber(SCNHANDLE offset) {
+ uint handle = offset >> SCNHANDLE_SHIFT; // calc memory handle to use
+
+ // range check the memory handle
+ assert(handle < numHandles);
+
+ MEMHANDLE *pH = handleTable + handle;
+
+ if (!TinselV2)
+ return 1;
+
+ return GetCD(pH->flags2 & fAllCds);
+}
+
} // end of namespace Tinsel