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.cpp1361
1 files changed, 1361 insertions, 0 deletions
diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp
new file mode 100644
index 0000000000..15237b5c54
--- /dev/null
+++ b/engines/parallaction/graphics.cpp
@@ -0,0 +1,1361 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2006 The ScummVM project
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $URL$
+ * $Id$
+ *
+ */
+
+#include "common/file.h"
+
+#include "parallaction/graphics.h"
+#include "parallaction/parser.h"
+#include "parallaction/parallaction.h"
+#include "parallaction/inventory.h"
+#include "parallaction/disk.h"
+
+
+extern OSystem *g_system;
+
+namespace Parallaction {
+
+
+byte * _maskBackup;
+byte * _pathBackup;
+
+
+
+uint16 _bgLayers[4];
+
+// FIXME:
+extern byte _glyphWidths[];
+
+Cnv Graphics::_font;
+bool Graphics::_proportionalFont = false;
+Point Graphics::_labelPosition[2] = { { 0, 0 }, { 0, 0 } };
+StaticCnv Graphics::_mouseComposedArrow;
+byte * Graphics::_buffers[];
+
+#define PALETTE_BACKUP PALETTE_SIZE
+
+PaletteFxRange _palettefx[6];
+byte _palette[PALETTE_SIZE];
+
+byte _black_palette[PALETTE_SIZE] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+#define BALLOON_WIDTH 12
+#define BALLOON_HEIGHT 10
+
+byte _resBalloon[2][BALLOON_WIDTH*BALLOON_HEIGHT] = {
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ },
+ {
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x01, 0x01, 0x00, 0x02, 0x02,
+ 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02
+ }
+};
+
+void Graphics::drawBalloon(int16 left, int16 top, uint16 width, uint16 height, uint16 winding) {
+// printf("Graphics::drawBalloon(%i, %i, %i, %i, %i)...", left, top, width, height, winding);
+
+ width+=5;
+ floodFill(0, left, top, left+width, top+height, kBitFront);
+ floodFill(1, left+1, top+2, left+width-1, top+height-1, kBitFront);
+
+ winding = (winding == 0 ? 1 : 0);
+ byte *s = _resBalloon[winding];
+ byte *d = _buffers[kBitFront] + (left + width/2 - 5) + (top + height - 1) * SCREEN_WIDTH;
+
+ for (uint16 i = 0; i < BALLOON_HEIGHT; i++) {
+ for (uint16 j = 0; j < BALLOON_WIDTH; j++) {
+ if (*s != 2) *d = *s;
+ d++;
+ s++;
+ }
+
+ d += (SCREEN_WIDTH - BALLOON_WIDTH);
+ }
+
+// printf("done\n");
+
+ return;
+}
+
+
+
+//
+// palette management
+//
+
+void Graphics::setPalette(byte *palette) {
+// printf("setPalette()\n");
+// memcpy(_palette, palette, PALETTE_SIZE);
+
+ byte syspal[PALETTE_COLORS*4];
+
+ for (uint32 i = 0; i < PALETTE_COLORS; i++) {
+ syspal[i*4] = (palette[i*3] << 2) | (palette[i*3] >> 4);
+ syspal[i*4+1] = (palette[i*3+1] << 2) | (palette[i*3+1] >> 4);
+ syspal[i*4+2] = (palette[i*3+2] << 2) | (palette[i*3+2] >> 4);
+ syspal[i*4+3] = 0;
+ }
+
+ g_system->setPalette(syspal, 0, PALETTE_COLORS);
+ g_system->updateScreen();
+ return;
+}
+
+void Graphics::getBlackPalette(byte *palette) {
+ memcpy(palette, _black_palette, PALETTE_SIZE);
+ return;
+}
+
+void Graphics::palUnk0(byte *palette) {
+#if 0
+ for (uint16 i = 0; i < PALETTE_SIZE; i++) {
+ palette[PALETTE_BACKUP+i] = _palette[i]/2;
+ }
+#endif
+ Graphics::setPalette(palette);
+
+ return;
+}
+
+
+void Graphics::buildBWPalette(byte *palette) {
+
+ for (uint16 i = 0; i < PALETTE_COLORS; i++) {
+ byte max;
+
+ if (_palette[i*3+1] > _palette[i*3+2]) {
+ max = _palette[i*3+1];
+ } else {
+ max = _palette[i*3+2];
+ }
+
+ if (_palette[i*3] > max) {
+ max = _palette[i*3];
+ } else {
+ if (_palette[i*3+1] > _palette[i*3+2]) {
+ max = _palette[i*3+1];
+ } else {
+ max = _palette[i*3+2];
+ }
+ }
+
+ palette[i*3] = max;
+ palette[i*3+1] = max;
+ palette[i*3+2] = max;
+ }
+
+ return;
+}
+
+void Graphics::fadePalette(byte *palette) {
+
+ for (uint16 i = 0; i < PALETTE_SIZE; i++)
+ if (palette[i] < _palette[i]) palette[i]++;
+
+
+ return;
+}
+
+void Graphics::quickFadePalette(byte *palette) {
+
+ for (uint16 i = 0; i <= PALETTE_SIZE; i++) {
+ if (palette[i] == _palette[i]) continue;
+ palette[i] += (palette[i] < _palette[i] ? 4 : -4);
+ }
+
+ return;
+}
+
+//
+// palette Animation
+//
+// FIXME: the effect is different from the original
+//
+void Graphics::animatePalette(byte *palette) {
+// printf("Graphics::animatePalette()\n");
+
+ byte tmp[3];
+
+ for (uint16 i = 0; i < 4; i++) {
+
+ if ((_palettefx[i]._flags & 1) == 0) continue; // animated palette
+
+ _palettefx[i]._timer += _palettefx[i]._step * 2; // update timer
+
+ if (_palettefx[i]._timer < 0x4000) continue; // check timeout
+
+ _palettefx[i]._timer = 0; // reset timer
+
+ if (_palettefx[i]._flags & 2) { // forward
+
+ tmp[0] = _palette[_palettefx[i]._first * 3];
+ tmp[1] = _palette[_palettefx[i]._first * 3 + 1];
+ tmp[2] = _palette[_palettefx[i]._first * 3 + 2];
+
+ memmove(palette+_palettefx[i]._first*3, _palette+(_palettefx[i]._first+1)*3, (_palettefx[i]._last - _palettefx[i]._first)*3);
+
+ palette[_palettefx[i]._last * 3] = tmp[0];
+ palette[_palettefx[i]._last * 3 + 1] = tmp[1];
+ palette[_palettefx[i]._last * 3 + 2] = tmp[2];
+
+ } else { // backward
+
+ tmp[0] = _palette[_palettefx[i]._last * 3];
+ tmp[1] = _palette[_palettefx[i]._last * 3 + 1];
+ tmp[2] = _palette[_palettefx[i]._last * 3 + 2];
+
+ memmove(palette+(_palettefx[i]._first+1)*3, _palette+_palettefx[i]._first*3, (_palettefx[i]._last - _palettefx[i]._first)*3);
+
+ palette[_palettefx[i]._first * 3] = tmp[0];
+ palette[_palettefx[i]._first * 3 + 1] = tmp[1];
+ palette[_palettefx[i]._first * 3 + 2] = tmp[2];
+
+ }
+
+ }
+
+ return;
+}
+
+
+
+
+void Graphics::updateScreen() {
+// printf("Graphics::updateScreen()\n");
+ g_system->copyRectToScreen(_buffers[kBitFront], SCREEN_WIDTH, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
+ g_system->updateScreen();
+ return;
+}
+
+
+void Graphics::swapBuffers() {
+ byte *temp = _buffers[kBitFront];
+ _buffers[kBitFront] = _buffers[kBitBack];
+ _buffers[kBitBack] = temp;
+ updateScreen();
+ return;
+}
+
+
+//
+// graphic primitives
+//
+void Graphics::clearScreen(Graphics::Buffers buffer) {
+ memset(_buffers[buffer], 0, SCREEN_WIDTH*SCREEN_HEIGHT);
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+}
+
+
+void Graphics::copyScreen(Graphics::Buffers srcbuffer, Graphics::Buffers dstbuffer) {
+ memcpy(_buffers[dstbuffer], _buffers[srcbuffer], SCREEN_WIDTH*SCREEN_HEIGHT);
+
+ if (dstbuffer == kBitFront) updateScreen();
+
+ return;
+}
+
+
+void Graphics::copyRect(Graphics::Buffers srcbuffer, uint16 sx, uint16 sy, Graphics::Buffers dstbuffer, uint16 dx, uint16 dy, uint16 w, uint16 h) {
+
+ byte *s = _buffers[srcbuffer] + (sx + sy * SCREEN_WIDTH);
+ byte *d = _buffers[dstbuffer] + (dx + dy * SCREEN_WIDTH);
+
+ for (uint16 i = 0; i < h; i++) {
+ memcpy(d, s, w);
+
+ s += SCREEN_WIDTH;
+ d += SCREEN_WIDTH;
+ }
+
+ if (dstbuffer == kBitFront) updateScreen();
+
+ return;
+
+}
+
+
+void Graphics::floodFill(byte color, uint16 left, uint16 top, uint16 right, uint16 bottom, Graphics::Buffers buffer) {
+// printf("Graphics::floodFill(%i, %i, %i, %i, %i)\n", color, left, top, right, bottom);
+
+ byte *d = _buffers[buffer] + (left + top * SCREEN_WIDTH);
+ uint16 w = right - left + 1;
+ uint16 h = bottom - top + 1;
+
+ for (uint16 i = 0; i < h; i++) {
+ memset(d, color, w);
+
+ d += SCREEN_WIDTH;
+ }
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+}
+
+
+void Graphics::flatBlit(uint16 w, uint16 h, int16 x, int16 y, byte *data, Graphics::Buffers buffer) {
+// printf("Graphics::flatBlit(%i, %i, %i, %i)\n", w, h, x, y);
+
+ int16 left = 0, top = 0;
+ int16 right = w, bottom = h;
+
+ if (x + w > SCREEN_WIDTH) right = SCREEN_WIDTH - x;
+ if (y + h > SCREEN_HEIGHT) bottom = SCREEN_HEIGHT - y;
+
+ if (x < 0) { // partially left clipped
+ left = -x;
+ x = 0;
+ }
+
+ if (y < 0) { // partially top clipped
+ top = -y;
+ y = 0;
+ }
+
+ if (left > right || top > bottom || x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; // fully clipped
+
+ byte *s = data + left + top * w;
+ byte *d = _buffers[buffer] + x + y * SCREEN_WIDTH;
+
+ for (uint16 i = top; i < bottom; i++) {
+ for (uint16 j = left; j < right; j++) {
+ if (*s != 0) *d = *s;
+ s++;
+ d++;
+ }
+
+ s += (w - right + left);
+ d += (SCREEN_WIDTH - right + left);
+ }
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+
+}
+
+
+void Graphics::blit(uint16 w, uint16 h, int16 x, int16 y, uint16 z, byte *data, Graphics::Buffers buffer, Graphics::Buffers mask) {
+// printf("Graphics::blit(%i, %i, %i, %i, %i)\n", w, h, x, y, z);
+
+ int16 left = 0, top = 0;
+ int16 right = w, bottom = h;
+
+ if (x + w > SCREEN_WIDTH) right = SCREEN_WIDTH - x;
+ if (y + h > SCREEN_HEIGHT) bottom = SCREEN_HEIGHT - y;
+
+ if (x < 0) { // partially left clipped
+ left = -x;
+ x = 0;
+ }
+
+ if (y < 0) { // partially top clipped
+ top = -y;
+ y = 0;
+ }
+
+ if (left > right || top > bottom || x >= SCREEN_WIDTH || y >= SCREEN_HEIGHT) return; // fully clipped
+
+ byte *s = data + left + top * w;
+ byte *d = _buffers[buffer] + x + y * SCREEN_WIDTH;
+
+ for (uint16 i = top; i < bottom; i++) {
+
+ uint16 r = x % 4;
+ byte *m = _buffers[mask] + x/4 + (y + i - top)*SCREENMASK_WIDTH;
+
+ for (uint16 j = left; j < right; j++) {
+ if (*s != 0) {
+ uint16 v = ((3 << (r << 1)) & *m) >> (r << 1);
+ if (z >= v) *d = *s;
+ }
+
+ r++;
+ if (r==4) m++;
+ r &= 0x3;
+
+ s++;
+ d++;
+ }
+
+ s += (w - right + left);
+ d += (SCREEN_WIDTH - right + left);
+ }
+
+ if (buffer == kBitFront) updateScreen();
+
+ return;
+
+}
+
+
+void jobDisplayLabel(void *parm, Job *j) {
+
+ StaticCnv *cnv = (StaticCnv*)parm;
+
+ if (cnv->_data0 == NULL) return;
+ _vm->_graphics->flatBlitCnv(cnv, Graphics::_labelPosition[0]._x, Graphics::_labelPosition[0]._y, Graphics::kBitBack, cnv->_data1);
+
+ return;
+}
+
+void jobEraseLabel(void *parm, Job *j) {
+ StaticCnv *cnv = (StaticCnv*)parm;
+
+ int16 _si, _di;
+
+ if (_vm->_activeItem._id != 0) {
+ _si = _mousePos._x + 16 - cnv->_width/2;
+ _di = _mousePos._y + 34;
+ } else {
+ _si = _mousePos._x + 8 - cnv->_width/2;
+ _di = _mousePos._y + 33;
+ }
+
+ if (_si < 0) _si = 0;
+ if (_di > 190) _di = 190;
+
+ if (cnv->_width > SCREEN_WIDTH)
+ _si = SCREEN_WIDTH - _si;
+
+
+ _vm->_graphics->restoreBackground(Graphics::_labelPosition[1]._x, Graphics::_labelPosition[1]._y, cnv->_width, cnv->_height);
+
+ Graphics::_labelPosition[1]._x = Graphics::_labelPosition[0]._x;
+ Graphics::_labelPosition[1]._y = Graphics::_labelPosition[0]._y;
+ Graphics::_labelPosition[0]._x = _si;
+ Graphics::_labelPosition[0]._y = _di;
+
+ return;
+}
+
+void Graphics::initMouse(uint16 arg_0) {
+
+ loadExternalStaticCnv("pointer", &_mouseComposedArrow);
+
+ byte temp[16*16];
+ memcpy(temp, _mouseArrow, 16*16);
+
+ uint16 k = 0;
+ for (uint16 i = 0; i < 4; i++) {
+ for (uint16 j = 0; j < 64; j++) _mouseArrow[k++] = temp[i + j * 4];
+ }
+
+ return;
+}
+
+void Graphics::setMousePointer(int16 index) {
+
+ if (index == kCursorArrow) { // standard mouse pointer
+
+ StaticCnv cnv;
+
+ cnv._width = 16;
+ cnv._height = 16;
+ cnv._data0 = _mouseArrow;
+
+ g_system->setMouseCursor(_mouseArrow, 16, 16, 0, 0, 0);
+ g_system->showMouse(true);
+
+ } else {
+
+ // FIXME: standard mouse arrow must be combined with item
+ // but it is not at the moment
+
+ // inventory item pointer
+ StaticCnv mouse_pointer;
+ memcpy(&mouse_pointer, &_mouseComposedArrow, sizeof(StaticCnv));
+ byte *v8 = mouse_pointer._data0;
+
+ // FIXME: target offseting is not clear
+ extractInventoryGraphics(index, v8 + 7 + 32 * 7);
+
+ g_system->setMouseCursor(v8, 32, 32, 0, 0, 0);
+
+ }
+
+ return;
+}
+
+
+
+
+//
+// Cnv management
+//
+void Graphics::flatBlitCnv(StaticCnv *cnv, int16 x, int16 y, Graphics::Buffers buffer, byte *unused) {
+ flatBlit(cnv->_width, cnv->_height, x, y, cnv->_data0, buffer);
+ return;
+}
+
+
+void Graphics::blitCnv(StaticCnv *cnv, int16 x, int16 y, uint16 z, Graphics::Buffers buffer, Graphics::Buffers mask) {
+ blit(cnv->_width, cnv->_height, x, y, z, cnv->_data0, buffer, mask);
+ return;
+}
+
+
+void Graphics::backupCnvBackground(StaticCnv *cnv, int16 x, int16 y) {
+
+ byte *s = _buffers[kBit2] + x + y * SCREEN_WIDTH;
+ byte *d = cnv->_data2;
+
+ for (uint16 i = 0; i < cnv->_height ; i++) {
+ memcpy(d, s, cnv->_width);
+
+ s += SCREEN_WIDTH;
+ d += cnv->_width;
+ }
+
+ return;
+}
+
+
+void Graphics::backupCnvBackgroundTransparent(StaticCnv *cnv, int16 x, int16 y) {
+
+ byte *t = cnv->_data0;
+ byte *s = _buffers[kBitBack] + x + y * SCREEN_WIDTH;
+ byte *d = cnv->_data2;
+
+ for (uint16 i = 0; i < cnv->_height ; i++) {
+ for (uint16 j = 0; j < cnv->_width ; j++) {
+ *d = (*t) ? *s : 0;
+
+ d++;
+ t++;
+ s++;
+ }
+
+ s += (SCREEN_WIDTH - cnv->_width);
+ }
+
+ return;
+}
+
+
+// restores a cnv backup on the background
+//
+//
+void Graphics::restoreCnvBackground(StaticCnv *cnv, int16 x, int16 y) {
+
+ byte *temp = cnv->_data0;
+ cnv->_data0 = cnv->_data2;
+
+ flatBlitCnv(cnv, x, y, kBitBack, cnv->_data1);
+ flatBlitCnv(cnv, x, y, kBit2, cnv->_data1);
+
+ cnv->_data0 = temp;
+
+ return;
+}
+
+
+
+//
+// strings
+//
+void Graphics::displayString(uint16 x, uint16 y, const char *text) {
+
+ uint16 len = strlen(text);
+ StaticCnv tmp;
+
+ for (uint16 i = 0; i < len; i++) {
+ char c = mapChar(text[i]);
+
+ tmp._width = _font._width;
+ tmp._height = _font._height;
+ tmp._data0 = _font._array[c];
+
+ flatBlitCnv(&tmp, x, y, kBitFront, NULL);
+
+ x += (_proportionalFont ? _glyphWidths[(int)c] : 8);
+
+ }
+
+ return;
+}
+
+
+void Graphics::displayBalloonString(uint16 x, uint16 y, const char *text, byte color) {
+
+ uint16 len = strlen(text);
+
+ for (uint16 i = 0; i < len; i++) {
+
+ char c = mapChar(text[i]);
+ uint16 w = _proportionalFont ? _glyphWidths[(int)c] : 8;
+ byte *s = _font._array[c];
+ byte *d = _buffers[kBitFront] + x + y*SCREEN_WIDTH;
+
+// printf("%i\n", text[i]);
+
+ for (uint16 j = 0; j < _font._height; j++) {
+ for (uint16 k = 0; k < w; k++) {
+ *d = (*s) ? 1 : color;
+ d++;
+ s++;
+ }
+
+ s += (8 - w);
+ d += (SCREEN_WIDTH - w);
+ }
+
+ x += w;
+ }
+
+ updateScreen();
+
+ return;
+}
+
+
+
+bool Graphics::displayWrappedString(char *text, uint16 x, uint16 y, uint16 maxwidth, byte color) {
+// printf("Graphics::displayWrappedString(%s, %i, %i, %i, %i)...", text, x, y, maxwidth, color);
+
+ uint16 lines = 0;
+ bool rv = false;
+ uint16 linewidth = 0;
+
+ _proportionalFont = true;
+ uint16 rx = x + 10;
+ uint16 ry = y + 4;
+
+ char token[40];
+
+ while (strlen(text) > 0) {
+
+ text = parseNextToken(text, token, 40, " ");
+ linewidth += getStringWidth(token);
+
+ if (linewidth > maxwidth) {
+ // wrap line
+ lines++;
+ rx = x + 10; // x
+ ry = y + 4 + lines*10; // y
+ linewidth = getStringWidth(token);
+ }
+
+ if (!scumm_stricmp(token, "%s")) {
+ sprintf(token, "%d", _score);
+ }
+ if (!scumm_stricmp(token, "%p")) {
+ rv = true;
+ } else
+ displayBalloonString(rx, ry, token, color);
+
+ rx += getStringWidth(token) + getStringWidth(" ");
+ linewidth += getStringWidth(" ");
+
+ text = skip_whitespace(text);
+ }
+
+// printf("done\n");
+
+ return rv;
+
+}
+
+
+
+uint16 Graphics::getStringWidth(const char *text) {
+ uint16 len = strlen(text);
+
+ if (_proportionalFont == 0) {
+ // fixed font
+ return len*8;
+ }
+
+ // proportional font
+ uint16 w = 0;
+ for (uint16 i = 0; i < len; i++) {
+ char c = mapChar(text[i]);
+ w += _glyphWidths[(int)c];
+ }
+
+ return w;
+}
+
+
+void Graphics::getStringExtent(char *text, uint16 maxwidth, int16* width, int16* height) {
+
+ uint16 lines = 0;
+ uint16 w = 0;
+ *width = 0;
+
+ _proportionalFont = true;
+
+ char token[40];
+
+ while (strlen(text) != 0) {
+
+ text = parseNextToken(text, token, 40, " ");
+ w += getStringWidth(token);
+
+ if (w > maxwidth) {
+ w -= getStringWidth(token);
+ lines++;
+ if (w > *width)
+ *width = w;
+
+ w = getStringWidth(token);
+ }
+
+ w += getStringWidth(" ");
+ text = skip_whitespace(text);
+ }
+
+ if (*width < w) *width = w;
+ *width += 10;
+
+ *height = lines * 10 + 20;
+
+ return;
+}
+
+
+// backups background mask
+//
+//
+void Graphics::backupBackgroundMask(Graphics::Buffers mask) {
+
+ byte *s = _buffers[mask];
+ byte *d = _maskBackup;
+
+ memcpy(d, s, SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+// restores background mask
+//
+//
+void Graphics::restoreBackgroundMask(Graphics::Buffers mask) {
+
+ byte *s = _maskBackup;
+ byte *d = _buffers[mask];
+
+ memcpy(d, s, SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+// backups background path
+//
+//
+void Graphics::backupBackgroundPath(Graphics::Buffers path) {
+
+ byte *s = _buffers[path];
+ byte *d = _pathBackup;
+
+ memcpy(d, s, SCREENPATH_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+//
+// restores background path
+//
+void Graphics::restoreBackgroundPath(Graphics::Buffers path) {
+
+ byte *s = _pathBackup;
+ byte *d = _buffers[path];
+
+ memcpy(d, s, SCREENPATH_WIDTH*SCREEN_HEIGHT);
+
+ return;
+}
+
+//
+// decompress a graphics block
+//
+uint16 Graphics::decompressChunk(byte *src, byte *dst, uint16 size) {
+
+ uint16 written = 0;
+ uint16 read = 0;
+ uint16 len = 0;
+
+ for (; written != size; written += len) {
+
+ len = src[read];
+ read++;
+
+ if (len <= 127) {
+ // copy run
+
+ len++;
+ memcpy(dst+written, src+read, len);
+ read += len;
+
+ } else {
+ // expand run
+
+ len = 257 - len;
+ memset(dst+written, src[read], len);
+ read++;
+
+ }
+
+ }
+
+ return read;
+}
+
+void Graphics::restoreBackground(int16 left, int16 top, uint16 width, uint16 height) {
+// printf("restoreBackground(%i, %i, %i, %i)\n", left, top, width, height);
+
+ if (left < 0) left = 0;
+ if (top < 0) top = 0;
+
+ if (left >= SCREEN_WIDTH) return;
+ if (top >= SCREEN_HEIGHT) return;
+
+ if (left+width >= SCREEN_WIDTH) width = SCREEN_WIDTH - left;
+ if (top+height >= SCREEN_HEIGHT) height = SCREEN_HEIGHT - top;
+
+ copyRect(kBit2, left, top, kBitBack, left, top, width, height);
+
+ return;
+}
+
+
+void Graphics::makeCnvFromString(StaticCnv *cnv, char *text) {
+// printf("makeCnvFromString('%s')\n", text);
+
+ uint16 len = strlen(text);
+
+ cnv->_width = _font._width * len;
+ cnv->_height = _font._height;
+
+// printf("%i x %i\n", cnv->_width, cnv->_height);
+
+ cnv->_data0 = (byte*)memAlloc(cnv->_width * cnv->_height);
+
+ for (uint16 i = 0; i < len; i++) {
+ char c = mapChar(text[i]);
+
+ byte *s = _font._array[c];
+ byte *d = cnv->_data0 + _font._width * i;
+
+ for (uint16 j = 0; j < _font._height; j++) {
+ memcpy(d, s, 8);
+
+ s += 8;
+ d += cnv->_width;
+ }
+ }
+
+ return;
+}
+
+//
+// internal character mapping
+//
+char Graphics::mapChar(char c) {
+ byte b = (byte)c;
+
+ if (b == 0xA5) return 0x5F;
+ if (b == 0xDF) return 0x60;
+
+ if (b > 0x7F) return b - 0x7F;
+
+ return b - 0x20;
+}
+
+
+//
+// loads a cnv from an external file
+//
+void Graphics::loadExternalCnv(const char *filename, Cnv *cnv) {
+// printf("Graphics::loadExternalCnv(%s)...", filename);
+
+ char path[PATH_LEN];
+
+ sprintf(path, "%s.cnv", filename);
+
+ Common::File stream;
+
+ if (!stream.open(path))
+ errorFileNotFound(path);
+
+ cnv->_count = cnv->_width = cnv->_height = 0;
+
+ stream.read(&cnv->_count, 1);
+ stream.read(&cnv->_width, 1);
+ stream.read(&cnv->_height, 1);
+
+ cnv->_array = (byte**)memAlloc(cnv->_count * sizeof(byte*));
+
+ uint16 size = cnv->_width*cnv->_height;
+ for (uint16 i = 0; i < cnv->_count; i++) {
+ cnv->_array[i] = (byte*)memAlloc(size);
+ stream.read(cnv->_array[i], size);
+ }
+
+ stream.close();
+
+// printf("done\n");
+
+
+ return;
+}
+
+
+
+
+void Graphics::loadExternalStaticCnv(const char *filename, StaticCnv *cnv) {
+
+ char path[PATH_LEN];
+
+ sprintf(path, "%s.cnv", filename);
+
+ Common::File stream;
+
+ if (!stream.open(path))
+ errorFileNotFound(path);
+
+ cnv->_width = cnv->_height = 0;
+
+ stream.skip(1);
+ stream.read(&cnv->_width, 1);
+ stream.read(&cnv->_height, 1);
+
+ uint16 size = cnv->_width*cnv->_height;
+
+ cnv->_data0 = (byte*)memAlloc(size);
+ stream.read(cnv->_data0, size);
+
+ stream.close();
+
+ return;
+}
+
+
+
+
+
+void Graphics::loadStaticCnv(const char *filename, StaticCnv *cnv) {
+// printf("Graphics::loadStaticCnv(%s)\n", filename);
+
+ char path[PATH_LEN];
+
+ strcpy(path, filename);
+ ArchivedFile *file = openArchivedFile(path);
+ if (!file) {
+ sprintf(path, "%s.pp", filename);
+ file = openArchivedFile(path);
+ if (!file) errorFileNotFound(path);
+ }
+
+ cnv->_width = cnv->_height = 0;
+
+ byte unk;
+ readArchivedFile(file, &unk, 1);
+ readArchivedFile(file, &cnv->_width, 1);
+ readArchivedFile(file, &cnv->_height, 1);
+
+ uint16 compressedsize = getArchivedFileLength(path) - 3;
+ byte *compressed = (byte*)memAlloc(compressedsize);
+
+ uint16 size = cnv->_width*cnv->_height;
+ cnv->_data0 = (byte*)memAlloc(size);
+
+ readArchivedFile(file, compressed, compressedsize);
+ closeArchivedFile(file);
+
+ decompressChunk(compressed, cnv->_data0, size);
+ memFree(compressed);
+
+ return;
+}
+
+
+
+
+void Graphics::loadCnv(const char *filename, Cnv *cnv) {
+// printf("Graphics::loadCnv(%s)\n", filename);
+
+ char path[PATH_LEN];
+
+ strcpy(path, filename);
+ ArchivedFile *file = openArchivedFile(path);
+ if (!file) {
+ sprintf(path, "%s.pp", filename);
+ file = openArchivedFile(path);
+ if (!file) errorFileNotFound(path);
+ }
+
+ cnv->_count = cnv->_width = cnv->_height = 0;
+
+ readArchivedFile(file, &cnv->_count, 1);
+ readArchivedFile(file, &cnv->_width, 1);
+ readArchivedFile(file, &cnv->_height, 1);
+
+ uint16 framesize = cnv->_width*cnv->_height;
+
+ cnv->_array = (byte**)memAlloc(cnv->_count * sizeof(byte*));
+
+ uint32 size = getArchivedFileLength(path) - 3;
+
+ byte *buf = (byte*)memAlloc(size);
+ readArchivedFile(file, buf, size);
+
+ byte *s = buf;
+
+ for (uint16 i = 0; i < cnv->_count; i++) {
+ cnv->_array[i] = (byte*)memAlloc(framesize);
+ uint16 read = decompressChunk(s, cnv->_array[i], framesize);
+
+// printf("frame %i decompressed: %i --> %i\n", i, read, framesize);
+
+ s += read;
+ }
+
+ closeArchivedFile(file);
+
+ memFree(buf);
+
+ return;
+}
+
+
+
+
+
+
+
+void Graphics::freeCnv(Cnv *cnv) {
+// printf("Graphics::freeCnv()\n");
+
+ if (!cnv) return;
+
+ for (uint16 _si = 0; _si < cnv->_count; _si++) {
+ memFree(cnv->_array[_si]);
+ }
+ memFree(cnv->_array);
+
+ return;
+}
+
+
+
+void Graphics::freeStaticCnv(StaticCnv *cnv) {
+// printf("free_static_cnv()\n");
+
+ if (!cnv) return;
+
+ if (!cnv || !cnv->_data0) return;
+ memFree(cnv->_data0);
+ cnv->_data0 = NULL;
+
+ return;
+}
+
+
+//
+// slides (background images) are stored compressed by scanline in a rle fashion
+//
+// the uncompressed data must then be unpacked to get:
+// * color data [bits 0-5]
+// * mask data [bits 6-7] (z buffer)
+// * path data [bit 8] (walkable areas)
+//
+
+uint16 _swap_16(uint16 *v) {
+
+ uint16 v2 = *v;
+ uint16 v3 = *v & 0xFF;
+ *v = (v3 << 8) | ((v2 >> 8) & 0xFF);
+
+ return *v;
+}
+
+
+void unpackBackgroundScanline(byte *src, byte *screen, byte *mask, byte *path) {
+
+ // update mask, path and screen
+ for (uint16 i = 0; i < SCREEN_WIDTH; i++) {
+ path[i/8] |= ((src[i] & 0x80) >> 7) << (i & 7);
+ mask[i/4] |= ((src[i] & 0x60) >> 5) << ((i & 3) << 1);
+ screen[i] = src[i] & 0x1F;
+ }
+
+ return;
+}
+
+
+
+
+void Graphics::loadBackground(const char *filename, Graphics::Buffers buffer) {
+// printf("Graphics::loadBackground(%s)\n", filename);
+
+ ArchivedFile *file = openArchivedFile(filename);
+ if (!file) errorFileNotFound(filename);
+
+// byte palette[PALETTE_SIZE];
+ byte v150[4];
+ readArchivedFile(file, _palette, PALETTE_SIZE);
+ readArchivedFile(file, &v150, 4);
+ readArchivedFile(file, _palettefx, sizeof(PaletteFxRange)*6);
+
+// setPalette(palette);
+
+ uint16 _si;
+ for (_si = 0; _si < 4; _si++) {
+ byte _al = v150[_si];
+ _bgLayers[_si] = _al;
+ }
+
+ for (_si = 0; _si < 6; _si++) {
+ _swap_16(&_palettefx[_si]._timer);
+ _swap_16(&_palettefx[_si]._step);
+ _swap_16(&_palettefx[_si]._flags);
+ }
+
+#if 0
+ uint16 v147;
+ for (v147 = 0; v147 < PALETTE_SIZE; v147++) {
+ byte _al = _palette[v147];
+ _palette[PALETTE_SIZE+v147] = _al / 2;
+ }
+#endif
+
+ memset(_buffers[kPath0], 0, SCREENPATH_WIDTH*SCREEN_HEIGHT);
+ memset(_buffers[kMask0], 0, SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ byte *v4 = (byte*)memAlloc(SCREEN_SIZE);
+ readArchivedFile(file, v4, SCREEN_SIZE);
+
+ byte v144[SCREEN_WIDTH];
+
+ byte *s = v4;
+ for (uint16 i = 0; i < SCREEN_HEIGHT; i++) {
+ s += decompressChunk(s, v144, SCREEN_WIDTH);
+ unpackBackgroundScanline(v144, _buffers[buffer]+SCREEN_WIDTH*i, _buffers[kMask0]+SCREENMASK_WIDTH*i, _buffers[kPath0]+SCREENPATH_WIDTH*i);
+ }
+
+ memFree(v4);
+ closeArchivedFile(file);
+
+ return;
+}
+
+//
+// read background path and mask from a file
+//
+// mask and path are normally combined (via OR) into the background picture itself
+// read the comment on the top of this file for more
+//
+void Graphics::loadMaskAndPath(const char *filename) {
+
+ ArchivedFile *file = openArchivedFile(filename);
+ if (!file) errorFileNotFound(filename);
+
+ byte v4[4];
+ readArchivedFile(file, v4, 4);
+ readArchivedFile(file, _buffers[kPath0], SCREENPATH_WIDTH*SCREEN_HEIGHT);
+ readArchivedFile(file, _buffers[kMask0], SCREENMASK_WIDTH*SCREEN_HEIGHT);
+
+ for (uint16 _si = 0; _si < 4; _si++) _bgLayers[_si] = v4[_si];
+
+ closeArchivedFile(file);
+ return;
+}
+
+
+void Graphics::copyRect(Graphics::Buffers dstbuffer, uint16 x, uint16 y, uint16 w, uint16 h, byte *src, uint16 pitch) {
+
+ byte *d = _buffers[dstbuffer] + x + SCREEN_WIDTH * y;
+ byte *s = src;
+
+ for (uint16 _si = 0; _si < h; _si++) {
+ memcpy(d, s, w);
+
+ s += pitch;
+ d += SCREEN_WIDTH;
+ }
+
+
+}
+
+
+void Graphics::drawBorder(Graphics::Buffers buffer, uint16 x, uint16 y, uint16 w, uint16 h, byte color) {
+
+ byte *d = _buffers[buffer] + x + SCREEN_WIDTH * y;
+
+ for (uint16 i = 0; i < h; i++) {
+ d[i] = color;
+ d[i + SCREEN_WIDTH * (h-1)] = color;
+ d[i * SCREEN_WIDTH] = color;
+ d[i * SCREEN_WIDTH + w - 1] = color;
+ }
+
+ return;
+}
+
+void Graphics::grabRect(Graphics::Buffers srcbuffer, byte *dst, uint16 x, uint16 y, uint16 w, uint16 h, uint16 pitch) {
+
+ byte *s = _buffers[srcbuffer] + x + SCREEN_WIDTH * y;
+
+ for (uint16 i = 0; i < h; i++) {
+ memcpy(dst, s, w);
+
+ s += SCREEN_WIDTH;
+ dst += pitch;
+ }
+
+ return;
+}
+
+
+void Graphics::maskOpNot(uint16 x, uint16 y, uint16 unused, Graphics::Buffers mask) {
+
+ uint16 _ax = x + y * SCREEN_WIDTH;
+ _buffers[mask][_ax >> 2] &= ~(3 << ((_ax & 3) << 1));
+
+ return;
+}
+
+
+
+void Graphics::maskClearRectangle(uint16 left, uint16 top, uint16 right, uint16 bottom, Graphics::Buffers mask) {
+
+ uint16 _di = left/4 + top*80;
+
+ for (uint16 _si = top; _si < bottom; _si++) {
+ memset(&_buffers[mask][_di], 0, (right - left)/4+1);
+ _di += 80;
+ }
+
+ return;
+
+}
+
+// HACK
+// this routine is only invoked from the 'intgrotta scenario'
+//
+void Graphics::intGrottaHackMask() {
+ memset(_buffers[kMask0] + 3600, 0, 3600);
+ _bgLayers[1] = 500;
+ return;
+}
+
+uint16 Graphics::queryPath(uint16 x, uint16 y) {
+
+ byte *v6 = _buffers[kPath0];
+
+ byte _al = v6[y*40 + x/8];
+ byte _dl = 1 << (x % 8);
+
+ return _al & _dl;
+
+}
+
+int16 Graphics::queryMask(int16 v) {
+
+ for (uint16 _si = 0; _si < 3; _si++) {
+ if (_bgLayers[_si+1] > v) return _si;
+ }
+
+ return 3;
+}
+
+void Graphics::initBuffers() {
+
+ _buffers[kBitFront] = (byte*)memAlloc(SCREEN_SIZE);
+ _buffers[kBitBack] = (byte*)memAlloc(SCREEN_SIZE);
+ _buffers[kBit2] = (byte*)memAlloc(SCREEN_SIZE);
+ _buffers[kBit3] = (byte*)memAlloc(SCREEN_SIZE); // this buffer is also used by menu so it must stay this size
+
+ _buffers[kMask0] = (byte*)memAlloc(SCREENMASK_WIDTH * SCREEN_HEIGHT);
+ _buffers[kPath0] = (byte*)memAlloc(SCREENPATH_WIDTH * SCREEN_HEIGHT);
+
+ _maskBackup = (byte*)memAlloc(SCREENMASK_WIDTH * SCREEN_HEIGHT);
+ _pathBackup = (byte*)memAlloc(SCREENPATH_WIDTH * SCREEN_HEIGHT);
+
+ return;
+}
+
+
+Graphics::Graphics(Parallaction* vm) :
+ _vm(vm) {
+
+ g_system->beginGFXTransaction();
+
+ g_system->initSize(SCREEN_WIDTH, SCREEN_HEIGHT);
+
+ g_system->endGFXTransaction();
+
+ initBuffers();
+
+ byte palette[PALETTE_SIZE];
+ getBlackPalette(palette);
+ setPalette(palette);
+
+ initMouse( 0 );
+
+ return;
+}
+
+Graphics::~Graphics() {
+
+ memFree(_buffers[kMask0]);
+ memFree(_buffers[kPath0]);
+
+ memFree(_buffers[kBitFront]);
+ memFree(_buffers[kBitBack]);
+ memFree(_buffers[kBit2]);
+ memFree(_buffers[kBit3]);
+
+ return;
+}
+
+
+} // namespace Parallaction