diff options
Diffstat (limited to 'engines/parallaction/graphics.cpp')
-rw-r--r-- | engines/parallaction/graphics.cpp | 1361 |
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 |