diff options
author | Nicola Mettifogo | 2008-12-06 04:51:04 +0000 |
---|---|---|
committer | Nicola Mettifogo | 2008-12-06 04:51:04 +0000 |
commit | 7681461b16ee09eb8620fc99d8cd9445c263594b (patch) | |
tree | 960f1af1edde885e2243214cf447b401e5b38615 | |
parent | 7a4984304721eb91ca5c3349871be1cab228451d (diff) | |
download | scummvm-rg350-7681461b16ee09eb8620fc99d8cd9445c263594b.tar.gz scummvm-rg350-7681461b16ee09eb8620fc99d8cd9445c263594b.tar.bz2 scummvm-rg350-7681461b16ee09eb8620fc99d8cd9445c263594b.zip |
Implemented horizontal scrolling for BRA, by using a back buffer. Dialogues in scrollable locations are a bit messed up for the moment.
svn-id: r35253
-rw-r--r-- | engines/parallaction/exec_br.cpp | 1 | ||||
-rw-r--r-- | engines/parallaction/gfxbase.cpp | 4 | ||||
-rw-r--r-- | engines/parallaction/graphics.cpp | 137 | ||||
-rw-r--r-- | engines/parallaction/graphics.h | 16 | ||||
-rw-r--r-- | engines/parallaction/input.cpp | 45 | ||||
-rw-r--r-- | engines/parallaction/input.h | 8 | ||||
-rw-r--r-- | engines/parallaction/inventory.cpp | 4 | ||||
-rw-r--r-- | engines/parallaction/parallaction.cpp | 28 | ||||
-rw-r--r-- | engines/parallaction/walk.cpp | 14 |
9 files changed, 187 insertions, 70 deletions
diff --git a/engines/parallaction/exec_br.cpp b/engines/parallaction/exec_br.cpp index bcc4a5b532..cc07578859 100644 --- a/engines/parallaction/exec_br.cpp +++ b/engines/parallaction/exec_br.cpp @@ -262,7 +262,6 @@ DECLARE_COMMAND_OPCODE(zeta) { DECLARE_COMMAND_OPCODE(scroll) { warning("Parallaction_br::cmdOp_scroll not yet implemented"); - _vm->_gfx->setVar("scroll_x", _ctxt.cmd->u._rvalue ); } diff --git a/engines/parallaction/gfxbase.cpp b/engines/parallaction/gfxbase.cpp index 8eb9753edd..5ed5c7a109 100644 --- a/engines/parallaction/gfxbase.cpp +++ b/engines/parallaction/gfxbase.cpp @@ -173,10 +173,8 @@ void Gfx::drawGfxObject(GfxObj *obj, Graphics::Surface &surf, bool scene) { Common::Rect rect; byte *data; - uint scrollX = (scene) ? -_varScrollX : 0; - obj->getRect(obj->frame, rect); - rect.translate(obj->x + scrollX, obj->y); + rect.translate(obj->x, obj->y); data = obj->getData(obj->frame); if (obj->getSize(obj->frame) == obj->getRawSize(obj->frame)) { diff --git a/engines/parallaction/graphics.cpp b/engines/parallaction/graphics.cpp index 7de5e882cb..74a936bb77 100644 --- a/engines/parallaction/graphics.cpp +++ b/engines/parallaction/graphics.cpp @@ -328,7 +328,7 @@ void Gfx::drawInventory() { _vm->_inventoryRenderer->getRect(r); byte *data = _vm->_inventoryRenderer->getData(); - _vm->_system->copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); + copyRectToScreen(data, r.width(), r.left, r.top, r.width(), r.height()); } void Gfx::drawItems() { @@ -336,11 +336,11 @@ void Gfx::drawItems() { return; } - Graphics::Surface *surf = _vm->_system->lockScreen(); + Graphics::Surface *surf = lockScreen(); for (uint i = 0; i < _numItems; i++) { drawGfxObject(_items[i].data, *surf, false); } - _vm->_system->unlockScreen(); + unlockScreen(); } void Gfx::drawBalloons() { @@ -348,15 +348,11 @@ void Gfx::drawBalloons() { return; } - Graphics::Surface *surf = _vm->_system->lockScreen(); + Graphics::Surface *surf = lockScreen(); for (uint i = 0; i < _balloons.size(); i++) { drawGfxObject(_balloons[i], *surf, false); } - _vm->_system->unlockScreen(); -} - -void Gfx::clearScreen() { - _vm->_system->clearScreen(); + unlockScreen(); } void Gfx::beginFrame() { @@ -390,18 +386,12 @@ void Gfx::beginFrame() { } _varDrawPathZones = getVar("draw_path_zones"); - if (_varDrawPathZones == 1 && _vm->getGameType() != GType_BRA) { + if (_varDrawPathZones == 1 && _gameType != GType_BRA) { setVar("draw_path_zones", 0); _varDrawPathZones = 0; warning("Path zones are supported only in Big Red Adventure"); } - if (_skipBackground || (_vm->_screenWidth >= _backgroundInfo->width)) { - _varScrollX = 0; - } else { - _varScrollX = getVar("scroll_x"); - } - _varAnimRenderMode = getRenderMode("anim_render_mode"); _varMiscRenderMode = getRenderMode("misc_render_mode"); } @@ -418,31 +408,85 @@ int32 Gfx::getRenderMode(const char *type) { } +void Gfx::copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h) { + if (_doubleBuffering) { + byte *dst = (byte*)_backBuffer.getBasePtr(x, y); + for (int i = 0; i < h; i++) { + memcpy(dst, buf, w); + buf += pitch; + dst += _backBuffer.pitch; + } + } else { + _vm->_system->copyRectToScreen(buf, pitch, x, y, w, h); + } +} + +void Gfx::clearScreen() { + if (_doubleBuffering) { + if (_backBuffer.pixels) { + Common::Rect r(_backBuffer.w, _backBuffer.h); + _backBuffer.fillRect(r, 0); + } + } else { + _vm->_system->clearScreen(); + } +} + +Graphics::Surface *Gfx::lockScreen() { + if (_doubleBuffering) { + return &_backBuffer; + } + return _vm->_system->lockScreen(); +} + +void Gfx::unlockScreen() { + if (_doubleBuffering) { + return; + } + _vm->_system->unlockScreen(); +} + +void Gfx::updateScreenIntern() { + if (_doubleBuffering) { + byte *data = (byte*)_backBuffer.getBasePtr(_scrollPos, 0); + _vm->_system->copyRectToScreen(data, _backBuffer.pitch, 0, 0, _vm->_screenWidth, _vm->_screenHeight); + } + + _vm->_system->updateScreen(); +} + +int Gfx::getScrollPos() { + return _scrollPos; +} + +void Gfx::setScrollPos(int scrollX) { + _scrollPos = CLIP(scrollX, _minScroll, _maxScroll); +} void Gfx::updateScreen() { if (!_skipBackground) { // background may not cover the whole screen, so adjust bulk update size - uint w = MIN(_vm->_screenWidth, (int32)_backgroundInfo->width); - uint h = MIN(_vm->_screenHeight, (int32)_backgroundInfo->height); + uint w = _backgroundInfo->width; + uint h = _backgroundInfo->height; byte *backgroundData = 0; uint16 backgroundPitch = 0; switch (_varBackgroundMode) { case 1: - backgroundData = (byte*)_backgroundInfo->bg.getBasePtr(_varScrollX, 0); + backgroundData = (byte*)_backgroundInfo->bg.getBasePtr(0, 0); backgroundPitch = _backgroundInfo->bg.pitch; break; case 2: - backgroundData = (byte*)_bitmapMask.getBasePtr(_varScrollX, 0); + backgroundData = (byte*)_bitmapMask.getBasePtr(0, 0); backgroundPitch = _bitmapMask.pitch; break; } - _vm->_system->copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); + copyRectToScreen(backgroundData, backgroundPitch, _backgroundInfo->x, _backgroundInfo->y, w, h); } if (_varDrawPathZones == 1) { - Graphics::Surface *surf = _vm->_system->lockScreen(); + Graphics::Surface *surf = lockScreen(); ZoneList::iterator b = _vm->_location._zones.begin(); ZoneList::iterator e = _vm->_location._zones.end(); for (; b != e; b++) { @@ -451,13 +495,13 @@ void Gfx::updateScreen() { surf->frameRect(Common::Rect(z->getX(), z->getY(), z->getX() + z->width(), z->getY() + z->height()), 2); } } - _vm->_system->unlockScreen(); + unlockScreen(); } _varRenderMode = _varAnimRenderMode; // TODO: transform objects coordinates to be drawn with scrolling - Graphics::Surface *surf = _vm->_system->lockScreen(); + Graphics::Surface *surf = lockScreen(); drawGfxObjects(*surf); if (_halfbrite) { @@ -481,7 +525,7 @@ void Gfx::updateScreen() { } } - _vm->_system->unlockScreen(); + unlockScreen(); _varRenderMode = _varMiscRenderMode; @@ -490,8 +534,7 @@ void Gfx::updateScreen() { drawBalloons(); drawLabels(); - _vm->_system->updateScreen(); - return; + updateScreenIntern(); } @@ -613,11 +656,11 @@ void Gfx::updateFloatingLabel() { Common::Rect r; _labels[_floatingLabel]->getRect(0, r); - if (_vm->getGameType() == GType_Nippon) { + if (_gameType == GType_Nippon) { FloatingLabelTraits traits_NS = { Common::Point(16 - r.width()/2, 34), Common::Point(8 - r.width()/2, 21), - 0, 0, _vm->_screenWidth - r.width(), 190 + 0, 0, _backgroundInfo->width - r.width(), 190 }; traits = &traits_NS; } else { @@ -625,13 +668,13 @@ void Gfx::updateFloatingLabel() { FloatingLabelTraits traits_BR = { Common::Point(34 - r.width()/2, 70), Common::Point(16 - r.width()/2, 37), - 0, 0, _vm->_screenWidth - r.width(), 390 + 0, 0, _backgroundInfo->width - r.width(), 390 }; traits = &traits_BR; } Common::Point cursor; - _vm->_input->getCursorPos(cursor); + _vm->_input->getAbsoluteCursorPos(cursor); Common::Point offset = (_vm->_input->_activeItem._id) ? traits->_offsetWithItem : traits->_offsetWithoutItem; _labels[_floatingLabel]->x = CLIP(cursor.x + offset.x, traits->_minX, traits->_maxX); @@ -684,7 +727,7 @@ void Gfx::showLabel(uint id, int16 x, int16 y) { _labels[id]->getRect(0, r); if (x == CENTER_LABEL_HORIZONTAL) { - x = CLIP<int16>((_vm->_screenWidth - r.width()) / 2, 0, _vm->_screenWidth/2); + x = CLIP<int16>((_backgroundInfo->width - r.width()) / 2, 0, _backgroundInfo->width/2); } if (y == CENTER_LABEL_VERTICAL) { @@ -715,13 +758,11 @@ void Gfx::drawLabels() { updateFloatingLabel(); - Graphics::Surface* surf = _vm->_system->lockScreen(); - + Graphics::Surface* surf = lockScreen(); for (uint i = 0; i < _labels.size(); i++) { drawGfxObject(_labels[i], *surf, false); } - - _vm->_system->unlockScreen(); + unlockScreen(); } @@ -747,9 +788,12 @@ void Gfx::grabBackground(const Common::Rect& r, Graphics::Surface &dst) { Gfx::Gfx(Parallaction* vm) : - _vm(vm), _disk(vm->_disk) { + _vm(vm), _disk(vm->_disk), _scrollPos(0), _minScroll(0), _maxScroll(0) { + + _gameType = _vm->getGameType(); + _doubleBuffering = _gameType != GType_Nippon; - initGraphics(_vm->_screenWidth, _vm->_screenHeight, _vm->getGameType() == GType_BRA); + initGraphics(_vm->_screenWidth, _vm->_screenHeight, _gameType == GType_BRA); setPalette(_palette); @@ -771,15 +815,12 @@ Gfx::Gfx(Parallaction* vm) : registerVar("background_mode", 1); _varBackgroundMode = 1; - registerVar("scroll_x", 0); - _varScrollX = 0; - registerVar("anim_render_mode", 1); registerVar("misc_render_mode", 1); registerVar("draw_path_zones", 0); - if ((_vm->getGameType() == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) { + if ((_gameType == GType_BRA) && (_vm->getPlatform() == Common::kPlatformPC)) { // this loads the backup palette needed by the PC version of BRA (see setBackground()). BackgroundInfo paletteInfo; _disk->loadSlide(paletteInfo, "pointer"); @@ -870,6 +911,18 @@ void Gfx::setBackground(uint type, BackgroundInfo *info) { _backgroundInfo->ranges[i]._flags = 0; // disable palette cycling for slides setPalette(_backgroundInfo->palette); } + + if (_gameType == GType_BRA) { + int width = CLIP(info->width, _vm->_screenWidth, info->width); + int height = CLIP(info->height, _vm->_screenHeight, info->height); + + if (width != _backBuffer.w || height != _backBuffer.h) { + _backBuffer.create(width, height, 1); + } + } + + _minScroll = 0; + _maxScroll = _backgroundInfo->width - _vm->_screenWidth; } } // namespace Parallaction diff --git a/engines/parallaction/graphics.h b/engines/parallaction/graphics.h index 90cc5f55b7..662bfc6b59 100644 --- a/engines/parallaction/graphics.h +++ b/engines/parallaction/graphics.h @@ -572,7 +572,6 @@ protected: // frame data stored in programmable variables int32 _varBackgroundMode; // 1 = normal, 2 = only mask - int32 _varScrollX; int32 _varAnimRenderMode; // 1 = normal, 2 = flat int32 _varMiscRenderMode; // 1 = normal, 2 = flat int32 _varRenderMode; @@ -580,6 +579,18 @@ protected: Graphics::Surface _bitmapMask; int32 getRenderMode(const char *type); + Graphics::Surface *lockScreen(); + void unlockScreen(); + void updateScreenIntern(); + + bool _doubleBuffering; + int _gameType; + Graphics::Surface _backBuffer; + void copyRectToScreen(const byte *buf, int pitch, int x, int y, int w, int h); + + int _scrollPos; + int _minScroll, _maxScroll; + public: struct Item { @@ -605,6 +616,9 @@ public: void copyRect(const Common::Rect &r, Graphics::Surface &src, Graphics::Surface &dst); + int getScrollPos(); + void setScrollPos(int scrollX); + // low level text and patches void drawText(Font *font, Graphics::Surface* surf, uint16 x, uint16 y, const char *text, byte color); diff --git a/engines/parallaction/input.cpp b/engines/parallaction/input.cpp index 67f2d9cfce..8690c4b433 100644 --- a/engines/parallaction/input.cpp +++ b/engines/parallaction/input.cpp @@ -89,6 +89,7 @@ Input::~Input() { // caller code, i.e. adding condition checks. // void Input::readInput() { + bool updateMousePos = false; Common::Event e; @@ -97,6 +98,7 @@ void Input::readInput() { Common::EventManager *eventMan = _vm->_system->getEventManager(); while (eventMan->pollEvent(e)) { + updateMousePos = true; switch (e.type) { case Common::EVENT_KEYDOWN: @@ -105,30 +107,24 @@ void Input::readInput() { if (e.kbd.flags == Common::KBD_CTRL && e.kbd.keycode == 'd') _vm->_debugger->attach(); + + updateMousePos = false; break; case Common::EVENT_LBUTTONDOWN: _mouseButtons = kMouseLeftDown; - _mousePos = e.mouse; break; case Common::EVENT_LBUTTONUP: _mouseButtons = kMouseLeftUp; - _mousePos = e.mouse; break; case Common::EVENT_RBUTTONDOWN: _mouseButtons = kMouseRightDown; - _mousePos = e.mouse; break; case Common::EVENT_RBUTTONUP: _mouseButtons = kMouseRightUp; - _mousePos = e.mouse; - break; - - case Common::EVENT_MOUSEMOVE: - _mousePos = e.mouse; break; case Common::EVENT_RTL: @@ -142,6 +138,10 @@ void Input::readInput() { } + if (updateMousePos) { + setCursorPos(e.mouse); + } + if (_vm->_debugger->isAttached()) _vm->_debugger->onFrame(); @@ -282,12 +282,13 @@ bool Input::translateGameInput() { return true; } + Common::Point mousePos; + getAbsoluteCursorPos(mousePos); // test if mouse is hovering on an interactive zone for the currently selected inventory item - ZonePtr z = _vm->hitZone(_activeItem._id, _mousePos.x, _mousePos.y); - Common::Point dest(_mousePos); + ZonePtr z = _vm->hitZone(_activeItem._id, mousePos.x, mousePos.y); if (((_mouseButtons == kMouseLeftUp) && (_activeItem._id == 0) && ((_engineFlags & kEngineWalking) == 0)) && ((!z) || ((z->_type & 0xFFFF) != kZoneCommand))) { - walkTo(dest); + walkTo(mousePos); return true; } @@ -307,10 +308,10 @@ bool Input::translateGameInput() { _delayedActionZone = z; _hasDelayedAction = true; if (z->_moveTo.y != 0) { - dest = z->_moveTo; + mousePos = z->_moveTo; } - walkTo(dest); + walkTo(mousePos); } _vm->beep(); @@ -323,7 +324,9 @@ bool Input::translateGameInput() { void Input::enterInventoryMode() { - bool hitCharacter = _vm->hitZone(kZoneYou, _mousePos.x, _mousePos.y); + Common::Point mousePos; + getAbsoluteCursorPos(mousePos); + bool hitCharacter = _vm->hitZone(kZoneYou, mousePos.x, mousePos.y); if (hitCharacter) { if (_activeItem._id != 0) { @@ -345,8 +348,10 @@ void Input::enterInventoryMode() { void Input::exitInventoryMode() { // right up hides inventory + Common::Point mousePos; + getAbsoluteCursorPos(mousePos); - int pos = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + int pos = _vm->getHoverInventoryItem(mousePos.x, mousePos.y); _vm->highlightInventoryItem(-1); // disable if ((_engineFlags & kEngineDragging)) { @@ -384,7 +389,10 @@ bool Input::updateInventoryInput() { return true; } - int16 _si = _vm->getHoverInventoryItem(_mousePos.x, _mousePos.y); + Common::Point mousePos; + getAbsoluteCursorPos(mousePos); + + int16 _si = _vm->getHoverInventoryItem(mousePos.x, mousePos.y); if (_si != _transCurrentHoverItem) { _transCurrentHoverItem = _si; _vm->highlightInventoryItem(_si); // enable @@ -418,6 +426,11 @@ bool Input::isMouseEnabled() { return (_mouseState == MOUSE_ENABLED_SHOW) || (_mouseState == MOUSE_ENABLED_HIDE); } +void Input::getAbsoluteCursorPos(Common::Point& p) const { + p = _mousePos; + p.x += _vm->_gfx->getScrollPos(); +} + void Input::initCursors() { diff --git a/engines/parallaction/input.h b/engines/parallaction/input.h index e7d20c0d2e..e26f4d71fd 100644 --- a/engines/parallaction/input.h +++ b/engines/parallaction/input.h @@ -98,10 +98,16 @@ public: Input(Parallaction *vm); virtual ~Input(); - void getCursorPos(Common::Point& p) { + void getAbsoluteCursorPos(Common::Point& p) const; + + void getCursorPos(Common::Point& p) const { p = _mousePos; } + void setCursorPos(const Common::Point& p) { + _mousePos = p; + } + int _inputMode; InventoryItem _activeItem; diff --git a/engines/parallaction/inventory.cpp b/engines/parallaction/inventory.cpp index 7b92974205..e1ba5bce34 100644 --- a/engines/parallaction/inventory.cpp +++ b/engines/parallaction/inventory.cpp @@ -180,9 +180,9 @@ void InventoryRenderer::showInventory() { uint16 lines = getNumLines(); Common::Point p; - _vm->_input->getCursorPos(p); + _vm->_input->getAbsoluteCursorPos(p); - _pos.x = CLIP((int)(p.x - (_props->_width / 2)), 0, (int)(_vm->_screenWidth - _props->_width)); + _pos.x = CLIP((int)(p.x - (_props->_width / 2)), 0, (int)(_vm->_gfx->_backgroundInfo->width - _props->_width)); _pos.y = CLIP((int)(p.y - 2 - (lines * _props->_itemHeight)), 0, (int)(_vm->_screenHeight - lines * _props->_itemHeight)); refresh(); diff --git a/engines/parallaction/parallaction.cpp b/engines/parallaction/parallaction.cpp index 7623025d7f..4a5436b4a6 100644 --- a/engines/parallaction/parallaction.cpp +++ b/engines/parallaction/parallaction.cpp @@ -143,12 +143,40 @@ Common::Error Parallaction::init() { return Common::kNoError; } +bool canScroll() { + return (_vm->_gfx->_backgroundInfo->width > _vm->_screenWidth); +} + void Parallaction::updateView() { if ((_engineFlags & kEnginePauseJobs) && (_input->_inputMode != Input::kInputModeInventory)) { return; } + #define SCROLL_BAND_WIDTH 120 + + if (canScroll()) { + int scrollX = _gfx->getScrollPos(); + + Common::Point foot; + _char.getFoot(foot); + + foot.x -= scrollX; + //foot.y -= ... + + int min = SCROLL_BAND_WIDTH; + int max = _vm->_screenWidth - SCROLL_BAND_WIDTH; + + if (foot.x < min) { + scrollX = CLIP(scrollX - (min - foot.x), 0, scrollX); + } else + if (foot.x > max) { + scrollX = CLIP(scrollX + (foot.x - max), scrollX, _vm->_gfx->_backgroundInfo->width - _vm->_screenWidth); + } + + _gfx->setScrollPos(scrollX); + } + _gfx->animatePalette(); _gfx->updateScreen(); _vm->_system->delayMillis(30); diff --git a/engines/parallaction/walk.cpp b/engines/parallaction/walk.cpp index 5fd67d26dc..145dfae17a 100644 --- a/engines/parallaction/walk.cpp +++ b/engines/parallaction/walk.cpp @@ -549,13 +549,19 @@ void PathWalker_BR::walk() { _step++; _step %= 8; + + int maxX = _vm->_gfx->_backgroundInfo->width; + int minX = 0; + int maxY = _vm->_gfx->_backgroundInfo->height; + int minY = 0; + int walkFrame = _step; _dirFrame = 0; Common::Point newpos(_startFoot), delta; Common::Point p(*_ch->_walkPath.begin()); - if (_startFoot.y < p.y && _startFoot.y < 400 && IS_PATH_CLEAR(_startFoot.x, yStep + _startFoot.y)) { + if (_startFoot.y < p.y && _startFoot.y < maxY && IS_PATH_CLEAR(_startFoot.x, yStep + _startFoot.y)) { if (yStep + _startFoot.y <= p.y) { _fieldC = 1; delta.y = yStep; @@ -566,7 +572,7 @@ void PathWalker_BR::walk() { } _dirFrame = 9; } else - if (_startFoot.y > p.y && _startFoot.y > 0 && IS_PATH_CLEAR(_startFoot.x, _startFoot.y - yStep)) { + if (_startFoot.y > p.y && _startFoot.y > minY && IS_PATH_CLEAR(_startFoot.x, _startFoot.y - yStep)) { if (_startFoot.y - yStep >= p.y) { _fieldC = 1; delta.y = yStep; @@ -578,7 +584,7 @@ void PathWalker_BR::walk() { _dirFrame = 0; } - if (_startFoot.x < p.x && _startFoot.x < 640 && IS_PATH_CLEAR(_startFoot.x + xStep, _startFoot.y)) { + if (_startFoot.x < p.x && _startFoot.x < maxX && IS_PATH_CLEAR(_startFoot.x + xStep, _startFoot.y)) { if (_startFoot.x + xStep <= p.x) { _fieldC = 1; delta.x = xStep; @@ -591,7 +597,7 @@ void PathWalker_BR::walk() { _dirFrame = 18; // right } } else - if (_startFoot.x > p.x && _startFoot.x > 0 && IS_PATH_CLEAR(_startFoot.x - xStep, _startFoot.y)) { + if (_startFoot.x > p.x && _startFoot.x > minX && IS_PATH_CLEAR(_startFoot.x - xStep, _startFoot.y)) { if (_startFoot.x - xStep >= p.x) { _fieldC = 1; delta.x = xStep; |