aboutsummaryrefslogtreecommitdiff
path: root/engines/parallaction/graphics.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/parallaction/graphics.cpp')
-rw-r--r--engines/parallaction/graphics.cpp117
1 files changed, 101 insertions, 16 deletions
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