diff options
author | Robert Göffringmann | 2003-12-16 02:10:15 +0000 |
---|---|---|
committer | Robert Göffringmann | 2003-12-16 02:10:15 +0000 |
commit | 189e08bc7985fc5664e7ab95195bbade07488f48 (patch) | |
tree | f12049da0a8e600bcdd425e4c314c50b5c9922f7 /sword1/screen.cpp | |
parent | c3a9b2df6789055325b7fea6dd591cea1d419682 (diff) | |
download | scummvm-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.cpp | 884 |
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); + } + } +} + |