aboutsummaryrefslogtreecommitdiff
path: root/sword1/screen.cpp
diff options
context:
space:
mode:
authorRobert Göffringmann2003-12-16 02:10:15 +0000
committerRobert Göffringmann2003-12-16 02:10:15 +0000
commit189e08bc7985fc5664e7ab95195bbade07488f48 (patch)
treef12049da0a8e600bcdd425e4c314c50b5c9922f7 /sword1/screen.cpp
parentc3a9b2df6789055325b7fea6dd591cea1d419682 (diff)
downloadscummvm-rg350-189e08bc7985fc5664e7ab95195bbade07488f48.tar.gz
scummvm-rg350-189e08bc7985fc5664e7ab95195bbade07488f48.tar.bz2
scummvm-rg350-189e08bc7985fc5664e7ab95195bbade07488f48.zip
Broken Sword 1: initial import
svn-id: r11664
Diffstat (limited to 'sword1/screen.cpp')
-rw-r--r--sword1/screen.cpp884
1 files changed, 884 insertions, 0 deletions
diff --git a/sword1/screen.cpp b/sword1/screen.cpp
new file mode 100644
index 0000000000..17ad57ce30
--- /dev/null
+++ b/sword1/screen.cpp
@@ -0,0 +1,884 @@
+/* ScummVM - Scumm Interpreter
+ * Copyright (C) 2003 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * $Header$
+ *
+ */
+
+#include "stdafx.h"
+#include "screen.h"
+#include "logic.h"
+#include "sworddefs.h"
+#include "text.h"
+#include "resman.h"
+#include "objectman.h"
+#include "scummsys.h"
+#include "common/util.h"
+#include "system.h"
+#include "router.h"
+
+#define SCROLL_FRACTION 16
+#define MAX_SCROLL_DISTANCE 8
+#define FADE_UP 1
+#define FADE_DOWN -1
+
+SwordScreen::SwordScreen(OSystem *system, ResMan *pResMan, ObjectMan *pObjMan) {
+ _system = system;
+ _resMan = pResMan;
+ _objMan = pObjMan;
+ _screenBuf = _screenGrid = NULL;
+ _backLength = _foreLength = _sortLength = 0;
+ _fadingStep = 0;
+}
+
+void SwordScreen::useTextManager(SwordText *pTextMan) {
+ _textMan = pTextMan;
+}
+
+int32 SwordScreen::inRange(int32 a, int32 b, int32 c) { // return b(!) so that: a <= b <= c
+ return (a > b) ? (a) : ((b < c) ? b : c);
+}
+
+void SwordScreen::setScrolling(int16 offsetX, int16 offsetY) {
+ if (!SwordLogic::_scriptVars[SCROLL_FLAG])
+ return ; // screen is smaller than 640x400 => no need for scrolling
+
+ int32 dx, dy;
+ uint32 scrlDistX, scrlDistY;
+ uint32 scrlToX, scrlToY;
+
+ offsetX = inRange(0, offsetX, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X]);
+ offsetY = inRange(0, offsetY, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
+ _oldScrollX = SwordLogic::_scriptVars[SCROLL_OFFSET_X];
+ _oldScrollY = SwordLogic::_scriptVars[SCROLL_OFFSET_Y];
+
+ if (SwordLogic::_scriptVars[SCROLL_FLAG] == 2) { // first time on this screen - need absolute scroll immediately!
+ scrlToX = (uint32)offsetX;
+ scrlToY = (uint32)offsetY;
+ } else { // catch up with required scroll offsets - speed depending on distance to catch up (dx and dy) & 'SCROLL_FRACTION' used
+ // but limit to certain number of pixels per cycle (MAX_SCROLL_DISTANCE)
+ dx = SwordLogic::_scriptVars[SCROLL_OFFSET_X] - offsetX;
+ dy = SwordLogic::_scriptVars[SCROLL_OFFSET_Y] - offsetY;
+ int8 sig = (dx < 0) ? (-1) : 1;
+ if (dx < 0)
+ dx = -dx;
+ scrlDistX = 1 + dx/SCROLL_FRACTION;
+ scrlDistX = inRange(0, scrlDistX, MAX_SCROLL_DISTANCE);
+ scrlToX = SwordLogic::_scriptVars[SCROLL_OFFSET_X] + sig * scrlDistX;
+
+ sig = (dy < 0) ? (-1) : 1;
+ if (dy < 0)
+ dy = -dy;
+ scrlDistY = 1 + dy/SCROLL_FRACTION;
+ scrlDistY = inRange(0, scrlDistY, MAX_SCROLL_DISTANCE);
+ scrlToY = SwordLogic::_scriptVars[SCROLL_OFFSET_Y] + sig * scrlDistY;
+ }
+ scrlToX = inRange(0, scrlToX, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X]);
+ scrlToY = inRange(0, scrlToY, SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y]);
+ if ((scrlToX != SwordLogic::_scriptVars[SCROLL_OFFSET_X]) || (scrlToY != SwordLogic::_scriptVars[SCROLL_OFFSET_Y])) {
+ _fullRefresh = true;
+ SwordLogic::_scriptVars[SCROLL_OFFSET_X] = scrlToX;
+ SwordLogic::_scriptVars[SCROLL_OFFSET_Y] = scrlToY;
+ } else
+ _fullRefresh = false;
+ if (SwordLogic::_scriptVars[SCROLL_FLAG] == 2) {
+ _oldScrollX = scrlToX;
+ _oldScrollY = scrlToY;
+ SwordLogic::_scriptVars[SCROLL_FLAG] = 1;
+ }
+}
+
+void SwordScreen::fadeDownPalette(void) {
+ _fadingStep = 15;
+ _fadingDirection = FADE_DOWN;
+}
+
+void SwordScreen::fadeUpPalette(void) {
+ _fadingStep = 15;
+ _fadingDirection = FADE_UP;
+}
+
+void SwordScreen::fnSetPalette(uint8 start, uint16 length, uint8 *data) {
+ memcpy(_targetPalette + start * 3, data, length * 3);
+ _system->set_palette(data, start, length);
+}
+
+void SwordScreen::fnSetFadeTargetPalette(uint8 start, uint16 length, uint8 *data) {
+ memcpy(_targetPalette + start * 3, data, length * 3);
+ debug(1, "fnSetFadeTargetPalette called");
+}
+
+bool SwordScreen::stillFading(void) {
+ return (_fadingStep > 0);
+}
+
+void SwordScreen::updateScreen(void) {
+ if (SwordLogic::_scriptVars[NEW_PALETTE]) {
+ _fadingStep = 1;
+ _fadingDirection = FADE_UP;
+ memcpy(_targetPalette, _resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[0]), 184 * 3); // set colours 0-183 for background palette
+ _resMan->resClose(_roomDefTable[_currentScreen].palettes[0]);
+ memcpy(_targetPalette + 184 * 3, _resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[1]), 72 * 3); // set colours 184-255 for sprite palette - george, icons & menubar
+ _resMan->resClose(_roomDefTable[_currentScreen].palettes[1]);
+ SwordLogic::_scriptVars[NEW_PALETTE] = 0;
+ }
+ if (_fadingStep) {
+ fadePalette();
+ _system->set_palette(_currentPalette, 0, 256);
+ }
+
+ uint16 scrlX = (uint16)SwordLogic::_scriptVars[SCROLL_OFFSET_X];
+ uint16 scrlY = (uint16)SwordLogic::_scriptVars[SCROLL_OFFSET_Y];
+ _fullRefresh = true;
+ if (_fullRefresh) {
+ _fullRefresh = false;
+ uint16 copyWidth = SCREEN_WIDTH;
+ uint16 copyHeight = SCREEN_DEPTH;
+ if (scrlX + copyWidth > _scrnSizeX)
+ copyWidth = _scrnSizeX - scrlX;
+ if (scrlY + copyHeight > _scrnSizeY)
+ copyHeight = _scrnSizeY - scrlY;
+ _system->copy_rect(_screenBuf + scrlY * _scrnSizeX + scrlX, _scrnSizeX, 0, 40, copyWidth, copyHeight);
+ } else {
+ // partial screen update only. The screen coordinates probably won't fit to the
+ // grid holding the informations on which blocks have to be updated.
+ // as the grid will be X pixel higher and Y pixel more to the left, this can be cured
+ // by first checking the top border, then the left column and then the remaining (aligned) part.
+ uint8 *gridPos = _screenGrid + (scrlX / SCRNGRID_X) + (scrlY / SCRNGRID_Y) * _gridSizeX;
+ uint8 *scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
+ uint8 diffX = (uint8)(scrlX % SCRNGRID_X);
+ uint8 diffY = (uint8)(scrlY % SCRNGRID_Y);
+ uint16 gridW = SCREEN_WIDTH / SCRNGRID_X;
+ uint16 gridH = SCREEN_DEPTH / SCRNGRID_Y;
+ if (diffY) {
+ uint8 cpHeight = SCRNGRID_Y - diffY;
+ uint16 cpWidth = 0;
+ for (uint16 cntx = 0; cntx < gridW; cntx++)
+ if (gridPos[cntx] & 1) {
+ gridPos[cntx] &= ~1;
+ cpWidth++;
+ } else if (cpWidth) {
+ int16 xPos = (cntx - cpWidth) * SCRNGRID_X - diffX;
+ if (xPos < 0)
+ xPos = 0;
+ _system->copy_rect(scrnBuf + xPos, _scrnSizeX, xPos, 40, cpWidth * SCRNGRID_X, cpHeight);
+ cpWidth = 0;
+ }
+ if (cpWidth) {
+ int16 xPos = (gridW - cpWidth) * SCRNGRID_X - diffX;
+ if (xPos < 0)
+ xPos = 0;
+ _system->copy_rect(scrnBuf + xPos, _scrnSizeX, xPos, 40, SCREEN_WIDTH - xPos, cpHeight);
+ }
+ } // okay, y scrolling is compensated. check x now.
+ gridPos += _gridSizeX;
+ scrnBuf = _screenBuf + scrlX + diffY * _scrnSizeX;
+ if (diffX) {
+ uint8 cpWidth = SCRNGRID_X - diffX;
+ uint16 cpHeight = 0;
+ for (uint16 cnty = 0; cnty < gridH; cnty++)
+ if (gridPos[cnty * SCRNGRID_X] & 1) {
+ gridPos[cnty * SCRNGRID_X] &= ~1;
+ cpHeight++;
+ } else if (cpHeight) {
+ uint16 yPos = (cnty - cpHeight) * SCRNGRID_Y;
+ _system->copy_rect(scrnBuf + yPos * _scrnSizeX, _scrnSizeX, 0, yPos + diffY + 40, cpWidth, cpHeight * SCRNGRID_Y);
+ }
+ if (cpHeight) {
+ uint16 yPos = (gridH - cpHeight) * SCRNGRID_Y;
+ _system->copy_rect(scrnBuf + yPos * _scrnSizeX, _scrnSizeX, 0, yPos + diffY + 40, cpWidth, SCREEN_DEPTH - (yPos + diffY));
+ }
+ } // x scroll is compensated, too. check the rest of the screen, now.
+ scrlX = (scrlX + SCRNGRID_X - 1) &~ (SCRNGRID_X - 1);
+ scrlY = (scrlY + SCRNGRID_Y - 1) &~ (SCRNGRID_Y - 1);
+ scrnBuf = _screenBuf + scrlY * _scrnSizeX + scrlX;
+ gridPos++;
+ for (uint16 cnty = 0; cnty < gridH; cnty++) {
+ uint16 cpWidth = 0;
+ uint16 cpHeight = SCRNGRID_Y;
+ if (cnty == gridH - 1)
+ cpHeight = SCRNGRID_Y - diffY;
+ for (uint16 cntx = 0; cntx < gridW; cntx++)
+ if (gridPos[cntx] & 1) {
+ gridPos[cntx] &= ~1;
+ cpWidth++;
+ } else if (cpWidth) {
+ _system->copy_rect(scrnBuf + (cntx - cpWidth) * SCRNGRID_X, _scrnSizeX, (cntx - cpWidth) * SCRNGRID_X + diffX, cnty * SCRNGRID_Y + diffY + 40, cpWidth * SCRNGRID_X, cpHeight);
+ }
+ if (cpWidth) {
+ uint16 xPos = (gridW - cpWidth) * SCRNGRID_X;
+ _system->copy_rect(scrnBuf + xPos, _scrnSizeX, xPos + diffX, cnty * SCRNGRID_Y + diffY + 40, SCREEN_WIDTH - (xPos + diffX), cpHeight);
+ }
+ gridPos += _gridSizeX;
+ scrnBuf += _scrnSizeX * SCRNGRID_Y;
+ }
+ }
+ _system->update_screen();
+}
+
+void SwordScreen::newScreen(uint32 screen) {
+ // set sizes and scrolling, initialize/load screengrid, force screen refresh
+ // force palette fadeup?
+ _currentScreen = screen;
+ _scrnSizeX = _roomDefTable[screen].sizeX;
+ _scrnSizeY = _roomDefTable[screen].sizeY;
+ _gridSizeX = _scrnSizeX / SCRNGRID_X;
+ _gridSizeY = _scrnSizeY / SCRNGRID_Y;
+ if ((_scrnSizeX % SCRNGRID_X) || (_scrnSizeY % SCRNGRID_Y))
+ error("Illegal screensize: %d: %d/%d", screen, _scrnSizeX, _scrnSizeY);
+ if ((_scrnSizeX > SCREEN_WIDTH) || (_scrnSizeY > SCREEN_DEPTH)) {
+ SwordLogic::_scriptVars[SCROLL_FLAG] = 2;
+ SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X] = _scrnSizeX - SCREEN_WIDTH;
+ SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y] = _scrnSizeY - SCREEN_DEPTH;
+ } else {
+ SwordLogic::_scriptVars[SCROLL_FLAG] = 0;
+ SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_X] = 0;
+ SwordLogic::_scriptVars[MAX_SCROLL_OFFSET_Y] = 0;
+ SwordLogic::_scriptVars[SCROLL_OFFSET_X] = 0;
+ SwordLogic::_scriptVars[SCROLL_OFFSET_Y] = 0;
+ }
+ _screenBuf = (uint8*)malloc(_scrnSizeX * _scrnSizeY);
+ _screenGrid = (uint8*)malloc(_gridSizeX * _gridSizeY);
+ memset(_screenGrid, 0x80, _gridSizeX * _gridSizeY); // force refresh
+ for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers; cnt++) {
+ // open and lock all resources, will be closed in closeScreen()
+ _layerBlocks[cnt] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].layers[cnt]);
+ }
+ for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers - 1; cnt++) {
+ // there's no grid for the background layer, so it's totalLayers - 1
+ _layerGrid[cnt] = (uint16*)_resMan->openFetchRes(_roomDefTable[_currentScreen].grids[cnt]);
+ _layerGrid[cnt] += 0x12; // not sure about the 0x12
+ }
+ _parallax[0] = _parallax[1] = NULL;
+ if (_roomDefTable[_currentScreen].parallax[0])
+ _parallax[0] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].parallax[0]);
+ if (_roomDefTable[_currentScreen].parallax[1])
+ _parallax[1] = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].parallax[1]);
+
+ // TEMPORARY!
+ uint8 *bgPal = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[0]);
+ uint8 *sprPal = (uint8*)_resMan->openFetchRes(_roomDefTable[_currentScreen].palettes[1]);
+ for (uint16 cnt = 0; cnt < 256; cnt++) {
+ _targetPalette[cnt * 4 + 0] = bgPal[cnt * 3 + 0] << 2;
+ _targetPalette[cnt * 4 + 1] = bgPal[cnt * 3 + 1] << 2;
+ _targetPalette[cnt * 4 + 2] = bgPal[cnt * 3 + 2] << 2;
+ }
+ /*for (uint16 cnt = 0; cnt < 72; cnt++) {
+ _targetPalette[(cnt + 184) * 4 + 0] = bgPal[cnt * 3 + 0];
+ _targetPalette[(cnt + 184) * 4 + 1] = bgPal[cnt * 3 + 1];
+ _targetPalette[(cnt + 184) * 4 + 2] = bgPal[cnt * 3 + 2];
+ }*/
+ _targetPalette[0] = _targetPalette[1] = _targetPalette[2] = 0;
+ _system->set_palette(_targetPalette, 0, 256);
+ _resMan->resClose(_roomDefTable[_currentScreen].palettes[0]);
+ _resMan->resClose(_roomDefTable[_currentScreen].palettes[1]);
+}
+
+void SwordScreen::quitScreen(void) {
+ for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers; cnt++)
+ _resMan->resClose(_roomDefTable[_currentScreen].layers[cnt]);
+ for (uint8 cnt = 0; cnt < _roomDefTable[_currentScreen].totalLayers - 1; cnt++)
+ _resMan->resClose(_roomDefTable[_currentScreen].grids[cnt]);
+ if (_roomDefTable[_currentScreen].parallax[0])
+ _resMan->resClose(_roomDefTable[_currentScreen].parallax[0]);
+ if (_roomDefTable[_currentScreen].parallax[1])
+ _resMan->resClose(_roomDefTable[_currentScreen].parallax[1]);
+}
+
+void SwordScreen::recreate() {
+ memcpy(_screenBuf, _layerBlocks[0], _scrnSizeX * _scrnSizeY);
+}
+
+void SwordScreen::spritesAndParallax(void) {
+ if ((_currentScreen == 54) && _parallax[0])
+ renderParallax(_parallax[0]); // rm54 has a BACKGROUND parallax layer in parallax[0]
+
+ for (uint8 cnt = 0; cnt < _backLength; cnt++)
+ processImage(_backList[cnt]);
+
+ SortSpr temp;
+ for (uint8 cnt = 0; cnt < _sortLength - 1; cnt++)
+ for (uint8 sCnt = 0; sCnt < _sortLength - 1; sCnt++)
+ if (_sortList[sCnt].y > _sortList[sCnt + 1].y) {
+ temp = _sortList[sCnt];
+ _sortList[sCnt] = _sortList[sCnt + 1];
+ _sortList[sCnt + 1] = temp;
+ }
+ for (uint8 cnt = 0; cnt < _sortLength; cnt++)
+ processImage(_sortList[cnt].id);
+
+ if ((_currentScreen != 54) && _parallax[0])
+ renderParallax(_parallax[0]); // screens other than 54 have FOREGROUND parallax layer in parallax[0]
+ if (_parallax[1])
+ renderParallax(_parallax[1]);
+
+ for (uint8 cnt = 0; cnt < _foreLength; cnt++)
+ processImage(_foreList[cnt]);
+
+ _backLength = _sortLength = _foreLength = 0;
+}
+
+void SwordScreen::processImage(uint32 id) {
+ BsObject *compact;
+ FrameHeader *frameHead;
+ int scale;
+
+ compact = _objMan->fetchObject(id);
+ if (compact->o_type == TYPE_TEXT)
+ frameHead = _textMan->giveSpriteData((uint8)compact->o_target);
+ else
+ frameHead = _resMan->fetchFrame(_resMan->openFetchRes(compact->o_resource), compact->o_frame);
+
+ uint8 *sprData = ((uint8*)frameHead) + sizeof(FrameHeader);
+
+ uint16 spriteX = compact->o_anim_x;
+ uint16 spriteY = compact->o_anim_y;
+ if (compact->o_status & STAT_SHRINK) {
+ scale = (compact->o_scale_a * compact->o_ycoord + compact->o_scale_b) / 256;
+ spriteX += (FROM_LE_16(frameHead->offsetX) * scale) / 256;
+ spriteY += (FROM_LE_16(frameHead->offsetY) * scale) / 256;
+ } else {
+ scale = 256;
+ spriteX += FROM_LE_16(frameHead->offsetX);
+ spriteY += FROM_LE_16(frameHead->offsetY);
+ }
+ if (scale > 512)
+ debug(1, "compact %d is oversized: scale = %d", id, scale);
+
+ uint8 *tonyBuf = NULL;
+ if (frameHead->runTimeComp[3] == '7') { // RLE7 encoded?
+ decompressRLE7(sprData, FROM_LE_32(frameHead->compSize), _rleBuffer);
+ sprData = _rleBuffer;
+ } else if (frameHead->runTimeComp[3] == '0') { // RLE0 encoded?
+ decompressRLE0(sprData, FROM_LE_32(frameHead->compSize), _rleBuffer, FROM_LE_16(frameHead->width));
+ sprData = _rleBuffer;
+ } else if (frameHead->runTimeComp[1] == 'I') { // new type
+ tonyBuf = (uint8*)malloc(FROM_LE_16(frameHead->width) * FROM_LE_16(frameHead->height));
+ decompressTony(sprData, FROM_LE_32(frameHead->compSize), tonyBuf);
+ sprData = tonyBuf;
+ }
+
+ uint16 sprSizeX, sprSizeY;
+ if (compact->o_status & STAT_SHRINK) {
+ sprSizeX = (scale * FROM_LE_16(frameHead->width)) / 256;
+ sprSizeY = (scale * FROM_LE_16(frameHead->height)) / 256;
+ fastShrink(sprData, FROM_LE_16(frameHead->width), FROM_LE_16(frameHead->height), scale, _shrinkBuffer);
+ sprData = _shrinkBuffer;
+ } else {
+ sprSizeX = FROM_LE_16(frameHead->width);
+ sprSizeY = FROM_LE_16(frameHead->height);
+ }
+ if (!(compact->o_status & STAT_OVERRIDE)) {
+ //mouse size linked to exact size & coordinates of sprite box - shrink friendly
+ if ((frameHead->offsetX) || (frameHead->offsetY)) {
+ //for megas the mouse area is reduced to account for sprite not
+ //filling the box size is reduced to 1/2 width, 4/5 height
+ compact->o_mouse_x1 = spriteX + sprSizeX / 4;
+ compact->o_mouse_x2 = spriteX + (3 * sprSizeX) / 4;
+ compact->o_mouse_y1 = spriteY + sprSizeY / 10;
+ compact->o_mouse_y2 = spriteY + (9 * sprSizeY) / 10;
+ } else {
+ compact->o_mouse_x1 = spriteX;
+ compact->o_mouse_x2 = spriteX + sprSizeX;
+ compact->o_mouse_y1 = spriteY;
+ compact->o_mouse_y2 = spriteY + sprSizeY;
+ }
+ }
+ uint16 sprPitch = sprSizeX;
+ uint16 incr;
+ spriteClipAndSet(&spriteX, &spriteY, &sprSizeX, &sprSizeY, &incr);
+ if ((sprSizeX > 0) && (sprSizeY > 0)) {
+ drawSprite(sprData + incr, spriteX, spriteY, sprSizeX, sprSizeY, sprPitch);
+ if (!(compact->o_status&STAT_FORE))
+ verticalMask(spriteX, spriteY, sprSizeX, sprSizeY);
+ }
+ if (compact->o_type != TYPE_TEXT)
+ _resMan->resClose(compact->o_resource);
+ if (tonyBuf)
+ free(tonyBuf);
+}
+
+void SwordScreen::verticalMask(uint16 x, uint16 y, uint16 bWidth, uint16 bHeight) {
+ if (_roomDefTable[_currentScreen].totalLayers <= 1)
+ return;
+ bWidth = (bWidth + (SCRNGRID_X - 1)) / SCRNGRID_X;
+ bHeight = (bHeight + (SCRNGRID_Y - 1)) / SCRNGRID_Y;
+
+ if (x & (SCRNGRID_X - 1))
+ bWidth++;
+ if (y & (SCRNGRID_Y - 1))
+ bHeight++;
+
+ x /= SCRNGRID_X;
+ y /= SCRNGRID_Y;
+ if (x + bWidth > _gridSizeX)
+ bWidth = _gridSizeX - x;
+ if (y + bHeight > _gridSizeY)
+ bHeight = _gridSizeY - y;
+
+ for (uint16 blkx = 0; blkx < bWidth; blkx++) {
+ for (uint8 z = 1; z < _roomDefTable[_currentScreen].totalLayers; z++) { // current layer
+ uint16 *grid = _layerGrid[z - 1] + x + blkx + y * _gridSizeX;
+ for (uint16 blky = 0; blky < bHeight; blky++) {
+ if (*grid) {
+ uint8 *blkData = _layerBlocks[z] + (READ_LE_UINT16(grid) - 1) * 128;
+ blitBlockClear(x + blkx, y + blky, blkData);
+ }
+ grid += _gridSizeX;
+ }
+ }
+ }
+}
+
+void SwordScreen::blitBlockClear(uint16 x, uint16 y, uint8 *data) {
+ uint8 *dest = _screenBuf + (y * SCRNGRID_Y) * _scrnSizeX + (x * SCRNGRID_X);
+ for (uint8 cnty = 0; cnty < SCRNGRID_Y; cnty++) {
+ for (uint8 cntx = 0; cntx < SCRNGRID_X; cntx++)
+ if (data[cntx])
+ dest[cntx] = data[cntx];
+ data += SCRNGRID_X;
+ dest += _scrnSizeX;
+ }
+}
+
+void SwordScreen::renderParallax(uint8 *data) {
+ ParallaxHeader *header = (ParallaxHeader*)data;
+ assert((FROM_LE_16(header->sizeX) >= SCREEN_WIDTH) && (FROM_LE_16(header->sizeY) >= SCREEN_DEPTH));
+ double scrlfx = FROM_LE_16(header->sizeX) / ((double)_scrnSizeX );
+ double scrlfy = FROM_LE_16(header->sizeY) / ((double)_scrnSizeY );
+ uint16 scrlX = (uint16)(SwordLogic::_scriptVars[SCROLL_OFFSET_X] * scrlfx);
+ uint16 scrlY = (uint16)(SwordLogic::_scriptVars[SCROLL_OFFSET_Y] * scrlfy);
+
+ for (uint16 cnty = 0; cnty < SCREEN_DEPTH; cnty++) {
+ uint8 *src = data + READ_LE_UINT32(header->lineIndexes + cnty + scrlY);
+ uint8 *dest = _screenBuf + SwordLogic::_scriptVars[SCROLL_OFFSET_X] + cnty * _scrnSizeX;
+ uint16 remain = scrlX;
+ uint16 xPos = 0;
+ bool copyFirst = false;
+ while (remain) { // skip past the first part of the parallax to get to the right scrolling position
+ uint8 doSkip = *src++;
+ if (doSkip <= remain)
+ remain -= doSkip;
+ else {
+ xPos = doSkip - remain;
+ dest += xPos;
+ remain = 0;
+ }
+ if (remain) {
+ uint8 doCopy = *src++;
+ if (doCopy <= remain) {
+ remain -= doCopy;
+ src += doCopy;
+ } else {
+ uint16 remCopy = doCopy - remain;
+ memcpy(dest, src + remain, remCopy);
+ dest += remCopy;
+ src += doCopy;
+ xPos = remCopy;
+ remain = 0;
+ }
+ } else
+ copyFirst = true;
+ }
+ while (xPos < SCREEN_WIDTH) {
+ if (!copyFirst) {
+ if (uint8 skip = *src++) {
+ dest += skip;
+ xPos += skip;
+ }
+ } else
+ copyFirst = false;
+ if (xPos < SCREEN_WIDTH) {
+ if (uint8 doCopy = *src++) {
+ if (xPos + doCopy > SCREEN_WIDTH)
+ doCopy = SCREEN_WIDTH - xPos;
+ memcpy(dest, src, doCopy);
+ dest += doCopy;
+ xPos += doCopy;
+ src += doCopy;
+ }
+ }
+ }
+ }
+}
+
+void SwordScreen::drawSprite(uint8 *sprData, uint16 sprX, uint16 sprY, uint16 sprWidth, uint16 sprHeight, uint16 sprPitch) {
+ uint8 *dest = _screenBuf + (sprY * _scrnSizeX) + sprX;
+ for (uint16 cnty = 0; cnty < sprHeight; cnty++) {
+ for (uint16 cntx = 0; cntx < sprWidth; cntx++)
+ if (sprData[cntx])
+ dest[cntx] = sprData[cntx];
+ sprData += sprPitch;
+ dest += _scrnSizeX;
+ }
+}
+
+// nearest neighbor filter:
+void SwordScreen::fastShrink(uint8 *src, uint32 width, uint32 height, uint32 scale, uint8 *dest) {
+ uint32 resHeight = (height * scale) >> 8;
+ uint32 resWidth = (width * scale) >> 8;
+ uint32 step = 0x10000 / scale;
+ uint8 columnTab[160];
+ uint32 res = step >> 1;
+ for (uint16 cnt = 0; cnt < resWidth; cnt++) {
+ columnTab[cnt] = (uint8)(res >> 8);
+ res += step;
+ }
+
+ uint32 newRow = step >> 1;
+ uint32 oldRow = 0;
+
+ uint8 *destPos = dest;
+ for (uint16 lnCnt = 0; lnCnt < resHeight; lnCnt++) {
+ while (oldRow < (newRow >> 8)) {
+ oldRow++;
+ src += width;
+ }
+ for (uint16 colCnt = 0; colCnt < resWidth; colCnt++) {
+ *destPos++ = src[columnTab[colCnt]];
+ }
+ newRow += step;
+ }
+ // scaled, now stipple shadows if there are any
+ for (uint16 lnCnt = 0; lnCnt < resHeight; lnCnt++) {
+ uint16 xCnt = lnCnt & 1;
+ destPos = dest + lnCnt * resWidth + (lnCnt & 1);
+ while (xCnt < resWidth) {
+ if (*destPos == 200)
+ *destPos = 0;
+ destPos += 2;
+ xCnt += 2;
+ }
+ }
+}
+
+void SwordScreen::addToGraphicList(uint8 listId, uint32 objId) {
+ if (listId == 0) {
+ _foreList[_foreLength++] = objId;
+ if (_foreLength > MAX_FORE)
+ error("foreList exceeded!");
+ }
+ if (listId == 1) {
+ BsObject *cpt = _objMan->fetchObject(objId);
+ _sortList[_sortLength].id = objId;
+ _sortList[_sortLength].y = cpt->o_anim_y; // gives feet coords if boxed mega, otherwise top of sprite box
+ if (!(cpt->o_status & STAT_SHRINK)) { // not a boxed mega using shrinking
+ Header *frameRaw = (Header*)_resMan->openFetchRes(cpt->o_resource);
+ FrameHeader *frameHead = _resMan->fetchFrame(frameRaw, cpt->o_frame);
+ _sortList[_sortLength].y += frameHead->height - 1; // now pointing to base of sprite
+ _resMan->resClose(cpt->o_resource);
+ }
+ _sortLength++;
+ if (_sortLength > MAX_SORT)
+ error("sortList exceeded!");
+ }
+ if (listId == 2) {
+ _backList[_backLength++] = objId;
+ if (_backLength > MAX_BACK)
+ error("backList exceeded!");
+ }
+}
+
+void SwordScreen::decompressTony(uint8 *src, uint32 compSize, uint8 *dest) {
+ uint8 *endOfData = src + compSize;
+ while (src < endOfData) {
+ uint8 numFlat = *src++;
+ if (numFlat) {
+ memset(dest, *src, numFlat);
+ src++;
+ dest += numFlat;
+ }
+ if (src < endOfData) {
+ uint8 numNoFlat = *src++;
+ memcpy(dest, src, numNoFlat);
+ src += numNoFlat;
+ dest += numNoFlat;
+ }
+ }
+}
+
+void SwordScreen::decompressRLE7(uint8 *src, uint32 compSize, uint8 *dest) {
+ uint8 *compBufEnd = src + compSize;
+ while (src < compBufEnd) {
+ uint8 code = *src++;
+ if ((code > 127) || (code == 0))
+ *dest++ = code;
+ else {
+ code++;
+ memset(dest, *src++, code);
+ dest += code;
+ }
+ }
+}
+
+void SwordScreen::decompressRLE0(uint8 *src, uint32 compSize, uint8 *dest, uint16 width) {
+ // these are saved vertically flipped. *SIIIIIIIGH*
+ uint8 *srcBufEnd = src + compSize;
+ uint16 destX = width-1;
+ while (src < srcBufEnd) {
+ uint8 color = *src++;
+ if (color) {
+ dest[destX] = color;
+ if (destX == 0) {
+ destX = width-1;
+ dest += width;
+ } else
+ destX--;
+ } else {
+ uint8 skip = *src++;
+ for (uint16 cnt = 0; cnt < skip; cnt++) {
+ dest[destX] = 0;
+ if (destX == 0) {
+ destX = width-1;
+ dest += width;
+ } else
+ destX--;
+ }
+ }
+ }
+}
+
+void SwordScreen::fadePalette(void) {
+ if (_fadingStep == 16)
+ memcpy(_currentPalette, _targetPalette, 256 * 4);
+ else
+ for (uint16 cnt = 0; cnt < 256 * 4; cnt++)
+ _currentPalette[cnt] = (_targetPalette[cnt] * _fadingStep) >> 4;
+
+ _fadingStep += _fadingDirection;
+ if (_fadingStep == 17)
+ _fadingStep = 0;
+}
+
+void SwordScreen::fnSetParallax(uint32 screen, uint32 resId) {
+ if ((screen == _currentScreen) && (resId != _roomDefTable[screen].parallax[0]))
+ warning("fnSetParallax: setting parallax for current room!!");
+ _roomDefTable[screen].parallax[0] = resId;
+}
+
+void SwordScreen::spriteClipAndSet(uint16 *pSprX, uint16 *pSprY, uint16 *pSprWidth, uint16 *pSprHeight, uint16 *incr) {
+ int16 sprX = *pSprX - SCREEN_LEFT_EDGE;
+ int16 sprY = *pSprY - SCREEN_TOP_EDGE;
+ int16 sprW = *pSprWidth;
+ int16 sprH = *pSprHeight;
+
+ if (sprY < 0) {
+ *incr = (uint16)((-sprY) * sprW);
+ sprH += sprY;
+ sprY = 0;
+ } else
+ *incr = 0;
+ if (sprX < 0) {
+ *incr -= sprX;
+ sprW += sprX;
+ sprX = 0;
+ }
+
+ if (sprY + sprH > _scrnSizeY)
+ sprH = _scrnSizeY - sprY;
+ if (sprX + sprW > _scrnSizeX)
+ sprW = _scrnSizeX - sprX;
+
+ if (sprH < 0)
+ *pSprHeight = 0;
+ else
+ *pSprHeight = (uint16)sprH;
+ if (sprW < 0)
+ *pSprWidth = 0;
+ else
+ *pSprWidth = (uint16)sprW;
+ *pSprX = (uint16)sprX;
+ *pSprY = (uint16)sprY;
+
+ uint16 gridH = (*pSprHeight + SCRNGRID_Y - 1) / SCRNGRID_Y;
+ uint16 gridW = (*pSprWidth + SCRNGRID_X - 1) / SCRNGRID_X;
+ uint16 gridX = sprX / SCRNGRID_X;
+ uint16 gridY = sprY / SCRNGRID_Y;
+ uint8 *gridBuf = _screenGrid + gridX + gridY * _gridSizeX;
+ if (gridX + gridW > _gridSizeX)
+ gridW = _gridSizeX - gridX;
+ if (gridY + gridH > _gridSizeY)
+ gridH = _gridSizeY - gridY;
+
+ for (uint16 cnty = 0; cnty < gridH; cnty++) {
+ for (uint16 cntx = 0; cntx < gridW; cntx++)
+ gridBuf[cntx] |= 0x80;
+ gridBuf += _gridSizeX;
+ }
+}
+
+void SwordScreen::showFrame(uint16 x, uint16 y, uint32 resId, uint32 frameNo) {
+ warning("stub: SwordScreen::showFrame(%d, %d, %d, %d)", x, y, resId, frameNo);
+}
+
+void SwordScreen::fnFlash(uint8 color) {
+ warning("stub: SwordScreen::fnFlash(%d)", color);
+}
+
+// ------------------- router debugging code --------------------------------
+
+void SwordScreen::vline(uint16 x, uint16 y1, uint16 y2) {
+ for (uint16 cnty = y1; cnty <= y2; cnty++)
+ _screenBuf[x + _scrnSizeX * cnty] = 0;
+}
+
+void SwordScreen::hline(uint16 x1, uint16 x2, uint16 y) {
+ for (uint16 cntx = x1; cntx <= x2; cntx++)
+ _screenBuf[y * _scrnSizeX + cntx] = 0;
+}
+
+void SwordScreen::bsubline_1(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddx = abs(x2 - x1);
+ ddy = abs(y2 - y1) << 1;
+ e = ddx - ddy;
+ ddx <<= 1;
+
+ if (x1 > x2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (x = x1, y = y1; x <= x2; x++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ y++;
+ e += ddx - ddy;
+ } else {
+ e -= ddy;
+ }
+ }
+}
+
+void SwordScreen::bsubline_2(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddx = abs(x2 - x1) << 1;
+ ddy = abs(y2 - y1);
+ e = ddy - ddx;
+ ddy <<= 1;
+
+ if (y1 > y2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (y = y1, x = x1; y <= y2; y++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ x++;
+ e += ddy - ddx;
+ } else {
+ e -= ddx;
+ }
+ }
+}
+
+void SwordScreen::bsubline_3(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddx = abs(x1 - x2) << 1;
+ ddy = abs(y2 - y1);
+ e = ddy - ddx;
+ ddy <<= 1;
+
+ if (y1 > y2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (y = y1, x = x1; y <= y2; y++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ x--;
+ e += ddy - ddx;
+ } else {
+ e -= ddx;
+ }
+ }
+}
+
+void SwordScreen::bsubline_4(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ int x, y, ddx, ddy, e;
+ ddy = abs(y2 - y1) << 1;
+ ddx = abs(x1 - x2);
+ e = ddx - ddy;
+ ddx <<= 1;
+
+ if (x1 > x2) {
+ uint16 tmp;
+ tmp = x1; x1 = x2; x2 = tmp;
+ tmp = y1; y1 = y2; y2 = tmp;
+ }
+
+ for (x = x1, y = y1; x <= x2; x++) {
+ _screenBuf[y * _scrnSizeX + x] = 0;
+ if (e < 0) {
+ y--;
+ e += ddx - ddy;
+ } else {
+ e -= ddy;
+ }
+ }
+}
+
+void SwordScreen::drawLine(uint16 x1, uint16 y1, uint16 x2, uint16 y2) {
+ if ((x1 == x2) && (y1 == y2)) {
+ _screenBuf[x1 + y1 * _scrnSizeX] = 0;
+ }
+ if (x1 == x2) {
+ vline(x1, min(y1, y2), max(y1, y2));
+ return;
+ }
+
+ if (y1 == y2) {
+ hline(min(x1, x2), max(x1, x2), y1);
+ return;
+ }
+
+ float k = float(y2 - y1) / float(x2 - x1);
+
+ if ((k >= 0) && (k <= 1)) {
+ bsubline_1(x1, y1, x2, y2);
+ } else if (k > 1) {
+ bsubline_2(x1, y1, x2, y2);
+ } else if ((k < 0) && (k >= -1)) {
+ bsubline_4(x1, y1, x2, y2);
+ } else {
+ bsubline_3(x1, y1, x2, y2);
+ }
+
+}
+
+void SwordScreen::showBarsAndNodes(SwordRouter *router) {
+ for (uint16 cnt = 0; cnt < router->_nBars; cnt++) {
+ drawLine(router->_bars[cnt].x1 - 128, router->_bars[cnt].y1 - 128, router->_bars[cnt].x2 - 128, router->_bars[cnt].y2 - 128);
+ }
+ if (!router->_nNodes)
+ return;
+ for (uint16 cnt = 0; cnt <= router->_nNodes; cnt++) {
+ uint16 y = router->_node[cnt].y - 128;
+ uint16 x = router->_node[cnt].x - 128;
+ vline(x, y - 2, y + 2);
+ hline(x - 2, x + 2, y);
+ if (router->_node[cnt].dist != 9999) {
+ drawLine(x, y, router->_node[router->_node[cnt].prev].x - 128, router->_node[router->_node[cnt].prev].y - 128);
+ }
+ }
+}
+