aboutsummaryrefslogtreecommitdiff
path: root/engines/sword2/protocol.cpp
diff options
context:
space:
mode:
authorFabio Battaglia2009-04-07 19:52:46 +0000
committerFabio Battaglia2009-04-07 19:52:46 +0000
commitdc9c538a62d64b40c3a39a673d2f680fa9422f41 (patch)
treeda10a2ff6b6804e714fb124aac805445fe204058 /engines/sword2/protocol.cpp
parentb80abe318d65679d5c0cd8a94a8c106534d240ea (diff)
downloadscummvm-rg350-dc9c538a62d64b40c3a39a673d2f680fa9422f41.tar.gz
scummvm-rg350-dc9c538a62d64b40c3a39a673d2f680fa9422f41.tar.bz2
scummvm-rg350-dc9c538a62d64b40c3a39a673d2f680fa9422f41.zip
Sword2: PSX version support, and GMM loading/saving
svn-id: r39896
Diffstat (limited to 'engines/sword2/protocol.cpp')
-rw-r--r--engines/sword2/protocol.cpp288
1 files changed, 256 insertions, 32 deletions
diff --git a/engines/sword2/protocol.cpp b/engines/sword2/protocol.cpp
index 65b236e2db..e5fbf53ee9 100644
--- a/engines/sword2/protocol.cpp
+++ b/engines/sword2/protocol.cpp
@@ -25,11 +25,13 @@
* $Id$
*/
-
+#include "common/file.h"
+#include "common/endian.h"
#include "sword2/sword2.h"
#include "sword2/header.h"
#include "sword2/resman.h"
+#include "sword2/logic.h"
namespace Sword2 {
@@ -39,11 +41,16 @@ namespace Sword2 {
*/
byte *Sword2Engine::fetchPalette(byte *screenFile) {
- MultiScreenHeader mscreenHeader;
+ byte *palette;
- mscreenHeader.read(screenFile + ResHeader::size());
+ if(isPsx()) { // PSX version doesn't have a "MultiScreenHeader", instead there's a ScreenHeader and a tag
+ palette = screenFile + ResHeader::size() + ScreenHeader::size() + 2;
+ } else {
+ MultiScreenHeader mscreenHeader;
- byte *palette = screenFile + ResHeader::size() + mscreenHeader.palette;
+ mscreenHeader.read(screenFile + ResHeader::size());
+ palette = screenFile + ResHeader::size() + mscreenHeader.palette;
+ }
// Always set colour 0 to black, because while most background screen
// palettes have a bright colour 0 it should come out as black in the
@@ -60,9 +67,14 @@ byte *Sword2Engine::fetchPalette(byte *screenFile) {
/**
* Returns a pointer to the start of the palette match table, given the pointer
* to the start of the screen file.
+ * It returns NULL when used with PSX version, as there are no palette match tables in
+ * the resource files.
*/
byte *Sword2Engine::fetchPaletteMatchTable(byte *screenFile) {
+
+ if (isPsx()) return NULL;
+
MultiScreenHeader mscreenHeader;
mscreenHeader.read(screenFile + ResHeader::size());
@@ -76,11 +88,14 @@ byte *Sword2Engine::fetchPaletteMatchTable(byte *screenFile) {
*/
byte *Sword2Engine::fetchScreenHeader(byte *screenFile) {
- MultiScreenHeader mscreenHeader;
-
- mscreenHeader.read(screenFile + ResHeader::size());
+ if (isPsx()) { // In PSX version there's no MultiScreenHeader, so just skip resource header
+ return screenFile + ResHeader::size();
+ } else {
+ MultiScreenHeader mscreenHeader;
- return screenFile + ResHeader::size() + mscreenHeader.screen;
+ mscreenHeader.read(screenFile + ResHeader::size());
+ return screenFile + ResHeader::size() + mscreenHeader.screen;
+ }
}
/**
@@ -97,19 +112,25 @@ byte *Sword2Engine::fetchLayerHeader(byte *screenFile, uint16 layerNo) {
assert(layerNo < screenHead.noLayers);
#endif
- MultiScreenHeader mscreenHeader;
-
- mscreenHeader.read(screenFile + ResHeader::size());
-
- return screenFile + ResHeader::size() + mscreenHeader.layers + layerNo * LayerHeader::size();
+ if (isPsx()) {
+ return screenFile + ResHeader::size() + ScreenHeader::size() + 2 + 0x400 + layerNo * LayerHeader::size();
+ } else {
+ MultiScreenHeader mscreenHeader;
+
+ mscreenHeader.read(screenFile + ResHeader::size());
+ return screenFile + ResHeader::size() + mscreenHeader.layers + layerNo * LayerHeader::size();
+ }
}
/**
* Returns a pointer to the start of the shading mask, given the pointer to the
* start of the screen file.
+ * If we are non PSX, this will return NULL, as we don't have shading masks.
*/
byte *Sword2Engine::fetchShadingMask(byte *screenFile) {
+ if (isPsx()) return NULL;
+
MultiScreenHeader mscreenHeader;
mscreenHeader.read(screenFile + ResHeader::size());
@@ -139,7 +160,7 @@ byte *Sword2Engine::fetchCdtEntry(byte *animFile, uint16 frameNo) {
animHead.read(fetchAnimHeader(animFile));
if (frameNo > animHead->noAnimFrames - 1)
- error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead.noAnimFrames);
+ error("fetchCdtEntry(animFile,%d) - anim only %d frames", frameNo, animHead->noAnimFrames);
#endif
return fetchAnimHeader(animFile) + AnimHeader::size() + frameNo * CdtEntry::size();
@@ -153,6 +174,7 @@ byte *Sword2Engine::fetchCdtEntry(byte *animFile, uint16 frameNo) {
byte *Sword2Engine::fetchFrameHeader(byte *animFile, uint16 frameNo) {
// required address = (address of the start of the anim header) + frameOffset
+
CdtEntry cdt;
cdt.read(fetchCdtEntry(animFile, frameNo));
@@ -165,30 +187,86 @@ byte *Sword2Engine::fetchFrameHeader(byte *animFile, uint16 frameNo) {
*/
byte *Sword2Engine::fetchBackgroundParallaxLayer(byte *screenFile, int layer) {
- MultiScreenHeader mscreenHeader;
-
- mscreenHeader.read(screenFile + ResHeader::size());
- assert(mscreenHeader.bg_parallax[layer]);
-
- return screenFile + ResHeader::size() + mscreenHeader.bg_parallax[layer];
+ if (isPsx()) {
+ byte *psxParallax = _screen->getPsxScrCache(0);
+
+ // Manage cache for background psx parallaxes
+ if (!_screen->getPsxScrCacheStatus(0)) { // This parallax layer is not present
+ return NULL;
+ } else if (psxParallax != NULL) { // Parallax layer present, and already in cache
+ return psxParallax;
+ } else { // Present, but not cached
+ uint32 locNo = _logic->getLocationNum();
+
+ // At game startup, we have a wrong location number stored
+ // in game vars (0, instead of 3), work around this.
+ locNo = (locNo == 0) ? 3 : locNo;
+
+ psxParallax = fetchPsxParallax(locNo, 0);
+ _screen->setPsxScrCache(psxParallax, 0);
+ return psxParallax;
+ }
+ } else {
+ MultiScreenHeader mscreenHeader;
+
+ mscreenHeader.read(screenFile + ResHeader::size());
+ assert(mscreenHeader.bg_parallax[layer]);
+ return screenFile + ResHeader::size() + mscreenHeader.bg_parallax[layer];
+ }
}
byte *Sword2Engine::fetchBackgroundLayer(byte *screenFile) {
- MultiScreenHeader mscreenHeader;
-
- mscreenHeader.read(screenFile + ResHeader::size());
- assert(mscreenHeader.screen);
-
- return screenFile + ResHeader::size() + mscreenHeader.screen + ScreenHeader::size();
+ if (isPsx()) {
+ byte *psxBackground = _screen->getPsxScrCache(1);
+
+ // Manage cache for psx backgrounds
+ if (psxBackground) { // Background is cached
+ return psxBackground;
+ } else { // Background not cached
+ uint32 locNo = _logic->getLocationNum();
+
+ // We have a wrong location number at start, fix that
+ locNo = (locNo == 0) ? 3 : locNo;
+
+ psxBackground = fetchPsxBackground(locNo);
+ _screen->setPsxScrCache(psxBackground, 1);
+ return psxBackground;
+ }
+ } else {
+ MultiScreenHeader mscreenHeader;
+
+ mscreenHeader.read(screenFile + ResHeader::size());
+ assert(mscreenHeader.screen);
+ return screenFile + ResHeader::size() + mscreenHeader.screen + ScreenHeader::size();
+ }
}
byte *Sword2Engine::fetchForegroundParallaxLayer(byte *screenFile, int layer) {
- MultiScreenHeader mscreenHeader;
-
- mscreenHeader.read(screenFile + ResHeader::size());
- assert(mscreenHeader.fg_parallax[layer]);
-
- return screenFile + ResHeader::size() + mscreenHeader.fg_parallax[layer];
+ if (isPsx()) {
+ byte *psxParallax = _screen->getPsxScrCache(2);
+
+ // Manage cache for psx parallaxes
+ if (!_screen->getPsxScrCacheStatus(2)) { // This parallax layer is not present
+ return NULL;
+ } else if (psxParallax) { // Parallax layer present and cached
+ return psxParallax;
+ } else { // Present, but still not cached
+ uint32 locNo = _logic->getLocationNum();
+
+ // We have a wrong location number at start, fix that
+ locNo = (locNo == 0) ? 3 : locNo;
+
+ psxParallax = fetchPsxParallax(locNo, 1);
+ _screen->setPsxScrCache(psxParallax, 2);
+ return psxParallax;
+ }
+ } else {
+ MultiScreenHeader mscreenHeader;
+
+ mscreenHeader.read(screenFile + ResHeader::size());
+ assert(mscreenHeader.fg_parallax[layer]);
+ return screenFile + ResHeader::size() + mscreenHeader.fg_parallax[layer];
+ }
}
byte *Sword2Engine::fetchTextLine(byte *file, uint32 text_line) {
@@ -211,6 +289,152 @@ byte *Sword2Engine::fetchTextLine(byte *file, uint32 text_line) {
return file + READ_LE_UINT32(file + ResHeader::size() + 4 + 4 * text_line);
}
+/**
+ * Returns a pointer to psx background data for passed location number
+ * At the beginning of the passed data there's an artificial header composed by
+ * uint16: background X resolution
+ * uint16: background Y resolution
+ * uint32: offset to subtract from offset table entries
+ */
+
+byte *Sword2Engine::fetchPsxBackground(uint32 location) {
+ Common::File file;
+ PSXScreensEntry header;
+ uint32 screenOffset, dataOffset;
+ uint32 totSize; // Total size of background, counting data, offset table and additional header
+ byte *buffer;
+
+ if (!file.open("screens.clu")) {
+ GUIErrorMessage("Broken Sword 2: Cannot open screens.clu");
+ return NULL;
+ }
+
+ file.seek(location * 4, SEEK_SET);
+ screenOffset = file.readUint32LE();
+
+ if (screenOffset == 0) { // We don't have screen data for this location number.
+ file.close();
+ return NULL;
+ }
+
+ // Get to the beginning of PSXScreensEntry
+ file.seek(screenOffset + ResHeader::size(), SEEK_SET);
+
+ buffer = (byte *)malloc(PSXScreensEntry::size());
+ file.read(buffer, PSXScreensEntry::size());
+
+ // Prepare the header
+ header.read(buffer);
+ free(buffer);
+
+ file.seek(screenOffset + header.bgOffset + 4, SEEK_SET);
+ dataOffset = file.readUint32LE();
+
+ file.seek(screenOffset + header.bgOffset, SEEK_SET);
+
+ totSize = header.bgSize + (dataOffset - header.bgOffset) + 8;
+ buffer = (byte *)malloc(totSize);
+
+ // Write some informations before background data
+ WRITE_LE_UINT16(buffer, header.bgXres);
+ WRITE_LE_UINT16(buffer + 2, header.bgYres);
+ WRITE_LE_UINT32(buffer + 4, header.bgOffset);
+
+ file.read(buffer + 8, totSize - 8); // Do not write on the header
+ file.close();
+
+ return buffer;
+}
+
+/**
+ * Returns a pointer to selected psx parallax data for passed location number
+ * At the beginning of the passed data there's an artificial header composed by
+ * uint16: parallax X resolution
+ * uint16: parallax Y resolution
+ * uint16: width in 64x16 tiles of parallax
+ * uint16: height in 64x16 tiles of parallax
+ */
+
+byte *Sword2Engine::fetchPsxParallax(uint32 location, uint8 level) {
+ Common::File file;
+ PSXScreensEntry header;
+ uint32 screenOffset;
+ uint16 horTiles; // Number of horizontal tiles in the parallax grid
+ uint16 verTiles; // Number of vertical tiles in parallax grid
+ uint32 totSize; // Total size of parallax, counting data, grid, and additional header
+ byte *buffer;
+
+ uint16 plxXres;
+ uint16 plxYres;
+ uint32 plxOffset;
+ uint32 plxSize;
+
+ if (level > 1)
+ return NULL;
+
+ if (!file.open("screens.clu")) {
+ GUIErrorMessage("Broken Sword 2: Cannot open screens.clu");
+ return NULL;
+ }
+
+ file.seek(location * 4, SEEK_SET);
+ screenOffset = file.readUint32LE();
+
+ if (screenOffset == 0) // There is no screen here
+ return NULL;
+
+ // Get to the beginning of PSXScreensEntry
+ file.seek(screenOffset + ResHeader::size(), SEEK_SET);
+
+ buffer = (byte *)malloc(PSXScreensEntry::size());
+ file.read(buffer, PSXScreensEntry::size());
+
+ // Initialize the header
+ header.read(buffer);
+ free(buffer);
+
+ // We are fetching...
+ if (level == 0) { // a background parallax
+ plxXres = header.bgPlxXres;
+ plxYres = header.bgPlxYres;
+ plxOffset = header.bgPlxOffset;
+ plxSize = header.bgPlxSize;
+ } else { // a foreground parallax
+ plxXres = header.fgPlxXres;
+ plxYres = header.fgPlxYres;
+ plxOffset = header.fgPlxOffset;
+ plxSize = header.fgPlxSize;
+ }
+
+ if (plxXres == 0 || plxYres == 0 || plxSize == 0) // This screen has no parallax data.
+ return NULL;
+
+ debug(2, "fetchPsxParallax() -> %s parallax, xRes: %u, yRes: %u", (level == 0) ? "Background" : "Foreground", plxXres, plxYres);
+
+ // Calculate the number of tiles which compose the parallax grid.
+ horTiles = plxXres % 64 ? (plxXres / 64) + 1 : plxXres / 64;
+ verTiles = plxYres % 16 ? (plxYres / 16) + 1 : plxYres / 16;
+
+ totSize = plxSize + horTiles * verTiles * 4 + 8;
+
+ file.seek(screenOffset + plxOffset, SEEK_SET);
+ buffer = (byte *)malloc(totSize);
+
+ // Insert parallax resolution information in the buffer,
+ // preceding parallax data.
+ WRITE_LE_UINT16(buffer, plxXres);
+ WRITE_LE_UINT16(buffer + 2, plxYres);
+ WRITE_LE_UINT16(buffer + 4, horTiles);
+ WRITE_LE_UINT16(buffer + 6, verTiles);
+
+ // Read parallax data from file and store it inside the buffer,
+ // skipping the generated header.
+ file.read(buffer + 8, totSize - 8);
+ file.close();
+
+ return buffer;
+}
+
// Used for testing text & speech (see fnISpeak in speech.cpp)
bool Sword2Engine::checkTextLine(byte *file, uint32 text_line) {