diff options
Diffstat (limited to 'engines/parallaction')
-rw-r--r-- | engines/parallaction/disk.h | 2 | ||||
-rw-r--r-- | engines/parallaction/disk_br.cpp | 30 | ||||
-rw-r--r-- | engines/parallaction/disk_ns.cpp | 19 | ||||
-rw-r--r-- | engines/parallaction/gfxbase.cpp | 16 | ||||
-rw-r--r-- | engines/parallaction/graphics.cpp | 117 | ||||
-rw-r--r-- | engines/parallaction/graphics.h | 24 | ||||
-rw-r--r-- | engines/parallaction/parser_br.cpp | 2 | ||||
-rw-r--r-- | engines/parallaction/walk.cpp | 10 |
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; } |