aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/parallaction/disk.h2
-rw-r--r--engines/parallaction/disk_br.cpp30
-rw-r--r--engines/parallaction/disk_ns.cpp19
-rw-r--r--engines/parallaction/gfxbase.cpp16
-rw-r--r--engines/parallaction/graphics.cpp117
-rw-r--r--engines/parallaction/graphics.h24
-rw-r--r--engines/parallaction/parser_br.cpp2
-rw-r--r--engines/parallaction/walk.cpp10
8 files changed, 177 insertions, 43 deletions
diff --git a/engines/parallaction/disk.h b/engines/parallaction/disk.h
index 96fb154906..441b2468b3 100644
--- a/engines/parallaction/disk.h
+++ b/engines/parallaction/disk.h
@@ -75,6 +75,7 @@ public:
virtual Common::SeekableReadStream* loadMusic(const char* name) = 0;
virtual Common::ReadStream* loadSound(const char* name) = 0;
virtual void loadMask(const char *name, MaskBuffer &buffer) { }
+ virtual void loadPath(const char *name, PathBuffer &buffer) { }
};
@@ -230,6 +231,7 @@ public:
Common::SeekableReadStream* loadMusic(const char* name);
Common::ReadStream* loadSound(const char* name);
void loadMask(const char *name, MaskBuffer &buffer);
+ void loadPath(const char *name, PathBuffer &buffer);
};
class DosDemoDisk_br : public DosDisk_br {
diff --git a/engines/parallaction/disk_br.cpp b/engines/parallaction/disk_br.cpp
index 5f2ddcd1b7..e026b908f0 100644
--- a/engines/parallaction/disk_br.cpp
+++ b/engines/parallaction/disk_br.cpp
@@ -318,6 +318,20 @@ void DosDisk_br::loadMask(const char *name, MaskBuffer &buffer) {
delete stream;
}
+void DosDisk_br::loadPath(const char *name, PathBuffer &buffer) {
+ if (!name) {
+ return;
+ }
+
+ Common::SeekableReadStream *stream = openFile("pth/" + Common::String(name), ".pth");
+
+ // NOTE: info.width and info.height are only valid if the background graphics
+ // have already been loaded
+ buffer.bigEndian = false;
+ stream->read(buffer.data, buffer.size);
+ delete stream;
+}
+
void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char *mask, const char* path) {
debugC(5, kDebugDisk, "DosDisk_br::loadScenery");
@@ -345,13 +359,9 @@ void DosDisk_br::loadScenery(BackgroundInfo& info, const char *name, const char
}
if (path) {
- stream = openFile("pth/" + Common::String(path), ".pth");
-
- // NOTE: info.width and info.height are only valid if the background graphics
- // have already been loaded
- info.path.create(info.width, info.height);
- stream->read(info.path.data, info.path.size);
- delete stream;
+ info._path = new PathBuffer;
+ info._path->create(info.width, info.height);
+ loadPath(path, *info._path);
}
return;
@@ -477,8 +487,10 @@ void AmigaDisk_br::loadScenery(BackgroundInfo& info, const char* name, const cha
if (stream) {
// NOTE: info.width and info.height are only valid if the background graphics
// have already been loaded
- info.path.create(info.width, info.height);
- stream->read(info.path.data, info.path.size);
+ info._path = new PathBuffer;
+ info._path->bigEndian = false;
+ info._path->create(info.width, info.height);
+ stream->read(info._path->data, info._path->size);
delete stream;
} else {
debugC(1, kDebugDisk, "AmigaDisk_br::loadScenery: (%s) not found", path);
diff --git a/engines/parallaction/disk_ns.cpp b/engines/parallaction/disk_ns.cpp
index c24eaf7007..43f20be054 100644
--- a/engines/parallaction/disk_ns.cpp
+++ b/engines/parallaction/disk_ns.cpp
@@ -460,10 +460,13 @@ void DosDisk_ns::loadBackground(BackgroundInfo& info, const char *filename) {
info._mask = new MaskBuffer;
info._mask->create(info.width, info.height);
info._mask->bigEndian = true;
- info.path.create(info.width, info.height);
+
+ info._path = new PathBuffer;
+ info._path->create(info.width, info.height);
+ info._path->bigEndian = true;
Graphics::PackBitsReadStream pbstream(*stream);
- unpackBackground(&pbstream, (byte*)info.bg.pixels, info._mask->data, info.path.data);
+ unpackBackground(&pbstream, (byte*)info.bg.pixels, info._mask->data, info._path->data);
delete stream;
}
@@ -479,8 +482,10 @@ void DosDisk_ns::loadMaskAndPath(BackgroundInfo& info, const char *name) {
sprintf(path, "%s.msk", name);
Common::SeekableReadStream *stream = openFile(path);
parseDepths(info, *stream);
- info.path.create(info.width, info.height);
- stream->read(info.path.data, info.path.size);
+ info._path = new PathBuffer;
+ info._path->create(info.width, info.height);
+ info._path->bigEndian = true;
+ stream->read(info._path->data, info._path->size);
info._mask = new MaskBuffer;
info._mask->create(info.width, info.height);
info._mask->bigEndian = true;
@@ -1075,8 +1080,10 @@ void AmigaDisk_ns::loadPath(BackgroundInfo& info, const char *name) {
Graphics::PackBitsReadStream stream(*s);
- info.path.create(info.width, info.height);
- stream.read(info.path.data, info.path.size);
+ info._path = new PathBuffer;
+ info._path->create(info.width, info.height);
+ info._path->bigEndian = false;
+ stream.read(info._path->data, info._path->size);
delete s;
diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp
index a585caa713..2c9039c275 100644
--- a/engines/parallaction/gfxbase.cpp
+++ b/engines/parallaction/gfxbase.cpp
@@ -168,6 +168,18 @@ void Gfx::loadGfxObjMask(const char *name, GfxObj *obj) {
obj->_hasMask = true;
}
+void Gfx::loadGfxObjPath(const char *name, GfxObj *obj) {
+ Common::Rect rect;
+ obj->getRect(0, rect);
+
+ PathBuffer *buf = new PathBuffer;
+ buf->create(rect.width(), rect.height());
+ _vm->_disk->loadPath(name, *buf);
+
+ obj->_pathId = _backgroundInfo->addPathPatch(buf);
+ obj->_hasPath = true;
+}
+
void Gfx::showGfxObj(GfxObj* obj, bool visible) {
if (!obj) {
return;
@@ -179,10 +191,12 @@ void Gfx::showGfxObj(GfxObj* obj, bool visible) {
obj->clearFlags(kGfxObjVisible);
}
- //TODO: move handling of mask existence inside MaskManager
if (obj->_hasMask) {
_backgroundInfo->toggleMaskPatch(obj->_maskId, obj->x, obj->y, visible);
}
+ if (obj->_hasPath) {
+ _backgroundInfo->togglePathPatch(obj->_pathId, obj->x, obj->y, visible);
+ }
}
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
index 1a233bb990..bab7ed0605 100644
--- a/engines/parallaction/graphics.cpp
+++ b/engines/parallaction/graphics.cpp
@@ -807,6 +807,7 @@ void Gfx::setBackground(uint type, BackgroundInfo *info) {
}
_backgroundInfo->finalizeMask();
+ _backgroundInfo->finalizePath();
if (_gameType == GType_BRA) {
int width = CLIP(info->width, (int)_vm->_screenWidth, info->width);
@@ -822,7 +823,7 @@ void Gfx::setBackground(uint type, BackgroundInfo *info) {
}
-BackgroundInfo::BackgroundInfo() : x(0), y(0), width(0), height(0), _mask(0) {
+BackgroundInfo::BackgroundInfo() : x(0), y(0), width(0), height(0), _mask(0), _path(0) {
layers[0] = layers[1] = layers[2] = layers[3] = 0;
memset(ranges, 0, sizeof(ranges));
}
@@ -830,7 +831,7 @@ BackgroundInfo::BackgroundInfo() : x(0), y(0), width(0), height(0), _mask(0) {
BackgroundInfo::~BackgroundInfo() {
bg.free();
clearMaskData();
- path.free();
+ clearPathData();
}
bool BackgroundInfo::hasMask() {
@@ -851,7 +852,11 @@ void BackgroundInfo::clearMaskData() {
void BackgroundInfo::finalizeMask() {
if (_mask) {
- _maskBackup.clone(*_mask);
+ if (_maskPatches.size() > 0) {
+ // since no more patches can be added after finalization,
+ // avoid creating the backup if there is none
+ _maskBackup.clone(*_mask);
+ }
} else {
clearMaskData();
}
@@ -890,6 +895,55 @@ void BackgroundInfo::setPaletteRange(int index, const PaletteFxRange& range) {
memcpy(&ranges[index], &range, sizeof(PaletteFxRange));
}
+bool BackgroundInfo::hasPath() {
+ return _path != 0;
+}
+
+void BackgroundInfo::clearPathData() {
+ // free mask data
+ PathPatchMap::iterator it = _pathPatches.begin();
+ for ( ; it != _pathPatches.end(); it++) {
+ delete (*it)._value;
+ }
+ _pathPatches.clear();
+ delete _path;
+ _path = 0;
+ _pathBackup.free();
+}
+
+void BackgroundInfo::finalizePath() {
+ if (_path) {
+ if (_pathPatches.size() > 0) {
+ // since no more patches can be added after finalization,
+ // avoid creating the backup if there is none
+ _pathBackup.clone(*_path);
+ }
+ } else {
+ clearPathData();
+ }
+}
+
+int BackgroundInfo::addPathPatch(PathBuffer *patch) {
+ int id = _pathPatches.size();
+ _pathPatches.setVal(id, patch);
+ return id;
+}
+
+void BackgroundInfo::togglePathPatch(int id, int x, int y, bool apply) {
+ if (!hasPath()) {
+ return;
+ }
+ if (!_pathPatches.contains(id)) {
+ return;
+ }
+ PathBuffer *patch = _pathPatches.getVal(id);
+ if (apply) {
+ _path->bltOr(x, y, *patch, 0, 0, patch->w, patch->h);
+ } else {
+ _path->bltCopy(x, y, _pathBackup, x, y, patch->w, patch->h);
+ }
+}
+
MaskBuffer::MaskBuffer() : w(0), internalWidth(0), h(0), size(0), data(0), bigEndian(true) {
}
@@ -973,13 +1027,22 @@ void MaskBuffer::bltCopy(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx,
-PathBuffer::PathBuffer() : w(0), internalWidth(0), h(0), size(0), data(0) {
+PathBuffer::PathBuffer() : w(0), internalWidth(0), h(0), size(0), data(0), bigEndian(true) {
}
PathBuffer::~PathBuffer() {
free();
}
+void PathBuffer::clone(const PathBuffer &buf) {
+ if (!buf.data)
+ return;
+
+ create(buf.w, buf.h);
+ bigEndian = buf.bigEndian;
+ memcpy(data, buf.data, size);
+}
+
void PathBuffer::create(uint16 width, uint16 height) {
free();
@@ -1001,21 +1064,43 @@ void PathBuffer::free() {
byte PathBuffer::getValue(uint16 x, uint16 y) const {
byte m = data[(x >> 3) + y * internalWidth];
- uint bit = 0;
- switch (_vm->getGameType()) {
- case GType_Nippon:
- bit = (_vm->getPlatform() == Common::kPlatformPC) ? (x & 7) : (7 - (x & 7));
- break;
+ uint bit = bigEndian ? (x & 7) : (7 - (x & 7));
+ return ((1 << bit) & m) >> bit;
+}
+
+byte* PathBuffer::getPtr(uint16 x, uint16 y) const {
+ return data + (x >> 3) + y * internalWidth;
+}
- case GType_BRA:
- // Amiga and PC versions pack the path bits the same way in BRA
- bit = 7 - (x & 7);
- break;
+void PathBuffer::bltOr(uint16 dx, uint16 dy, const PathBuffer &src, uint16 sx, uint16 sy, uint width, uint height) {
+ assert((width <= w) && (width <= src.w) && (height <= h) && (height <= src.h));
- default:
- error("path mask not yet implemented for this game type");
+ byte *s = src.getPtr(sx, sy);
+ byte *d = getPtr(dx, dy);
+
+ // this code assumes buffers are aligned on 4-pixels boundaries, as the original does
+ uint16 linewidth = width >> 3;
+ for (uint16 i = 0; i < height; i++) {
+ for (uint16 j = 0; j < linewidth; j++) {
+ *d++ |= *s++;
+ }
+ d += internalWidth - linewidth;
+ s += src.internalWidth - linewidth;
+ }
+}
+
+void PathBuffer::bltCopy(uint16 dx, uint16 dy, const PathBuffer &src, uint16 sx, uint16 sy, uint width, uint height) {
+ assert((width <= w) && (width <= src.w) && (height <= h) && (height <= src.h));
+
+ byte *s = src.getPtr(sx, sy);
+ byte *d = getPtr(dx, dy);
+
+ // this code assumes buffers are aligned on 4-pixels boundaries, as the original does
+ for (uint16 i = 0; i < height; i++) {
+ memcpy(d, s, (width >> 3));
+ d += internalWidth;
+ s += src.internalWidth;
}
- return ((1 << bit) & m) >> bit;
}
} // namespace Parallaction
diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h
index db80586a70..88c43ee4c5 100644
--- a/engines/parallaction/graphics.h
+++ b/engines/parallaction/graphics.h
@@ -192,6 +192,8 @@ struct MaskBuffer {
bool bigEndian;
byte* getPtr(uint16 x, uint16 y) const;
+ void bltOr(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx, uint16 sy, uint width, uint height);
+ void bltCopy(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx, uint16 sy, uint width, uint height);
public:
MaskBuffer();
@@ -202,8 +204,6 @@ public:
void free();
byte getValue(uint16 x, uint16 y) const;
- void bltOr(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx, uint16 sy, uint width, uint height);
- void bltCopy(uint16 dx, uint16 dy, const MaskBuffer &src, uint16 sx, uint16 sy, uint width, uint height);
};
@@ -215,11 +215,17 @@ struct PathBuffer {
uint16 h;
uint size;
byte *data;
+ bool bigEndian;
+
+ byte* getPtr(uint16 x, uint16 y) const;
+ void bltOr(uint16 dx, uint16 dy, const PathBuffer &src, uint16 sx, uint16 sy, uint width, uint height);
+ void bltCopy(uint16 dx, uint16 dy, const PathBuffer &src, uint16 sx, uint16 sy, uint width, uint height);
public:
PathBuffer();
~PathBuffer();
+ void clone(const PathBuffer &buf);
void create(uint16 width, uint16 height);
void free();
byte getValue(uint16 x, uint16 y) const;
@@ -304,7 +310,9 @@ public:
uint scale;
int _maskId;
- bool _hasMask;
+ bool _hasMask;
+ int _pathId;
+ bool _hasPath;
GfxObj(uint type, Frames *frames, const char *name = NULL);
@@ -340,9 +348,13 @@ protected:
typedef Common::HashMap<int, MaskBuffer*> MaskPatchMap;
MaskPatchMap _maskPatches;
MaskBuffer _maskBackup;
-
void clearMaskData();
+ typedef Common::HashMap<int, PathBuffer*> PathPatchMap;
+ PathPatchMap _pathPatches;
+ PathBuffer _pathBackup;
+ void clearPathData();
+
public:
int x, y; // used to display bitmaps smaller than the screen
int width;
@@ -350,7 +362,7 @@ public:
Graphics::Surface bg;
MaskBuffer *_mask;
- PathBuffer path;
+ PathBuffer *_path;
Palette palette;
@@ -374,6 +386,7 @@ public:
bool hasPath();
int addPathPatch(PathBuffer *patch);
void togglePathPatch(int id, int x, int y, bool apply);
+ void finalizePath();
};
@@ -425,6 +438,7 @@ public:
void showGfxObj(GfxObj* obj, bool visible);
void clearGfxObjects(uint filter);
void loadGfxObjMask(const char *name, GfxObj *obj);
+ void loadGfxObjPath(const char *name, GfxObj *obj);
void sortScene();
void blt(const Common::Rect& r, byte *data, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor);
void unpackBlt(const Common::Rect& r, byte *data, uint size, Graphics::Surface *surf, uint16 z, uint scale, byte transparentColor);
diff --git a/engines/parallaction/parser_br.cpp b/engines/parallaction/parser_br.cpp
index 3b5efd2c3f..04ffb5c083 100644
--- a/engines/parallaction/parser_br.cpp
+++ b/engines/parallaction/parser_br.cpp
@@ -792,7 +792,7 @@ void LocationParser_br::parseGetData(ZonePtr z) {
}
if (!scumm_stricmp(_tokens[0], "path")) {
-
+ _vm->_gfx->loadGfxObjPath(_tokens[1], data->gfxobj);
}
if (!scumm_stricmp(_tokens[0], "icon")) {
diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp
index 5a646caa9f..77251bc319 100644
--- a/engines/parallaction/walk.cpp
+++ b/engines/parallaction/walk.cpp
@@ -27,7 +27,7 @@
namespace Parallaction {
-#define IS_PATH_CLEAR(x,y) _vm->_gfx->_backgroundInfo->path.getValue((x), (y))
+#define IS_PATH_CLEAR(x,y) _vm->_gfx->_backgroundInfo->_path->getValue((x), (y))
// adjusts position towards nearest walkable point
//
@@ -35,8 +35,8 @@ void PathBuilder_NS::correctPathPoint(Common::Point &to) {
if (IS_PATH_CLEAR(to.x, to.y)) return;
- int maxX = _vm->_gfx->_backgroundInfo->path.w;
- int maxY = _vm->_gfx->_backgroundInfo->path.h;
+ int maxX = _vm->_gfx->_backgroundInfo->_path->w;
+ int maxY = _vm->_gfx->_backgroundInfo->_path->h;
int16 right = to.x;
int16 left = to.x;
@@ -229,7 +229,7 @@ uint16 PathBuilder_NS::walkFunc1(const Common::Point &to, Common::Point& node) {
void PathWalker_NS::clipMove(Common::Point& pos, const Common::Point& to) {
- if ((pos.x < to.x) && (pos.x < _vm->_gfx->_backgroundInfo->path.w) && IS_PATH_CLEAR(pos.x + 2, pos.y)) {
+ if ((pos.x < to.x) && (pos.x < _vm->_gfx->_backgroundInfo->_path->w) && IS_PATH_CLEAR(pos.x + 2, pos.y)) {
pos.x = (pos.x + 2 < to.x) ? pos.x + 2 : to.x;
}
@@ -237,7 +237,7 @@ void PathWalker_NS::clipMove(Common::Point& pos, const Common::Point& to) {
pos.x = (pos.x - 2 > to.x) ? pos.x - 2 : to.x;
}
- if ((pos.y < to.y) && (pos.y < _vm->_gfx->_backgroundInfo->path.h) && IS_PATH_CLEAR(pos.x, pos.y + 2)) {
+ if ((pos.y < to.y) && (pos.y < _vm->_gfx->_backgroundInfo->_path->h) && IS_PATH_CLEAR(pos.x, pos.y + 2)) {
pos.y = (pos.y + 2 <= to.y) ? pos.y + 2 : to.y;
}