From d99aa0f12634bed7b5101b4b5a64f50ee744961b Mon Sep 17 00:00:00 2001 From: Filippos Karapetis Date: Tue, 5 Jan 2010 01:37:57 +0000 Subject: More renaming svn-id: r47009 --- engines/sci/console.cpp | 2 +- engines/sci/engine/kernel.cpp | 2 +- engines/sci/engine/kevent.cpp | 2 +- engines/sci/engine/kgraphics.cpp | 22 +- engines/sci/engine/kmenu.cpp | 2 +- engines/sci/engine/kmovement.cpp | 2 +- engines/sci/engine/state.h | 2 +- engines/sci/event.cpp | 2 +- engines/sci/graphics/animate.cpp | 559 ++++++++++++++++++ engines/sci/graphics/animate.h | 99 ++++ engines/sci/graphics/controls.cpp | 231 ++++++++ engines/sci/graphics/controls.h | 60 ++ engines/sci/graphics/cursor.cpp | 227 +++++++ engines/sci/graphics/cursor.h | 84 +++ engines/sci/graphics/font.cpp | 101 ++++ engines/sci/graphics/font.h | 63 ++ engines/sci/graphics/gfx.cpp | 536 +++++++++++++++++ engines/sci/graphics/gfx.h | 130 +++++ engines/sci/graphics/gui.cpp | 86 +-- engines/sci/graphics/gui.h | 42 +- engines/sci/graphics/gui_animate.cpp | 559 ------------------ engines/sci/graphics/gui_animate.h | 99 ---- engines/sci/graphics/gui_controls.cpp | 231 -------- engines/sci/graphics/gui_controls.h | 60 -- engines/sci/graphics/gui_cursor.cpp | 227 ------- engines/sci/graphics/gui_cursor.h | 84 --- engines/sci/graphics/gui_font.cpp | 101 ---- engines/sci/graphics/gui_font.h | 63 -- engines/sci/graphics/gui_gfx.cpp | 536 ----------------- engines/sci/graphics/gui_gfx.h | 130 ----- engines/sci/graphics/gui_helpers.h | 130 ----- engines/sci/graphics/gui_menu.cpp | 648 -------------------- engines/sci/graphics/gui_menu.h | 123 ---- engines/sci/graphics/gui_palette.cpp | 380 ------------ engines/sci/graphics/gui_palette.h | 66 --- engines/sci/graphics/gui_picture.cpp | 973 ------------------------------- engines/sci/graphics/gui_picture.h | 82 --- engines/sci/graphics/gui_portrait.cpp | 66 --- engines/sci/graphics/gui_portrait.h | 49 -- engines/sci/graphics/gui_screen.cpp | 513 ---------------- engines/sci/graphics/gui_screen.h | 130 ----- engines/sci/graphics/gui_text.cpp | 410 ------------- engines/sci/graphics/gui_text.h | 83 --- engines/sci/graphics/gui_transitions.cpp | 576 ------------------ engines/sci/graphics/gui_transitions.h | 106 ---- engines/sci/graphics/gui_view.cpp | 513 ---------------- engines/sci/graphics/gui_view.h | 91 --- engines/sci/graphics/gui_windowmgr.cpp | 286 --------- engines/sci/graphics/gui_windowmgr.h | 71 --- engines/sci/graphics/helpers.h | 130 +++++ engines/sci/graphics/menu.cpp | 648 ++++++++++++++++++++ engines/sci/graphics/menu.h | 123 ++++ engines/sci/graphics/palette.cpp | 380 ++++++++++++ engines/sci/graphics/palette.h | 66 +++ engines/sci/graphics/picture.cpp | 973 +++++++++++++++++++++++++++++++ engines/sci/graphics/picture.h | 82 +++ engines/sci/graphics/portrait.cpp | 66 +++ engines/sci/graphics/portrait.h | 49 ++ engines/sci/graphics/screen.cpp | 513 ++++++++++++++++ engines/sci/graphics/screen.h | 130 +++++ engines/sci/graphics/text.cpp | 410 +++++++++++++ engines/sci/graphics/text.h | 83 +++ engines/sci/graphics/transitions.cpp | 576 ++++++++++++++++++ engines/sci/graphics/transitions.h | 106 ++++ engines/sci/graphics/view.cpp | 513 ++++++++++++++++ engines/sci/graphics/view.h | 91 +++ engines/sci/graphics/windowmgr.cpp | 286 +++++++++ engines/sci/graphics/windowmgr.h | 71 +++ engines/sci/module.mk | 28 +- engines/sci/resource.h | 2 +- engines/sci/sci.cpp | 12 +- 71 files changed, 7489 insertions(+), 7489 deletions(-) create mode 100644 engines/sci/graphics/animate.cpp create mode 100644 engines/sci/graphics/animate.h create mode 100644 engines/sci/graphics/controls.cpp create mode 100644 engines/sci/graphics/controls.h create mode 100644 engines/sci/graphics/cursor.cpp create mode 100644 engines/sci/graphics/cursor.h create mode 100644 engines/sci/graphics/font.cpp create mode 100644 engines/sci/graphics/font.h create mode 100644 engines/sci/graphics/gfx.cpp create mode 100644 engines/sci/graphics/gfx.h delete mode 100644 engines/sci/graphics/gui_animate.cpp delete mode 100644 engines/sci/graphics/gui_animate.h delete mode 100644 engines/sci/graphics/gui_controls.cpp delete mode 100644 engines/sci/graphics/gui_controls.h delete mode 100644 engines/sci/graphics/gui_cursor.cpp delete mode 100644 engines/sci/graphics/gui_cursor.h delete mode 100644 engines/sci/graphics/gui_font.cpp delete mode 100644 engines/sci/graphics/gui_font.h delete mode 100644 engines/sci/graphics/gui_gfx.cpp delete mode 100644 engines/sci/graphics/gui_gfx.h delete mode 100644 engines/sci/graphics/gui_helpers.h delete mode 100644 engines/sci/graphics/gui_menu.cpp delete mode 100644 engines/sci/graphics/gui_menu.h delete mode 100644 engines/sci/graphics/gui_palette.cpp delete mode 100644 engines/sci/graphics/gui_palette.h delete mode 100644 engines/sci/graphics/gui_picture.cpp delete mode 100644 engines/sci/graphics/gui_picture.h delete mode 100644 engines/sci/graphics/gui_portrait.cpp delete mode 100644 engines/sci/graphics/gui_portrait.h delete mode 100644 engines/sci/graphics/gui_screen.cpp delete mode 100644 engines/sci/graphics/gui_screen.h delete mode 100644 engines/sci/graphics/gui_text.cpp delete mode 100644 engines/sci/graphics/gui_text.h delete mode 100644 engines/sci/graphics/gui_transitions.cpp delete mode 100644 engines/sci/graphics/gui_transitions.h delete mode 100644 engines/sci/graphics/gui_view.cpp delete mode 100644 engines/sci/graphics/gui_view.h delete mode 100644 engines/sci/graphics/gui_windowmgr.cpp delete mode 100644 engines/sci/graphics/gui_windowmgr.h create mode 100644 engines/sci/graphics/helpers.h create mode 100644 engines/sci/graphics/menu.cpp create mode 100644 engines/sci/graphics/menu.h create mode 100644 engines/sci/graphics/palette.cpp create mode 100644 engines/sci/graphics/palette.h create mode 100644 engines/sci/graphics/picture.cpp create mode 100644 engines/sci/graphics/picture.h create mode 100644 engines/sci/graphics/portrait.cpp create mode 100644 engines/sci/graphics/portrait.h create mode 100644 engines/sci/graphics/screen.cpp create mode 100644 engines/sci/graphics/screen.h create mode 100644 engines/sci/graphics/text.cpp create mode 100644 engines/sci/graphics/text.h create mode 100644 engines/sci/graphics/transitions.cpp create mode 100644 engines/sci/graphics/transitions.h create mode 100644 engines/sci/graphics/view.cpp create mode 100644 engines/sci/graphics/view.h create mode 100644 engines/sci/graphics/windowmgr.cpp create mode 100644 engines/sci/graphics/windowmgr.h (limited to 'engines/sci') diff --git a/engines/sci/console.cpp b/engines/sci/console.cpp index dfd9a03e62..d29ea7126e 100644 --- a/engines/sci/console.cpp +++ b/engines/sci/console.cpp @@ -44,7 +44,7 @@ #include "sci/sound/softseq/mididriver.h" #include "sci/vocabulary.h" #include "sci/graphics/gui.h" -#include "sci/graphics/gui_cursor.h" +#include "sci/graphics/cursor.h" #include "graphics/video/avi_decoder.h" #include "sci/video/seq_decoder.h" diff --git a/engines/sci/engine/kernel.cpp b/engines/sci/engine/kernel.cpp index 43451728f4..0b80871ce4 100644 --- a/engines/sci/engine/kernel.cpp +++ b/engines/sci/engine/kernel.cpp @@ -709,7 +709,7 @@ void kernel_sleep(SciEvent *event, uint32 msecs ) { while (true) { // let backend process events and update the screen event->get(SCI_EVENT_PEEK); - // TODO: we need to call SciGuiCursor::refreshPosition() before each screen update to limit the mouse cursor position + // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position g_system->updateScreen(); time = g_system->getMillis(); if (time + 10 < wakeup_time) { diff --git a/engines/sci/engine/kevent.cpp b/engines/sci/engine/kevent.cpp index 8d04bc7354..e9ac8a3e45 100644 --- a/engines/sci/engine/kevent.cpp +++ b/engines/sci/engine/kevent.cpp @@ -30,7 +30,7 @@ #include "sci/debug.h" // for g_debug_simulated_key #include "sci/event.h" #include "sci/graphics/gui.h" -#include "sci/graphics/gui_cursor.h" +#include "sci/graphics/cursor.h" namespace Sci { diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 3021aa6f5b..4cc0086de3 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -34,10 +34,10 @@ #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/graphics/gui.h" -#include "sci/graphics/gui_animate.h" -#include "sci/graphics/gui_cursor.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_view.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/cursor.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/view.h" namespace Sci { @@ -701,12 +701,12 @@ void _k_GenericDrawControl(EngineState *s, reg_t controlObject, bool hilite) { reg_t textReference = GET_SEL32(s->_segMan, controlObject, text); Common::String text; Common::Rect rect; - GuiTextAlignment alignment; + TextAlignment alignment; int16 mode, maxChars, cursorPos, upperPos, listCount, i; int16 upperOffset, cursorOffset; GuiResourceId viewId; - GuiViewLoopNo loopNo; - GuiViewCelNo celNo; + LoopNo loopNo; + CelNo celNo; reg_t listSeeker; Common::String *listStrings = NULL; const char **listEntries = NULL; @@ -842,8 +842,8 @@ reg_t kEditControl(EngineState *s, int argc, reg_t *argv) { reg_t kAddToPic(EngineState *s, int argc, reg_t *argv) { GuiResourceId viewId; - GuiViewLoopNo loopNo; - GuiViewCelNo celNo; + LoopNo loopNo; + CelNo celNo; int16 leftPos, topPos, priority, control; switch (argc) { @@ -909,8 +909,8 @@ reg_t kSetPort(EngineState *s, int argc, reg_t *argv) { reg_t kDrawCel(EngineState *s, int argc, reg_t *argv) { GuiResourceId viewId = argv[0].toSint16(); - GuiViewLoopNo loopNo = argv[1].toSint16(); - GuiViewCelNo celNo = argv[2].toSint16(); + LoopNo loopNo = argv[1].toSint16(); + CelNo celNo = argv[2].toSint16(); uint16 x = argv[3].toUint16(); uint16 y = argv[4].toUint16(); int16 priority = (argc > 5) ? argv[5].toSint16() : -1; diff --git a/engines/sci/engine/kmenu.cpp b/engines/sci/engine/kmenu.cpp index d426b9f8a1..90cd2adbe9 100644 --- a/engines/sci/engine/kmenu.cpp +++ b/engines/sci/engine/kmenu.cpp @@ -28,7 +28,7 @@ #include "sci/engine/state.h" #include "sci/engine/kernel.h" #include "sci/graphics/gui.h" -#include "sci/graphics/gui_cursor.h" +#include "sci/graphics/cursor.h" namespace Sci { diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp index da667037c6..1aef51a276 100644 --- a/engines/sci/engine/kmovement.cpp +++ b/engines/sci/engine/kmovement.cpp @@ -27,7 +27,7 @@ #include "sci/resource.h" #include "sci/engine/state.h" #include "sci/engine/kernel.h" -#include "sci/graphics/gui_animate.h" +#include "sci/graphics/animate.h" namespace Sci { diff --git a/engines/sci/engine/state.h b/engines/sci/engine/state.h index da5ccdf73e..26e4893b27 100644 --- a/engines/sci/engine/state.h +++ b/engines/sci/engine/state.h @@ -52,7 +52,7 @@ namespace Sci { class SciEvent; class Menubar; class SciGui; -class SciGuiCursor; +class Cursor; class MessageState; class SoundCommandParser; diff --git a/engines/sci/event.cpp b/engines/sci/event.cpp index b25c0bd486..455066a812 100644 --- a/engines/sci/event.cpp +++ b/engines/sci/event.cpp @@ -329,7 +329,7 @@ sciEvent SciEvent::get(unsigned int mask) { //sci_event_t error_event = { SCI_EVT_ERROR, 0, 0, 0 }; sciEvent event = { 0, 0, 0, 0 }; - // TODO: we need to call SciGuiCursor::refreshPosition() before each screen update to limit the mouse cursor position + // TODO: we need to call Cursor::refreshPosition() before each screen update to limit the mouse cursor position // Update the screen here, since it's called very often g_system->updateScreen(); diff --git a/engines/sci/graphics/animate.cpp b/engines/sci/graphics/animate.cpp new file mode 100644 index 0000000000..c82fcbf10e --- /dev/null +++ b/engines/sci/graphics/animate.cpp @@ -0,0 +1,559 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/engine/vm.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/view.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/transitions.h" +#include "sci/graphics/animate.h" + +namespace Sci { + +SciGuiAnimate::SciGuiAnimate(EngineState *state, Gfx *gfx, Screen *screen, SciPalette *palette) + : _s(state), _gfx(gfx), _screen(screen), _palette(palette) { + init(); +} + +SciGuiAnimate::~SciGuiAnimate() { + free(_listData); + free(_lastCastData); +} + +void SciGuiAnimate::init() { + _listData = NULL; + _listCount = 0; + _lastCastData = NULL; + _lastCastCount = 0; + + _ignoreFastCast = false; + // fastCast object is not found in any SCI games prior SCI1 + if (getSciVersion() <= SCI_VERSION_01) + _ignoreFastCast = true; + // Also if fastCast object exists at gamestartup, we can assume that the interpreter doesnt do kAnimate aborts + // (found in larry 1) + if (!_s->_segMan->findObjectByName("fastCast").isNull()) + _ignoreFastCast = true; +} + +void SciGuiAnimate::disposeLastCast() { + _lastCastCount = 0; +} + +bool SciGuiAnimate::invoke(List *list, int argc, reg_t *argv) { + reg_t curAddress = list->first; + Node *curNode = _s->_segMan->lookupNode(curAddress); + reg_t curObject; + uint16 signal; + + while (curNode) { + curObject = curNode->value; + + if (!_ignoreFastCast) { + // Check if the game has a fastCast object set + // if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes. + reg_t global84 = _s->script_000->_localsBlock->_locals[84]; + + if (!global84.isNull()) { + if (!strcmp(_s->_segMan->getObjectName(global84), "fastCast")) + return false; + } + } + + signal = GET_SEL32V(_s->_segMan, curObject, signal); + if (!(signal & kSignalFrozen)) { + // Call .doit method of that object + invoke_selector(_s, curObject, _s->_kernel->_selectorCache.doit, kContinueOnInvalidSelector, argv, argc, 0); + // Lookup node again, since the nodetable it was in may have been reallocated + curNode = _s->_segMan->lookupNode(curAddress); + } + curAddress = curNode->succ; + curNode = _s->_segMan->lookupNode(curAddress); + } + return true; +} + +bool sortHelper(const AnimateEntry* entry1, const AnimateEntry* entry2) { + return (entry1->y == entry2->y) ? (entry1->z < entry2->z) : (entry1->y < entry2->y); +} + +void SciGuiAnimate::makeSortedList(List *list) { + reg_t curAddress = list->first; + Node *curNode = _s->_segMan->lookupNode(curAddress); + reg_t curObject; + AnimateEntry *listEntry; + int16 listNr, listCount = 0; + + // Count the list entries + while (curNode) { + listCount++; + curAddress = curNode->succ; + curNode = _s->_segMan->lookupNode(curAddress); + } + + _list.clear(); + + // No entries -> exit immediately + if (listCount == 0) + return; + + // Adjust list size, if needed + if ((_listData == NULL) || (_listCount < listCount)) { + free(_listData); + _listData = (AnimateEntry *)malloc(listCount * sizeof(AnimateEntry)); + if (!_listData) + error("Could not allocate memory for _listData"); + _listCount = listCount; + + free(_lastCastData); + _lastCastData = (AnimateEntry *)malloc(listCount * sizeof(AnimateEntry)); + if (!_lastCastData) + error("Could not allocate memory for _lastCastData"); + _lastCastCount = 0; + } + + // Fill the list + curAddress = list->first; + curNode = _s->_segMan->lookupNode(curAddress); + listEntry = _listData; + for (listNr = 0; listNr < listCount; listNr++) { + curObject = curNode->value; + listEntry->object = curObject; + + // Get data from current object + listEntry->viewId = GET_SEL32V(_s->_segMan, curObject, view); + listEntry->loopNo = GET_SEL32V(_s->_segMan, curObject, loop); + listEntry->celNo = GET_SEL32V(_s->_segMan, curObject, cel); + listEntry->paletteNo = GET_SEL32V(_s->_segMan, curObject, palette); + listEntry->x = GET_SEL32V(_s->_segMan, curObject, x); + listEntry->y = GET_SEL32V(_s->_segMan, curObject, y); + listEntry->z = GET_SEL32V(_s->_segMan, curObject, z); + listEntry->priority = GET_SEL32V(_s->_segMan, curObject, priority); + listEntry->signal = GET_SEL32V(_s->_segMan, curObject, signal); + // listEntry->celRect is filled in AnimateFill() + listEntry->showBitsFlag = false; + + _list.push_back(listEntry); + + listEntry++; + curAddress = curNode->succ; + curNode = _s->_segMan->lookupNode(curAddress); + } + + // Now sort the list according y and z (descending) + AnimateList::iterator listBegin = _list.begin(); + AnimateList::iterator listEnd = _list.end(); + + Common::sort(_list.begin(), _list.end(), sortHelper); +} + +void SciGuiAnimate::fill(byte &old_picNotValid) { + reg_t curObject; + AnimateEntry *listEntry; + uint16 signal; + View *view = NULL; + AnimateList::iterator listIterator; + AnimateList::iterator listEnd = _list.end(); + + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + + // Get the corresponding view + view = _gfx->getView(listEntry->viewId); + + // adjust loop and cel, if any of those is invalid + if (listEntry->loopNo >= view->getLoopCount()) { + listEntry->loopNo = 0; + PUT_SEL32V(_s->_segMan, curObject, loop, listEntry->loopNo); + } + if (listEntry->celNo >= view->getCelCount(listEntry->loopNo)) { + listEntry->celNo = 0; + PUT_SEL32V(_s->_segMan, curObject, cel, listEntry->celNo); + } + + // Create rect according to coordinates and given cel + view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect); + PUT_SEL32V(_s->_segMan, curObject, nsLeft, listEntry->celRect.left); + PUT_SEL32V(_s->_segMan, curObject, nsTop, listEntry->celRect.top); + PUT_SEL32V(_s->_segMan, curObject, nsRight, listEntry->celRect.right); + PUT_SEL32V(_s->_segMan, curObject, nsBottom, listEntry->celRect.bottom); + + signal = listEntry->signal; + + // Calculate current priority according to y-coordinate + if (!(signal & kSignalFixedPriority)) { + listEntry->priority = _gfx->CoordinateToPriority(listEntry->y); + PUT_SEL32V(_s->_segMan, curObject, priority, listEntry->priority); + } + + if (signal & kSignalNoUpdate) { + if (signal & (kSignalForceUpdate | kSignalViewUpdated) + || (signal & kSignalHidden && !(signal & kSignalRemoveView)) + || (!(signal & kSignalHidden) && signal & kSignalRemoveView) + || (signal & kSignalAlwaysUpdate)) + old_picNotValid++; + signal &= 0xFFFF ^ kSignalStopUpdate; + } else { + if (signal & kSignalStopUpdate || signal & kSignalAlwaysUpdate) + old_picNotValid++; + signal &= 0xFFFF ^ kSignalForceUpdate; + } + listEntry->signal = signal; + + listIterator++; + } +} + +void SciGuiAnimate::update() { + reg_t curObject; + AnimateEntry *listEntry; + uint16 signal; + reg_t bitsHandle; + Common::Rect rect; + AnimateList::iterator listIterator; + AnimateList::iterator listBegin = _list.begin(); + AnimateList::iterator listEnd = _list.end(); + + // Remove all no-update cels, if requested + listIterator = _list.reverse_begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + if (signal & kSignalNoUpdate) { + if (!(signal & kSignalRemoveView)) { + bitsHandle = GET_SEL32(_s->_segMan, curObject, underBits); + if (_screen->_picNotValid != 1) { + _gfx->BitsRestore(bitsHandle); + listEntry->showBitsFlag = true; + } else { + _gfx->BitsFree(bitsHandle); + } + PUT_SEL32V(_s->_segMan, curObject, underBits, 0); + } + signal &= 0xFFFF ^ kSignalForceUpdate; + signal &= signal & kSignalViewUpdated ? 0xFFFF ^ (kSignalViewUpdated | kSignalNoUpdate) : 0xFFFF; + } else if (signal & kSignalStopUpdate) { + signal = (signal & (0xFFFF ^ kSignalStopUpdate)) | kSignalNoUpdate; + } + listEntry->signal = signal; + listIterator--; + } + + // Draw always-update cels + listIterator = listBegin; + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + if (signal & kSignalAlwaysUpdate) { + // draw corresponding cel + _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); + listEntry->showBitsFlag = true; + + signal &= 0xFFFF ^ (kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate); + if ((signal & kSignalIgnoreActor) == 0) { + rect = listEntry->celRect; + rect.top = CLIP(_gfx->PriorityToCoordinate(listEntry->priority) - 1, rect.top, rect.bottom - 1); + _gfx->FillRect(rect, SCI_SCREEN_MASK_CONTROL, 0, 0, 15); + } + listEntry->signal = signal; + } + listIterator++; + } + + // Saving background for all NoUpdate-cels + listIterator = listBegin; + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + if (signal & kSignalNoUpdate) { + if (signal & kSignalHidden) { + signal |= kSignalRemoveView; + } else { + signal &= 0xFFFF ^ kSignalRemoveView; + if (signal & kSignalIgnoreActor) + bitsHandle = _gfx->BitsSave(listEntry->celRect, SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY); + else + bitsHandle = _gfx->BitsSave(listEntry->celRect, SCI_SCREEN_MASK_ALL); + PUT_SEL32(_s->_segMan, curObject, underBits, bitsHandle); + } + listEntry->signal = signal; + } + listIterator++; + } + + // Draw NoUpdate cels + listIterator = listBegin; + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + if (signal & kSignalNoUpdate && !(signal & kSignalHidden)) { + // draw corresponding cel + _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); + listEntry->showBitsFlag = true; + + if ((signal & kSignalIgnoreActor) == 0) { + rect = listEntry->celRect; + rect.top = CLIP(_gfx->PriorityToCoordinate(listEntry->priority) - 1, rect.top, rect.bottom - 1); + _gfx->FillRect(rect, SCI_SCREEN_MASK_CONTROL, 0, 0, 15); + } + } + listIterator++; + } +} + +void SciGuiAnimate::drawCels() { + reg_t curObject; + AnimateEntry *listEntry; + AnimateEntry *lastCastEntry = _lastCastData; + uint16 signal; + reg_t bitsHandle; + AnimateList::iterator listIterator; + AnimateList::iterator listEnd = _list.end(); + + _lastCastCount = 0; + + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) { + // Save background + bitsHandle = _gfx->BitsSave(listEntry->celRect, SCI_SCREEN_MASK_ALL); + PUT_SEL32(_s->_segMan, curObject, underBits, bitsHandle); + + // draw corresponding cel + _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); + listEntry->showBitsFlag = true; + + if (signal & kSignalRemoveView) { + signal &= 0xFFFF ^ kSignalRemoveView; + } + listEntry->signal = signal; + + // Remember that entry in lastCast + memcpy(lastCastEntry, listEntry, sizeof(AnimateEntry)); + lastCastEntry++; _lastCastCount++; + } + listIterator++; + } +} + +void SciGuiAnimate::updateScreen(byte oldPicNotValid) { + reg_t curObject; + AnimateEntry *listEntry; + uint16 signal; + AnimateList::iterator listIterator; + AnimateList::iterator listEnd = _list.end(); + Common::Rect lsRect; + Common::Rect workerRect; + + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + if (listEntry->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) || + (!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) { + lsRect.left = GET_SEL32V(_s->_segMan, curObject, lsLeft); + lsRect.top = GET_SEL32V(_s->_segMan, curObject, lsTop); + lsRect.right = GET_SEL32V(_s->_segMan, curObject, lsRight); + lsRect.bottom = GET_SEL32V(_s->_segMan, curObject, lsBottom); + + workerRect = lsRect; + workerRect.clip(listEntry->celRect); + + if (!workerRect.isEmpty()) { + workerRect = lsRect; + workerRect.extend(listEntry->celRect); + } else { + _gfx->BitsShow(lsRect); + workerRect = listEntry->celRect; + } + PUT_SEL32V(_s->_segMan, curObject, lsLeft, workerRect.left); + PUT_SEL32V(_s->_segMan, curObject, lsTop, workerRect.top); + PUT_SEL32V(_s->_segMan, curObject, lsRight, workerRect.right); + PUT_SEL32V(_s->_segMan, curObject, lsBottom, workerRect.bottom); + _gfx->BitsShow(workerRect); + + if (signal & kSignalHidden) { + listEntry->signal |= kSignalRemoveView; + } + } + + listIterator++; + } + // use this for debug purposes + // _screen->copyToScreen(); +} + +void SciGuiAnimate::restoreAndDelete(int argc, reg_t *argv) { + reg_t curObject; + AnimateEntry *listEntry; + uint16 signal; + AnimateList::iterator listIterator; + AnimateList::iterator listEnd = _list.end(); + + + // This has to be done in a separate loop. At least in sq1 some .dispose modifies FIXEDLOOP flag in signal for + // another object. In that case we would overwrite the new signal with our version of the old signal + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + signal = listEntry->signal; + + // Finally update signal + PUT_SEL32V(_s->_segMan, curObject, signal, signal); + listIterator++; + } + + listIterator = _list.reverse_begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + // We read out signal here again, this is not by accident but to ensure that we got an up-to-date signal + signal = GET_SEL32V(_s->_segMan, curObject, signal); + + if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) { + _gfx->BitsRestore(GET_SEL32(_s->_segMan, curObject, underBits)); + PUT_SEL32V(_s->_segMan, curObject, underBits, 0); + } + + if (signal & kSignalDisposeMe) { + // Call .delete_ method of that object + invoke_selector(_s, curObject, _s->_kernel->_selectorCache.delete_, kContinueOnInvalidSelector, argv, argc, 0); + } + listIterator--; + } +} + +void SciGuiAnimate::reAnimate(Common::Rect rect) { + AnimateEntry *lastCastEntry; + uint16 lastCastCount; + + if (_lastCastCount > 0) { + lastCastEntry = _lastCastData; + lastCastCount = _lastCastCount; + while (lastCastCount > 0) { + lastCastEntry->castHandle = _gfx->BitsSave(lastCastEntry->celRect, SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY); + _gfx->drawCel(lastCastEntry->viewId, lastCastEntry->loopNo, lastCastEntry->celNo, lastCastEntry->celRect, lastCastEntry->priority, lastCastEntry->paletteNo); + lastCastEntry++; lastCastCount--; + } + _gfx->BitsShow(rect); + // restoring + lastCastCount = _lastCastCount; + while (lastCastCount > 0) { + lastCastEntry--; + _gfx->BitsRestore(lastCastEntry->castHandle); + lastCastCount--; + } + } else { + _gfx->BitsShow(rect); + } + + /* + if (!_lastCast->isEmpty()) { + HEAPHANDLE hnode = _lastCast->getFirst(); + sciCast *pCast; + CResView *res; + while (hnode) { + pCast = (sciCast *)heap2Ptr(hnode); + res = (CResView *)ResMgr.ResLoad(SCI_RES_VIEW, pCast->view); + pCast->hSaved = _gfx->SaveBits(pCast->rect, 3); + res->drawCel(pCast->loop, pCast->cel, &pCast->rect, pCast->z, pCast->pal); + hnode = pCast->node.next; + } + _gfx->BitsShow(rect); + // restoring + hnode = _lastCast->getLast(); + while (hnode) { + pCast = (sciCast *)heap2Ptr(hnode); + _gfx->BitsShow(pCast->hSaved); + hnode = pCast->node.prev; + } + */ +} + +void SciGuiAnimate::addToPicDrawCels() { + reg_t curObject; + AnimateEntry *listEntry; + View *view = NULL; + AnimateList::iterator listIterator; + AnimateList::iterator listEnd = _list.end(); + + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + curObject = listEntry->object; + + if (listEntry->priority == -1) + listEntry->priority = _gfx->CoordinateToPriority(listEntry->y); + + // Get the corresponding view + view = _gfx->getView(listEntry->viewId); + + // Create rect according to coordinates and given cel + view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect); + + // draw corresponding cel + _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); + if ((listEntry->signal & kSignalIgnoreActor) == 0) { + listEntry->celRect.top = CLIP(_gfx->PriorityToCoordinate(listEntry->priority) - 1, listEntry->celRect.top, listEntry->celRect.bottom - 1); + _gfx->FillRect(listEntry->celRect, SCI_SCREEN_MASK_CONTROL, 0, 0, 15); + } + + listIterator++; + } +} + +void SciGuiAnimate::addToPicDrawView(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) { + View *view = _gfx->getView(viewId); + Common::Rect celRect; + + // Create rect according to coordinates and given cel + view->getCelRect(loopNo, celNo, leftPos, topPos, priority, &celRect); + _gfx->drawCel(view, loopNo, celNo, celRect, priority, 0); +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/animate.h b/engines/sci/graphics/animate.h new file mode 100644 index 0000000000..a71e0a769a --- /dev/null +++ b/engines/sci/graphics/animate.h @@ -0,0 +1,99 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_ANIMATE_H +#define SCI_GRAPHICS_ANIMATE_H + +#include "sci/graphics/helpers.h" + +namespace Sci { + +// Flags for the signal selector +enum ViewSignals { + kSignalStopUpdate = 0x0001, + kSignalViewUpdated = 0x0002, + kSignalNoUpdate = 0x0004, + kSignalHidden = 0x0008, + kSignalFixedPriority = 0x0010, + kSignalAlwaysUpdate = 0x0020, + kSignalForceUpdate = 0x0040, + kSignalRemoveView = 0x0080, + kSignalFrozen = 0x0100, + kSignalExtraActor = 0x0200, // unused by us, defines all actors that may be included into the background if speed to slow + kSignalHitObstacle = 0x0400, // used in the actor movement code by kDoBresen() + kSignalDoesntTurn = 0x0800, // used by _k_dirloop() to determine if an actor can turn or not + kSignalNoCycler = 0x1000, // unused by us + kSignalIgnoreHorizon = 0x2000, // unused by us, defines actor that can ignore horizon + kSignalIgnoreActor = 0x4000, + kSignalDisposeMe = 0x8000, + + kSignalStopUpdHack = 0x20000000 // View has been stop-updated (again???) - a hack used by the old GUI code only, for dynamic views +}; + +class Gfx; +class Screen; +class SciPalette; +class Transitions; +class SciGuiAnimate { +public: + SciGuiAnimate(EngineState *state, Gfx *gfx, Screen *screen, SciPalette *palette); + ~SciGuiAnimate(); + + // FIXME: Don't store EngineState + void resetEngineState(EngineState *newState) { _s = newState; } + + void disposeLastCast(); + bool invoke(List *list, int argc, reg_t *argv); + void makeSortedList(List *list); + void fill(byte &oldPicNotValid); + void update(); + void drawCels(); + void updateScreen(byte oldPicNotValid); + void restoreAndDelete(int argc, reg_t *argv); + void reAnimate(Common::Rect rect); + void addToPicDrawCels(); + void addToPicDrawView(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); + +private: + void init(); + + EngineState *_s; + Gfx *_gfx; + Screen *_screen; + SciPalette *_palette; + + uint16 _listCount; + AnimateEntry *_listData; + AnimateList _list; + + uint16 _lastCastCount; + AnimateEntry *_lastCastData; + + bool _ignoreFastCast; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/controls.cpp b/engines/sci/graphics/controls.cpp new file mode 100644 index 0000000000..ba6ded2936 --- /dev/null +++ b/engines/sci/graphics/controls.cpp @@ -0,0 +1,231 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/event.h" +#include "sci/engine/state.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/font.h" +#include "sci/graphics/text.h" +#include "sci/graphics/controls.h" + +namespace Sci { + +SciGuiControls::SciGuiControls(SegManager *segMan, Gfx *gfx, Text *text) + : _segMan(segMan), _gfx(gfx), _text(text) { + init(); +} + +SciGuiControls::~SciGuiControls() { +} + +void SciGuiControls::init() { + _texteditCursorVisible = false; +} + +const char controlListUpArrow[2] = { 0x18, 0 }; +const char controlListDownArrow[2] = { 0x19, 0 }; + +void SciGuiControls::drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 upperPos, int16 cursorPos, bool isAlias) { + Common::Rect workerRect = rect; + GuiResourceId oldFontId = _text->GetFontId(); + int16 oldPenColor = _gfx->_curPort->penClr; + uint16 fontSize = 0; + int16 i; + const char *listEntry; + int16 listEntryLen; + int16 lastYpos; + + // draw basic window + _gfx->EraseRect(workerRect); + workerRect.grow(1); + _gfx->FrameRect(workerRect); + + // draw UP/DOWN arrows + // we draw UP arrow one pixel lower than sierra did, because it looks nicer. Also the DOWN arrow has one pixel + // line inbetween as well + workerRect.top++; + _text->Box(controlListUpArrow, 0, workerRect, SCI_TEXT_ALIGNMENT_CENTER, 0); + workerRect.top = workerRect.bottom - 10; + _text->Box(controlListDownArrow, 0, workerRect, SCI_TEXT_ALIGNMENT_CENTER, 0); + + // Draw inner lines + workerRect.top = rect.top + 9; + workerRect.bottom -= 10; + _gfx->FrameRect(workerRect); + workerRect.grow(-1); + + _text->SetFont(fontId); + fontSize = _gfx->_curPort->fontHeight; + _gfx->PenColor(_gfx->_curPort->penClr); _gfx->BackColor(_gfx->_curPort->backClr); + workerRect.bottom = workerRect.top + 9; + lastYpos = rect.bottom - fontSize; + + // Write actual text + for (i = upperPos; i < count; i++) { + _gfx->EraseRect(workerRect); + listEntry = entries[i]; + if (listEntry[0]) { + _gfx->MoveTo(workerRect.left, workerRect.top); + listEntryLen = strlen(listEntry); + _text->Draw(listEntry, 0, MIN(maxChars, listEntryLen), oldFontId, oldPenColor); + if ((!isAlias) && (i == cursorPos)) { + _gfx->InvertRect(workerRect); + } + } + workerRect.translate(0, fontSize); + if (workerRect.bottom > lastYpos) + break; + } + + _text->SetFont(oldFontId); +} + +void SciGuiControls::TexteditCursorDraw(Common::Rect rect, const char *text, uint16 curPos) { + int16 textWidth, i; + if (!_texteditCursorVisible) { + textWidth = 0; + for (i = 0; i < curPos; i++) { + textWidth += _text->_font->getCharWidth(text[i]); + } + _texteditCursorRect.left = rect.left + textWidth; + _texteditCursorRect.top = rect.top; + _texteditCursorRect.bottom = _texteditCursorRect.top + _text->_font->getHeight(); + _texteditCursorRect.right = _texteditCursorRect.left + (text[curPos] == 0 ? 1 : _text->_font->getCharWidth(text[curPos])); + _gfx->InvertRect(_texteditCursorRect); + _gfx->BitsShow(_texteditCursorRect); + _texteditCursorVisible = true; + TexteditSetBlinkTime(); + } +} + +void SciGuiControls::TexteditCursorErase() { + if (_texteditCursorVisible) { + _gfx->InvertRect(_texteditCursorRect); + _gfx->BitsShow(_texteditCursorRect); + _texteditCursorVisible = false; + } + TexteditSetBlinkTime(); +} + +void SciGuiControls::TexteditSetBlinkTime() { + _texteditBlinkTime = g_system->getMillis() + (30 * 1000 / 60); +} + +void SciGuiControls::TexteditChange(reg_t controlObject, reg_t eventObject) { + uint16 cursorPos = GET_SEL32V(_segMan, controlObject, cursor); + uint16 maxChars = GET_SEL32V(_segMan, controlObject, max); + reg_t textReference = GET_SEL32(_segMan, controlObject, text); + Common::String text; + uint16 textSize, eventType, eventKey; + bool textChanged = false; + Common::Rect rect; + + if (textReference.isNull()) + error("kEditControl called on object that doesnt have a text reference"); + text = _segMan->getString(textReference); + + if (!eventObject.isNull()) { + textSize = text.size(); + eventType = GET_SEL32V(_segMan, eventObject, type); + + switch (eventType) { + case SCI_EVENT_MOUSE_PRESS: + // TODO: Implement mouse support for cursor change + break; + case SCI_EVENT_KEYBOARD: + eventKey = GET_SEL32V(_segMan, eventObject, message); + switch (eventKey) { + case SCI_KEY_BACKSPACE: + if (cursorPos > 0) { + cursorPos--; text.deleteChar(cursorPos); + textChanged = true; + } + break; + case SCI_KEY_DELETE: + text.deleteChar(cursorPos); + textChanged = true; + break; + case SCI_KEY_HOME: // HOME + cursorPos = 0; textChanged = true; + break; + case SCI_KEY_END: // END + cursorPos = textSize; textChanged = true; + break; + case SCI_KEY_LEFT: // LEFT + if (cursorPos > 0) { + cursorPos--; textChanged = true; + } + break; + case SCI_KEY_RIGHT: // RIGHT + if (cursorPos + 1 <= textSize) { + cursorPos++; textChanged = true; + } + break; + default: + if (eventKey > 31 && eventKey < 256 && textSize < maxChars) { + // insert pressed character + // we check, if there is space left for this character + + text.insertChar(eventKey, cursorPos++); + textChanged = true; + } + break; + } + break; + } + } + + if (textChanged) { + GuiResourceId oldFontId = _text->GetFontId(); + GuiResourceId fontId = GET_SEL32V(_segMan, controlObject, font); + rect = Common::Rect(GET_SEL32V(_segMan, controlObject, nsLeft), GET_SEL32V(_segMan, controlObject, nsTop), + GET_SEL32V(_segMan, controlObject, nsRight), GET_SEL32V(_segMan, controlObject, nsBottom)); + TexteditCursorErase(); + _gfx->EraseRect(rect); + _text->Box(text.c_str(), 0, rect, SCI_TEXT_ALIGNMENT_LEFT, fontId); + _gfx->BitsShow(rect); + _text->SetFont(fontId); + TexteditCursorDraw(rect, text.c_str(), cursorPos); + _text->SetFont(oldFontId); + // Write back string + _segMan->strcpy(textReference, text.c_str()); + } else { + if (g_system->getMillis() >= _texteditBlinkTime) { + _gfx->InvertRect(_texteditCursorRect); + _gfx->BitsShow(_texteditCursorRect); + _texteditCursorVisible = !_texteditCursorVisible; + TexteditSetBlinkTime(); + } + } + + PUT_SEL32V(_segMan, controlObject, cursor, cursorPos); +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/controls.h b/engines/sci/graphics/controls.h new file mode 100644 index 0000000000..1d0b9e1ac6 --- /dev/null +++ b/engines/sci/graphics/controls.h @@ -0,0 +1,60 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_CONTROLS_H +#define SCI_GRAPHICS_CONTROLS_H + +namespace Sci { + +class Gfx; +class Font; +class Text; +class SciGuiControls { +public: + SciGuiControls(SegManager *segMan, Gfx *gfx, Text *text); + ~SciGuiControls(); + + void drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 upperPos, int16 cursorPos, bool isAlias); + void TexteditCursorDraw(Common::Rect rect, const char *text, uint16 curPos); + void TexteditCursorErase(); + void TexteditChange(reg_t controlObject, reg_t eventObject); + +private: + void init(); + void TexteditSetBlinkTime(); + + SegManager *_segMan; + Gfx *_gfx; + Text *_text; + + // Textedit-Control related + Common::Rect _texteditCursorRect; + bool _texteditCursorVisible; + uint32 _texteditBlinkTime; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp new file mode 100644 index 0000000000..4682fd42a6 --- /dev/null +++ b/engines/sci/graphics/cursor.cpp @@ -0,0 +1,227 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 "graphics/cursorman.h" +#include "common/util.h" +#include "common/events.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/view.h" +#include "sci/graphics/cursor.h" + +namespace Sci { + +Cursor::Cursor(ResourceManager *resMan, SciPalette *palette, Screen *screen) + : _resMan(resMan), _palette(palette), _screen(screen) { + + _upscaledHires = _screen->getUpscaledHires(); + // center mouse cursor + setPosition(Common::Point(_screen->_displayWidth / 2, _screen->_displayHeight / 2)); + setMoveZone(Common::Rect(0, 0, _screen->_displayWidth, _screen->_displayHeight)); + + _isVisible = true; +} + +Cursor::~Cursor() { + purgeCache(); +} + +void Cursor::show() { + CursorMan.showMouse(true); + _isVisible = true; +} + +void Cursor::hide() { + CursorMan.showMouse(false); + _isVisible = false; +} + +bool Cursor::isVisible() { + return _isVisible; +} + +void Cursor::purgeCache() { + for (CursorCache::iterator iter = _cachedCursors.begin(); iter != _cachedCursors.end(); ++iter) { + delete iter->_value; + iter->_value = 0; + } + + _cachedCursors.clear(); +} + +void Cursor::setShape(GuiResourceId resourceId) { + Resource *resource; + byte *resourceData; + Common::Point hotspot = Common::Point(0, 0); + byte colorMapping[4]; + int16 x, y; + byte color; + int16 maskA, maskB; + byte *pOut; + byte *rawBitmap = new byte[SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH]; + + if (resourceId == -1) { + // no resourceId given, so we actually hide the cursor + hide(); + delete[] rawBitmap; + return; + } + + // Load cursor resource... + resource = _resMan->findResource(ResourceId(kResourceTypeCursor, resourceId), false); + if (!resource) + error("cursor resource %d not found", resourceId); + if (resource->size != SCI_CURSOR_SCI0_RESOURCESIZE) + error("cursor resource %d has invalid size", resourceId); + + resourceData = resource->data; + // hotspot is specified for SCI1 cursors + hotspot.x = READ_LE_UINT16(resourceData); + hotspot.y = READ_LE_UINT16(resourceData + 2); + // bit 0 of resourceData[3] is set on _colorWhite; // White is also hardcoded + colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; + colorMapping[3] = _palette->matchColor(&_palette->_sysPalette, 170, 170, 170); // Grey + + // Seek to actual data + resourceData += 4; + + pOut = rawBitmap; + for (y = 0; y < SCI_CURSOR_SCI0_HEIGHTWIDTH; y++) { + maskA = READ_LE_UINT16(resourceData + (y << 1)); + maskB = READ_LE_UINT16(resourceData + 32 + (y << 1)); + + for (x = 0; x < SCI_CURSOR_SCI0_HEIGHTWIDTH; x++) { + color = (((maskA << x) & 0x8000) | (((maskB << x) >> 1) & 0x4000)) >> 14; + *pOut++ = colorMapping[color]; + } + } + + CursorMan.replaceCursor(rawBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); + CursorMan.showMouse(true); + + delete[] rawBitmap; +} + +void Cursor::setView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot) { + if (_cachedCursors.size() >= MAX_CACHED_CURSORS) + purgeCache(); + + if (!_cachedCursors.contains(viewNum)) + _cachedCursors[viewNum] = new View(_resMan, _screen, _palette, viewNum); + + View *cursorView = _cachedCursors[viewNum]; + + CelInfo *celInfo = cursorView->getCelInfo(loopNum, celNum); + int16 width = celInfo->width; + int16 height = celInfo->height; + byte clearKey = celInfo->clearKey; + Common::Point *cursorHotspot = hotspot; + if (!cursorHotspot) + // Compute hotspot from xoffset/yoffset + cursorHotspot = new Common::Point((celInfo->width >> 1) - celInfo->displaceX, celInfo->height - celInfo->displaceY - 1); + + // Eco Quest 1 uses a 1x1 transparent cursor to hide the cursor from the user. Some scalers don't seem to support this + if (width < 2 || height < 2) { + hide(); + delete cursorHotspot; + return; + } + + byte *cursorBitmap = cursorView->getBitmap(loopNum, celNum); + + if (_upscaledHires) { + // Scale cursor by 2x + width *= 2; + height *= 2; + cursorHotspot->x *= 2; + cursorHotspot->y *= 2; + cursorBitmap = new byte[width * height]; + _screen->scale2x(celInfo->rawBitmap, cursorBitmap, celInfo->width, celInfo->height); + } + + CursorMan.replaceCursor(cursorBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey); + + if (_upscaledHires) + delete[] cursorBitmap; + + show(); + + delete cursorHotspot; +} + +void Cursor::setPosition(Common::Point pos) { + if (!_upscaledHires) { + g_system->warpMouse(pos.x, pos.y); + } else { + g_system->warpMouse(pos.x * 2, pos.y * 2); + } +} + +Common::Point Cursor::getPosition() { + Common::Point mousePos = g_system->getEventManager()->getMousePos(); + + if (_upscaledHires) { + mousePos.x /= 2; + mousePos.y /= 2; + } + + return mousePos; +} + +void Cursor::refreshPosition() { + bool clipped = false; + Common::Point mousePoint = getPosition(); + + if (mousePoint.x < _moveZone.left) { + mousePoint.x = _moveZone.left; + clipped = true; + } else if (mousePoint.x >= _moveZone.right) { + mousePoint.x = _moveZone.right - 1; + clipped = true; + } + + if (mousePoint.y < _moveZone.top) { + mousePoint.y = _moveZone.top; + clipped = true; + } else if (mousePoint.y >= _moveZone.bottom) { + mousePoint.y = _moveZone.bottom - 1; + clipped = true; + } + + // FIXME: Do this only when mouse is grabbed? + if (clipped) + setPosition(mousePoint); +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/cursor.h b/engines/sci/graphics/cursor.h new file mode 100644 index 0000000000..c714faff87 --- /dev/null +++ b/engines/sci/graphics/cursor.h @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_CURSOR_H +#define SCI_GRAPHICS_CURSOR_H + +#include "common/hashmap.h" + +namespace Sci { + +#define SCI_CURSOR_SCI0_HEIGHTWIDTH 16 +#define SCI_CURSOR_SCI0_RESOURCESIZE 68 + +#define SCI_CURSOR_SCI0_TRANSPARENCYCOLOR 1 + +#define MAX_CACHED_CURSORS 10 + +class View; +class SciPalette; + +typedef Common::HashMap CursorCache; + +class Cursor { +public: + Cursor(ResourceManager *resMan, SciPalette *palette, Screen *screen); + ~Cursor(); + + void show(); + void hide(); + bool isVisible(); + void setShape(GuiResourceId resourceId); + void setView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot); + void setPosition(Common::Point pos); + Common::Point getPosition(); + void refreshPosition(); + + /** + * Limits the mouse movement to a given rectangle. + * + * @param[in] rect The rectangle + */ + void setMoveZone(Common::Rect zone) { _moveZone = zone; } + +private: + void purgeCache(); + + ResourceManager *_resMan; + Screen *_screen; + SciPalette *_palette; + + bool _upscaledHires; + + Common::Rect _moveZone; // Rectangle in which the pointer can move + + CursorCache _cachedCursors; + + bool _isVisible; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp new file mode 100644 index 0000000000..6b20899c26 --- /dev/null +++ b/engines/sci/graphics/font.cpp @@ -0,0 +1,101 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/font.h" + +namespace Sci { + +Font::Font(ResourceManager *resMan, GuiResourceId resourceId) + : _resourceId(resourceId), _resMan(resMan) { + assert(resourceId != -1); + + // Workaround: lsl1sci mixes its own internal fonts with the global + // SCI ones, so we translate them here, by removing their extra bits + if (!resMan->testResource(ResourceId(kResourceTypeFont, resourceId))) + resourceId = resourceId & 0x7ff; + + _resource = resMan->findResource(ResourceId(kResourceTypeFont, resourceId), true); + if (!_resource) { + error("font resource %d not found", resourceId); + } + _resourceData = _resource->data; + + _numChars = READ_LE_UINT16(_resourceData + 2); + _fontHeight = READ_LE_UINT16(_resourceData + 4); + _chars = new Charinfo[_numChars]; + // filling info for every char + for (int16 i = 0; i < _numChars; i++) { + _chars[i].offset = READ_LE_UINT16(_resourceData + 6 + i * 2); + _chars[i].w = _resourceData[_chars[i].offset]; + _chars[i].h = _resourceData[_chars[i].offset + 1]; + } +} + +Font::~Font() { + delete []_chars; + _resMan->unlockResource(_resource); +} + +GuiResourceId Font::getResourceId() { + return _resourceId; +} + +byte Font::getHeight() { + return _fontHeight; +} +byte Font::getCharWidth(byte chr) { + return chr < _numChars ? _chars[chr].w : 0; +} +byte Font::getCharHeight(byte chr) { + return chr < _numChars ? _chars[chr].h : 0; +} +byte *Font::getCharData(byte chr) { + return chr < _numChars ? _resourceData + _chars[chr].offset + 2 : 0; +} + +void Font::draw(Screen *screen, int16 chr, int16 top, int16 left, byte color, bool greyedOutput) { + int charWidth = MIN(getCharWidth(chr), screen->_width - left); + int charHeight = MIN(getCharHeight(chr), 200 - top); + byte b = 0, mask = 0xFF; + int y = top; + + byte *pIn = getCharData(chr); + for (int i = 0; i < charHeight; i++, y++) { + if (greyedOutput) + mask = top++ % 2 ? 0xAA : 0x55; + for (int done = 0; done < charWidth; done++) { + if ((done & 7) == 0) // fetching next data byte + b = *(pIn++) & mask; + if (b & 0x80) // if MSB is set - paint it + screen->putPixel(left + done, y, 1, color, 0, 0); + b = b << 1; + } + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h new file mode 100644 index 0000000000..102b8ac92d --- /dev/null +++ b/engines/sci/graphics/font.h @@ -0,0 +1,63 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_FONT_H +#define SCI_GRAPHICS_FONT_H + +#include "sci/graphics/helpers.h" + +namespace Sci { + +class Font { +public: + Font(ResourceManager *resMan, GuiResourceId resourceId); + ~Font(); + + GuiResourceId getResourceId(); + byte getHeight(); + byte getCharWidth(byte chr); + byte getCharHeight(byte chr); + byte *getCharData(byte chr); + void draw(Screen *screen, int16 chr, int16 top, int16 left, byte color, bool greyedOutput); + +private: + ResourceManager *_resMan; + + Resource *_resource; + GuiResourceId _resourceId; + byte *_resourceData; + + struct Charinfo { + byte w, h; + int16 offset; + }; + byte _fontHeight; + uint16 _numChars; + Charinfo *_chars; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/gfx.cpp b/engines/sci/graphics/gfx.cpp new file mode 100644 index 0000000000..be4c7d357d --- /dev/null +++ b/engines/sci/graphics/gfx.cpp @@ -0,0 +1,536 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/font.h" +#include "sci/graphics/picture.h" +#include "sci/graphics/view.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/text.h" + +namespace Sci { + +Gfx::Gfx(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, Screen *screen, SciPalette *palette) + : _resMan(resMan), _segMan(segMan), _kernel(kernel), _screen(screen), _palette(palette) { +} + +Gfx::~Gfx() { + purgeCache(); + + delete _mainPort; + delete _menuPort; +} + +void Gfx::init(Text *text) { + _text = text; + + // _mainPort is not known to windowmanager, that's okay according to sierra sci + // its not even used currently in our engine + _mainPort = new Port(0); + SetPort(_mainPort); + OpenPort(_mainPort); + + // _menuPort has actually hardcoded id 0xFFFF. Its not meant to be known to windowmanager according to sierra sci + _menuPort = new Port(0xFFFF); + OpenPort(_menuPort); + _text->SetFont(0); + _menuPort->rect = Common::Rect(0, 0, _screen->_width, _screen->_height); + _menuBarRect = Common::Rect(0, 0, _screen->_width, 9); +} + +void Gfx::purgeCache() { + for (ViewCache::iterator iter = _cachedViews.begin(); iter != _cachedViews.end(); ++iter) { + delete iter->_value; + iter->_value = 0; + } + + _cachedViews.clear(); +} + +View *Gfx::getView(GuiResourceId viewNum) { + if (_cachedViews.size() >= MAX_CACHED_VIEWS) + purgeCache(); + + if (!_cachedViews.contains(viewNum)) + _cachedViews[viewNum] = new View(_resMan, _screen, _palette, viewNum); + + return _cachedViews[viewNum]; +} + +Port *Gfx::SetPort(Port *newPort) { + Port *oldPort = _curPort; + _curPort = newPort; + return oldPort; +} + +Port *Gfx::GetPort() { + return _curPort; +} + +void Gfx::SetOrigin(int16 left, int16 top) { + _curPort->left = left; + _curPort->top = top; +} + +void Gfx::MoveTo(int16 left, int16 top) { + _curPort->curTop = top; + _curPort->curLeft = left; +} + +void Gfx::Move(int16 left, int16 top) { + _curPort->curTop += top; + _curPort->curLeft += left; +} + +void Gfx::OpenPort(Port *port) { + port->fontId = 0; + port->fontHeight = 8; + + Port *tmp = _curPort; + _curPort = port; + _text->SetFont(port->fontId); + _curPort = tmp; + + port->top = 0; + port->left = 0; + port->greyedOutput = false; + port->penClr = 0; + port->backClr = 255; + port->penMode = 0; + port->rect = _bounds; +} + +void Gfx::PenColor(int16 color) { + _curPort->penClr = color; +} + +void Gfx::BackColor(int16 color) { + _curPort->backClr = color; +} + +void Gfx::PenMode(int16 mode) { + _curPort->penMode = mode; +} + +void Gfx::TextGreyedOutput(bool state) { + _curPort->greyedOutput = state; +} + +int16 Gfx::GetPointSize() { + return _curPort->fontHeight; +} + +void Gfx::ClearScreen(byte color) { + FillRect(_curPort->rect, SCI_SCREEN_MASK_ALL, color, 0, 0); +} + +void Gfx::InvertRect(const Common::Rect &rect) { + int16 oldpenmode = _curPort->penMode; + _curPort->penMode = 2; + FillRect(rect, 1, _curPort->penClr, _curPort->backClr); + _curPort->penMode = oldpenmode; +} + +void Gfx::EraseRect(const Common::Rect &rect) { + FillRect(rect, 1, _curPort->backClr); +} + +void Gfx::PaintRect(const Common::Rect &rect) { + FillRect(rect, 1, _curPort->penClr); +} + +void Gfx::FillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack, byte bControl) { + Common::Rect r = rect; + r.clip(_curPort->rect); + if (r.isEmpty()) // nothing to fill + return; + + int16 oldPenMode = _curPort->penMode; + OffsetRect(r); + int16 x, y; + byte curVisual; + + // Doing visual first + if (drawFlags & SCI_SCREEN_MASK_VISUAL) { + if (oldPenMode == 2) { // invert mode + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + curVisual = _screen->getVisual(x, y); + if (curVisual == clrPen) { + _screen->putPixel(x, y, 1, clrBack, 0, 0); + } else if (curVisual == clrBack) { + _screen->putPixel(x, y, 1, clrPen, 0, 0); + } + } + } + } else { // just fill rect with ClrPen + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->putPixel(x, y, 1, clrPen, 0, 0); + } + } + } + } + + if (drawFlags < 2) + return; + drawFlags &= SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL; + + if (oldPenMode != 2) { + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->putPixel(x, y, drawFlags, 0, clrBack, bControl); + } + } + } else { + for (y = r.top; y < r.bottom; y++) { + for (x = r.left; x < r.right; x++) { + _screen->putPixel(x, y, drawFlags, 0, !_screen->getPriority(x, y), !_screen->getControl(x, y)); + } + } + } +} + +void Gfx::FrameRect(const Common::Rect &rect) { + Common::Rect r; + // left + r = rect; + r.right = rect.left + 1; + PaintRect(r); + // right + r.right = rect.right; + r.left = rect.right - 1; + PaintRect(r); + //top + r.left = rect.left; + r.bottom = rect.top + 1; + PaintRect(r); + //bottom + r.bottom = rect.bottom; + r.top = rect.bottom - 1; + PaintRect(r); +} + +void Gfx::OffsetRect(Common::Rect &r) { + r.top += _curPort->top; + r.bottom += _curPort->top; + r.left += _curPort->left; + r.right += _curPort->left; +} + +void Gfx::OffsetLine(Common::Point &start, Common::Point &end) { + start.x += _curPort->left; + start.y += _curPort->top; + end.x += _curPort->left; + end.y += _curPort->top; +} + +void Gfx::BitsShow(const Common::Rect &rect) { + Common::Rect workerRect(rect.left, rect.top, rect.right, rect.bottom); + workerRect.clip(_curPort->rect); + if (workerRect.isEmpty()) // nothing to show + return; + + OffsetRect(workerRect); + _screen->copyRectToScreen(workerRect); +} + +MemoryHandle Gfx::BitsSave(const Common::Rect &rect, byte screenMask) { + MemoryHandle memoryId; + byte *memoryPtr; + int size; + + Common::Rect workerRect(rect.left, rect.top, rect.right, rect.bottom); + workerRect.clip(_curPort->rect); + if (workerRect.isEmpty()) // nothing to save + return NULL_REG; + + OffsetRect(workerRect); + + // now actually ask _screen how much space it will need for saving + size = _screen->bitsGetDataSize(workerRect, screenMask); + + memoryId = kalloc(_segMan, "SaveBits()", size); + memoryPtr = kmem(_segMan, memoryId); + _screen->bitsSave(workerRect, screenMask, memoryPtr); + return memoryId; +} + +void Gfx::BitsGetRect(MemoryHandle memoryHandle, Common::Rect *destRect) { + byte *memoryPtr = NULL; + + if (!memoryHandle.isNull()) { + memoryPtr = kmem(_segMan, memoryHandle); + + if (memoryPtr) { + _screen->bitsGetRect(memoryPtr, destRect); + } + } +} + +void Gfx::BitsRestore(MemoryHandle memoryHandle) { + byte *memoryPtr = NULL; + + if (!memoryHandle.isNull()) { + memoryPtr = kmem(_segMan, memoryHandle); + + if (memoryPtr) { + _screen->bitsRestore(memoryPtr); + kfree(_segMan, memoryHandle); + } + } +} + +void Gfx::BitsFree(MemoryHandle memoryHandle) { + if (!memoryHandle.isNull()) { + kfree(_segMan, memoryHandle); + } +} + +void Gfx::drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId) { + SciGuiPicture *picture = new SciGuiPicture(_resMan, this, _screen, _palette, pictureId); + + // do we add to a picture? if not -> clear screen with white + if (!addToFlag) + ClearScreen(_screen->_colorWhite); + + picture->draw(animationNr, mirroredFlag, addToFlag, paletteId); + delete picture; +} + +// This one is the only one that updates screen! +void Gfx::drawCel(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, int16 origHeight) { + View *view = getView(viewId); + Common::Rect rect; + Common::Rect clipRect; + if (view) { + rect.left = leftPos; + rect.top = topPos; + rect.right = rect.left + view->getWidth(loopNo, celNo); + rect.bottom = rect.top + view->getHeight(loopNo, celNo); + clipRect = rect; + clipRect.clip(_curPort->rect); + if (clipRect.isEmpty()) { // nothing to draw + return; + } + + Common::Rect clipRectTranslated = clipRect; + OffsetRect(clipRectTranslated); + view->draw(rect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo, origHeight); + if (getSciVersion() >= SCI_VERSION_1_1) { + if (!_screen->_picNotValidSci11) + BitsShow(rect); + } else { + if (!_screen->_picNotValid) + BitsShow(rect); + } + } +} + +// This version of drawCel is not supposed to call BitsShow()! +void Gfx::drawCel(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo) { + View *view = getView(viewId); + Common::Rect clipRect; + if (view) { + clipRect = celRect; + clipRect.clip(_curPort->rect); + if (clipRect.isEmpty()) { // nothing to draw + return; + } + + Common::Rect clipRectTranslated = clipRect; + OffsetRect(clipRectTranslated); + view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo); + } +} + +// This version of drawCel is not supposed to call BitsShow()! +void Gfx::drawCel(View *view, LoopNo loopNo, CelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo) { + Common::Rect clipRect; + clipRect = celRect; + clipRect.clip(_curPort->rect); + if (clipRect.isEmpty()) // nothing to draw + return; + + Common::Rect clipRectTranslated = clipRect; + OffsetRect(clipRectTranslated); + view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo); +} + +uint16 Gfx::onControl(uint16 screenMask, Common::Rect rect) { + Common::Rect outRect(rect.left, rect.top, rect.right, rect.bottom); + int16 x, y; + uint16 result = 0; + + outRect.clip(_curPort->rect); + if (outRect.isEmpty()) // nothing to control + return 0; + OffsetRect(outRect); + + if (screenMask & SCI_SCREEN_MASK_PRIORITY) { + for (y = outRect.top; y < outRect.bottom; y++) { + for (x = outRect.left; x < outRect.right; x++) { + result |= 1 << _screen->getPriority(x, y); + } + } + } else { + for (y = outRect.top; y < outRect.bottom; y++) { + for (x = outRect.left; x < outRect.right; x++) { + result |= 1 << _screen->getControl(x, y); + } + } + } + return result; +} + +static inline int sign_extend_byte(int value) { + if (value & 0x80) + return value - 256; + else + return value; +} + +void Gfx::PriorityBandsInit(int16 bandCount, int16 top, int16 bottom) { + int16 y; + int32 bandSize; + + if (bandCount != -1) + _priorityBandCount = bandCount; + + _priorityTop = top; + _priorityBottom = bottom; + + // Do NOT modify this algo or optimize it anyhow, sierra sci used int32 for calculating the + // priority bands and by using double or anything rounding WILL destroy the result + bandSize = ((_priorityBottom - _priorityTop) * 2000) / _priorityBandCount; + + memset(_priorityBands, 0, sizeof(byte) * _priorityTop); + for (y = _priorityTop; y < _priorityBottom; y++) + _priorityBands[y] = 1 + (((y - _priorityTop) * 2000) / bandSize); + if (_priorityBandCount == 15) { + // When having 15 priority bands, we actually replace band 15 with band 14, cause the original sci interpreter also + // does it that way as well + y = _priorityBottom; + while (_priorityBands[--y] == _priorityBandCount) + _priorityBands[y]--; + } + // We fill space that is left over with the highest band + for (y = _priorityBottom; y < _screen->_height; y++) + _priorityBands[y] = _priorityBandCount; +} + +void Gfx::PriorityBandsInit(byte *data) { + int i = 0, inx; + byte priority = 0; + + for (inx = 0; inx < 14; inx++) { + priority = *data++; + while (i < priority) + _priorityBands[i++] = inx; + } + while (i < 200) + _priorityBands[i++] = inx; +} + +byte Gfx::CoordinateToPriority(int16 y) { + if (y < _priorityTop) + return _priorityBands[_priorityTop]; + if (y > _priorityBottom) + return _priorityBands[_priorityBottom]; + return _priorityBands[y]; +} + +int16 Gfx::PriorityToCoordinate(byte priority) { + int16 y; + if (priority <= _priorityBandCount) { + for (y = 0; y <= _priorityBottom; y++) + if (_priorityBands[y] == priority) + return y; + } + return _priorityBottom; +} + +bool Gfx::CanBeHereCheckRectList(reg_t checkObject, Common::Rect checkRect, List *list) { + reg_t curAddress = list->first; + Node *curNode = _segMan->lookupNode(curAddress); + reg_t curObject; + uint16 signal; + Common::Rect curRect; + + while (curNode) { + curObject = curNode->value; + if (curObject != checkObject) { + signal = GET_SEL32V(_segMan, curObject, signal); + if ((signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate)) == 0) { + curRect.left = GET_SEL32V(_segMan, curObject, brLeft); + curRect.top = GET_SEL32V(_segMan, curObject, brTop); + curRect.right = GET_SEL32V(_segMan, curObject, brRight); + curRect.bottom = GET_SEL32V(_segMan, curObject, brBottom); + // Check if curRect is within checkRect + if (curRect.right > checkRect.left && curRect.left < checkRect.right && curRect.bottom > checkRect.top && curRect.top < checkRect.bottom) { + return false; + } + } + } + curAddress = curNode->succ; + curNode = _segMan->lookupNode(curAddress); + } + return true; +} + +void Gfx::SetNowSeen(reg_t objectReference) { + View *view = NULL; + Common::Rect celRect(0, 0); + GuiResourceId viewId = (GuiResourceId)GET_SEL32V(_segMan, objectReference, view); + LoopNo loopNo = sign_extend_byte((LoopNo)GET_SEL32V(_segMan, objectReference, loop)); + CelNo celNo = sign_extend_byte((CelNo)GET_SEL32V(_segMan, objectReference, cel)); + int16 x = (int16)GET_SEL32V(_segMan, objectReference, x); + int16 y = (int16)GET_SEL32V(_segMan, objectReference, y); + int16 z = 0; + if (_kernel->_selectorCache.z > -1) + z = (int16)GET_SEL32V(_segMan, objectReference, z); + + // now get cel rectangle + view = getView(viewId); + view->getCelRect(loopNo, celNo, x, y, z, &celRect); + + // TODO: sometimes loop is negative. Check what it means + if (lookup_selector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) { + PUT_SEL32V(_segMan, objectReference, nsLeft, celRect.left); + PUT_SEL32V(_segMan, objectReference, nsRight, celRect.right); + PUT_SEL32V(_segMan, objectReference, nsTop, celRect.top); + PUT_SEL32V(_segMan, objectReference, nsBottom, celRect.bottom); + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/gfx.h b/engines/sci/graphics/gfx.h new file mode 100644 index 0000000000..c6edd36ec8 --- /dev/null +++ b/engines/sci/graphics/gfx.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_GFX_H +#define SCI_GRAPHICS_GFX_H + +#include "sci/graphics/gui.h" + +#include "common/hashmap.h" + +namespace Sci { + +#define SCI_TEXT_ALIGNMENT_RIGHT -1 +#define SCI_TEXT_ALIGNMENT_CENTER 1 +#define SCI_TEXT_ALIGNMENT_LEFT 0 + +#define MAX_CACHED_VIEWS 50 + +class Screen; +class SciPalette; +class Font; +class SciGuiPicture; +class View; + +typedef Common::HashMap ViewCache; + +class Gfx { +public: + Gfx(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, Screen *screen, SciPalette *palette); + ~Gfx(); + + void init(Text *text); + + byte *GetSegment(byte seg); + void ResetScreen(); + + Port *SetPort(Port *port); + Port *GetPort(); + void SetOrigin(int16 left, int16 top); + void MoveTo(int16 left, int16 top); + void Move(int16 left, int16 top); + void OpenPort(Port *port); + void PenColor(int16 color); + void BackColor(int16 color); + void PenMode(int16 mode); + void TextGreyedOutput(bool state); + int16 GetPointSize(); + + void ClearScreen(byte color = 255); + void InvertRect(const Common::Rect &rect); + void EraseRect(const Common::Rect &rect); + void PaintRect(const Common::Rect &rect); + void FillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack = 0, byte bControl = 0); + void FrameRect(const Common::Rect &rect); + void OffsetRect(Common::Rect &r); + void OffsetLine(Common::Point &start, Common::Point &end); + + void BitsShow(const Common::Rect &r); + MemoryHandle BitsSave(const Common::Rect &rect, byte screenFlags); + void BitsGetRect(MemoryHandle memoryHandle, Common::Rect *destRect); + void BitsRestore(MemoryHandle memoryHandle); + void BitsFree(MemoryHandle memoryHandle); + + void drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId); + void drawCel(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, int16 origHeight = -1); + void drawCel(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo); + void drawCel(View *view, LoopNo loopNo, CelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo); + + uint16 onControl(uint16 screenMask, Common::Rect rect); + + void PriorityBandsInit(int16 bandCount, int16 top, int16 bottom); + void PriorityBandsInit(byte *data); + byte CoordinateToPriority(int16 y); + int16 PriorityToCoordinate(byte priority); + + bool CanBeHereCheckRectList(reg_t checkObject, Common::Rect checkRect, List *list); + + void SetNowSeen(reg_t objectReference); + + Port *_menuPort; + Common::Rect _menuBarRect; + Port *_curPort; + + View *getView(GuiResourceId viewNum); + +private: + void purgeCache(); + + ResourceManager *_resMan; + SegManager *_segMan; + Kernel *_kernel; + Screen *_screen; + SciPalette *_palette; + Text *_text; + + Common::Rect _bounds; + Port *_mainPort; + + // Priority Bands related variables + int16 _priorityTop, _priorityBottom, _priorityBandCount; + byte _priorityBands[200]; + + ViewCache _cachedViews; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/gui.cpp b/engines/sci/graphics/gui.cpp index ee1543995b..8931459a26 100644 --- a/engines/sci/graphics/gui.cpp +++ b/engines/sci/graphics/gui.cpp @@ -31,35 +31,35 @@ #include "sci/event.h" #include "sci/engine/state.h" #include "sci/graphics/gui.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_cursor.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_windowmgr.h" -#include "sci/graphics/gui_animate.h" -#include "sci/graphics/gui_controls.h" -#include "sci/graphics/gui_menu.h" -#include "sci/graphics/gui_text.h" -#include "sci/graphics/gui_transitions.h" -#include "sci/graphics/gui_view.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/cursor.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/windowmgr.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/controls.h" +#include "sci/graphics/menu.h" +#include "sci/graphics/text.h" +#include "sci/graphics/transitions.h" +#include "sci/graphics/view.h" namespace Sci { // for debug purposes // class SciGui32 : public SciGui { // public: -// SciGui32(EngineState *s, SciGuiScreen *screen, SciGuiPalette *palette, SciGuiCursor *cursor); +// SciGui32(EngineState *s, Screen *screen, SciPalette *palette, Cursor *cursor); // ~SciGui32(); // }; -SciGui::SciGui(EngineState *state, SciGuiScreen *screen, SciGuiPalette *palette, SciGuiCursor *cursor) +SciGui::SciGui(EngineState *state, Screen *screen, SciPalette *palette, Cursor *cursor) : _s(state), _screen(screen), _palette(palette), _cursor(cursor) { - _gfx = new SciGuiGfx(_s->resMan, _s->_segMan, _s->_kernel, _screen, _palette); - _transitions = new SciGuiTransitions(this, _screen, _palette, _s->resMan->isVGA()); + _gfx = new Gfx(_s->resMan, _s->_segMan, _s->_kernel, _screen, _palette); + _transitions = new Transitions(this, _screen, _palette, _s->resMan->isVGA()); _animate = new SciGuiAnimate(_s, _gfx, _screen, _palette); - _text = new SciGuiText(_s->resMan, _gfx, _screen); - _windowMgr = new SciGuiWindowMgr(this, _screen, _gfx, _text); + _text = new Text(_s->resMan, _gfx, _screen); + _windowMgr = new WindowMgr(this, _screen, _gfx, _text); _controls = new SciGuiControls(_s->_segMan, _gfx, _text); _menu = new SciGuiMenu(_s->_event, _s->_segMan, _gfx, _text, _screen, _cursor); // _gui32 = new SciGui32(_s, _screen, _palette, _cursor); // for debug purposes @@ -142,13 +142,13 @@ reg_t SciGui::getPort() { } void SciGui::globalToLocal(int16 *x, int16 *y) { - GuiPort *curPort = _gfx->GetPort(); + Port *curPort = _gfx->GetPort(); *x = *x - curPort->left; *y = *y - curPort->top; } void SciGui::localToGlobal(int16 *x, int16 *y) { - GuiPort *curPort = _gfx->GetPort(); + Port *curPort = _gfx->GetPort(); *x = *x + curPort->left; *y = *y + curPort->top; } @@ -162,7 +162,7 @@ int16 SciGui::priorityToCoordinate(int16 priority) { } reg_t SciGui::newWindow(Common::Rect dims, Common::Rect restoreRect, uint16 style, int16 priority, int16 colorPen, int16 colorBack, const char *title) { - GuiWindow *wnd = NULL; + Window *wnd = NULL; if (restoreRect.top != 0 && restoreRect.left != 0 && restoreRect.height() != 0 && restoreRect.width() != 0) wnd = _windowMgr->NewWindow(dims, &restoreRect, title, style, priority, false); @@ -176,7 +176,7 @@ reg_t SciGui::newWindow(Common::Rect dims, Common::Rect restoreRect, uint16 styl } void SciGui::disposeWindow(uint16 windowPtr, bool reanimate) { - GuiWindow *wnd = (GuiWindow *)_windowMgr->getPortById(windowPtr); + Window *wnd = (Window *)_windowMgr->getPortById(windowPtr); _windowMgr->DisposeWindow(wnd, reanimate); } @@ -193,13 +193,13 @@ void SciGui::disposeWindow(uint16 windowPtr, bool reanimate) { void SciGui::display(const char *text, int argc, reg_t *argv) { int displayArg; - GuiTextAlignment alignment = SCI_TEXT_ALIGNMENT_LEFT; + TextAlignment alignment = SCI_TEXT_ALIGNMENT_LEFT; int16 bgcolor = -1, width = -1, bRedraw = 1; bool doSaveUnder = false; Common::Rect rect; // Make a "backup" of the port settings - GuiPort oldPort = *_gfx->GetPort(); + Port oldPort = *_gfx->GetPort(); // setting defaults _gfx->PenMode(0); @@ -274,7 +274,7 @@ void SciGui::display(const char *text, int argc, reg_t *argv) { if (_screen->_picNotValid == 0 && bRedraw) _gfx->BitsShow(rect); // restoring port and cursor pos - GuiPort *currport = _gfx->GetPort(); + Port *currport = _gfx->GetPort(); uint16 tTop = currport->curTop; uint16 tLeft = currport->curLeft; *currport = oldPort; @@ -300,7 +300,7 @@ void SciGui::textColors(int argc, reg_t *argv) { } void SciGui::drawStatus(const char *text, int16 colorPen, int16 colorBack) { - GuiPort *oldPort = _gfx->SetPort(_gfx->_menuPort); + Port *oldPort = _gfx->SetPort(_gfx->_menuPort); _gfx->FillRect(_gfx->_menuBarRect, 1, colorBack); _gfx->PenColor(colorPen); @@ -313,7 +313,7 @@ void SciGui::drawStatus(const char *text, int16 colorPen, int16 colorBack) { void SciGui::drawMenuBar(bool clear) { if (!clear) { - GuiPort *oldPort = _gfx->SetPort(_gfx->_menuPort); + Port *oldPort = _gfx->SetPort(_gfx->_menuPort); _menu->drawBar(); if (_screen->_picNotValid == 0) _gfx->BitsShow(_gfx->_menuBarRect); @@ -345,7 +345,7 @@ reg_t SciGui::menuSelect(reg_t eventObject) { } void SciGui::drawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) { - GuiPort *oldPort = _gfx->SetPort((GuiPort *)_windowMgr->_picWind); + Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind); if (_windowMgr->isFrontWindow(_windowMgr->_picWind)) { _screen->_picNotValid = 1; @@ -359,7 +359,7 @@ void SciGui::drawPicture(GuiResourceId pictureId, int16 animationNr, bool animat _gfx->SetPort(oldPort); } -void SciGui::drawCel(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, int16 origHeight) { +void SciGui::drawCel(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, int16 origHeight) { _gfx->drawCel(viewId, loopNo, celNo, leftPos, topPos, priority, paletteNo, origHeight); _palette->setOnScreen(); } @@ -392,7 +392,7 @@ void SciGui::drawControlButton(Common::Rect rect, reg_t obj, const char *text, i } } -void SciGui::drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, GuiTextAlignment alignment, int16 style, bool hilite) { +void SciGui::drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, TextAlignment alignment, int16 style, bool hilite) { if (!hilite) { rect.grow(1); _gfx->EraseRect(rect); @@ -430,7 +430,7 @@ void SciGui::drawControlTextEdit(Common::Rect rect, reg_t obj, const char *text, _gfx->BitsShow(rect); } -void SciGui::drawControlIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 style, bool hilite) { +void SciGui::drawControlIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, LoopNo loopNo, CelNo celNo, int16 style, bool hilite) { if (!hilite) { _gfx->drawCel(viewId, loopNo, celNo, rect.left, rect.top, 255, 0); if (style & 0x20) { @@ -510,7 +510,7 @@ void SciGui::graphUpdateBox(Common::Rect rect) { void SciGui::graphRedrawBox(Common::Rect rect) { localToGlobal(&rect.left, &rect.top); localToGlobal(&rect.right, &rect.bottom); - GuiPort *oldPort = _gfx->SetPort((GuiPort *)_windowMgr->_picWind); + Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind); globalToLocal(&rect.left, &rect.top); globalToLocal(&rect.right, &rect.bottom); @@ -596,7 +596,7 @@ void SciGui::shakeScreen(uint16 shakeCount, uint16 directions) { } uint16 SciGui::onControl(byte screenMask, Common::Rect rect) { - GuiPort *oldPort = _gfx->SetPort((GuiPort *)_windowMgr->_picWind); + Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind); uint16 result; result = _gfx->onControl(screenMask, rect); @@ -605,7 +605,7 @@ uint16 SciGui::onControl(byte screenMask, Common::Rect rect) { } void SciGui::animateShowPic() { - GuiPort *picPort = _windowMgr->_picWind; + Port *picPort = _windowMgr->_picWind; Common::Rect picRect = picPort->rect; bool previousCursorState = _cursor->isVisible(); @@ -637,7 +637,7 @@ void SciGui::animate(reg_t listReference, bool cycle, int argc, reg_t *argv) { return; } - GuiPort *oldPort = _gfx->SetPort((GuiPort *)_windowMgr->_picWind); + Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind); _animate->disposeLastCast(); _animate->makeSortedList(list); @@ -670,7 +670,7 @@ void SciGui::addToPicSetPicNotValid() { void SciGui::addToPicList(reg_t listReference, int argc, reg_t *argv) { List *list; - _gfx->SetPort((GuiPort *)_windowMgr->_picWind); + _gfx->SetPort((Port *)_windowMgr->_picWind); list = _s->_segMan->lookupList(listReference); if (!list) @@ -682,8 +682,8 @@ void SciGui::addToPicList(reg_t listReference, int argc, reg_t *argv) { addToPicSetPicNotValid(); } -void SciGui::addToPicView(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) { - _gfx->SetPort((GuiPort *)_windowMgr->_picWind); +void SciGui::addToPicView(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) { + _gfx->SetPort((Port *)_windowMgr->_picWind); _animate->addToPicDrawView(viewId, loopNo, celNo, leftPos, topPos, priority, control); addToPicSetPicNotValid(); } @@ -693,7 +693,7 @@ void SciGui::setNowSeen(reg_t objectReference) { } bool SciGui::canBeHere(reg_t curObject, reg_t listReference) { - GuiPort *oldPort = _gfx->SetPort((GuiPort *)_windowMgr->_picWind); + Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind); Common::Rect checkRect; uint16 signal, controlMask; bool result; @@ -717,8 +717,8 @@ bool SciGui::canBeHere(reg_t curObject, reg_t listReference) { } bool SciGui::isItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo, Common::Point position) { - SciGuiView *tmpView = _gfx->getView(viewId); - sciViewCelInfo *celInfo = tmpView->getCelInfo(loopNo, celNo); + View *tmpView = _gfx->getView(viewId); + CelInfo *celInfo = tmpView->getCelInfo(loopNo, celNo); position.x = CLIP(position.x, 0, celInfo->width - 1); position.y = CLIP(position.y, 0, celInfo->height - 1); byte *celData = tmpView->getBitmap(loopNo, celNo); @@ -733,10 +733,10 @@ void SciGui::baseSetter(reg_t object) { int16 z = (_s->_kernel->_selectorCache.z > -1) ? GET_SEL32V(_s->_segMan, object, z) : 0; int16 yStep = GET_SEL32V(_s->_segMan, object, yStep); GuiResourceId viewId = GET_SEL32V(_s->_segMan, object, view); - GuiViewLoopNo loopNo = GET_SEL32V(_s->_segMan, object, loop); - GuiViewCelNo celNo = GET_SEL32V(_s->_segMan, object, cel); + LoopNo loopNo = GET_SEL32V(_s->_segMan, object, loop); + CelNo celNo = GET_SEL32V(_s->_segMan, object, cel); - SciGuiView *tmpView = _gfx->getView(viewId); + View *tmpView = _gfx->getView(viewId); Common::Rect celRect; tmpView->getCelRect(loopNo, celNo, x, y, z, &celRect); diff --git a/engines/sci/graphics/gui.h b/engines/sci/graphics/gui.h index 1411a2eac6..db25698fe1 100644 --- a/engines/sci/graphics/gui.h +++ b/engines/sci/graphics/gui.h @@ -23,10 +23,10 @@ * */ -#ifndef SCI_GUI_GUI_H -#define SCI_GUI_GUI_H +#ifndef SCI_GRAPHICS_GUI_H +#define SCI_GRAPHICS_GUI_H -#include "sci/graphics/gui_helpers.h" +#include "sci/graphics/helpers.h" namespace Sci { @@ -41,21 +41,21 @@ enum { SCI_CONTROLS_TYPE_DUMMY = 10 }; -class SciGuiScreen; -class SciGuiPalette; -class SciGuiCursor; -class SciGuiGfx; -class SciGuiWindowMgr; +class Screen; +class SciPalette; +class Cursor; +class Gfx; +class WindowMgr; class SciGuiAnimate; class SciGuiControls; class SciGuiMenu; -class SciGuiText; -class SciGuiTransitions; +class Text; +class Transitions; class SciGui32; // for debug purposes class SciGui { public: - SciGui(EngineState *s, SciGuiScreen *screen, SciGuiPalette *palette, SciGuiCursor *cursor); + SciGui(EngineState *s, Screen *screen, SciPalette *palette, Cursor *cursor); SciGui(); virtual ~SciGui(); @@ -89,11 +89,11 @@ public: virtual reg_t menuSelect(reg_t eventObject); virtual void drawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo); - virtual void drawCel(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, int16 origHeight = -1); + virtual void drawCel(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, int16 origHeight = -1); virtual void drawControlButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite); virtual void drawControlText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 alignment, int16 style, bool hilite); virtual void drawControlTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite); - virtual void drawControlIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 style, bool hilite); + virtual void drawControlIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, LoopNo loopNo, CelNo celNo, int16 style, bool hilite); virtual void drawControlList(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 style, int16 upperPos, int16 cursorPos, bool isAlias, bool hilite); virtual void editControl(reg_t controlObject, reg_t eventObject); @@ -125,7 +125,7 @@ public: virtual void animateShowPic(); virtual void animate(reg_t listReference, bool cycle, int argc, reg_t *argv); virtual void addToPicList(reg_t listReference, int argc, reg_t *argv); - virtual void addToPicView(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); + virtual void addToPicView(GuiResourceId viewId, LoopNo loopNo, CelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); virtual void setNowSeen(reg_t objectReference); virtual bool canBeHere(reg_t curObject, reg_t listReference); virtual bool isItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo, Common::Point position); @@ -170,23 +170,23 @@ public: virtual void resetEngineState(EngineState *s); protected: - SciGuiCursor *_cursor; + Cursor *_cursor; EngineState *_s; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - SciGuiGfx *_gfx; + Screen *_screen; + SciPalette *_palette; + Gfx *_gfx; private: virtual void initPriorityBands(); virtual void addToPicSetPicNotValid(); virtual int getControlPicNotValid(); - SciGuiWindowMgr *_windowMgr; + WindowMgr *_windowMgr; SciGuiAnimate *_animate; SciGuiControls *_controls; SciGuiMenu *_menu; - SciGuiText *_text; - SciGuiTransitions *_transitions; + Text *_text; + Transitions *_transitions; // SciGui32 *_gui32; // for debug purposes bool _usesOldGfxFunctions; diff --git a/engines/sci/graphics/gui_animate.cpp b/engines/sci/graphics/gui_animate.cpp deleted file mode 100644 index ad9332e3a1..0000000000 --- a/engines/sci/graphics/gui_animate.cpp +++ /dev/null @@ -1,559 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/engine/vm.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_view.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_transitions.h" -#include "sci/graphics/gui_animate.h" - -namespace Sci { - -SciGuiAnimate::SciGuiAnimate(EngineState *state, SciGuiGfx *gfx, SciGuiScreen *screen, SciGuiPalette *palette) - : _s(state), _gfx(gfx), _screen(screen), _palette(palette) { - init(); -} - -SciGuiAnimate::~SciGuiAnimate() { - free(_listData); - free(_lastCastData); -} - -void SciGuiAnimate::init() { - _listData = NULL; - _listCount = 0; - _lastCastData = NULL; - _lastCastCount = 0; - - _ignoreFastCast = false; - // fastCast object is not found in any SCI games prior SCI1 - if (getSciVersion() <= SCI_VERSION_01) - _ignoreFastCast = true; - // Also if fastCast object exists at gamestartup, we can assume that the interpreter doesnt do kAnimate aborts - // (found in larry 1) - if (!_s->_segMan->findObjectByName("fastCast").isNull()) - _ignoreFastCast = true; -} - -void SciGuiAnimate::disposeLastCast() { - _lastCastCount = 0; -} - -bool SciGuiAnimate::invoke(List *list, int argc, reg_t *argv) { - reg_t curAddress = list->first; - Node *curNode = _s->_segMan->lookupNode(curAddress); - reg_t curObject; - uint16 signal; - - while (curNode) { - curObject = curNode->value; - - if (!_ignoreFastCast) { - // Check if the game has a fastCast object set - // if we don't abort kAnimate processing, at least in kq5 there will be animation cels drawn into speech boxes. - reg_t global84 = _s->script_000->_localsBlock->_locals[84]; - - if (!global84.isNull()) { - if (!strcmp(_s->_segMan->getObjectName(global84), "fastCast")) - return false; - } - } - - signal = GET_SEL32V(_s->_segMan, curObject, signal); - if (!(signal & kSignalFrozen)) { - // Call .doit method of that object - invoke_selector(_s, curObject, _s->_kernel->_selectorCache.doit, kContinueOnInvalidSelector, argv, argc, 0); - // Lookup node again, since the nodetable it was in may have been reallocated - curNode = _s->_segMan->lookupNode(curAddress); - } - curAddress = curNode->succ; - curNode = _s->_segMan->lookupNode(curAddress); - } - return true; -} - -bool sortHelper(const GuiAnimateEntry* entry1, const GuiAnimateEntry* entry2) { - return (entry1->y == entry2->y) ? (entry1->z < entry2->z) : (entry1->y < entry2->y); -} - -void SciGuiAnimate::makeSortedList(List *list) { - reg_t curAddress = list->first; - Node *curNode = _s->_segMan->lookupNode(curAddress); - reg_t curObject; - GuiAnimateEntry *listEntry; - int16 listNr, listCount = 0; - - // Count the list entries - while (curNode) { - listCount++; - curAddress = curNode->succ; - curNode = _s->_segMan->lookupNode(curAddress); - } - - _list.clear(); - - // No entries -> exit immediately - if (listCount == 0) - return; - - // Adjust list size, if needed - if ((_listData == NULL) || (_listCount < listCount)) { - free(_listData); - _listData = (GuiAnimateEntry *)malloc(listCount * sizeof(GuiAnimateEntry)); - if (!_listData) - error("Could not allocate memory for _listData"); - _listCount = listCount; - - free(_lastCastData); - _lastCastData = (GuiAnimateEntry *)malloc(listCount * sizeof(GuiAnimateEntry)); - if (!_lastCastData) - error("Could not allocate memory for _lastCastData"); - _lastCastCount = 0; - } - - // Fill the list - curAddress = list->first; - curNode = _s->_segMan->lookupNode(curAddress); - listEntry = _listData; - for (listNr = 0; listNr < listCount; listNr++) { - curObject = curNode->value; - listEntry->object = curObject; - - // Get data from current object - listEntry->viewId = GET_SEL32V(_s->_segMan, curObject, view); - listEntry->loopNo = GET_SEL32V(_s->_segMan, curObject, loop); - listEntry->celNo = GET_SEL32V(_s->_segMan, curObject, cel); - listEntry->paletteNo = GET_SEL32V(_s->_segMan, curObject, palette); - listEntry->x = GET_SEL32V(_s->_segMan, curObject, x); - listEntry->y = GET_SEL32V(_s->_segMan, curObject, y); - listEntry->z = GET_SEL32V(_s->_segMan, curObject, z); - listEntry->priority = GET_SEL32V(_s->_segMan, curObject, priority); - listEntry->signal = GET_SEL32V(_s->_segMan, curObject, signal); - // listEntry->celRect is filled in AnimateFill() - listEntry->showBitsFlag = false; - - _list.push_back(listEntry); - - listEntry++; - curAddress = curNode->succ; - curNode = _s->_segMan->lookupNode(curAddress); - } - - // Now sort the list according y and z (descending) - GuiAnimateList::iterator listBegin = _list.begin(); - GuiAnimateList::iterator listEnd = _list.end(); - - Common::sort(_list.begin(), _list.end(), sortHelper); -} - -void SciGuiAnimate::fill(byte &old_picNotValid) { - reg_t curObject; - GuiAnimateEntry *listEntry; - uint16 signal; - SciGuiView *view = NULL; - GuiAnimateList::iterator listIterator; - GuiAnimateList::iterator listEnd = _list.end(); - - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - - // Get the corresponding view - view = _gfx->getView(listEntry->viewId); - - // adjust loop and cel, if any of those is invalid - if (listEntry->loopNo >= view->getLoopCount()) { - listEntry->loopNo = 0; - PUT_SEL32V(_s->_segMan, curObject, loop, listEntry->loopNo); - } - if (listEntry->celNo >= view->getCelCount(listEntry->loopNo)) { - listEntry->celNo = 0; - PUT_SEL32V(_s->_segMan, curObject, cel, listEntry->celNo); - } - - // Create rect according to coordinates and given cel - view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect); - PUT_SEL32V(_s->_segMan, curObject, nsLeft, listEntry->celRect.left); - PUT_SEL32V(_s->_segMan, curObject, nsTop, listEntry->celRect.top); - PUT_SEL32V(_s->_segMan, curObject, nsRight, listEntry->celRect.right); - PUT_SEL32V(_s->_segMan, curObject, nsBottom, listEntry->celRect.bottom); - - signal = listEntry->signal; - - // Calculate current priority according to y-coordinate - if (!(signal & kSignalFixedPriority)) { - listEntry->priority = _gfx->CoordinateToPriority(listEntry->y); - PUT_SEL32V(_s->_segMan, curObject, priority, listEntry->priority); - } - - if (signal & kSignalNoUpdate) { - if (signal & (kSignalForceUpdate | kSignalViewUpdated) - || (signal & kSignalHidden && !(signal & kSignalRemoveView)) - || (!(signal & kSignalHidden) && signal & kSignalRemoveView) - || (signal & kSignalAlwaysUpdate)) - old_picNotValid++; - signal &= 0xFFFF ^ kSignalStopUpdate; - } else { - if (signal & kSignalStopUpdate || signal & kSignalAlwaysUpdate) - old_picNotValid++; - signal &= 0xFFFF ^ kSignalForceUpdate; - } - listEntry->signal = signal; - - listIterator++; - } -} - -void SciGuiAnimate::update() { - reg_t curObject; - GuiAnimateEntry *listEntry; - uint16 signal; - reg_t bitsHandle; - Common::Rect rect; - GuiAnimateList::iterator listIterator; - GuiAnimateList::iterator listBegin = _list.begin(); - GuiAnimateList::iterator listEnd = _list.end(); - - // Remove all no-update cels, if requested - listIterator = _list.reverse_begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - if (signal & kSignalNoUpdate) { - if (!(signal & kSignalRemoveView)) { - bitsHandle = GET_SEL32(_s->_segMan, curObject, underBits); - if (_screen->_picNotValid != 1) { - _gfx->BitsRestore(bitsHandle); - listEntry->showBitsFlag = true; - } else { - _gfx->BitsFree(bitsHandle); - } - PUT_SEL32V(_s->_segMan, curObject, underBits, 0); - } - signal &= 0xFFFF ^ kSignalForceUpdate; - signal &= signal & kSignalViewUpdated ? 0xFFFF ^ (kSignalViewUpdated | kSignalNoUpdate) : 0xFFFF; - } else if (signal & kSignalStopUpdate) { - signal = (signal & (0xFFFF ^ kSignalStopUpdate)) | kSignalNoUpdate; - } - listEntry->signal = signal; - listIterator--; - } - - // Draw always-update cels - listIterator = listBegin; - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - if (signal & kSignalAlwaysUpdate) { - // draw corresponding cel - _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); - listEntry->showBitsFlag = true; - - signal &= 0xFFFF ^ (kSignalStopUpdate | kSignalViewUpdated | kSignalNoUpdate | kSignalForceUpdate); - if ((signal & kSignalIgnoreActor) == 0) { - rect = listEntry->celRect; - rect.top = CLIP(_gfx->PriorityToCoordinate(listEntry->priority) - 1, rect.top, rect.bottom - 1); - _gfx->FillRect(rect, SCI_SCREEN_MASK_CONTROL, 0, 0, 15); - } - listEntry->signal = signal; - } - listIterator++; - } - - // Saving background for all NoUpdate-cels - listIterator = listBegin; - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - if (signal & kSignalNoUpdate) { - if (signal & kSignalHidden) { - signal |= kSignalRemoveView; - } else { - signal &= 0xFFFF ^ kSignalRemoveView; - if (signal & kSignalIgnoreActor) - bitsHandle = _gfx->BitsSave(listEntry->celRect, SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY); - else - bitsHandle = _gfx->BitsSave(listEntry->celRect, SCI_SCREEN_MASK_ALL); - PUT_SEL32(_s->_segMan, curObject, underBits, bitsHandle); - } - listEntry->signal = signal; - } - listIterator++; - } - - // Draw NoUpdate cels - listIterator = listBegin; - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - if (signal & kSignalNoUpdate && !(signal & kSignalHidden)) { - // draw corresponding cel - _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); - listEntry->showBitsFlag = true; - - if ((signal & kSignalIgnoreActor) == 0) { - rect = listEntry->celRect; - rect.top = CLIP(_gfx->PriorityToCoordinate(listEntry->priority) - 1, rect.top, rect.bottom - 1); - _gfx->FillRect(rect, SCI_SCREEN_MASK_CONTROL, 0, 0, 15); - } - } - listIterator++; - } -} - -void SciGuiAnimate::drawCels() { - reg_t curObject; - GuiAnimateEntry *listEntry; - GuiAnimateEntry *lastCastEntry = _lastCastData; - uint16 signal; - reg_t bitsHandle; - GuiAnimateList::iterator listIterator; - GuiAnimateList::iterator listEnd = _list.end(); - - _lastCastCount = 0; - - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - if (!(signal & (kSignalNoUpdate | kSignalHidden | kSignalAlwaysUpdate))) { - // Save background - bitsHandle = _gfx->BitsSave(listEntry->celRect, SCI_SCREEN_MASK_ALL); - PUT_SEL32(_s->_segMan, curObject, underBits, bitsHandle); - - // draw corresponding cel - _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); - listEntry->showBitsFlag = true; - - if (signal & kSignalRemoveView) { - signal &= 0xFFFF ^ kSignalRemoveView; - } - listEntry->signal = signal; - - // Remember that entry in lastCast - memcpy(lastCastEntry, listEntry, sizeof(GuiAnimateEntry)); - lastCastEntry++; _lastCastCount++; - } - listIterator++; - } -} - -void SciGuiAnimate::updateScreen(byte oldPicNotValid) { - reg_t curObject; - GuiAnimateEntry *listEntry; - uint16 signal; - GuiAnimateList::iterator listIterator; - GuiAnimateList::iterator listEnd = _list.end(); - Common::Rect lsRect; - Common::Rect workerRect; - - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - if (listEntry->showBitsFlag || !(signal & (kSignalRemoveView | kSignalNoUpdate) || - (!(signal & kSignalRemoveView) && (signal & kSignalNoUpdate) && oldPicNotValid))) { - lsRect.left = GET_SEL32V(_s->_segMan, curObject, lsLeft); - lsRect.top = GET_SEL32V(_s->_segMan, curObject, lsTop); - lsRect.right = GET_SEL32V(_s->_segMan, curObject, lsRight); - lsRect.bottom = GET_SEL32V(_s->_segMan, curObject, lsBottom); - - workerRect = lsRect; - workerRect.clip(listEntry->celRect); - - if (!workerRect.isEmpty()) { - workerRect = lsRect; - workerRect.extend(listEntry->celRect); - } else { - _gfx->BitsShow(lsRect); - workerRect = listEntry->celRect; - } - PUT_SEL32V(_s->_segMan, curObject, lsLeft, workerRect.left); - PUT_SEL32V(_s->_segMan, curObject, lsTop, workerRect.top); - PUT_SEL32V(_s->_segMan, curObject, lsRight, workerRect.right); - PUT_SEL32V(_s->_segMan, curObject, lsBottom, workerRect.bottom); - _gfx->BitsShow(workerRect); - - if (signal & kSignalHidden) { - listEntry->signal |= kSignalRemoveView; - } - } - - listIterator++; - } - // use this for debug purposes - // _screen->copyToScreen(); -} - -void SciGuiAnimate::restoreAndDelete(int argc, reg_t *argv) { - reg_t curObject; - GuiAnimateEntry *listEntry; - uint16 signal; - GuiAnimateList::iterator listIterator; - GuiAnimateList::iterator listEnd = _list.end(); - - - // This has to be done in a separate loop. At least in sq1 some .dispose modifies FIXEDLOOP flag in signal for - // another object. In that case we would overwrite the new signal with our version of the old signal - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - signal = listEntry->signal; - - // Finally update signal - PUT_SEL32V(_s->_segMan, curObject, signal, signal); - listIterator++; - } - - listIterator = _list.reverse_begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - // We read out signal here again, this is not by accident but to ensure that we got an up-to-date signal - signal = GET_SEL32V(_s->_segMan, curObject, signal); - - if ((signal & (kSignalNoUpdate | kSignalRemoveView)) == 0) { - _gfx->BitsRestore(GET_SEL32(_s->_segMan, curObject, underBits)); - PUT_SEL32V(_s->_segMan, curObject, underBits, 0); - } - - if (signal & kSignalDisposeMe) { - // Call .delete_ method of that object - invoke_selector(_s, curObject, _s->_kernel->_selectorCache.delete_, kContinueOnInvalidSelector, argv, argc, 0); - } - listIterator--; - } -} - -void SciGuiAnimate::reAnimate(Common::Rect rect) { - GuiAnimateEntry *lastCastEntry; - uint16 lastCastCount; - - if (_lastCastCount > 0) { - lastCastEntry = _lastCastData; - lastCastCount = _lastCastCount; - while (lastCastCount > 0) { - lastCastEntry->castHandle = _gfx->BitsSave(lastCastEntry->celRect, SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY); - _gfx->drawCel(lastCastEntry->viewId, lastCastEntry->loopNo, lastCastEntry->celNo, lastCastEntry->celRect, lastCastEntry->priority, lastCastEntry->paletteNo); - lastCastEntry++; lastCastCount--; - } - _gfx->BitsShow(rect); - // restoring - lastCastCount = _lastCastCount; - while (lastCastCount > 0) { - lastCastEntry--; - _gfx->BitsRestore(lastCastEntry->castHandle); - lastCastCount--; - } - } else { - _gfx->BitsShow(rect); - } - - /* - if (!_lastCast->isEmpty()) { - HEAPHANDLE hnode = _lastCast->getFirst(); - sciCast *pCast; - CResView *res; - while (hnode) { - pCast = (sciCast *)heap2Ptr(hnode); - res = (CResView *)ResMgr.ResLoad(SCI_RES_VIEW, pCast->view); - pCast->hSaved = _gfx->SaveBits(pCast->rect, 3); - res->drawCel(pCast->loop, pCast->cel, &pCast->rect, pCast->z, pCast->pal); - hnode = pCast->node.next; - } - _gfx->BitsShow(rect); - // restoring - hnode = _lastCast->getLast(); - while (hnode) { - pCast = (sciCast *)heap2Ptr(hnode); - _gfx->BitsShow(pCast->hSaved); - hnode = pCast->node.prev; - } - */ -} - -void SciGuiAnimate::addToPicDrawCels() { - reg_t curObject; - GuiAnimateEntry *listEntry; - SciGuiView *view = NULL; - GuiAnimateList::iterator listIterator; - GuiAnimateList::iterator listEnd = _list.end(); - - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - curObject = listEntry->object; - - if (listEntry->priority == -1) - listEntry->priority = _gfx->CoordinateToPriority(listEntry->y); - - // Get the corresponding view - view = _gfx->getView(listEntry->viewId); - - // Create rect according to coordinates and given cel - view->getCelRect(listEntry->loopNo, listEntry->celNo, listEntry->x, listEntry->y, listEntry->z, &listEntry->celRect); - - // draw corresponding cel - _gfx->drawCel(listEntry->viewId, listEntry->loopNo, listEntry->celNo, listEntry->celRect, listEntry->priority, listEntry->paletteNo); - if ((listEntry->signal & kSignalIgnoreActor) == 0) { - listEntry->celRect.top = CLIP(_gfx->PriorityToCoordinate(listEntry->priority) - 1, listEntry->celRect.top, listEntry->celRect.bottom - 1); - _gfx->FillRect(listEntry->celRect, SCI_SCREEN_MASK_CONTROL, 0, 0, 15); - } - - listIterator++; - } -} - -void SciGuiAnimate::addToPicDrawView(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) { - SciGuiView *view = _gfx->getView(viewId); - Common::Rect celRect; - - // Create rect according to coordinates and given cel - view->getCelRect(loopNo, celNo, leftPos, topPos, priority, &celRect); - _gfx->drawCel(view, loopNo, celNo, celRect, priority, 0); -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_animate.h b/engines/sci/graphics/gui_animate.h deleted file mode 100644 index 51204ef5ac..0000000000 --- a/engines/sci/graphics/gui_animate.h +++ /dev/null @@ -1,99 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_ANIMATE_H -#define SCI_GUI_ANIMATE_H - -#include "sci/graphics/gui_helpers.h" - -namespace Sci { - -// Flags for the signal selector -enum ViewSignals { - kSignalStopUpdate = 0x0001, - kSignalViewUpdated = 0x0002, - kSignalNoUpdate = 0x0004, - kSignalHidden = 0x0008, - kSignalFixedPriority = 0x0010, - kSignalAlwaysUpdate = 0x0020, - kSignalForceUpdate = 0x0040, - kSignalRemoveView = 0x0080, - kSignalFrozen = 0x0100, - kSignalExtraActor = 0x0200, // unused by us, defines all actors that may be included into the background if speed to slow - kSignalHitObstacle = 0x0400, // used in the actor movement code by kDoBresen() - kSignalDoesntTurn = 0x0800, // used by _k_dirloop() to determine if an actor can turn or not - kSignalNoCycler = 0x1000, // unused by us - kSignalIgnoreHorizon = 0x2000, // unused by us, defines actor that can ignore horizon - kSignalIgnoreActor = 0x4000, - kSignalDisposeMe = 0x8000, - - kSignalStopUpdHack = 0x20000000 // View has been stop-updated (again???) - a hack used by the old GUI code only, for dynamic views -}; - -class SciGuiGfx; -class SciGuiScreen; -class SciGuiPalette; -class SciGuiTransitions; -class SciGuiAnimate { -public: - SciGuiAnimate(EngineState *state, SciGuiGfx *gfx, SciGuiScreen *screen, SciGuiPalette *palette); - ~SciGuiAnimate(); - - // FIXME: Don't store EngineState - void resetEngineState(EngineState *newState) { _s = newState; } - - void disposeLastCast(); - bool invoke(List *list, int argc, reg_t *argv); - void makeSortedList(List *list); - void fill(byte &oldPicNotValid); - void update(); - void drawCels(); - void updateScreen(byte oldPicNotValid); - void restoreAndDelete(int argc, reg_t *argv); - void reAnimate(Common::Rect rect); - void addToPicDrawCels(); - void addToPicDrawView(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 leftPos, int16 topPos, int16 priority, int16 control); - -private: - void init(); - - EngineState *_s; - SciGuiGfx *_gfx; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - - uint16 _listCount; - GuiAnimateEntry *_listData; - GuiAnimateList _list; - - uint16 _lastCastCount; - GuiAnimateEntry *_lastCastData; - - bool _ignoreFastCast; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_controls.cpp b/engines/sci/graphics/gui_controls.cpp deleted file mode 100644 index 073819a654..0000000000 --- a/engines/sci/graphics/gui_controls.cpp +++ /dev/null @@ -1,231 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/event.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_font.h" -#include "sci/graphics/gui_text.h" -#include "sci/graphics/gui_controls.h" - -namespace Sci { - -SciGuiControls::SciGuiControls(SegManager *segMan, SciGuiGfx *gfx, SciGuiText *text) - : _segMan(segMan), _gfx(gfx), _text(text) { - init(); -} - -SciGuiControls::~SciGuiControls() { -} - -void SciGuiControls::init() { - _texteditCursorVisible = false; -} - -const char controlListUpArrow[2] = { 0x18, 0 }; -const char controlListDownArrow[2] = { 0x19, 0 }; - -void SciGuiControls::drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 upperPos, int16 cursorPos, bool isAlias) { - Common::Rect workerRect = rect; - GuiResourceId oldFontId = _text->GetFontId(); - int16 oldPenColor = _gfx->_curPort->penClr; - uint16 fontSize = 0; - int16 i; - const char *listEntry; - int16 listEntryLen; - int16 lastYpos; - - // draw basic window - _gfx->EraseRect(workerRect); - workerRect.grow(1); - _gfx->FrameRect(workerRect); - - // draw UP/DOWN arrows - // we draw UP arrow one pixel lower than sierra did, because it looks nicer. Also the DOWN arrow has one pixel - // line inbetween as well - workerRect.top++; - _text->Box(controlListUpArrow, 0, workerRect, SCI_TEXT_ALIGNMENT_CENTER, 0); - workerRect.top = workerRect.bottom - 10; - _text->Box(controlListDownArrow, 0, workerRect, SCI_TEXT_ALIGNMENT_CENTER, 0); - - // Draw inner lines - workerRect.top = rect.top + 9; - workerRect.bottom -= 10; - _gfx->FrameRect(workerRect); - workerRect.grow(-1); - - _text->SetFont(fontId); - fontSize = _gfx->_curPort->fontHeight; - _gfx->PenColor(_gfx->_curPort->penClr); _gfx->BackColor(_gfx->_curPort->backClr); - workerRect.bottom = workerRect.top + 9; - lastYpos = rect.bottom - fontSize; - - // Write actual text - for (i = upperPos; i < count; i++) { - _gfx->EraseRect(workerRect); - listEntry = entries[i]; - if (listEntry[0]) { - _gfx->MoveTo(workerRect.left, workerRect.top); - listEntryLen = strlen(listEntry); - _text->Draw(listEntry, 0, MIN(maxChars, listEntryLen), oldFontId, oldPenColor); - if ((!isAlias) && (i == cursorPos)) { - _gfx->InvertRect(workerRect); - } - } - workerRect.translate(0, fontSize); - if (workerRect.bottom > lastYpos) - break; - } - - _text->SetFont(oldFontId); -} - -void SciGuiControls::TexteditCursorDraw(Common::Rect rect, const char *text, uint16 curPos) { - int16 textWidth, i; - if (!_texteditCursorVisible) { - textWidth = 0; - for (i = 0; i < curPos; i++) { - textWidth += _text->_font->getCharWidth(text[i]); - } - _texteditCursorRect.left = rect.left + textWidth; - _texteditCursorRect.top = rect.top; - _texteditCursorRect.bottom = _texteditCursorRect.top + _text->_font->getHeight(); - _texteditCursorRect.right = _texteditCursorRect.left + (text[curPos] == 0 ? 1 : _text->_font->getCharWidth(text[curPos])); - _gfx->InvertRect(_texteditCursorRect); - _gfx->BitsShow(_texteditCursorRect); - _texteditCursorVisible = true; - TexteditSetBlinkTime(); - } -} - -void SciGuiControls::TexteditCursorErase() { - if (_texteditCursorVisible) { - _gfx->InvertRect(_texteditCursorRect); - _gfx->BitsShow(_texteditCursorRect); - _texteditCursorVisible = false; - } - TexteditSetBlinkTime(); -} - -void SciGuiControls::TexteditSetBlinkTime() { - _texteditBlinkTime = g_system->getMillis() + (30 * 1000 / 60); -} - -void SciGuiControls::TexteditChange(reg_t controlObject, reg_t eventObject) { - uint16 cursorPos = GET_SEL32V(_segMan, controlObject, cursor); - uint16 maxChars = GET_SEL32V(_segMan, controlObject, max); - reg_t textReference = GET_SEL32(_segMan, controlObject, text); - Common::String text; - uint16 textSize, eventType, eventKey; - bool textChanged = false; - Common::Rect rect; - - if (textReference.isNull()) - error("kEditControl called on object that doesnt have a text reference"); - text = _segMan->getString(textReference); - - if (!eventObject.isNull()) { - textSize = text.size(); - eventType = GET_SEL32V(_segMan, eventObject, type); - - switch (eventType) { - case SCI_EVENT_MOUSE_PRESS: - // TODO: Implement mouse support for cursor change - break; - case SCI_EVENT_KEYBOARD: - eventKey = GET_SEL32V(_segMan, eventObject, message); - switch (eventKey) { - case SCI_KEY_BACKSPACE: - if (cursorPos > 0) { - cursorPos--; text.deleteChar(cursorPos); - textChanged = true; - } - break; - case SCI_KEY_DELETE: - text.deleteChar(cursorPos); - textChanged = true; - break; - case SCI_KEY_HOME: // HOME - cursorPos = 0; textChanged = true; - break; - case SCI_KEY_END: // END - cursorPos = textSize; textChanged = true; - break; - case SCI_KEY_LEFT: // LEFT - if (cursorPos > 0) { - cursorPos--; textChanged = true; - } - break; - case SCI_KEY_RIGHT: // RIGHT - if (cursorPos + 1 <= textSize) { - cursorPos++; textChanged = true; - } - break; - default: - if (eventKey > 31 && eventKey < 256 && textSize < maxChars) { - // insert pressed character - // we check, if there is space left for this character - - text.insertChar(eventKey, cursorPos++); - textChanged = true; - } - break; - } - break; - } - } - - if (textChanged) { - GuiResourceId oldFontId = _text->GetFontId(); - GuiResourceId fontId = GET_SEL32V(_segMan, controlObject, font); - rect = Common::Rect(GET_SEL32V(_segMan, controlObject, nsLeft), GET_SEL32V(_segMan, controlObject, nsTop), - GET_SEL32V(_segMan, controlObject, nsRight), GET_SEL32V(_segMan, controlObject, nsBottom)); - TexteditCursorErase(); - _gfx->EraseRect(rect); - _text->Box(text.c_str(), 0, rect, SCI_TEXT_ALIGNMENT_LEFT, fontId); - _gfx->BitsShow(rect); - _text->SetFont(fontId); - TexteditCursorDraw(rect, text.c_str(), cursorPos); - _text->SetFont(oldFontId); - // Write back string - _segMan->strcpy(textReference, text.c_str()); - } else { - if (g_system->getMillis() >= _texteditBlinkTime) { - _gfx->InvertRect(_texteditCursorRect); - _gfx->BitsShow(_texteditCursorRect); - _texteditCursorVisible = !_texteditCursorVisible; - TexteditSetBlinkTime(); - } - } - - PUT_SEL32V(_segMan, controlObject, cursor, cursorPos); -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_controls.h b/engines/sci/graphics/gui_controls.h deleted file mode 100644 index a2d027d514..0000000000 --- a/engines/sci/graphics/gui_controls.h +++ /dev/null @@ -1,60 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_CONTROLS_H -#define SCI_GUI_CONTROLS_H - -namespace Sci { - -class SciGuiGfx; -class SciGuiFont; -class SciGuiText; -class SciGuiControls { -public: - SciGuiControls(SegManager *segMan, SciGuiGfx *gfx, SciGuiText *text); - ~SciGuiControls(); - - void drawListControl(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 upperPos, int16 cursorPos, bool isAlias); - void TexteditCursorDraw(Common::Rect rect, const char *text, uint16 curPos); - void TexteditCursorErase(); - void TexteditChange(reg_t controlObject, reg_t eventObject); - -private: - void init(); - void TexteditSetBlinkTime(); - - SegManager *_segMan; - SciGuiGfx *_gfx; - SciGuiText *_text; - - // Textedit-Control related - Common::Rect _texteditCursorRect; - bool _texteditCursorVisible; - uint32 _texteditBlinkTime; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_cursor.cpp b/engines/sci/graphics/gui_cursor.cpp deleted file mode 100644 index 603b3f589e..0000000000 --- a/engines/sci/graphics/gui_cursor.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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 "graphics/cursorman.h" -#include "common/util.h" -#include "common/events.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_view.h" -#include "sci/graphics/gui_cursor.h" - -namespace Sci { - -SciGuiCursor::SciGuiCursor(ResourceManager *resMan, SciGuiPalette *palette, SciGuiScreen *screen) - : _resMan(resMan), _palette(palette), _screen(screen) { - - _upscaledHires = _screen->getUpscaledHires(); - // center mouse cursor - setPosition(Common::Point(_screen->_displayWidth / 2, _screen->_displayHeight / 2)); - setMoveZone(Common::Rect(0, 0, _screen->_displayWidth, _screen->_displayHeight)); - - _isVisible = true; -} - -SciGuiCursor::~SciGuiCursor() { - purgeCache(); -} - -void SciGuiCursor::show() { - CursorMan.showMouse(true); - _isVisible = true; -} - -void SciGuiCursor::hide() { - CursorMan.showMouse(false); - _isVisible = false; -} - -bool SciGuiCursor::isVisible() { - return _isVisible; -} - -void SciGuiCursor::purgeCache() { - for (CursorCache::iterator iter = _cachedCursors.begin(); iter != _cachedCursors.end(); ++iter) { - delete iter->_value; - iter->_value = 0; - } - - _cachedCursors.clear(); -} - -void SciGuiCursor::setShape(GuiResourceId resourceId) { - Resource *resource; - byte *resourceData; - Common::Point hotspot = Common::Point(0, 0); - byte colorMapping[4]; - int16 x, y; - byte color; - int16 maskA, maskB; - byte *pOut; - byte *rawBitmap = new byte[SCI_CURSOR_SCI0_HEIGHTWIDTH * SCI_CURSOR_SCI0_HEIGHTWIDTH]; - - if (resourceId == -1) { - // no resourceId given, so we actually hide the cursor - hide(); - delete[] rawBitmap; - return; - } - - // Load cursor resource... - resource = _resMan->findResource(ResourceId(kResourceTypeCursor, resourceId), false); - if (!resource) - error("cursor resource %d not found", resourceId); - if (resource->size != SCI_CURSOR_SCI0_RESOURCESIZE) - error("cursor resource %d has invalid size", resourceId); - - resourceData = resource->data; - // hotspot is specified for SCI1 cursors - hotspot.x = READ_LE_UINT16(resourceData); - hotspot.y = READ_LE_UINT16(resourceData + 2); - // bit 0 of resourceData[3] is set on _colorWhite; // White is also hardcoded - colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; - colorMapping[3] = _palette->matchColor(&_palette->_sysPalette, 170, 170, 170); // Grey - - // Seek to actual data - resourceData += 4; - - pOut = rawBitmap; - for (y = 0; y < SCI_CURSOR_SCI0_HEIGHTWIDTH; y++) { - maskA = READ_LE_UINT16(resourceData + (y << 1)); - maskB = READ_LE_UINT16(resourceData + 32 + (y << 1)); - - for (x = 0; x < SCI_CURSOR_SCI0_HEIGHTWIDTH; x++) { - color = (((maskA << x) & 0x8000) | (((maskB << x) >> 1) & 0x4000)) >> 14; - *pOut++ = colorMapping[color]; - } - } - - CursorMan.replaceCursor(rawBitmap, SCI_CURSOR_SCI0_HEIGHTWIDTH, SCI_CURSOR_SCI0_HEIGHTWIDTH, hotspot.x, hotspot.y, SCI_CURSOR_SCI0_TRANSPARENCYCOLOR); - CursorMan.showMouse(true); - - delete[] rawBitmap; -} - -void SciGuiCursor::setView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot) { - if (_cachedCursors.size() >= MAX_CACHED_CURSORS) - purgeCache(); - - if (!_cachedCursors.contains(viewNum)) - _cachedCursors[viewNum] = new SciGuiView(_resMan, _screen, _palette, viewNum); - - SciGuiView *cursorView = _cachedCursors[viewNum]; - - sciViewCelInfo *celInfo = cursorView->getCelInfo(loopNum, celNum); - int16 width = celInfo->width; - int16 height = celInfo->height; - byte clearKey = celInfo->clearKey; - Common::Point *cursorHotspot = hotspot; - if (!cursorHotspot) - // Compute hotspot from xoffset/yoffset - cursorHotspot = new Common::Point((celInfo->width >> 1) - celInfo->displaceX, celInfo->height - celInfo->displaceY - 1); - - // Eco Quest 1 uses a 1x1 transparent cursor to hide the cursor from the user. Some scalers don't seem to support this - if (width < 2 || height < 2) { - hide(); - delete cursorHotspot; - return; - } - - byte *cursorBitmap = cursorView->getBitmap(loopNum, celNum); - - if (_upscaledHires) { - // Scale cursor by 2x - width *= 2; - height *= 2; - cursorHotspot->x *= 2; - cursorHotspot->y *= 2; - cursorBitmap = new byte[width * height]; - _screen->scale2x(celInfo->rawBitmap, cursorBitmap, celInfo->width, celInfo->height); - } - - CursorMan.replaceCursor(cursorBitmap, width, height, cursorHotspot->x, cursorHotspot->y, clearKey); - - if (_upscaledHires) - delete[] cursorBitmap; - - show(); - - delete cursorHotspot; -} - -void SciGuiCursor::setPosition(Common::Point pos) { - if (!_upscaledHires) { - g_system->warpMouse(pos.x, pos.y); - } else { - g_system->warpMouse(pos.x * 2, pos.y * 2); - } -} - -Common::Point SciGuiCursor::getPosition() { - Common::Point mousePos = g_system->getEventManager()->getMousePos(); - - if (_upscaledHires) { - mousePos.x /= 2; - mousePos.y /= 2; - } - - return mousePos; -} - -void SciGuiCursor::refreshPosition() { - bool clipped = false; - Common::Point mousePoint = getPosition(); - - if (mousePoint.x < _moveZone.left) { - mousePoint.x = _moveZone.left; - clipped = true; - } else if (mousePoint.x >= _moveZone.right) { - mousePoint.x = _moveZone.right - 1; - clipped = true; - } - - if (mousePoint.y < _moveZone.top) { - mousePoint.y = _moveZone.top; - clipped = true; - } else if (mousePoint.y >= _moveZone.bottom) { - mousePoint.y = _moveZone.bottom - 1; - clipped = true; - } - - // FIXME: Do this only when mouse is grabbed? - if (clipped) - setPosition(mousePoint); -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_cursor.h b/engines/sci/graphics/gui_cursor.h deleted file mode 100644 index 293c508bdb..0000000000 --- a/engines/sci/graphics/gui_cursor.h +++ /dev/null @@ -1,84 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_CURSOR_H -#define SCI_GUI_CURSOR_H - -#include "common/hashmap.h" - -namespace Sci { - -#define SCI_CURSOR_SCI0_HEIGHTWIDTH 16 -#define SCI_CURSOR_SCI0_RESOURCESIZE 68 - -#define SCI_CURSOR_SCI0_TRANSPARENCYCOLOR 1 - -#define MAX_CACHED_CURSORS 10 - -class SciGuiView; -class SciGuiPalette; - -typedef Common::HashMap CursorCache; - -class SciGuiCursor { -public: - SciGuiCursor(ResourceManager *resMan, SciGuiPalette *palette, SciGuiScreen *screen); - ~SciGuiCursor(); - - void show(); - void hide(); - bool isVisible(); - void setShape(GuiResourceId resourceId); - void setView(GuiResourceId viewNum, int loopNum, int celNum, Common::Point *hotspot); - void setPosition(Common::Point pos); - Common::Point getPosition(); - void refreshPosition(); - - /** - * Limits the mouse movement to a given rectangle. - * - * @param[in] rect The rectangle - */ - void setMoveZone(Common::Rect zone) { _moveZone = zone; } - -private: - void purgeCache(); - - ResourceManager *_resMan; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - - bool _upscaledHires; - - Common::Rect _moveZone; // Rectangle in which the pointer can move - - CursorCache _cachedCursors; - - bool _isVisible; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_font.cpp b/engines/sci/graphics/gui_font.cpp deleted file mode 100644 index 7416a6a467..0000000000 --- a/engines/sci/graphics/gui_font.cpp +++ /dev/null @@ -1,101 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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 "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_font.h" - -namespace Sci { - -SciGuiFont::SciGuiFont(ResourceManager *resMan, GuiResourceId resourceId) - : _resourceId(resourceId), _resMan(resMan) { - assert(resourceId != -1); - - // Workaround: lsl1sci mixes its own internal fonts with the global - // SCI ones, so we translate them here, by removing their extra bits - if (!resMan->testResource(ResourceId(kResourceTypeFont, resourceId))) - resourceId = resourceId & 0x7ff; - - _resource = resMan->findResource(ResourceId(kResourceTypeFont, resourceId), true); - if (!_resource) { - error("font resource %d not found", resourceId); - } - _resourceData = _resource->data; - - _numChars = READ_LE_UINT16(_resourceData + 2); - _fontHeight = READ_LE_UINT16(_resourceData + 4); - _chars = new Charinfo[_numChars]; - // filling info for every char - for (int16 i = 0; i < _numChars; i++) { - _chars[i].offset = READ_LE_UINT16(_resourceData + 6 + i * 2); - _chars[i].w = _resourceData[_chars[i].offset]; - _chars[i].h = _resourceData[_chars[i].offset + 1]; - } -} - -SciGuiFont::~SciGuiFont() { - delete []_chars; - _resMan->unlockResource(_resource); -} - -GuiResourceId SciGuiFont::getResourceId() { - return _resourceId; -} - -byte SciGuiFont::getHeight() { - return _fontHeight; -} -byte SciGuiFont::getCharWidth(byte chr) { - return chr < _numChars ? _chars[chr].w : 0; -} -byte SciGuiFont::getCharHeight(byte chr) { - return chr < _numChars ? _chars[chr].h : 0; -} -byte *SciGuiFont::getCharData(byte chr) { - return chr < _numChars ? _resourceData + _chars[chr].offset + 2 : 0; -} - -void SciGuiFont::draw(SciGuiScreen *screen, int16 chr, int16 top, int16 left, byte color, bool greyedOutput) { - int charWidth = MIN(getCharWidth(chr), screen->_width - left); - int charHeight = MIN(getCharHeight(chr), 200 - top); - byte b = 0, mask = 0xFF; - int y = top; - - byte *pIn = getCharData(chr); - for (int i = 0; i < charHeight; i++, y++) { - if (greyedOutput) - mask = top++ % 2 ? 0xAA : 0x55; - for (int done = 0; done < charWidth; done++) { - if ((done & 7) == 0) // fetching next data byte - b = *(pIn++) & mask; - if (b & 0x80) // if MSB is set - paint it - screen->putPixel(left + done, y, 1, color, 0, 0); - b = b << 1; - } - } -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_font.h b/engines/sci/graphics/gui_font.h deleted file mode 100644 index fa3909dad9..0000000000 --- a/engines/sci/graphics/gui_font.h +++ /dev/null @@ -1,63 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_FONT_H -#define SCI_GUI_FONT_H - -#include "sci/graphics/gui_helpers.h" - -namespace Sci { - -class SciGuiFont { -public: - SciGuiFont(ResourceManager *resMan, GuiResourceId resourceId); - ~SciGuiFont(); - - GuiResourceId getResourceId(); - byte getHeight(); - byte getCharWidth(byte chr); - byte getCharHeight(byte chr); - byte *getCharData(byte chr); - void draw(SciGuiScreen *screen, int16 chr, int16 top, int16 left, byte color, bool greyedOutput); - -private: - ResourceManager *_resMan; - - Resource *_resource; - GuiResourceId _resourceId; - byte *_resourceData; - - struct Charinfo { - byte w, h; - int16 offset; - }; - byte _fontHeight; - uint16 _numChars; - Charinfo *_chars; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_gfx.cpp b/engines/sci/graphics/gui_gfx.cpp deleted file mode 100644 index f6ccfc486e..0000000000 --- a/engines/sci/graphics/gui_gfx.cpp +++ /dev/null @@ -1,536 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_animate.h" -#include "sci/graphics/gui_font.h" -#include "sci/graphics/gui_picture.h" -#include "sci/graphics/gui_view.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_text.h" - -namespace Sci { - -SciGuiGfx::SciGuiGfx(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, SciGuiScreen *screen, SciGuiPalette *palette) - : _resMan(resMan), _segMan(segMan), _kernel(kernel), _screen(screen), _palette(palette) { -} - -SciGuiGfx::~SciGuiGfx() { - purgeCache(); - - delete _mainPort; - delete _menuPort; -} - -void SciGuiGfx::init(SciGuiText *text) { - _text = text; - - // _mainPort is not known to windowmanager, that's okay according to sierra sci - // its not even used currently in our engine - _mainPort = new GuiPort(0); - SetPort(_mainPort); - OpenPort(_mainPort); - - // _menuPort has actually hardcoded id 0xFFFF. Its not meant to be known to windowmanager according to sierra sci - _menuPort = new GuiPort(0xFFFF); - OpenPort(_menuPort); - _text->SetFont(0); - _menuPort->rect = Common::Rect(0, 0, _screen->_width, _screen->_height); - _menuBarRect = Common::Rect(0, 0, _screen->_width, 9); -} - -void SciGuiGfx::purgeCache() { - for (ViewCache::iterator iter = _cachedViews.begin(); iter != _cachedViews.end(); ++iter) { - delete iter->_value; - iter->_value = 0; - } - - _cachedViews.clear(); -} - -SciGuiView *SciGuiGfx::getView(GuiResourceId viewNum) { - if (_cachedViews.size() >= MAX_CACHED_VIEWS) - purgeCache(); - - if (!_cachedViews.contains(viewNum)) - _cachedViews[viewNum] = new SciGuiView(_resMan, _screen, _palette, viewNum); - - return _cachedViews[viewNum]; -} - -GuiPort *SciGuiGfx::SetPort(GuiPort *newPort) { - GuiPort *oldPort = _curPort; - _curPort = newPort; - return oldPort; -} - -GuiPort *SciGuiGfx::GetPort() { - return _curPort; -} - -void SciGuiGfx::SetOrigin(int16 left, int16 top) { - _curPort->left = left; - _curPort->top = top; -} - -void SciGuiGfx::MoveTo(int16 left, int16 top) { - _curPort->curTop = top; - _curPort->curLeft = left; -} - -void SciGuiGfx::Move(int16 left, int16 top) { - _curPort->curTop += top; - _curPort->curLeft += left; -} - -void SciGuiGfx::OpenPort(GuiPort *port) { - port->fontId = 0; - port->fontHeight = 8; - - GuiPort *tmp = _curPort; - _curPort = port; - _text->SetFont(port->fontId); - _curPort = tmp; - - port->top = 0; - port->left = 0; - port->greyedOutput = false; - port->penClr = 0; - port->backClr = 255; - port->penMode = 0; - port->rect = _bounds; -} - -void SciGuiGfx::PenColor(int16 color) { - _curPort->penClr = color; -} - -void SciGuiGfx::BackColor(int16 color) { - _curPort->backClr = color; -} - -void SciGuiGfx::PenMode(int16 mode) { - _curPort->penMode = mode; -} - -void SciGuiGfx::TextGreyedOutput(bool state) { - _curPort->greyedOutput = state; -} - -int16 SciGuiGfx::GetPointSize() { - return _curPort->fontHeight; -} - -void SciGuiGfx::ClearScreen(byte color) { - FillRect(_curPort->rect, SCI_SCREEN_MASK_ALL, color, 0, 0); -} - -void SciGuiGfx::InvertRect(const Common::Rect &rect) { - int16 oldpenmode = _curPort->penMode; - _curPort->penMode = 2; - FillRect(rect, 1, _curPort->penClr, _curPort->backClr); - _curPort->penMode = oldpenmode; -} - -void SciGuiGfx::EraseRect(const Common::Rect &rect) { - FillRect(rect, 1, _curPort->backClr); -} - -void SciGuiGfx::PaintRect(const Common::Rect &rect) { - FillRect(rect, 1, _curPort->penClr); -} - -void SciGuiGfx::FillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack, byte bControl) { - Common::Rect r = rect; - r.clip(_curPort->rect); - if (r.isEmpty()) // nothing to fill - return; - - int16 oldPenMode = _curPort->penMode; - OffsetRect(r); - int16 x, y; - byte curVisual; - - // Doing visual first - if (drawFlags & SCI_SCREEN_MASK_VISUAL) { - if (oldPenMode == 2) { // invert mode - for (y = r.top; y < r.bottom; y++) { - for (x = r.left; x < r.right; x++) { - curVisual = _screen->getVisual(x, y); - if (curVisual == clrPen) { - _screen->putPixel(x, y, 1, clrBack, 0, 0); - } else if (curVisual == clrBack) { - _screen->putPixel(x, y, 1, clrPen, 0, 0); - } - } - } - } else { // just fill rect with ClrPen - for (y = r.top; y < r.bottom; y++) { - for (x = r.left; x < r.right; x++) { - _screen->putPixel(x, y, 1, clrPen, 0, 0); - } - } - } - } - - if (drawFlags < 2) - return; - drawFlags &= SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL; - - if (oldPenMode != 2) { - for (y = r.top; y < r.bottom; y++) { - for (x = r.left; x < r.right; x++) { - _screen->putPixel(x, y, drawFlags, 0, clrBack, bControl); - } - } - } else { - for (y = r.top; y < r.bottom; y++) { - for (x = r.left; x < r.right; x++) { - _screen->putPixel(x, y, drawFlags, 0, !_screen->getPriority(x, y), !_screen->getControl(x, y)); - } - } - } -} - -void SciGuiGfx::FrameRect(const Common::Rect &rect) { - Common::Rect r; - // left - r = rect; - r.right = rect.left + 1; - PaintRect(r); - // right - r.right = rect.right; - r.left = rect.right - 1; - PaintRect(r); - //top - r.left = rect.left; - r.bottom = rect.top + 1; - PaintRect(r); - //bottom - r.bottom = rect.bottom; - r.top = rect.bottom - 1; - PaintRect(r); -} - -void SciGuiGfx::OffsetRect(Common::Rect &r) { - r.top += _curPort->top; - r.bottom += _curPort->top; - r.left += _curPort->left; - r.right += _curPort->left; -} - -void SciGuiGfx::OffsetLine(Common::Point &start, Common::Point &end) { - start.x += _curPort->left; - start.y += _curPort->top; - end.x += _curPort->left; - end.y += _curPort->top; -} - -void SciGuiGfx::BitsShow(const Common::Rect &rect) { - Common::Rect workerRect(rect.left, rect.top, rect.right, rect.bottom); - workerRect.clip(_curPort->rect); - if (workerRect.isEmpty()) // nothing to show - return; - - OffsetRect(workerRect); - _screen->copyRectToScreen(workerRect); -} - -GuiMemoryHandle SciGuiGfx::BitsSave(const Common::Rect &rect, byte screenMask) { - GuiMemoryHandle memoryId; - byte *memoryPtr; - int size; - - Common::Rect workerRect(rect.left, rect.top, rect.right, rect.bottom); - workerRect.clip(_curPort->rect); - if (workerRect.isEmpty()) // nothing to save - return NULL_REG; - - OffsetRect(workerRect); - - // now actually ask _screen how much space it will need for saving - size = _screen->bitsGetDataSize(workerRect, screenMask); - - memoryId = kalloc(_segMan, "SaveBits()", size); - memoryPtr = kmem(_segMan, memoryId); - _screen->bitsSave(workerRect, screenMask, memoryPtr); - return memoryId; -} - -void SciGuiGfx::BitsGetRect(GuiMemoryHandle memoryHandle, Common::Rect *destRect) { - byte *memoryPtr = NULL; - - if (!memoryHandle.isNull()) { - memoryPtr = kmem(_segMan, memoryHandle); - - if (memoryPtr) { - _screen->bitsGetRect(memoryPtr, destRect); - } - } -} - -void SciGuiGfx::BitsRestore(GuiMemoryHandle memoryHandle) { - byte *memoryPtr = NULL; - - if (!memoryHandle.isNull()) { - memoryPtr = kmem(_segMan, memoryHandle); - - if (memoryPtr) { - _screen->bitsRestore(memoryPtr); - kfree(_segMan, memoryHandle); - } - } -} - -void SciGuiGfx::BitsFree(GuiMemoryHandle memoryHandle) { - if (!memoryHandle.isNull()) { - kfree(_segMan, memoryHandle); - } -} - -void SciGuiGfx::drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId) { - SciGuiPicture *picture = new SciGuiPicture(_resMan, this, _screen, _palette, pictureId); - - // do we add to a picture? if not -> clear screen with white - if (!addToFlag) - ClearScreen(_screen->_colorWhite); - - picture->draw(animationNr, mirroredFlag, addToFlag, paletteId); - delete picture; -} - -// This one is the only one that updates screen! -void SciGuiGfx::drawCel(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, int16 origHeight) { - SciGuiView *view = getView(viewId); - Common::Rect rect; - Common::Rect clipRect; - if (view) { - rect.left = leftPos; - rect.top = topPos; - rect.right = rect.left + view->getWidth(loopNo, celNo); - rect.bottom = rect.top + view->getHeight(loopNo, celNo); - clipRect = rect; - clipRect.clip(_curPort->rect); - if (clipRect.isEmpty()) { // nothing to draw - return; - } - - Common::Rect clipRectTranslated = clipRect; - OffsetRect(clipRectTranslated); - view->draw(rect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo, origHeight); - if (getSciVersion() >= SCI_VERSION_1_1) { - if (!_screen->_picNotValidSci11) - BitsShow(rect); - } else { - if (!_screen->_picNotValid) - BitsShow(rect); - } - } -} - -// This version of drawCel is not supposed to call BitsShow()! -void SciGuiGfx::drawCel(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo) { - SciGuiView *view = getView(viewId); - Common::Rect clipRect; - if (view) { - clipRect = celRect; - clipRect.clip(_curPort->rect); - if (clipRect.isEmpty()) { // nothing to draw - return; - } - - Common::Rect clipRectTranslated = clipRect; - OffsetRect(clipRectTranslated); - view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo); - } -} - -// This version of drawCel is not supposed to call BitsShow()! -void SciGuiGfx::drawCel(SciGuiView *view, GuiViewLoopNo loopNo, GuiViewCelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo) { - Common::Rect clipRect; - clipRect = celRect; - clipRect.clip(_curPort->rect); - if (clipRect.isEmpty()) // nothing to draw - return; - - Common::Rect clipRectTranslated = clipRect; - OffsetRect(clipRectTranslated); - view->draw(celRect, clipRect, clipRectTranslated, loopNo, celNo, priority, paletteNo); -} - -uint16 SciGuiGfx::onControl(uint16 screenMask, Common::Rect rect) { - Common::Rect outRect(rect.left, rect.top, rect.right, rect.bottom); - int16 x, y; - uint16 result = 0; - - outRect.clip(_curPort->rect); - if (outRect.isEmpty()) // nothing to control - return 0; - OffsetRect(outRect); - - if (screenMask & SCI_SCREEN_MASK_PRIORITY) { - for (y = outRect.top; y < outRect.bottom; y++) { - for (x = outRect.left; x < outRect.right; x++) { - result |= 1 << _screen->getPriority(x, y); - } - } - } else { - for (y = outRect.top; y < outRect.bottom; y++) { - for (x = outRect.left; x < outRect.right; x++) { - result |= 1 << _screen->getControl(x, y); - } - } - } - return result; -} - -static inline int sign_extend_byte(int value) { - if (value & 0x80) - return value - 256; - else - return value; -} - -void SciGuiGfx::PriorityBandsInit(int16 bandCount, int16 top, int16 bottom) { - int16 y; - int32 bandSize; - - if (bandCount != -1) - _priorityBandCount = bandCount; - - _priorityTop = top; - _priorityBottom = bottom; - - // Do NOT modify this algo or optimize it anyhow, sierra sci used int32 for calculating the - // priority bands and by using double or anything rounding WILL destroy the result - bandSize = ((_priorityBottom - _priorityTop) * 2000) / _priorityBandCount; - - memset(_priorityBands, 0, sizeof(byte) * _priorityTop); - for (y = _priorityTop; y < _priorityBottom; y++) - _priorityBands[y] = 1 + (((y - _priorityTop) * 2000) / bandSize); - if (_priorityBandCount == 15) { - // When having 15 priority bands, we actually replace band 15 with band 14, cause the original sci interpreter also - // does it that way as well - y = _priorityBottom; - while (_priorityBands[--y] == _priorityBandCount) - _priorityBands[y]--; - } - // We fill space that is left over with the highest band - for (y = _priorityBottom; y < _screen->_height; y++) - _priorityBands[y] = _priorityBandCount; -} - -void SciGuiGfx::PriorityBandsInit(byte *data) { - int i = 0, inx; - byte priority = 0; - - for (inx = 0; inx < 14; inx++) { - priority = *data++; - while (i < priority) - _priorityBands[i++] = inx; - } - while (i < 200) - _priorityBands[i++] = inx; -} - -byte SciGuiGfx::CoordinateToPriority(int16 y) { - if (y < _priorityTop) - return _priorityBands[_priorityTop]; - if (y > _priorityBottom) - return _priorityBands[_priorityBottom]; - return _priorityBands[y]; -} - -int16 SciGuiGfx::PriorityToCoordinate(byte priority) { - int16 y; - if (priority <= _priorityBandCount) { - for (y = 0; y <= _priorityBottom; y++) - if (_priorityBands[y] == priority) - return y; - } - return _priorityBottom; -} - -bool SciGuiGfx::CanBeHereCheckRectList(reg_t checkObject, Common::Rect checkRect, List *list) { - reg_t curAddress = list->first; - Node *curNode = _segMan->lookupNode(curAddress); - reg_t curObject; - uint16 signal; - Common::Rect curRect; - - while (curNode) { - curObject = curNode->value; - if (curObject != checkObject) { - signal = GET_SEL32V(_segMan, curObject, signal); - if ((signal & (kSignalIgnoreActor | kSignalRemoveView | kSignalNoUpdate)) == 0) { - curRect.left = GET_SEL32V(_segMan, curObject, brLeft); - curRect.top = GET_SEL32V(_segMan, curObject, brTop); - curRect.right = GET_SEL32V(_segMan, curObject, brRight); - curRect.bottom = GET_SEL32V(_segMan, curObject, brBottom); - // Check if curRect is within checkRect - if (curRect.right > checkRect.left && curRect.left < checkRect.right && curRect.bottom > checkRect.top && curRect.top < checkRect.bottom) { - return false; - } - } - } - curAddress = curNode->succ; - curNode = _segMan->lookupNode(curAddress); - } - return true; -} - -void SciGuiGfx::SetNowSeen(reg_t objectReference) { - SciGuiView *view = NULL; - Common::Rect celRect(0, 0); - GuiResourceId viewId = (GuiResourceId)GET_SEL32V(_segMan, objectReference, view); - GuiViewLoopNo loopNo = sign_extend_byte((GuiViewLoopNo)GET_SEL32V(_segMan, objectReference, loop)); - GuiViewCelNo celNo = sign_extend_byte((GuiViewCelNo)GET_SEL32V(_segMan, objectReference, cel)); - int16 x = (int16)GET_SEL32V(_segMan, objectReference, x); - int16 y = (int16)GET_SEL32V(_segMan, objectReference, y); - int16 z = 0; - if (_kernel->_selectorCache.z > -1) - z = (int16)GET_SEL32V(_segMan, objectReference, z); - - // now get cel rectangle - view = getView(viewId); - view->getCelRect(loopNo, celNo, x, y, z, &celRect); - - // TODO: sometimes loop is negative. Check what it means - if (lookup_selector(_segMan, objectReference, _kernel->_selectorCache.nsTop, NULL, NULL) == kSelectorVariable) { - PUT_SEL32V(_segMan, objectReference, nsLeft, celRect.left); - PUT_SEL32V(_segMan, objectReference, nsRight, celRect.right); - PUT_SEL32V(_segMan, objectReference, nsTop, celRect.top); - PUT_SEL32V(_segMan, objectReference, nsBottom, celRect.bottom); - } -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_gfx.h b/engines/sci/graphics/gui_gfx.h deleted file mode 100644 index 75750544f1..0000000000 --- a/engines/sci/graphics/gui_gfx.h +++ /dev/null @@ -1,130 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_GFX_H -#define SCI_GUI_GFX_H - -#include "sci/graphics/gui.h" - -#include "common/hashmap.h" - -namespace Sci { - -#define SCI_TEXT_ALIGNMENT_RIGHT -1 -#define SCI_TEXT_ALIGNMENT_CENTER 1 -#define SCI_TEXT_ALIGNMENT_LEFT 0 - -#define MAX_CACHED_VIEWS 50 - -class SciGuiScreen; -class SciGuiPalette; -class SciGuiFont; -class SciGuiPicture; -class SciGuiView; - -typedef Common::HashMap ViewCache; - -class SciGuiGfx { -public: - SciGuiGfx(ResourceManager *resMan, SegManager *segMan, Kernel *kernel, SciGuiScreen *screen, SciGuiPalette *palette); - ~SciGuiGfx(); - - void init(SciGuiText *text); - - byte *GetSegment(byte seg); - void ResetScreen(); - - GuiPort *SetPort(GuiPort *port); - GuiPort *GetPort(); - void SetOrigin(int16 left, int16 top); - void MoveTo(int16 left, int16 top); - void Move(int16 left, int16 top); - void OpenPort(GuiPort *port); - void PenColor(int16 color); - void BackColor(int16 color); - void PenMode(int16 mode); - void TextGreyedOutput(bool state); - int16 GetPointSize(); - - void ClearScreen(byte color = 255); - void InvertRect(const Common::Rect &rect); - void EraseRect(const Common::Rect &rect); - void PaintRect(const Common::Rect &rect); - void FillRect(const Common::Rect &rect, int16 drawFlags, byte clrPen, byte clrBack = 0, byte bControl = 0); - void FrameRect(const Common::Rect &rect); - void OffsetRect(Common::Rect &r); - void OffsetLine(Common::Point &start, Common::Point &end); - - void BitsShow(const Common::Rect &r); - GuiMemoryHandle BitsSave(const Common::Rect &rect, byte screenFlags); - void BitsGetRect(GuiMemoryHandle memoryHandle, Common::Rect *destRect); - void BitsRestore(GuiMemoryHandle memoryHandle); - void BitsFree(GuiMemoryHandle memoryHandle); - - void drawPicture(GuiResourceId pictureId, int16 animationNr, bool mirroredFlag, bool addToFlag, GuiResourceId paletteId); - void drawCel(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, int16 origHeight = -1); - void drawCel(GuiResourceId viewId, GuiViewLoopNo loopNo, GuiViewCelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo); - void drawCel(SciGuiView *view, GuiViewLoopNo loopNo, GuiViewCelNo celNo, Common::Rect celRect, byte priority, uint16 paletteNo); - - uint16 onControl(uint16 screenMask, Common::Rect rect); - - void PriorityBandsInit(int16 bandCount, int16 top, int16 bottom); - void PriorityBandsInit(byte *data); - byte CoordinateToPriority(int16 y); - int16 PriorityToCoordinate(byte priority); - - bool CanBeHereCheckRectList(reg_t checkObject, Common::Rect checkRect, List *list); - - void SetNowSeen(reg_t objectReference); - - GuiPort *_menuPort; - Common::Rect _menuBarRect; - GuiPort *_curPort; - - SciGuiView *getView(GuiResourceId viewNum); - -private: - void purgeCache(); - - ResourceManager *_resMan; - SegManager *_segMan; - Kernel *_kernel; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - SciGuiText *_text; - - Common::Rect _bounds; - GuiPort *_mainPort; - - // Priority Bands related variables - int16 _priorityTop, _priorityBottom, _priorityBandCount; - byte _priorityBands[200]; - - ViewCache _cachedViews; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_helpers.h b/engines/sci/graphics/gui_helpers.h deleted file mode 100644 index 554282e312..0000000000 --- a/engines/sci/graphics/gui_helpers.h +++ /dev/null @@ -1,130 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_HELPERS_H -#define SCI_GUI_HELPERS_H - -#include "common/endian.h" // for READ_LE_UINT16 -#include "common/rect.h" -#include "sci/engine/vm_types.h" - -namespace Sci { - -#define SCI_SHAKE_DIRECTION_VERTICAL 1 -#define SCI_SHAKE_DIRECTION_HORIZONTAL 2 - -typedef int GuiResourceId; // is a resource-number and -1 means no parameter given -typedef reg_t GuiMemoryHandle; -typedef int16 GuiViewLoopNo; -typedef int16 GuiViewCelNo; - -typedef int16 GuiTextAlignment; - -struct GuiPort { - uint16 id; - int16 top, left; - Common::Rect rect; - int16 curTop, curLeft; - int16 fontHeight; - GuiResourceId fontId; - bool greyedOutput; - int16 penClr, backClr; - int16 penMode; - - GuiPort(uint16 theId) : id(theId), top(0), left(0), - curTop(0), curLeft(0), - fontHeight(0), fontId(0), greyedOutput(false), - penClr(0), backClr(0xFF), penMode(0) { - } -}; - -struct GuiWindow : public GuiPort { - Common::Rect dims; // client area of window - Common::Rect restoreRect; // total area of window including borders - uint16 wndStyle; - uint16 saveScreenMask; - reg_t hSaved1; - reg_t hSaved2; - Common::String title; - bool bDrawn; - - GuiWindow(uint16 theId) : GuiPort(theId), - wndStyle(0), saveScreenMask(0), - hSaved1(NULL_REG), hSaved2(NULL_REG), - bDrawn(false) { - } -}; - -struct GuiAnimateEntry { - reg_t object; - GuiResourceId viewId; - GuiViewLoopNo loopNo; - GuiViewCelNo celNo; - int16 paletteNo; - int16 x, y, z; - int16 priority; - uint16 signal; - Common::Rect celRect; - bool showBitsFlag; - GuiMemoryHandle castHandle; -}; -typedef Common::List GuiAnimateList; - -struct GuiColor { - byte used; - byte r, g, b; -}; - -struct GuiPalette { - byte mapping[256]; - uint32 timestamp; - GuiColor colors[256]; - byte intensity[256]; -}; - -struct GuiPalSchedule { - byte from; - uint32 schedule; -}; - -/** Button and frame control flags. */ -enum controlStateFlags { - kControlStateEnabled = 0x0001, ///< 0001 - enabled buttons (used by the interpreter) - kControlStateDisabled = 0x0004, ///< 0010 - grayed out buttons (used by the interpreter) - kControlStateFramed = 0x0008, ///< 1000 - widgets surrounded by a frame (used by the interpreter) - kControlStateDitherFramed = 0x1000 ///< 0001 0000 0000 0000 - widgets surrounded by a dithered frame (used in kgraphics) -}; - -enum ViewType { - kViewUnknown, - kViewEga, - kViewVga, - kViewVga11, - kViewAmiga -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_menu.cpp b/engines/sci/graphics/gui_menu.cpp deleted file mode 100644 index e5ca8be68f..0000000000 --- a/engines/sci/graphics/gui_menu.cpp +++ /dev/null @@ -1,648 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/event.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_helpers.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_cursor.h" -#include "sci/graphics/gui_font.h" -#include "sci/graphics/gui_text.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_menu.h" - -namespace Sci { - -SciGuiMenu::SciGuiMenu(SciEvent *event, SegManager *segMan, SciGuiGfx *gfx, SciGuiText *text, SciGuiScreen *screen, SciGuiCursor *cursor) - : _event(event), _segMan(segMan), _gfx(gfx), _text(text), _screen(screen), _cursor(cursor) { - - _listCount = 0; - // We actually set active item in here and remember last selection of the user - // sierra sci always defaulted to first item every time menu was called via ESC, we dont follow that logic - _curMenuId = 1; - _curItemId = 1; - - _menuSaveHandle = NULL_REG; - _barSaveHandle = NULL_REG; - _oldPort = NULL; -} - -SciGuiMenu::~SciGuiMenu() { - // TODO: deallocate _list and _itemList -} - -void SciGuiMenu::add(Common::String title, Common::String content, reg_t contentVmPtr) { - GuiMenuEntry *menuEntry; - uint16 itemCount = 0; - GuiMenuItemEntry *itemEntry; - int contentSize = content.size(); - int separatorCount; - int curPos, beginPos, endPos, tempPos; - int tagPos, rightAlignedPos, functionPos, altPos, controlPos; - - // Sierra SCI starts with id 1, so we do so as well - _listCount++; - menuEntry = new GuiMenuEntry(_listCount); - menuEntry->text = title; - _list.push_back(menuEntry); - - curPos = 0; - do { - itemCount++; - itemEntry = new GuiMenuItemEntry(_listCount, itemCount); - - beginPos = curPos; - - // Now go through the content till we find end-marker and collect data about it - // ':' is an end-marker for each item - tagPos = 0; rightAlignedPos = 0; - controlPos = 0; altPos = 0; functionPos = 0; - while ((curPos < contentSize) && (content[curPos] != ':')) { - switch (content[curPos]) { - case '=': // Set tag - if (tagPos) - error("multiple tag markers within one menu-item"); - tagPos = curPos; - break; - case '`': // Right-aligned - if (rightAlignedPos) - error("multiple right-aligned markers within one menu-item"); - rightAlignedPos = curPos; - break; - case '^': // Ctrl-prefix - if (controlPos) - error("multiple control markers within one menu-item"); - controlPos = curPos; - break; - case '@': // Alt-prefix - if (altPos) - error("multiple alt markers within one menu-item"); - altPos = curPos; - break; - case '#': // Function-prefix - if (functionPos) - error("multiple function markers within one menu-item"); - functionPos = curPos; - break; - } - curPos++; - } - endPos = curPos; - - // Control/Alt/Function key mapping... - if (controlPos) { - content.setChar(SCI_MENU_REPLACE_ONCONTROL, controlPos); - itemEntry->keyModifier = SCI_KEYMOD_CTRL; - tempPos = controlPos + 1; - if (tempPos >= contentSize) - error("control marker at end of item"); - itemEntry->keyPress = tolower(content[tempPos]); - content.setChar(toupper(content[tempPos]), tempPos); - } - if (altPos) { - content.setChar(SCI_MENU_REPLACE_ONALT, altPos); - itemEntry->keyModifier = SCI_KEYMOD_ALT; - tempPos = altPos + 1; - if (tempPos >= contentSize) - error("alt marker at end of item"); - itemEntry->keyPress = tolower(content[tempPos]); - content.setChar(toupper(content[tempPos]), tempPos); - } - if (functionPos) { - content.setChar(SCI_MENU_REPLACE_ONFUNCTION, functionPos); - tempPos = functionPos + 1; - if (tempPos >= contentSize) - error("function marker at end of item"); - itemEntry->keyPress = content[tempPos]; - switch (content[functionPos + 1]) { - case '1': itemEntry->keyPress = SCI_KEY_F1; break; - case '2': itemEntry->keyPress = SCI_KEY_F2; break; - case '3': itemEntry->keyPress = SCI_KEY_F3; break; - case '4': itemEntry->keyPress = SCI_KEY_F4; break; - case '5': itemEntry->keyPress = SCI_KEY_F5; break; - case '6': itemEntry->keyPress = SCI_KEY_F6; break; - case '7': itemEntry->keyPress = SCI_KEY_F7; break; - case '8': itemEntry->keyPress = SCI_KEY_F8; break; - case '9': itemEntry->keyPress = SCI_KEY_F9; break; - case '0': itemEntry->keyPress = SCI_KEY_F10; break; - default: - error("illegal function key specified"); - } - } - - // Now get all strings - tempPos = endPos; - if (rightAlignedPos) { - tempPos = rightAlignedPos; - } else if (tagPos) { - tempPos = tagPos; - } - curPos = beginPos; - separatorCount = 0; - while (curPos < tempPos) { - switch (content[curPos]) { - case '!': - case '-': - case ' ': - separatorCount++; - } - curPos++; - } - if (separatorCount == tempPos - beginPos) { - itemEntry->separatorLine = true; - } else { - EngineState *s = ((SciEngine *)g_engine)->getEngineState(); // HACK: needed for strSplit() - itemEntry->text = s->strSplit(Common::String(content.c_str() + beginPos, tempPos - beginPos).c_str()); - } - itemEntry->textVmPtr = contentVmPtr; - itemEntry->textVmPtr.offset += beginPos; - - if (rightAlignedPos) { - rightAlignedPos++; - tempPos = endPos; - // Shouldnt be needed at all, cause right aligned occurs after tag (hopefully) - // If no game is found that causes problems, remove this line (29.11.2009) - //if (tagPos && tagPos >= rightAlignedPos) - // tempPos = tagPos; - itemEntry->textRightAligned = Common::String(content.c_str() + rightAlignedPos, tempPos - rightAlignedPos); - } - - if (tagPos) { - tempPos = functionPos + 1; - if (tempPos >= contentSize) - error("tag marker at end of item"); - itemEntry->tag = atoi(content.c_str() + tempPos); - } - - curPos = endPos + 1; - - _itemList.push_back(itemEntry); - } while (curPos < contentSize); -} - -GuiMenuItemEntry *SciGuiMenu::findItem(uint16 menuId, uint16 itemId) { - GuiMenuItemList::iterator listIterator; - GuiMenuItemList::iterator listEnd = _itemList.end(); - GuiMenuItemEntry *listEntry; - - listIterator = _itemList.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - if ((listEntry->menuId == menuId) && (listEntry->id == itemId)) - return listEntry; - - listIterator++; - } - return NULL; -} - -void SciGuiMenu::setAttribute(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value) { - EngineState *s = ((SciEngine *)g_engine)->getEngineState(); // HACK: needed for strSplit() - GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); - if (!itemEntry) - error("Tried to setAttribute() on non-existant menu-item %d:%d", menuId, itemId); - switch (attributeId) { - case SCI_MENU_ATTRIBUTE_ENABLED: - itemEntry->enabled = value.isNull() ? false : true; - break; - case SCI_MENU_ATTRIBUTE_SAID: - itemEntry->saidVmPtr = value; - break; - case SCI_MENU_ATTRIBUTE_TEXT: - itemEntry->text = s->strSplit(_segMan->getString(value).c_str()); - itemEntry->textVmPtr = value; - // We assume here that no script ever creates a separatorLine dynamically - break; - case SCI_MENU_ATTRIBUTE_KEYPRESS: - itemEntry->keyPress = tolower(value.offset); - itemEntry->keyModifier = 0; - // TODO: Find out how modifier is handled - printf("setAttr keypress %X %X\n", value.segment, value.offset); - break; - case SCI_MENU_ATTRIBUTE_TAG: - itemEntry->tag = value.offset; - break; - default: - // Happens when loading a game in LSL3 - attribute 1A - warning("setAttribute() called with unsupported attributeId %X", attributeId); - } -} - -reg_t SciGuiMenu::getAttribute(uint16 menuId, uint16 itemId, uint16 attributeId) { - GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); - if (!itemEntry) - error("Tried to getAttribute() on non-existant menu-item %d:%d", menuId, itemId); - switch (attributeId) { - case SCI_MENU_ATTRIBUTE_ENABLED: - if (itemEntry->enabled) - return make_reg(0, 1); - break; - case SCI_MENU_ATTRIBUTE_SAID: - return itemEntry->saidVmPtr; - case SCI_MENU_ATTRIBUTE_TEXT: - return itemEntry->textVmPtr; - case SCI_MENU_ATTRIBUTE_KEYPRESS: - // TODO: Find out how modifier is handled - return make_reg(0, itemEntry->keyPress); - case SCI_MENU_ATTRIBUTE_TAG: - return make_reg(0, itemEntry->tag); - default: - error("getAttribute() called with unsupported attributeId %X", attributeId); - } - return NULL_REG; -} - -void SciGuiMenu::drawBar() { - GuiMenuEntry *listEntry; - GuiMenuList::iterator listIterator; - GuiMenuList::iterator listEnd = _list.end(); - - // Hardcoded black on white - _gfx->FillRect(_gfx->_menuBarRect, 1, _screen->_colorWhite); - _gfx->PenColor(0); - _gfx->MoveTo(8, 1); - - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - _text->Draw_String(listEntry->text.c_str()); - - listIterator++; - } -} - -// This helper calculates all text widths for all menus/items -void SciGuiMenu::calculateTextWidth() { - GuiMenuList::iterator menuIterator; - GuiMenuList::iterator menuEnd = _list.end(); - GuiMenuEntry *menuEntry; - GuiMenuItemList::iterator itemIterator; - GuiMenuItemList::iterator itemEnd = _itemList.end(); - GuiMenuItemEntry *itemEntry; - int16 dummyHeight; - - menuIterator = _list.begin(); - while (menuIterator != menuEnd) { - menuEntry = *menuIterator; - _text->StringWidth(menuEntry->text.c_str(), 0, menuEntry->textWidth, dummyHeight); - - menuIterator++; - } - - itemIterator = _itemList.begin(); - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - _text->StringWidth(itemEntry->text.c_str(), 0, itemEntry->textWidth, dummyHeight); - _text->StringWidth(itemEntry->textRightAligned.c_str(), 0, itemEntry->textRightAlignedWidth, dummyHeight); - - itemIterator++; - } -} - -reg_t SciGuiMenu::select(reg_t eventObject) { - int16 eventType = GET_SEL32V(_segMan, eventObject, type); - int16 keyPress, keyModifier; - Common::Point mousePosition; - GuiMenuItemList::iterator itemIterator = _itemList.begin(); - GuiMenuItemList::iterator itemEnd = _itemList.end(); - GuiMenuItemEntry *itemEntry = NULL; - bool forceClaimed = false; - EngineState *s; - byte saidSpec[64]; - - switch (eventType) { - case SCI_EVENT_KEYBOARD: - keyPress = GET_SEL32V(_segMan, eventObject, message); - keyModifier = GET_SEL32V(_segMan, eventObject, modifiers); - switch (keyPress) { - case 0: - break; - case SCI_KEY_ESC: - itemEntry = interactiveWithKeyboard(); - forceClaimed = true; - break; - default: - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - if ((itemEntry->keyPress == keyPress) && (itemEntry->keyModifier == keyModifier)) - break; - itemIterator++; - } - if (itemIterator == itemEnd) - itemEntry = NULL; - } - break; - - case SCI_EVENT_SAID: - // HACK: should be removed as soon as said() is cleaned up - s = ((SciEngine *)g_engine)->getEngineState(); - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - - if (!itemEntry->saidVmPtr.isNull()) { - // TODO: get a pointer to saidVmPtr or make said() work on VmPtrs - _segMan->memcpy(saidSpec, itemEntry->saidVmPtr, 64); - if (said(s, saidSpec, 0) != SAID_NO_MATCH) - break; - } - itemIterator++; - } - if (itemIterator == itemEnd) - itemEntry = NULL; - break; - - case SCI_EVENT_MOUSE_PRESS: - mousePosition = _cursor->getPosition(); - if (mousePosition.y < 10) { - itemEntry = interactiveWithMouse(); - forceClaimed = true; - } - break; - } - - if (!_menuSaveHandle.isNull()) { - _gfx->BitsRestore(_menuSaveHandle); - _gfx->BitsShow(_menuRect); - _menuSaveHandle = NULL_REG; - // TODO: Change to ReAnimate() - } - if (!_barSaveHandle.isNull()) { - _gfx->BitsRestore(_barSaveHandle); - _gfx->BitsShow(_gfx->_menuBarRect); - _barSaveHandle = NULL_REG; - } - if (_oldPort) - _gfx->SetPort(_oldPort); - - if ((itemEntry) || (forceClaimed)) - PUT_SEL32(_segMan, eventObject, claimed, make_reg(0, 1)); - if (itemEntry) - return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id)); - return NULL_REG; -} - -GuiMenuItemEntry *SciGuiMenu::interactiveGetItem(uint16 menuId, uint16 itemId, bool menuChanged) { - GuiMenuItemList::iterator itemIterator = _itemList.begin(); - GuiMenuItemList::iterator itemEnd = _itemList.end(); - GuiMenuItemEntry *itemEntry; - GuiMenuItemEntry *firstItemEntry = NULL; - GuiMenuItemEntry *lastItemEntry = NULL; - - // Fixup menuId if needed - if (menuId > _listCount) - menuId = 1; - if (menuId == 0) - menuId = _listCount; - while (itemIterator != itemEnd) { - itemEntry = *itemIterator; - if (itemEntry->menuId == menuId) { - if (itemEntry->id == itemId) - return itemEntry; - if (!firstItemEntry) - firstItemEntry = itemEntry; - if ((!lastItemEntry) || (itemEntry->id > lastItemEntry->id)) - lastItemEntry = itemEntry; - } - itemIterator++; - } - if ((itemId == 0) || (menuChanged)) - return lastItemEntry; - return firstItemEntry; -} - -void SciGuiMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) { - GuiMenuEntry *listEntry; - GuiMenuList::iterator listIterator; - GuiMenuList::iterator listEnd = _list.end(); - GuiMenuItemEntry *listItemEntry; - GuiMenuItemList::iterator listItemIterator; - GuiMenuItemList::iterator listItemEnd = _itemList.end(); - Common::Rect menuTextRect; - uint16 listNr = 0; - int16 maxTextWidth = 0, maxTextRightAlignedWidth = 0; - int16 topPos; - Common::Point pixelPos; - - // Remove menu, if one is displayed - if (!_menuSaveHandle.isNull()) { - _gfx->BitsRestore(_menuSaveHandle); - _gfx->BitsShow(_menuRect); - // TODO: Change to ReAnimate() - } - - // First calculate rect of menu and also invert old and new menu text - _menuRect.top = _gfx->_menuBarRect.bottom; - menuTextRect.top = _gfx->_menuBarRect.top; - menuTextRect.bottom = _gfx->_menuBarRect.bottom; - menuTextRect.left = menuTextRect.right = 7; - listIterator = _list.begin(); - while (listIterator != listEnd) { - listEntry = *listIterator; - listNr++; - menuTextRect.left = menuTextRect.right; - menuTextRect.right += listEntry->textWidth; - if (listNr == newMenuId) - _menuRect.left = menuTextRect.left; - if ((listNr == newMenuId) || (listNr == oldMenuId)) { - menuTextRect.translate(1, 0); - _gfx->InvertRect(menuTextRect); - menuTextRect.translate(-1, 0); - } - - listIterator++; - } - if (oldMenuId != 0) - _gfx->BitsShow(_gfx->_menuBarRect); - - _menuRect.bottom = _menuRect.top + 2; - listItemIterator = _itemList.begin(); - while (listItemIterator != listItemEnd) { - listItemEntry = *listItemIterator; - if (listItemEntry->menuId == newMenuId) { - _menuRect.bottom += _gfx->_curPort->fontHeight; - maxTextWidth = MAX(maxTextWidth, listItemEntry->textWidth); - maxTextRightAlignedWidth = MAX(maxTextRightAlignedWidth, listItemEntry->textRightAlignedWidth); - } - listItemIterator++; - } - _menuRect.right = _menuRect.left + 16 + 4 + 2; - _menuRect.right += maxTextWidth + maxTextRightAlignedWidth; - if (!maxTextRightAlignedWidth) - _menuRect.right -= 5; - - // Save background - _menuSaveHandle = _gfx->BitsSave(_menuRect, SCI_SCREEN_MASK_VISUAL); - - // Do the drawing - _gfx->FillRect(_menuRect, SCI_SCREEN_MASK_VISUAL, 0); - _menuRect.left++; _menuRect.right--; _menuRect.bottom--; - _gfx->FillRect(_menuRect, SCI_SCREEN_MASK_VISUAL, _screen->_colorWhite); - - _menuRect.left += 8; - topPos = _menuRect.top + 1; - listItemIterator = _itemList.begin(); - while (listItemIterator != listItemEnd) { - listItemEntry = *listItemIterator; - if (listItemEntry->menuId == newMenuId) { - if (!listItemEntry->separatorLine) { - _gfx->TextGreyedOutput(listItemEntry->enabled ? false : true); - _gfx->MoveTo(_menuRect.left, topPos); - _text->Draw_String(listItemEntry->text.c_str()); - _gfx->MoveTo(_menuRect.right - listItemEntry->textRightAlignedWidth - 5, topPos); - _text->Draw_String(listItemEntry->textRightAligned.c_str()); - } else { - // We dont 100% follow sierra here, we draw the line from left to right. Looks better - // BTW. SCI1.1 seems to put 2 pixels and then skip one, we don't do this at all (lsl6) - pixelPos.y = topPos + (_gfx->_curPort->fontHeight >> 1) - 1; - pixelPos.x = _menuRect.left - 7; - while (pixelPos.x < (_menuRect.right - 1)) { - _screen->putPixel(pixelPos.x, pixelPos.y, SCI_SCREEN_MASK_VISUAL, 0, 0, 0); - pixelPos.x += 2; - } - } - topPos += _gfx->_curPort->fontHeight; - } - listItemIterator++; - } - _gfx->TextGreyedOutput(false); - - - _menuRect.left -= 8; - _menuRect.left--; _menuRect.right++; _menuRect.bottom++; - _gfx->BitsShow(_menuRect); -} - -void SciGuiMenu::invertMenuSelection(uint16 itemId) { - Common::Rect itemRect = _menuRect; - - itemRect.top += (itemId - 1) * _gfx->_curPort->fontHeight; - itemRect.bottom = itemRect.top + _gfx->_curPort->fontHeight + 1; - itemRect.left++; itemRect.right--; - - _gfx->InvertRect(itemRect); - _gfx->BitsShow(itemRect); -} - -GuiMenuItemEntry *SciGuiMenu::interactiveWithKeyboard() { - sciEvent curEvent; - uint16 newMenuId = _curMenuId; - uint16 newItemId = _curItemId; - GuiMenuItemEntry *curItemEntry = findItem(_curMenuId, _curItemId); - GuiMenuItemEntry *newItemEntry = curItemEntry; - - // We don't 100% follow sierra here: we select last item instead of selecting first item of first menu everytime - - calculateTextWidth(); - _oldPort = _gfx->SetPort(_gfx->_menuPort); - _barSaveHandle = _gfx->BitsSave(_gfx->_menuBarRect, SCI_SCREEN_MASK_VISUAL); - - _gfx->PenColor(0); - _gfx->BackColor(_screen->_colorWhite); - - drawBar(); - drawMenu(0, curItemEntry->menuId); - invertMenuSelection(curItemEntry->id); - _gfx->BitsShow(_gfx->_menuBarRect); - _gfx->BitsShow(_menuRect); - - while (true) { - curEvent = _event->get(SCI_EVENT_ANY); - - switch (curEvent.type) { - case SCI_EVENT_KEYBOARD: - // We don't 100% follow sierra here: - sierra didn't wrap around when changing item id - // - sierra allowed item id to be 0, which didnt make any sense - do { - switch (curEvent.data) { - case SCI_KEY_ESC: - _curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id; - return NULL; - case SCI_KEY_ENTER: - if (curItemEntry->enabled) { - _curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id; - return curItemEntry; - } - break; - case SCI_KEY_LEFT: - newMenuId--; newItemId = 1; - break; - case SCI_KEY_RIGHT: - newMenuId++; newItemId = 1; - break; - case SCI_KEY_UP: - newItemId--; - break; - case SCI_KEY_DOWN: - newItemId++; - break; - } - if ((newMenuId != curItemEntry->menuId) || (newItemId != curItemEntry->id)) { - // Selection changed, fix up new selection if required - newItemEntry = interactiveGetItem(newMenuId, newItemId, newMenuId != curItemEntry->menuId); - newMenuId = newItemEntry->menuId; newItemId = newItemEntry->id; - - // if we do this step again because of a separator line -> don't repeat left/right, but go down - switch (curEvent.data) { - case SCI_KEY_LEFT: - case SCI_KEY_RIGHT: - curEvent.data = SCI_KEY_DOWN; - } - } - } while (newItemEntry->separatorLine); - if ((newMenuId != curItemEntry->menuId) || (newItemId != curItemEntry->id)) { - // paint old and new - if (newMenuId != curItemEntry->menuId) { - // Menu changed, remove cur menu and paint new menu - drawMenu(curItemEntry->menuId, newMenuId); - } else { - invertMenuSelection(curItemEntry->id); - } - invertMenuSelection(newItemId); - - curItemEntry = newItemEntry; - } - break; - - case SCI_EVENT_NONE: - kernel_sleep(_event, 2500 / 1000); - break; - } - } -} - -GuiMenuItemEntry *SciGuiMenu::interactiveWithMouse() { - calculateTextWidth(); - - // TODO - - return NULL; -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_menu.h b/engines/sci/graphics/gui_menu.h deleted file mode 100644 index a396378dc0..0000000000 --- a/engines/sci/graphics/gui_menu.h +++ /dev/null @@ -1,123 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_MENU_H -#define SCI_GUI_MENU_H - -namespace Sci { - -enum { - SCI_MENU_ATTRIBUTE_SAID = 0x6d, - SCI_MENU_ATTRIBUTE_TEXT = 0x6e, - SCI_MENU_ATTRIBUTE_KEYPRESS = 0x6f, - SCI_MENU_ATTRIBUTE_ENABLED = 0x70, - SCI_MENU_ATTRIBUTE_TAG = 0x71 -}; - -enum { - SCI_MENU_REPLACE_ONCONTROL = 0x03, - SCI_MENU_REPLACE_ONALT = 0x02, - SCI_MENU_REPLACE_ONFUNCTION = 'F' -}; - -struct GuiMenuEntry { - uint16 id; - Common::String text; - int16 textWidth; - - GuiMenuEntry(uint16 curId) - : id(curId), textWidth(0) { } -}; -typedef Common::List GuiMenuList; - -struct GuiMenuItemEntry { - uint16 menuId; - uint16 id; - bool enabled; - uint16 tag; - uint16 keyPress; - uint16 keyModifier; - bool separatorLine; - reg_t saidVmPtr; - Common::String text; - reg_t textVmPtr; - int16 textWidth; - Common::String textRightAligned; - int16 textRightAlignedWidth; - - GuiMenuItemEntry(uint16 curMenuId, uint16 curId) - : menuId(curMenuId), id(curId), - enabled(true), tag(0), keyPress(0), keyModifier(0), separatorLine(false), textWidth(0), textRightAlignedWidth(0) { - saidVmPtr = NULL_REG; - textVmPtr = NULL_REG; - } -}; -typedef Common::List GuiMenuItemList; - -class SciGuiMenu { -public: - SciGuiMenu(SciEvent *event, SegManager *segMan, SciGuiGfx *gfx, SciGuiText *text, SciGuiScreen *screen, SciGuiCursor *cursor); - ~SciGuiMenu(); - - void reset(); - void add(Common::String title, Common::String content, reg_t contentVmPtr); - void setAttribute(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value); - reg_t getAttribute(uint16 menuId, uint16 itemId, uint16 attributeId); - - void drawBar(); - reg_t select(reg_t eventObject); - -private: - GuiMenuItemEntry *findItem(uint16 menuId, uint16 itemId); - void calculateTextWidth(); - void drawMenu(uint16 oldMenuId, uint16 newMenuId); - void invertMenuSelection(uint16 itemId); - GuiMenuItemEntry *interactiveWithKeyboard(); - GuiMenuItemEntry *interactiveWithMouse(); - GuiMenuItemEntry *interactiveGetItem(uint16 menuId, uint16 itemId, bool menuChanged); - - SciEvent *_event; - SegManager *_segMan; - SciGuiGfx *_gfx; - SciGuiText *_text; - SciGuiScreen *_screen; - SciGuiCursor *_cursor; - - uint16 _listCount; - GuiMenuList _list; - GuiMenuItemList _itemList; - - uint16 _curMenuId; - uint16 _curItemId; - - GuiPort *_oldPort; - GuiMemoryHandle _barSaveHandle; - GuiMemoryHandle _menuSaveHandle; - Common::Rect _menuRect; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_palette.cpp b/engines/sci/graphics/gui_palette.cpp deleted file mode 100644 index 8e1eea4409..0000000000 --- a/engines/sci/graphics/gui_palette.cpp +++ /dev/null @@ -1,380 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/timer.h" -#include "common/util.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" - -namespace Sci { - -SciGuiPalette::SciGuiPalette(ResourceManager *resMan, SciGuiScreen *screen, bool autoSetPalette) - : _resMan(resMan), _screen(screen) { - int16 color; - - _sysPalette.timestamp = 0; - for (color = 0; color < 256; color++) { - _sysPalette.colors[color].used = 0; - _sysPalette.colors[color].r = 0; - _sysPalette.colors[color].g = 0; - _sysPalette.colors[color].b = 0; - _sysPalette.intensity[color] = 100; - _sysPalette.mapping[color] = color; - } - // Black and white are hardcoded - _sysPalette.colors[0].used = 1; - _sysPalette.colors[255].used = 1; - _sysPalette.colors[255].r = 255; - _sysPalette.colors[255].g = 255; - _sysPalette.colors[255].b = 255; - - if (autoSetPalette) { - if (_resMan->getViewType() == kViewEga) - setEGA(); - else if (_resMan->getViewType() == kViewAmiga) - setAmiga(); - else - setFromResource(999, 2); - } -} - -SciGuiPalette::~SciGuiPalette() { -} - -#define SCI_PAL_FORMAT_CONSTANT 1 -#define SCI_PAL_FORMAT_VARIABLE 0 - -void SciGuiPalette::createFromData(byte *data, GuiPalette *paletteOut) { - int palFormat = 0; - int palOffset = 0; - int palColorStart = 0; - int palColorCount = 0; - int colorNo = 0; - - memset(paletteOut, 0, sizeof(GuiPalette)); - // Setup default mapping - for (colorNo = 0; colorNo < 256; colorNo++) { - paletteOut->mapping[colorNo] = colorNo; - } - if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_LE_UINT16(data + 29) == 0)) { - // SCI0/SCI1 palette - palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT; - palOffset = 260; - palColorStart = 0; palColorCount = 256; - //memcpy(&paletteOut->mapping, data, 256); - } else { - // SCI1.1 palette - palFormat = data[32]; - palOffset = 37; - palColorStart = READ_LE_UINT16(data + 25); palColorCount = READ_LE_UINT16(data + 29); - } - switch (palFormat) { - case SCI_PAL_FORMAT_CONSTANT: - for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { - paletteOut->colors[colorNo].used = 1; - paletteOut->colors[colorNo].r = data[palOffset++]; - paletteOut->colors[colorNo].g = data[palOffset++]; - paletteOut->colors[colorNo].b = data[palOffset++]; - } - break; - case SCI_PAL_FORMAT_VARIABLE: - for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { - paletteOut->colors[colorNo].used = data[palOffset++]; - paletteOut->colors[colorNo].r = data[palOffset++]; - paletteOut->colors[colorNo].g = data[palOffset++]; - paletteOut->colors[colorNo].b = data[palOffset++]; - } - break; - } -} - - -// Will try to set amiga palette by using "spal" file. If not found, we return false -bool SciGuiPalette::setAmiga() { - Common::File file; - int curColor, byte1, byte2; - - if (file.open("spal")) { - for (curColor = 0; curColor < 32; curColor++) { - byte1 = file.readByte(); - byte2 = file.readByte(); - if ((byte1 == EOF) || (byte2 == EOF)) - error("Amiga palette file ends prematurely"); - _sysPalette.colors[curColor].used = 1; - _sysPalette.colors[curColor].r = (byte1 & 0x0F) * 0x11; - _sysPalette.colors[curColor].g = ((byte2 & 0xF0) >> 4) * 0x11; - _sysPalette.colors[curColor].b = (byte2 & 0x0F) * 0x11; - } - file.close(); - setOnScreen(); - return true; - } - return false; -} - -void SciGuiPalette::setEGA() { - int i; - byte color1, color2; - _sysPalette.colors[1].r = 0x000; _sysPalette.colors[1].g = 0x000; _sysPalette.colors[1].b = 0x0AA; - _sysPalette.colors[2].r = 0x000; _sysPalette.colors[2].g = 0x0AA; _sysPalette.colors[2].b = 0x000; - _sysPalette.colors[3].r = 0x000; _sysPalette.colors[3].g = 0x0AA; _sysPalette.colors[3].b = 0x0AA; - _sysPalette.colors[4].r = 0x0AA; _sysPalette.colors[4].g = 0x000; _sysPalette.colors[4].b = 0x000; - _sysPalette.colors[5].r = 0x0AA; _sysPalette.colors[5].g = 0x000; _sysPalette.colors[5].b = 0x0AA; - _sysPalette.colors[6].r = 0x0AA; _sysPalette.colors[6].g = 0x055; _sysPalette.colors[6].b = 0x000; - _sysPalette.colors[7].r = 0x0AA; _sysPalette.colors[7].g = 0x0AA; _sysPalette.colors[7].b = 0x0AA; - _sysPalette.colors[8].r = 0x055; _sysPalette.colors[8].g = 0x055; _sysPalette.colors[8].b = 0x055; - _sysPalette.colors[9].r = 0x055; _sysPalette.colors[9].g = 0x055; _sysPalette.colors[9].b = 0x0FF; - _sysPalette.colors[10].r = 0x055; _sysPalette.colors[10].g = 0x0FF; _sysPalette.colors[10].b = 0x055; - _sysPalette.colors[11].r = 0x055; _sysPalette.colors[11].g = 0x0FF; _sysPalette.colors[11].b = 0x0FF; - _sysPalette.colors[12].r = 0x0FF; _sysPalette.colors[12].g = 0x055; _sysPalette.colors[12].b = 0x055; - _sysPalette.colors[13].r = 0x0FF; _sysPalette.colors[13].g = 0x055; _sysPalette.colors[13].b = 0x0FF; - _sysPalette.colors[14].r = 0x0FF; _sysPalette.colors[14].g = 0x0FF; _sysPalette.colors[14].b = 0x055; - _sysPalette.colors[15].r = 0x0FF; _sysPalette.colors[15].g = 0x0FF; _sysPalette.colors[15].b = 0x0FF; - for (i = 0; i <= 15; i++) { - _sysPalette.colors[i].used = 1; - } - // Now setting colors 16-254 to the correct mix colors that occur when not doing a dithering run on - // finished pictures - for (i = 0x10; i <= 0xFE; i++) { - _sysPalette.colors[i].used = 1; - color1 = i & 0x0F; color2 = i >> 4; - _sysPalette.colors[i].r = (_sysPalette.colors[color1].r >> 1) + (_sysPalette.colors[color2].r >> 1); - _sysPalette.colors[i].g = (_sysPalette.colors[color1].g >> 1) + (_sysPalette.colors[color2].g >> 1); - _sysPalette.colors[i].b = (_sysPalette.colors[color1].b >> 1) + (_sysPalette.colors[color2].b >> 1); - } - setOnScreen(); -} - -bool SciGuiPalette::setFromResource(GuiResourceId resourceId, uint16 flag) { - Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), 0); - GuiPalette palette; - - if (palResource) { - createFromData(palResource->data, &palette); - set(&palette, 2); - return true; - } - return false; -} - -void SciGuiPalette::set(GuiPalette *sciPal, uint16 flag) { - uint32 systime = _sysPalette.timestamp; - if (flag == 2 || sciPal->timestamp != systime) { - merge(sciPal, &_sysPalette, flag); - sciPal->timestamp = _sysPalette.timestamp; - if (_screen->_picNotValid == 0 && systime != _sysPalette.timestamp) - setOnScreen(); - } -} - -void SciGuiPalette::merge(GuiPalette *pFrom, GuiPalette *pTo, uint16 flag) { - uint16 res; - int i,j; - // colors 0 (black) and 255 (white) are not affected by merging - for (i = 1 ; i < 255; i++) { - if (!pFrom->colors[i].used)// color is not used - so skip it - continue; - // forced palette merging or dest color is not used yet - if (flag == 2 || (!pTo->colors[i].used)) { - pTo->colors[i].used = pFrom->colors[i].used; - pTo->colors[i].r = pFrom->colors[i].r; - pTo->colors[i].g = pFrom->colors[i].g; - pTo->colors[i].b = pFrom->colors[i].b; - pFrom->mapping[i] = i; - continue; - } - // is the same color already at the same position? -> match it directly w/o lookup - // this fixes games like lsl1demo/sq5 where the same rgb color exists multiple times and where we would - // otherwise match the wrong one (which would result into the pixels affected (or not) by palette changes) - if ((pTo->colors[i].r == pFrom->colors[i].r) && (pTo->colors[i].g == pFrom->colors[i].g) && (pTo->colors[i].b == pFrom->colors[i].b)) { - pFrom->mapping[i] = i; - continue; - } - // check if exact color could be matched - res = matchColor(pTo, pFrom->colors[i].r, pFrom->colors[i].g, pFrom->colors[i].b); - if (res & 0x8000) { // exact match was found - pFrom->mapping[i] = res & 0xFF; - continue; - } - // no exact match - see if there is an unused color - for (j = 1; j < 256; j++) - if (!pTo->colors[j].used) { - pTo->colors[j].used = pFrom->colors[i].used; - pTo->colors[j].r = pFrom->colors[i].r; - pTo->colors[j].g = pFrom->colors[i].g; - pTo->colors[j].b = pFrom->colors[i].b; - pFrom->mapping[i] = j; - break; - } - // if still no luck - set an approximate color - if (j == 256) { - pFrom->mapping[i] = res & 0xFF; - pTo->colors[res & 0xFF].used |= 0x10; - } - } - pTo->timestamp = g_system->getMillis() * 60 / 1000; -} - -uint16 SciGuiPalette::matchColor(GuiPalette *pPal, byte r, byte g, byte b) { - byte found = 0xFF; - int diff = 0x2FFFF, cdiff; - int16 dr,dg,db; - - for (int i = 1; i < 255; i++) { - if ((!pPal->colors[i].used)) - continue; - dr = pPal->colors[i].r - r; - dg = pPal->colors[i].g - g; - db = pPal->colors[i].b - b; -// minimum squares match - cdiff = (dr*dr) + (dg*dg) + (db*db); -// minimum sum match (Sierra's) -// cdiff = ABS(dr) + ABS(dg) + ABS(db); - if (cdiff < diff) { - if (cdiff == 0) - return i | 0x8000; // setting this flag to indicate exact match - found = i; - diff = cdiff; - } - } - return found; -} - -void SciGuiPalette::getSys(GuiPalette *pal) { - if (pal != &_sysPalette) - memcpy(pal, &_sysPalette,sizeof(GuiPalette)); -} - -void SciGuiPalette::setOnScreen() { -// if (pal != &_sysPalette) -// memcpy(&_sysPalette,pal,sizeof(GuiPalette)); - _screen->setPalette(&_sysPalette); -} - -void SciGuiPalette::setFlag(uint16 fromColor, uint16 toColor, uint16 flag) { - uint16 colorNr; - for (colorNr = fromColor; colorNr < toColor; colorNr++) { - _sysPalette.colors[colorNr].used |= flag; - } -} - -void SciGuiPalette::unsetFlag(uint16 fromColor, uint16 toColor, uint16 flag) { - uint16 colorNr; - for (colorNr = fromColor; colorNr < toColor; colorNr++) { - _sysPalette.colors[colorNr].used &= ~flag; - } -} - -void SciGuiPalette::setIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette) { - memset(&_sysPalette.intensity[0] + fromColor, intensity, toColor - fromColor); - if (setPalette) - setOnScreen(); -} - -// Returns true, if palette got changed -bool SciGuiPalette::animate(byte fromColor, byte toColor, int speed) { - GuiColor col; - //byte colorNr; - int16 colorCount; - uint32 now = g_system->getMillis() * 60 / 1000; - - // search for sheduled animations with the same 'from' value - // schedule animation... - int scheduleCount = _schedules.size(); - int scheduleNr; - for (scheduleNr = 0; scheduleNr < scheduleCount; scheduleNr++) { - if (_schedules[scheduleNr].from == fromColor) - break; - } - if (scheduleNr == scheduleCount) { - // adding a new schedule - GuiPalSchedule newSchedule; - newSchedule.from = fromColor; - newSchedule.schedule = now + ABS(speed); - _schedules.push_back(newSchedule); - scheduleCount++; - } - - for (scheduleNr = 0; scheduleNr < scheduleCount; scheduleNr++) { - if (_schedules[scheduleNr].from == fromColor) { - if (_schedules[scheduleNr].schedule <= now) { - if (speed > 0) { - // TODO: Not really sure about this, sierra sci seems to do exactly this here - col = _sysPalette.colors[fromColor]; - if (fromColor < toColor) { - colorCount = toColor - fromColor - 1; - memmove(&_sysPalette.colors[fromColor], &_sysPalette.colors[fromColor + 1], colorCount * sizeof(GuiColor)); - } - _sysPalette.colors[toColor - 1] = col; - } else { - col = _sysPalette.colors[toColor - 1]; - if (fromColor < toColor) { - colorCount = toColor - fromColor - 1; - memmove(&_sysPalette.colors[fromColor + 1], &_sysPalette.colors[fromColor], colorCount * sizeof(GuiColor)); - } - _sysPalette.colors[fromColor] = col; - } - // removing schedule - _schedules[scheduleNr].schedule = now + ABS(speed); - // TODO: Not sure when sierra actually removes a schedule - //_schedules.remove_at(scheduleNr); - return true; - } - return false; - } - } - return false; -} - -// palVary -// init - only does, if palVaryOn == false -// target, start, new palette allocation -// palVaryOn = true -// palDirection = 1 -// palStop = 64 -// palTime = from caller -// copy resource palette to target -// init target palette (used = 1 on all colors, color 0 = RGB 0, 0, 0 color 255 = RGB 0xFF, 0xFF, 0xFF -// copy sysPalette to startPalette -// init new palette like target palette -// palPercent = 1 -// do various things -// return 1 -// deinit - unloads target palette, kills timer hook, disables palVaryOn -// pause - counts up or down, if counter != 0 -> signal wont get counted up by timer -// will only count down to 0 -// -// Restarting game -// palVary = false -// palPercent = 0 -// call palVary deinit -// -// Saving/restoring -// need to save start and target-palette, when palVaryOn = true - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_palette.h b/engines/sci/graphics/gui_palette.h deleted file mode 100644 index d785e418e1..0000000000 --- a/engines/sci/graphics/gui_palette.h +++ /dev/null @@ -1,66 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_PALETTE_H -#define SCI_GUI_PALETTE_H - -#include "sci/graphics/gui_helpers.h" - -namespace Sci { - -class SciGuiScreen; -class SciGuiPalette { -public: - SciGuiPalette(ResourceManager *resMan, SciGuiScreen *screen, bool autoSetPalette = true); - ~SciGuiPalette(); - - void createFromData(byte *data, GuiPalette *paletteOut); - bool setAmiga(); - void setEGA(); - bool setFromResource(GuiResourceId resourceId, uint16 flag); - void set(GuiPalette *sciPal, uint16 flag); - void merge(GuiPalette *pFrom, GuiPalette *pTo, uint16 flag); - uint16 matchColor(GuiPalette *pPal, byte r, byte g, byte b); - void getSys(GuiPalette *pal); - - void setOnScreen(); - - void setFlag(uint16 fromColor, uint16 toColor, uint16 flag); - void unsetFlag(uint16 fromColor, uint16 toColor, uint16 flag); - void setIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette); - bool animate(byte fromColor, byte toColor, int speed); - - GuiPalette _sysPalette; - -private: - SciGuiScreen *_screen; - ResourceManager *_resMan; - - Common::Array _schedules; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_picture.cpp b/engines/sci/graphics/gui_picture.cpp deleted file mode 100644 index 8505233a2c..0000000000 --- a/engines/sci/graphics/gui_picture.cpp +++ /dev/null @@ -1,973 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/stack.h" -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_picture.h" - -namespace Sci { - -SciGuiPicture::SciGuiPicture(ResourceManager *resMan, SciGuiGfx *gfx, SciGuiScreen *screen, SciGuiPalette *palette, GuiResourceId resourceId) - : _resMan(resMan), _gfx(gfx), _screen(screen), _palette(palette), _resourceId(resourceId) { - assert(resourceId != -1); - initData(resourceId); -} - -SciGuiPicture::~SciGuiPicture() { -} - -void SciGuiPicture::initData(GuiResourceId resourceId) { - _resource = _resMan->findResource(ResourceId(kResourceTypePic, resourceId), false); - if (!_resource) { - error("picture resource %d not found", resourceId); - } -} - -GuiResourceId SciGuiPicture::getResourceId() { - return _resourceId; -} - -// TODO: subclass this -void SciGuiPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) { - uint16 headerSize; - - _animationNr = animationNr; - _mirroredFlag = mirroredFlag; - _addToFlag = addToFlag; - _EGApaletteNo = EGApaletteNo; - _priority = 0; - - headerSize = READ_LE_UINT16(_resource->data); - switch (headerSize) { - case 0x26: // SCI 1.1 VGA picture - drawSci11Vga(); - break; -#ifdef ENABLE_SCI32 - case 0x0e: // SCI32 VGA picture - drawSci32Vga(); - break; -#endif - default: - // VGA, EGA or Amiga vector data - drawVectorData(_resource->data, _resource->size); - } -} - -void SciGuiPicture::reset() { - int16 x, y; - for (y = _gfx->GetPort()->top; y < _screen->_height; y++) { - for (x = 0; x < _screen->_width; x++) { - _screen->putPixel(x, y, SCI_SCREEN_MASK_ALL, 255, 0, 0); - } - } -} - -void SciGuiPicture::drawSci11Vga() { - byte *inbuffer = _resource->data; - int size = _resource->size; - int has_cel = READ_LE_UINT16(inbuffer + 4); - int vector_dataPos = READ_LE_UINT16(inbuffer + 16); - int vector_size = size - vector_dataPos; - int palette_data_ptr = READ_LE_UINT16(inbuffer + 28); - int cel_headerPos = READ_LE_UINT16(inbuffer + 32); - int cel_RlePos = READ_LE_UINT16(inbuffer + cel_headerPos + 24); - int cel_LiteralPos = READ_LE_UINT16(inbuffer + cel_headerPos + 28); - GuiPalette palette; - - // Create palette and set it - _palette->createFromData(inbuffer + palette_data_ptr, &palette); - _palette->set(&palette, 2); - - // display Cel-data - if (has_cel) { - drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false); - } - - // process vector data - drawVectorData(inbuffer + vector_dataPos, vector_size); -} - -#ifdef ENABLE_SCI32 -void SciGuiPicture::drawSci32Vga() { - byte *inbuffer = _resource->data; - int size = _resource->size; - int header_size = READ_LE_UINT16(inbuffer); - int palette_data_ptr = READ_LE_UINT16(inbuffer + 6); - int cel_headerPos = header_size; - int cel_RlePos = READ_LE_UINT16(inbuffer + cel_headerPos + 24); - int cel_LiteralPos = READ_LE_UINT16(inbuffer + cel_headerPos + 28); - GuiPalette palette; - - // Create palette and set it - _palette->createFromData(inbuffer + palette_data_ptr, &palette); - _palette->set(&palette, 2); - - drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, true); - - // TODO: find out where priority map is stored -} -#endif - -void SciGuiPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header) { - byte *celBitmap = NULL; - byte *ptr = NULL; - byte *headerPtr = inbuffer + headerPos; - byte *rlePtr = inbuffer + rlePos; - byte *literalPtr = inbuffer + literalPos; - uint16 width = READ_LE_UINT16(headerPtr + 0); - uint16 height = READ_LE_UINT16(headerPtr + 2); - int16 displaceX, displaceY; - byte priority = _addToFlag ? _priority : 0; - byte clearColor; - bool compression = true; - byte curByte, runLength; - int16 y, lastY, x, leftX, rightX; - uint16 pixelNr, pixelCount; - -#ifdef ENABLE_SCI32 - if (!hasSci32Header) { -#endif - displaceX = (signed char)headerPtr[4]; - displaceY = (unsigned char)headerPtr[5]; - clearColor = headerPtr[6]; -#ifdef ENABLE_SCI32 - } else { - displaceX = READ_LE_UINT16(headerPtr + 4); // probably signed?!? - displaceY = READ_LE_UINT16(headerPtr + 6); // probably signed?!? - clearColor = headerPtr[8]; - if (headerPtr[9] == 0) - compression = false; - } -#endif - - if (displaceX || displaceY) - error("unsupported embedded cel-data in picture"); - - pixelCount = width * height; - celBitmap = new byte[pixelCount]; - if (!celBitmap) - error("Unable to allocate temporary memory for picture drawing"); - - if (compression) { - // We will unpack cel-data into a temporary buffer and then plot it to screen - // That needs to be done cause a mirrored picture may be requested - memset(celBitmap, clearColor, pixelCount); - pixelNr = 0; - ptr = celBitmap; - if (literalPos == 0) { - // decompression for data that has only one stream (vecor embedded view data) - switch (_resMan->getViewType()) { - case kViewEga: - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - runLength = curByte >> 4; - memset(ptr + pixelNr, curByte & 0x0F, MIN(runLength, pixelCount - pixelNr)); - pixelNr += runLength; - } - break; - case kViewVga: - case kViewVga11: - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - runLength = curByte & 0x3F; - switch (curByte & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNr < pixelCount) - ptr[pixelNr++] = *rlePtr++; - break; - case 0x80: // fill with color - memset(ptr + pixelNr, *rlePtr++, MIN(runLength, pixelCount - pixelNr)); - pixelNr += runLength; - break; - case 0xC0: // fill with transparent - pixelNr += runLength; - break; - } - } - break; - case kViewAmiga: - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - if (curByte & 0x07) { // fill with color - runLength = curByte & 0x07; - curByte = curByte >> 3; - while (runLength-- && pixelNr < pixelCount) { - ptr[pixelNr++] = curByte; - } - } else { // fill with transparent - runLength = curByte >> 3; - pixelNr += runLength; - } - } - break; - - default: - error("Unsupported picture viewtype"); - } - } else { - // decompression for data that has two separate streams (probably SCI 1.1 picture) - while (pixelNr < pixelCount) { - curByte = *rlePtr++; - runLength = curByte & 0x3F; - switch (curByte & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNr < pixelCount) - ptr[pixelNr++] = *literalPtr++; - break; - case 0x80: // fill with color - memset(ptr + pixelNr, *literalPtr++, MIN(runLength, pixelCount - pixelNr)); - pixelNr += runLength; - break; - case 0xC0: // fill with transparent - pixelNr += runLength; - break; - } - } - } - } else { - // No compression (some SCI32 pictures) - memcpy(celBitmap, rlePtr, pixelCount); - } - - // Set initial vertical coordinate by using current port - y = callerY + _gfx->GetPort()->top; - lastY = MIN(height + y, _gfx->GetPort()->rect.bottom + _gfx->GetPort()->top); - leftX = callerX + _gfx->GetPort()->left; - rightX = MIN(width + leftX, _gfx->GetPort()->rect.right + _gfx->GetPort()->left); - - // Change clearcolor to white, if we dont add to an existing picture. That way we will paint everything on screen - // but white and that wont matter because the screen is supposed to be already white. It seems that most (if not all) - // SCI1.1 games use color 0 as transparency and SCI1 games use color 255 as transparency. Sierra SCI seems to paint - // the whole data to screen and wont skip over transparent pixels. So this will actually make it work like Sierra - if (!_addToFlag) - clearColor = _screen->_colorWhite; - - ptr = celBitmap; - if (!_mirroredFlag) { - // Draw bitmap to screen - x = leftX; - while (y < lastY) { - curByte = *ptr++; - if ((curByte != clearColor) && (priority >= _screen->getPriority(x, y))) - _screen->putPixel(x, y, SCI_SCREEN_MASK_VISUAL | SCI_SCREEN_MASK_PRIORITY, curByte, priority, 0); - x++; - if (x >= rightX) { - x = leftX; y++; - } - } - } else { - // Draw bitmap to screen (mirrored) - x = rightX - 1; - while (y < lastY) { - curByte = *ptr++; - if ((curByte != clearColor) && (priority >= _screen->getPriority(x, y))) - _screen->putPixel(x, y, SCI_SCREEN_MASK_VISUAL | SCI_SCREEN_MASK_PRIORITY, curByte, priority, 0); - if (x == leftX) { - x = rightX; y++; - } - x--; - } - } - delete[] celBitmap; -} - -enum { - PIC_OP_SET_COLOR = 0xf0, - PIC_OP_DISABLE_VISUAL = 0xf1, - PIC_OP_SET_PRIORITY = 0xf2, - PIC_OP_DISABLE_PRIORITY = 0xf3, - PIC_OP_SHORT_PATTERNS = 0xf4, - PIC_OP_MEDIUM_LINES = 0xf5, - PIC_OP_LONG_LINES = 0xf6, - PIC_OP_SHORT_LINES = 0xf7, - PIC_OP_FILL = 0xf8, - PIC_OP_SET_PATTERN = 0xf9, - PIC_OP_ABSOLUTE_PATTERN = 0xfa, - PIC_OP_SET_CONTROL = 0xfb, - PIC_OP_DISABLE_CONTROL = 0xfc, - PIC_OP_MEDIUM_PATTERNS = 0xfd, - PIC_OP_OPX = 0xfe, - PIC_OP_TERMINATE = 0xff -}; -#define PIC_OP_FIRST PIC_OP_SET_COLOR - -enum { - PIC_OPX_EGA_SET_PALETTE_ENTRIES = 0, - PIC_OPX_EGA_SET_PALETTE = 1, - PIC_OPX_EGA_MONO0 = 2, - PIC_OPX_EGA_MONO1 = 3, - PIC_OPX_EGA_MONO2 = 4, - PIC_OPX_EGA_MONO3 = 5, - PIC_OPX_EGA_MONO4 = 6, - PIC_OPX_EGA_EMBEDDED_VIEW = 7, - PIC_OPX_EGA_SET_PRIORITY_TABLE = 8 -}; - -enum { - PIC_OPX_VGA_SET_PALETTE_ENTRIES = 0, - PIC_OPX_VGA_EMBEDDED_VIEW = 1, - PIC_OPX_VGA_SET_PALETTE = 2, - PIC_OPX_VGA_PRIORITY_TABLE_EQDIST = 3, - PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT = 4 -}; - -#define PIC_EGAPALETTE_COUNT 4 -#define PIC_EGAPALETTE_SIZE 40 -#define PIC_EGAPALETTE_TOTALSIZE PIC_EGAPALETTE_COUNT*PIC_EGAPALETTE_SIZE -#define PIC_EGAPRIORITY_SIZE PIC_EGAPALETTE_SIZE - -static const byte vector_defaultEGApalette[PIC_EGAPALETTE_SIZE] = { - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, - 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x88, - 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, - 0x88, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, - 0x08, 0x91, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x88 -}; - -static const byte vector_defaultEGApriority[PIC_EGAPRIORITY_SIZE] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 -}; - -void SciGuiPicture::drawVectorData(byte *data, int dataSize) { - byte pic_op; - byte pic_color = _screen->_colorDefaultVectorData; - byte pic_priority = 255, pic_control = 255; - int16 x = 0, y = 0, oldx, oldy; - byte EGApalettes[PIC_EGAPALETTE_TOTALSIZE] = {0}; - byte *EGApalette = &EGApalettes[_EGApaletteNo * PIC_EGAPALETTE_SIZE]; - byte EGApriority[PIC_EGAPRIORITY_SIZE] = {0}; - bool isEGA = false; - int curPos = 0; - uint16 size; - byte pixel; - int i; - GuiPalette palette; - int16 pattern_Code = 0, pattern_Texture = 0; - - memset(&palette, 0, sizeof(palette)); - - if (_EGApaletteNo >= PIC_EGAPALETTE_COUNT) - _EGApaletteNo = 0; - - if (_resMan->getViewType() == kViewEga) { - isEGA = true; - // setup default mapping tables - for (i = 0; i < PIC_EGAPALETTE_TOTALSIZE; i += PIC_EGAPALETTE_SIZE) - memcpy(&EGApalettes[i], &vector_defaultEGApalette, sizeof(vector_defaultEGApalette)); - memcpy(&EGApriority, &vector_defaultEGApriority, sizeof(vector_defaultEGApriority)); - } - - // Drawing - while (curPos < dataSize) { - //warning("%X at %d", data[curPos], curPos); - switch (pic_op = data[curPos++]) { - case PIC_OP_SET_COLOR: - pic_color = data[curPos++]; - if (isEGA) { - pic_color = EGApalette[pic_color]; - pic_color ^= pic_color << 4; - } - break; - case PIC_OP_DISABLE_VISUAL: - pic_color = 0xFF; - break; - - case PIC_OP_SET_PRIORITY: - pic_priority = data[curPos++] & 0x0F; - if (isEGA) { - pic_priority = EGApriority[pic_priority]; - } - break; - case PIC_OP_DISABLE_PRIORITY: - pic_priority = 255; - break; - - case PIC_OP_SET_CONTROL: - pic_control = data[curPos++] & 0x0F; - break; - case PIC_OP_DISABLE_CONTROL: - pic_control = 255; - break; - - case PIC_OP_SHORT_LINES: // short line - vectorGetAbsCoords(data, curPos, x, y); - while (vectorIsNonOpcode(data[curPos])) { - oldx = x; oldy = y; - vectorGetRelCoords(data, curPos, x, y); - Common::Point startPoint(oldx, oldy); - Common::Point endPoint(x, y); - _gfx->OffsetLine(startPoint, endPoint); - _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); - } - break; - case PIC_OP_MEDIUM_LINES: // medium line - vectorGetAbsCoords(data, curPos, x, y); - while (vectorIsNonOpcode(data[curPos])) { - oldx = x; oldy = y; - vectorGetRelCoordsMed(data, curPos, x, y); - Common::Point startPoint(oldx, oldy); - Common::Point endPoint(x, y); - _gfx->OffsetLine(startPoint, endPoint); - _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); - } - break; - case PIC_OP_LONG_LINES: // long line - vectorGetAbsCoords(data, curPos, x, y); - while (vectorIsNonOpcode(data[curPos])) { - oldx = x; oldy = y; - vectorGetAbsCoords(data, curPos, x, y); - Common::Point startPoint(oldx, oldy); - Common::Point endPoint(x, y); - _gfx->OffsetLine(startPoint, endPoint); - _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); - } - break; - - case PIC_OP_FILL: //fill - while (vectorIsNonOpcode(data[curPos])) { - vectorGetAbsCoords(data, curPos, x, y); - vectorFloodFill(x, y, pic_color, pic_priority, pic_control); - } - break; - - case PIC_OP_SET_PATTERN: - pattern_Code = data[curPos++]; - break; - case PIC_OP_SHORT_PATTERNS: - vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); - vectorGetAbsCoords(data, curPos, x, y); - vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); - while (vectorIsNonOpcode(data[curPos])) { - vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); - vectorGetRelCoords(data, curPos, x, y); - vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); - } - break; - case PIC_OP_MEDIUM_PATTERNS: - vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); - vectorGetAbsCoords(data, curPos, x, y); - vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); - while (vectorIsNonOpcode(data[curPos])) { - vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); - vectorGetRelCoordsMed(data, curPos, x, y); - vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); - } - break; - case PIC_OP_ABSOLUTE_PATTERN: - while (vectorIsNonOpcode(data[curPos])) { - vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); - vectorGetAbsCoords(data, curPos, x, y); - vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); - } - break; - - case PIC_OP_OPX: // Extended functions - if (isEGA) { - switch (pic_op = data[curPos++]) { - case PIC_OPX_EGA_SET_PALETTE_ENTRIES: - while (vectorIsNonOpcode(data[curPos])) { - pixel = data[curPos++]; - if (pixel >= PIC_EGAPALETTE_TOTALSIZE) { - error("picture trying to write to invalid EGA-palette"); - } - EGApalettes[pixel] = data[curPos++]; - } - break; - case PIC_OPX_EGA_SET_PALETTE: - pixel = data[curPos++]; - if (pixel >= PIC_EGAPALETTE_COUNT) { - error("picture trying to write to invalid palette %d", (int)pixel); - } - pixel *= PIC_EGAPALETTE_SIZE; - for (i = 0; i < PIC_EGAPALETTE_SIZE; i++) { - EGApalettes[pixel + i] = data[curPos++]; - } - break; - case PIC_OPX_EGA_MONO0: - curPos += 41; - break; - case PIC_OPX_EGA_MONO1: - case PIC_OPX_EGA_MONO3: - curPos++; - break; - case PIC_OPX_EGA_MONO2: - case PIC_OPX_EGA_MONO4: - break; - case PIC_OPX_EGA_EMBEDDED_VIEW: - vectorGetAbsCoordsNoMirror(data, curPos, x, y); - size = READ_LE_UINT16(data + curPos); curPos += 2; - _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well - drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false); - curPos += size; - break; - case PIC_OPX_EGA_SET_PRIORITY_TABLE: - _gfx->PriorityBandsInit(data + curPos); - curPos += 14; - break; - default: - error("Unsupported sci1 extended pic-operation %X", pic_op); - } - } else { - switch (pic_op = data[curPos++]) { - case PIC_OPX_VGA_SET_PALETTE_ENTRIES: - while (vectorIsNonOpcode(data[curPos])) { - curPos++; // skip commands - } - break; - case PIC_OPX_VGA_SET_PALETTE: - curPos += 256 + 4; // Skip over mapping and timestamp - for (i = 0; i < 256; i++) { - palette.colors[i].used = data[curPos++]; - palette.colors[i].r = data[curPos++]; palette.colors[i].g = data[curPos++]; palette.colors[i].b = data[curPos++]; - } - _palette->set(&palette, 2); - break; - case PIC_OPX_VGA_EMBEDDED_VIEW: // draw cel - vectorGetAbsCoordsNoMirror(data, curPos, x, y); - size = READ_LE_UINT16(data + curPos); curPos += 2; - _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well - drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false); - curPos += size; - break; - case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST: - _gfx->PriorityBandsInit(-1, READ_LE_UINT16(data + curPos), READ_LE_UINT16(data + curPos + 2)); - curPos += 4; - break; - case PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT: - _gfx->PriorityBandsInit(data + curPos); - curPos += 14; - break; - default: - error("Unsupported sci1 extended pic-operation %X", pic_op); - } - } - break; - case PIC_OP_TERMINATE: - _priority = pic_priority; - // Dithering EGA pictures - if (isEGA) { - _screen->dither(_addToFlag); - } - return; - default: - error("Unsupported pic-operation %X", pic_op); - } - //printf("picop %X\n", pic_op); - // for debug purposes - //_screen->copyToScreen(); - //g_system->updateScreen(); - //g_system->delayMillis(500); - } - error("picture vector data without terminator"); -} - -bool SciGuiPicture::vectorIsNonOpcode(byte pixel) { - if (pixel >= PIC_OP_FIRST) - return false; - return true; -} - -void SciGuiPicture::vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y) { - byte pixel = data[curPos++]; - x = data[curPos++] + ((pixel & 0xF0) << 4); - y = data[curPos++] + ((pixel & 0x0F) << 8); - if (_mirroredFlag) x = 319 - x; -} - -void SciGuiPicture::vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y) { - byte pixel = data[curPos++]; - x = data[curPos++] + ((pixel & 0xF0) << 4); - y = data[curPos++] + ((pixel & 0x0F) << 8); -} - -void SciGuiPicture::vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y) { - byte pixel = data[curPos++]; - if (pixel & 0x80) { - x -= ((pixel >> 4) & 7) * (_mirroredFlag ? -1 : 1); - } else { - x += (pixel >> 4) * (_mirroredFlag ? -1 : 1); - } - if (pixel & 0x08) { - y -= (pixel & 7); - } else { - y += (pixel & 7); - } -} - -void SciGuiPicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y) { - byte pixel = data[curPos++]; - if (pixel & 0x80) { - y -= (pixel & 0x7F); - } else { - y += pixel; - } - pixel = data[curPos++]; - if (pixel & 0x80) { - x -= (128 - (pixel & 0x7F)) * (_mirroredFlag ? -1 : 1); - } else { - x += pixel * (_mirroredFlag ? -1 : 1); - } -} - -void SciGuiPicture::vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture) { - if (pattern_Code & SCI_PATTERN_CODE_USE_TEXTURE) { - pattern_Texture = (data[curPos++] >> 1) & 0x7f; - } -} - -// Do not replace w/ some generic code. This algo really needs to behave exactly as the one from sierra -void SciGuiPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, byte control) { - GuiPort *curPort = _gfx->GetPort(); - Common::Stack stack; - Common::Point p, p1; - byte screenMask = _screen->getDrawingMask(color, priority, control); - byte matchedMask, matchMask; - int16 w, e, a_set, b_set; - - p.x = x + curPort->left; - p.y = y + curPort->top; - stack.push(p); - - byte searchColor = _screen->getVisual(p.x, p.y); - byte searchPriority = _screen->getPriority(p.x, p.y); - byte searchControl = _screen->getControl(p.x, p.y); - - // This logic was taken directly from sierra sci, floodfill will get aborted on various occations - if (screenMask & SCI_SCREEN_MASK_VISUAL) { - if ((color == _screen->_colorWhite) || (searchColor != _screen->_colorWhite)) - return; - } else if (screenMask & SCI_SCREEN_MASK_PRIORITY) { - if ((priority == 0) || (searchPriority != 0)) - return; - } else if (screenMask & SCI_SCREEN_MASK_CONTROL) { - if ((control == 0) || (searchControl != 0)) - return; - } - - // Now remove screens, that already got the right color/priority/control - if ((screenMask & SCI_SCREEN_MASK_VISUAL) && (searchColor == color)) - screenMask ^= SCI_SCREEN_MASK_VISUAL; - if ((screenMask & SCI_SCREEN_MASK_PRIORITY) && (searchPriority == priority)) - screenMask ^= SCI_SCREEN_MASK_PRIORITY; - if ((screenMask & SCI_SCREEN_MASK_CONTROL) && (searchControl == control)) - screenMask ^= SCI_SCREEN_MASK_CONTROL; - - // Exit, if no screens left - if (!screenMask) - return; - - if (screenMask & SCI_SCREEN_MASK_VISUAL) { - matchMask = SCI_SCREEN_MASK_VISUAL; - } else if (screenMask & SCI_SCREEN_MASK_PRIORITY) { - matchMask = SCI_SCREEN_MASK_PRIORITY; - } else { - matchMask = SCI_SCREEN_MASK_CONTROL; - } - - // hard borders for filling - int l = curPort->rect.left + curPort->left; - int t = curPort->rect.top + curPort->top; - int r = curPort->rect.right + curPort->left - 1; - int b = curPort->rect.bottom + curPort->top - 1; - while (stack.size()) { - p = stack.pop(); - if ((matchedMask = _screen->isFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl)) == 0) // already filled - continue; - _screen->putPixel(p.x, p.y, screenMask, color, priority, control); - w = p.x; - e = p.x; - // moving west and east pointers as long as there is a matching color to fill - while (w > l && (matchedMask = _screen->isFillMatch(w - 1, p.y, matchMask, searchColor, searchPriority, searchControl))) - _screen->putPixel(--w, p.y, screenMask, color, priority, control); - while (e < r && (matchedMask = _screen->isFillMatch(e + 1, p.y, matchMask, searchColor, searchPriority, searchControl))) - _screen->putPixel(++e, p.y, screenMask, color, priority, control); - // checking lines above and below for possible flood targets - a_set = b_set = 0; - while (w <= e) { - if (p.y > t && (matchedMask = _screen->isFillMatch(w, p.y - 1, matchMask, searchColor, searchPriority, searchControl))) { // one line above - if (a_set == 0) { - p1.x = w; - p1.y = p.y - 1; - stack.push(p1); - a_set = 1; - } - } else - a_set = 0; - - if (p.y < b && (matchedMask = _screen->isFillMatch(w, p.y + 1, matchMask, searchColor, searchPriority, searchControl))) { // one line below - if (b_set == 0) { - p1.x = w; - p1.y = p.y + 1; - stack.push(p1); - b_set = 1; - } - } else - b_set = 0; - w++; - } - } -} - -// Bitmap for drawing sierra circles -static const byte vectorPatternCircles[8][30] = { - { 0x01 }, - { 0x72, 0x02 }, - { 0xCE, 0xF7, 0x7D, 0x0E }, - { 0x1C, 0x3E, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x00 }, - { 0x38, 0xF8, 0xF3, 0xDF, 0x7F, 0xFF, 0xFD, 0xF7, 0x9F, 0x3F, 0x38 }, - { 0x70, 0xC0, 0x1F, 0xFE, 0xE3, 0x3F, 0xFF, 0xF7, 0x7F, 0xFF, 0xE7, 0x3F, 0xFE, 0xC3, 0x1F, 0xF8, 0x00 }, - { 0xF0, 0x01, 0xFF, 0xE1, 0xFF, 0xF8, 0x3F, 0xFF, 0xDF, 0xFF, 0xF7, 0xFF, 0xFD, 0x7F, 0xFF, 0x9F, 0xFF, - 0xE3, 0xFF, 0xF0, 0x1F, 0xF0, 0x01 }, - { 0xE0, 0x03, 0xF8, 0x0F, 0xFC, 0x1F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, - 0x7F, 0xFF, 0x7F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8, 0x0F, 0xE0, 0x03 } -// { 0x01 }; -// { 0x03, 0x03, 0x03 }, -// { 0x02, 0x07, 0x07, 0x07, 0x02 }, -// { 0x06, 0x06, 0x0F, 0x0F, 0x0F, 0x06, 0x06 }, -// { 0x04, 0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x04 }, -// { 0x0C, 0x1E, 0x1E, 0x1E, 0x3F, 0x3F, 0x3F, 0x1E, 0x1E, 0x1E, 0x0C }, -// { 0x1C, 0x3E, 0x3E, 0x3E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E, 0x3E, 0x3E, 0x1C }, -// { 0x18, 0x3C, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x3C, 0x18 } -}; - -// TODO: perhaps this is a better way to set the s_patternTextures array below? -// in that case one would need to adjust bits of secondary table. Bit 256 is ignored by original interpreter -#if 0 -static const byte patternTextures[32 * 2] = { - 0x04, 0x29, 0x40, 0x24, 0x09, 0x41, 0x25, 0x45, - 0x41, 0x90, 0x50, 0x44, 0x48, 0x08, 0x42, 0x28, - 0x89, 0x52, 0x89, 0x88, 0x10, 0x48, 0xA4, 0x08, - 0x44, 0x15, 0x28, 0x24, 0x00, 0x0A, 0x24, 0x20, - // Now the table is actually duplicated, so we won't need to wrap around - 0x04, 0x29, 0x40, 0x24, 0x09, 0x41, 0x25, 0x45, - 0x41, 0x90, 0x50, 0x44, 0x48, 0x08, 0x42, 0x28, - 0x89, 0x52, 0x89, 0x88, 0x10, 0x48, 0xA4, 0x08, - 0x44, 0x15, 0x28, 0x24, 0x00, 0x0A, 0x24, 0x20, -}; -#endif - -// This table is bitwise upwards (from bit0 to bit7), sierras original table went down the bits (bit7 to bit0) -// this was done to simplify things, so we can just run through the table w/o worrying too much about clipping -static const bool vectorPatternTextures[32 * 8 * 2] = { - false, false, true, false, false, false, false, false, // 0x04 - true, false, false, true, false, true, false, false, // 0x29 - false, false, false, false, false, false, true, false, // 0x40 - false, false, true, false, false, true, false, false, // 0x24 - true, false, false, true, false, false, false, false, // 0x09 - true, false, false, false, false, false, true, false, // 0x41 - true, false, true, false, false, true, false, false, // 0x25 - true, false, true, false, false, false, true, false, // 0x45 - true, false, false, false, false, false, true, false, // 0x41 - false, false, false, false, true, false, false, true, // 0x90 - false, false, false, false, true, false, true, false, // 0x50 - false, false, true, false, false, false, true, false, // 0x44 - false, false, false, true, false, false, true, false, // 0x48 - false, false, false, true, false, false, false, false, // 0x08 - false, true, false, false, false, false, true, false, // 0x42 - false, false, false, true, false, true, false, false, // 0x28 - true, false, false, true, false, false, false, true, // 0x89 - false, true, false, false, true, false, true, false, // 0x52 - true, false, false, true, false, false, false, true, // 0x89 - false, false, false, true, false, false, false, true, // 0x88 - false, false, false, false, true, false, false, false, // 0x10 - false, false, false, true, false, false, true, false, // 0x48 - false, false, true, false, false, true, false, true, // 0xA4 - false, false, false, true, false, false, false, false, // 0x08 - false, false, true, false, false, false, true, false, // 0x44 - true, false, true, false, true, false, false, false, // 0x15 - false, false, false, true, false, true, false, false, // 0x28 - false, false, true, false, false, true, false, false, // 0x24 - false, false, false, false, false, false, false, false, // 0x00 - false, true, false, true, false, false, false, false, // 0x0A - false, false, true, false, false, true, false, false, // 0x24 - false, false, false, false, false, true, false, // 0x20 (last bit is not mentioned cause original interpreter also ignores that bit) - // Now the table is actually duplicated, so we won't need to wrap around - false, false, true, false, false, false, false, false, // 0x04 - true, false, false, true, false, true, false, false, // 0x29 - false, false, false, false, false, false, true, false, // 0x40 - false, false, true, false, false, true, false, false, // 0x24 - true, false, false, true, false, false, false, false, // 0x09 - true, false, false, false, false, false, true, false, // 0x41 - true, false, true, false, false, true, false, false, // 0x25 - true, false, true, false, false, false, true, false, // 0x45 - true, false, false, false, false, false, true, false, // 0x41 - false, false, false, false, true, false, false, true, // 0x90 - false, false, false, false, true, false, true, false, // 0x50 - false, false, true, false, false, false, true, false, // 0x44 - false, false, false, true, false, false, true, false, // 0x48 - false, false, false, true, false, false, false, false, // 0x08 - false, true, false, false, false, false, true, false, // 0x42 - false, false, false, true, false, true, false, false, // 0x28 - true, false, false, true, false, false, false, true, // 0x89 - false, true, false, false, true, false, true, false, // 0x52 - true, false, false, true, false, false, false, true, // 0x89 - false, false, false, true, false, false, false, true, // 0x88 - false, false, false, false, true, false, false, false, // 0x10 - false, false, false, true, false, false, true, false, // 0x48 - false, false, true, false, false, true, false, true, // 0xA4 - false, false, false, true, false, false, false, false, // 0x08 - false, false, true, false, false, false, true, false, // 0x44 - true, false, true, false, true, false, false, false, // 0x15 - false, false, false, true, false, true, false, false, // 0x28 - false, false, true, false, false, true, false, false, // 0x24 - false, false, false, false, false, false, false, false, // 0x00 - false, true, false, true, false, false, false, false, // 0x0A - false, false, true, false, false, true, false, false, // 0x24 - false, false, false, false, false, true, false, // 0x20 (last bit is not mentioned cause original interpreter also ignores that bit) -}; - -// Bit offsets into pattern_textures -static const byte vectorPatternTextureOffset[128] = { - 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, - 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, - 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, - 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, - 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, - 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, - 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, - 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, - 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, - 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, - 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, - 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, - 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, - 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, - 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 -}; - -void SciGuiPicture::vectorPatternBox(Common::Rect box, byte color, byte prio, byte control) { - byte flag = _screen->getDrawingMask(color, prio, control); - int y, x; - - for (y = box.top; y < box.bottom; y++) { - for (x = box.left; x < box.right; x++) { - _screen->putPixel(x, y, flag, color, prio, control); - } - } -} - -void SciGuiPicture::vectorPatternTexturedBox(Common::Rect box, byte color, byte prio, byte control, byte texture) { - byte flag = _screen->getDrawingMask(color, prio, control); - const bool *textureData = &vectorPatternTextures[vectorPatternTextureOffset[texture]]; - int y, x; - - for (y = box.top; y < box.bottom; y++) { - for (x = box.left; x < box.right; x++) { - if (*textureData) { - _screen->putPixel(x, y, flag, color, prio, control); - } - textureData++; - } - } -} - -void SciGuiPicture::vectorPatternCircle(Common::Rect box, byte size, byte color, byte prio, byte control) { - byte flag = _screen->getDrawingMask(color, prio, control); - const byte *circleData = vectorPatternCircles[size]; - byte bitmap = *circleData; - byte bitNo = 0; - int y, x; - - for (y = box.top; y < box.bottom; y++) { - for (x = box.left; x < box.right; x++) { - if (bitmap & 1) { - _screen->putPixel(x, y, flag, color, prio, control); - } - bitNo++; - if (bitNo == 8) { - circleData++; bitmap = *circleData; bitNo = 0; - } else { - bitmap = bitmap >> 1; - } - } - } -} - -void SciGuiPicture::vectorPatternTexturedCircle(Common::Rect box, byte size, byte color, byte prio, byte control, byte texture) { - byte flag = _screen->getDrawingMask(color, prio, control); - const byte *circleData = vectorPatternCircles[size]; - byte bitmap = *circleData; - byte bitNo = 0; - const bool *textureData = &vectorPatternTextures[vectorPatternTextureOffset[texture]]; - int y, x; - - for (y = box.top; y < box.bottom; y++) { - for (x = box.left; x < box.right; x++) { - if (bitmap & 1) { - if (*textureData) { - _screen->putPixel(x, y, flag, color, prio, control); - } - textureData++; - } - bitNo++; - if (bitNo == 8) { - circleData++; bitmap = *circleData; bitNo = 0; - } else { - bitmap = bitmap >> 1; - } - } - } -} - -void SciGuiPicture::vectorPattern(int16 x, int16 y, byte color, byte priority, byte control, byte code, byte texture) { - byte size = code & SCI_PATTERN_CODE_PENSIZE; - Common::Rect rect; - - // We need to adjust the given coordinates, because the ones given us do not define upper left but somewhat middle - y -= size; if (y < 0) y = 0; - x -= size; if (x < 0) x = 0; - - rect.top = y; rect.left = x; - rect.setHeight((size*2)+1); rect.setWidth((size*2)+2); - _gfx->OffsetRect(rect); - rect.clip(_screen->_width, _screen->_height); - - if (code & SCI_PATTERN_CODE_RECTANGLE) { - // Rectangle - if (code & SCI_PATTERN_CODE_USE_TEXTURE) { - vectorPatternTexturedBox(rect, color, priority, control, texture); - } else { - vectorPatternBox(rect, color, priority, control); - } - - } else { - // Circle - if (code & SCI_PATTERN_CODE_USE_TEXTURE) { - vectorPatternTexturedCircle(rect, size, color, priority, control, texture); - } else { - vectorPatternCircle(rect, size, color, priority, control); - } - } -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_picture.h b/engines/sci/graphics/gui_picture.h deleted file mode 100644 index 4c3283c53b..0000000000 --- a/engines/sci/graphics/gui_picture.h +++ /dev/null @@ -1,82 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_PICTURE_H -#define SCI_GUI_PICTURE_H - -namespace Sci { - -#define SCI_PATTERN_CODE_RECTANGLE 0x10 -#define SCI_PATTERN_CODE_USE_TEXTURE 0x20 -#define SCI_PATTERN_CODE_PENSIZE 0x07 - -class SciGuiPicture { -public: - SciGuiPicture(ResourceManager *resMan, SciGuiGfx *gfx, SciGuiScreen *screen, SciGuiPalette *palette, GuiResourceId resourceId); - ~SciGuiPicture(); - - GuiResourceId getResourceId(); - void draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo); - -private: - void initData(GuiResourceId resourceId); - void reset(); - void drawSci11Vga(); -#ifdef ENABLE_SCI32 - void drawSci32Vga(); -#endif - void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header); - void drawVectorData(byte *data, int size); - bool vectorIsNonOpcode(byte pixel); - void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y); - void vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture); - void vectorFloodFill(int16 x, int16 y, byte color, byte prio, byte control); - void vectorPattern(int16 x, int16 y, byte pic_color, byte pic_priority, byte pic_control, byte code, byte texture); - void vectorPatternBox(Common::Rect box, byte color, byte prio, byte control); - void vectorPatternTexturedBox(Common::Rect box, byte color, byte prio, byte control, byte texture); - void vectorPatternCircle(Common::Rect box, byte size, byte color, byte prio, byte control); - void vectorPatternTexturedCircle(Common::Rect box, byte size, byte color, byte prio, byte control, byte texture); - - ResourceManager *_resMan; - SciGuiGfx *_gfx; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - - int16 _resourceId; - Resource *_resource; - - int16 _animationNr; - bool _mirroredFlag; - bool _addToFlag; - int16 _EGApaletteNo; - byte _priority; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_portrait.cpp b/engines/sci/graphics/gui_portrait.cpp deleted file mode 100644 index de3da9bc84..0000000000 --- a/engines/sci/graphics/gui_portrait.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_portrait.h" - -namespace Sci { - -SciGuiPortrait::SciGuiPortrait(ResourceManager *resMan, SciGuiScreen *screen, SciGuiPalette *palette, Common::String resourceName) - : _resMan(resMan), _screen(screen), _palette(palette), _resourceName(resourceName) { - init(); -} - -SciGuiPortrait::~SciGuiPortrait() { -} - -void SciGuiPortrait::init() { - // .BIN files are loaded from actors directory and from .\ directory - // header: - // 3 bytes "WIN" - // 2 bytes main height (should be the same as first bitmap header height) - // 2 bytes main width (should be the same as first bitmap header width) - // 2 bytes animation count - // 2 bytes unknown - // 2 bytes unknown - // 4 bytes paletteSize (base 1) - // paletteSize bytes paletteData - // 14 bytes bitmap header - // -> 4 bytes unknown - // -> 2 bytes height - // -> 2 bytes width - // -> 6 bytes unknown - // height * width bitmap data - // another animation count times bitmap header and data -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_portrait.h b/engines/sci/graphics/gui_portrait.h deleted file mode 100644 index b97f3dd2a6..0000000000 --- a/engines/sci/graphics/gui_portrait.h +++ /dev/null @@ -1,49 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_PORTRAITS_H -#define SCI_GUI_PORTRAITS_H - -namespace Sci { - -class SciGuiPortrait { -public: - SciGuiPortrait(ResourceManager *resMan, SciGuiScreen *screen, SciGuiPalette *palette, Common::String resourceName); - ~SciGuiPortrait(); - -private: - void init(); - - ResourceManager *_resMan; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - - Common::String _resourceName; - byte *_resourceData; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_screen.cpp b/engines/sci/graphics/gui_screen.cpp deleted file mode 100644 index 13f969e55f..0000000000 --- a/engines/sci/graphics/gui_screen.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/timer.h" -#include "common/util.h" -#include "graphics/surface.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_screen.h" - -namespace Sci { - -SciGuiScreen::SciGuiScreen(ResourceManager *resMan, int16 width, int16 height, bool upscaledHires) : - _resMan(resMan), _width(width), _height(height), _upscaledHires(upscaledHires) { - - _pixels = _width * _height; - - _displayWidth = _width; - _displayHeight = _height; - if (_upscaledHires) { - _displayWidth *= 2; - _displayHeight *= 2; - } - _displayPixels = _displayWidth * _displayHeight; - - _visualScreen = (byte *)calloc(_pixels, 1); - _priorityScreen = (byte *)calloc(_pixels, 1); - _controlScreen = (byte *)calloc(_pixels, 1); - _displayScreen = (byte *)calloc(_displayPixels, 1); - - // Sets display screen to be actually displayed - _activeScreen = _displayScreen; - - _picNotValid = 0; - _picNotValidSci11 = 0; - _unditherState = true; - - if (_resMan->isVGA()) { - _colorWhite = 255; - if (getSciVersion() >= SCI_VERSION_1_1) - _colorDefaultVectorData = 255; - else - _colorDefaultVectorData = 0; - } else { - _colorWhite = 15; - _colorDefaultVectorData = 0; - } - - // Initialize the actual screen - initGraphics(_displayWidth, _displayHeight, _displayWidth > 320); -} - -SciGuiScreen::~SciGuiScreen() { - free(_visualScreen); - free(_priorityScreen); - free(_controlScreen); - free(_displayScreen); -} - -void SciGuiScreen::copyToScreen() { - g_system->copyRectToScreen(_activeScreen, _displayWidth, 0, 0, _displayWidth, _displayHeight); -} - -void SciGuiScreen::copyFromScreen(byte *buffer) { - Graphics::Surface *screen; - screen = g_system->lockScreen(); - memcpy(buffer, screen->pixels, _displayWidth * _displayHeight); - g_system->unlockScreen(); -} - -void SciGuiScreen::copyRectToScreen(const Common::Rect &rect) { - if (!_upscaledHires) { - g_system->copyRectToScreen(_activeScreen + rect.top * _displayWidth + rect.left, _displayWidth, rect.left, rect.top, rect.width(), rect.height()); - } else { - g_system->copyRectToScreen(_activeScreen + rect.top * 2 * _displayWidth + rect.left * 2, _displayWidth, rect.left * 2, rect.top * 2, rect.width() * 2, rect.height() * 2); - } -} - -void SciGuiScreen::copyRectToScreen(const Common::Rect &rect, int16 x, int16 y) { - if (!_upscaledHires) { - g_system->copyRectToScreen(_activeScreen + rect.top * _displayWidth + rect.left, _displayWidth, x, y, rect.width(), rect.height()); - } else { - g_system->copyRectToScreen(_activeScreen + rect.top * 2 * _displayWidth + rect.left * 2, _displayWidth, x * 2, y * 2, rect.width() * 2, rect.height() * 2); - } -} - -byte SciGuiScreen::getDrawingMask(byte color, byte prio, byte control) { - byte flag = 0; - if (color != 255) - flag |= SCI_SCREEN_MASK_VISUAL; - if (prio != 255) - flag |= SCI_SCREEN_MASK_PRIORITY; - if (control != 255) - flag |= SCI_SCREEN_MASK_CONTROL; - return flag; -} - -void SciGuiScreen::putPixel(int x, int y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _width + x; - - if (drawMask & SCI_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - if (!_upscaledHires) { - _displayScreen[offset] = color; - } else { - int displayOffset = y * 2 * _displayWidth + x * 2; - _displayScreen[displayOffset] = color; - _displayScreen[displayOffset + 1] = color; - _displayScreen[displayOffset + _displayWidth] = color; - _displayScreen[displayOffset + _displayWidth + 1] = color; - } - } - if (drawMask & SCI_SCREEN_MASK_PRIORITY) - _priorityScreen[offset] = priority; - if (drawMask & SCI_SCREEN_MASK_CONTROL) - _controlScreen[offset] = control; -} - -// This will just change a pixel directly on displayscreen. Its supposed to get only used on upscaled-Hires games where -// hires content needs to get drawn ONTO the upscaled display screen (like japanese fonts, hires portraits, etc.) -void SciGuiScreen::putPixelOnDisplay(int x, int y, byte color) { - int offset = y * _width + x; - _displayScreen[offset] = color; -} - -// Sierra's Bresenham line drawing -// WARNING: Do not just blindly replace this with Graphics::drawLine(), as it seems to create issues with flood fill -void SciGuiScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) { - int16 left = startPoint.x; - int16 top = startPoint.y; - int16 right = endPoint.x; - int16 bottom = endPoint.y; - - //set_drawing_flag - byte drawMask = getDrawingMask(color, priority, control); - - // horizontal line - if (top == bottom) { - if (right < left) - SWAP(right, left); - for (int i = left; i <= right; i++) - putPixel(i, top, drawMask, color, priority, control); - return; - } - // vertical line - if (left == right) { - if (top > bottom) - SWAP(top, bottom); - for (int i = top; i <= bottom; i++) - putPixel(left, i, drawMask, color, priority, control); - return; - } - // sloped line - draw with Bresenham algorithm - int dy = bottom - top; - int dx = right - left; - int stepy = dy < 0 ? -1 : 1; - int stepx = dx < 0 ? -1 : 1; - dy = ABS(dy) << 1; - dx = ABS(dx) << 1; - - // setting the 1st and last pixel - putPixel(left, top, drawMask, color, priority, control); - putPixel(right, bottom, drawMask, color, priority, control); - // drawing the line - if (dx > dy) { // going horizontal - int fraction = dy - (dx >> 1); - while (left != right) { - if (fraction >= 0) { - top += stepy; - fraction -= dx; - } - left += stepx; - fraction += dy; - putPixel(left, top, drawMask, color, priority, control); - } - } else { // going vertical - int fraction = dx - (dy >> 1); - while (top != bottom) { - if (fraction >= 0) { - left += stepx; - fraction -= dy; - } - top += stepy; - fraction += dx; - putPixel(left, top, drawMask, color, priority, control); - } - } -} - -byte SciGuiScreen::getVisual(int x, int y) { - return _visualScreen[y * _width + x]; -} - -byte SciGuiScreen::getPriority(int x, int y) { - return _priorityScreen[y * _width + x]; -} - -byte SciGuiScreen::getControl(int x, int y) { - return _controlScreen[y * _width + x]; -} - -byte SciGuiScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con) { - int offset = y * _width + x; - byte match = 0; - - if (screenMask & SCI_SCREEN_MASK_VISUAL && *(_visualScreen + offset) == t_color) - match |= SCI_SCREEN_MASK_VISUAL; - if (screenMask & SCI_SCREEN_MASK_PRIORITY && *(_priorityScreen + offset) == t_pri) - match |= SCI_SCREEN_MASK_PRIORITY; - if (screenMask & SCI_SCREEN_MASK_CONTROL && *(_controlScreen + offset) == t_con) - match |= SCI_SCREEN_MASK_CONTROL; - return match; -} - -int SciGuiScreen::bitsGetDataSize(Common::Rect rect, byte mask) { - int byteCount = sizeof(rect) + sizeof(mask); - int pixels = rect.width() * rect.height(); - if (mask & SCI_SCREEN_MASK_VISUAL) { - byteCount += pixels; // _visualScreen - if (!_upscaledHires) { - byteCount += pixels; // _displayScreen - } else { - byteCount += pixels * 4; // _displayScreen (upscaled hires) - } - } - if (mask & SCI_SCREEN_MASK_PRIORITY) { - byteCount += pixels; // _priorityScreen - } - if (mask & SCI_SCREEN_MASK_CONTROL) { - byteCount += pixels; // _controlScreen - } - if (mask & SCI_SCREEN_MASK_DISPLAY) { - if (!_upscaledHires) - error("bitsGetDataSize() called w/o being in upscaled hires mode"); - byteCount += pixels; // _displayScreen (coordinates actually are given to us for hires displayScreen) - } - - return byteCount; -} - -void SciGuiScreen::bitsSave(Common::Rect rect, byte mask, byte *memoryPtr) { - memcpy(memoryPtr, (void *)&rect, sizeof(rect)); memoryPtr += sizeof(rect); - memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask); - - if (mask & SCI_SCREEN_MASK_VISUAL) { - bitsSaveScreen(rect, _visualScreen, memoryPtr); - bitsSaveDisplayScreen(rect, memoryPtr); - } - if (mask & SCI_SCREEN_MASK_PRIORITY) { - bitsSaveScreen(rect, _priorityScreen, memoryPtr); - } - if (mask & SCI_SCREEN_MASK_CONTROL) { - bitsSaveScreen(rect, _controlScreen, memoryPtr); - } - if (mask & SCI_SCREEN_MASK_DISPLAY) { - if (!_upscaledHires) - error("bitsSave() called w/o being in upscaled hires mode"); - bitsSaveScreen(rect, _displayScreen, memoryPtr); - } -} - -void SciGuiScreen::bitsSaveScreen(Common::Rect rect, byte *screen, byte *&memoryPtr) { - int width = rect.width(); - int y; - - screen += (rect.top * _width) + rect.left; - - for (y = rect.top; y < rect.bottom; y++) { - memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; - screen += _width; - } -} - -void SciGuiScreen::bitsSaveDisplayScreen(Common::Rect rect, byte *&memoryPtr) { - byte *screen = _displayScreen; - int width = rect.width(); - int y; - - if (!_upscaledHires) { - screen += (rect.top * _displayWidth) + rect.left; - } else { - screen += (rect.top * 2 * _displayWidth) + rect.left * 2; - width *= 2; - rect.top *= 2; rect.bottom *= 2; - } - - for (y = rect.top; y < rect.bottom; y++) { - memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; - screen += _displayWidth; - } -} - -void SciGuiScreen::bitsGetRect(byte *memoryPtr, Common::Rect *destRect) { - memcpy((void *)destRect, memoryPtr, sizeof(Common::Rect)); -} - -void SciGuiScreen::bitsRestore(byte *memoryPtr) { - Common::Rect rect; - byte mask; - - memcpy((void *)&rect, memoryPtr, sizeof(rect)); memoryPtr += sizeof(rect); - memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask); - - if (mask & SCI_SCREEN_MASK_VISUAL) { - bitsRestoreScreen(rect, memoryPtr, _visualScreen); - bitsRestoreDisplayScreen(rect, memoryPtr); - } - if (mask & SCI_SCREEN_MASK_PRIORITY) { - bitsRestoreScreen(rect, memoryPtr, _priorityScreen); - } - if (mask & SCI_SCREEN_MASK_CONTROL) { - bitsRestoreScreen(rect, memoryPtr, _controlScreen); - } - if (mask & SCI_SCREEN_MASK_DISPLAY) { - if (!_upscaledHires) - error("bitsRestore() called w/o being in upscaled hires mode"); - bitsRestoreScreen(rect, memoryPtr, _displayScreen); - } -} - -void SciGuiScreen::bitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *screen) { - int width = rect.width(); - int y; - - screen += (rect.top * _width) + rect.left; - - for (y = rect.top; y < rect.bottom; y++) { - memcpy((void*) screen, memoryPtr, width); memoryPtr += width; - screen += _width; - } -} - -void SciGuiScreen::bitsRestoreDisplayScreen(Common::Rect rect, byte *&memoryPtr) { - byte *screen = _displayScreen; - int width = rect.width(); - int y; - - if (!_upscaledHires) { - screen += (rect.top * _displayWidth) + rect.left; - } else { - screen += (rect.top * 2 * _displayWidth) + rect.left * 2; - width *= 2; - rect.top *= 2; rect.bottom *= 2; - } - - for (y = rect.top; y < rect.bottom; y++) { - memcpy((void*) screen, memoryPtr, width); memoryPtr += width; - screen += _displayWidth; - } -} - -void SciGuiScreen::setPalette(GuiPalette*pal) { - // just copy palette to system - byte bpal[4 * 256]; - // Get current palette, update it and put back - g_system->grabPalette(bpal, 0, 256); - for (int16 i = 0; i < 256; i++) { - if (!pal->colors[i].used) - continue; - bpal[i * 4] = pal->colors[i].r * pal->intensity[i] / 100; - bpal[i * 4 + 1] = pal->colors[i].g * pal->intensity[i] / 100; - bpal[i * 4 + 2] = pal->colors[i].b * pal->intensity[i] / 100; - bpal[i * 4 + 3] = 100; - } - g_system->setPalette(bpal, 0, 256); -} - -void SciGuiScreen::setVerticalShakePos(uint16 shakePos) { - if (!_upscaledHires) - g_system->setShakePos(shakePos); - else - g_system->setShakePos(shakePos * 2); -} - -void SciGuiScreen::dither(bool addToFlag) { - int y, x; - byte color, ditheredColor; - byte *visualPtr = _visualScreen; - byte *displayPtr = _displayScreen; - - if (!_unditherState) { - // Do dithering on visual and display-screen - for (y = 0; y < _height; y++) { - for (x = 0; x < _width; x++) { - color = *visualPtr; - if (color & 0xF0) { - color ^= color << 4; - color = ((x^y) & 1) ? color >> 4 : color & 0x0F; - *displayPtr = color; - if (_upscaledHires) { - *(displayPtr + 1) = color; - *(displayPtr + _displayWidth) = color; - *(displayPtr + _displayWidth + 1) = color; - } - *visualPtr = color; - } - visualPtr++; displayPtr++; - if (_upscaledHires) - displayPtr++; - } - if (_upscaledHires) - displayPtr += _displayWidth; - } - } else { - if (!addToFlag) - memset(&_unditherMemorial, 0, sizeof(_unditherMemorial)); - // Do dithering on visual screen and put decoded but undithered byte onto display-screen - for (y = 0; y < _height; y++) { - for (x = 0; x < _width; x++) { - color = *visualPtr; - if (color & 0xF0) { - color ^= color << 4; - // remember dither combination for cel-undithering - _unditherMemorial[color]++; - // if decoded color wants do dither with black on left side, we turn it around - // otherwise the normal ega color would get used for display - if (color & 0xF0) { - ditheredColor = color; - } else { - ditheredColor = color << 4; - } - *displayPtr = ditheredColor; - if (_upscaledHires) { - *(displayPtr + 1) = ditheredColor; - *(displayPtr + _displayWidth) = ditheredColor; - *(displayPtr + _displayWidth + 1) = ditheredColor; - } - color = ((x^y) & 1) ? color >> 4 : color & 0x0F; - *visualPtr = color; - } - visualPtr++; displayPtr++; - if (_upscaledHires) - displayPtr++; - } - if (_upscaledHires) - displayPtr += _displayWidth; - } - } -} - -void SciGuiScreen::unditherSetState(bool flag) { - _unditherState = flag; -} - -int16 *SciGuiScreen::unditherGetMemorial() { - if (_unditherState) - return (int16 *)&_unditherMemorial; - else - return NULL; -} - -void SciGuiScreen::debugShowMap(int mapNo) { - // We cannot really support changing maps when in upscaledHires mode - if (_upscaledHires) - return; - - switch (mapNo) { - case 0: - _activeScreen = _visualScreen; - break; - case 1: - _activeScreen = _priorityScreen; - break; - case 2: - _activeScreen = _controlScreen; - break; - case 3: - _activeScreen = _displayScreen; - break; - } - copyToScreen(); -} - -void SciGuiScreen::scale2x(byte *src, byte *dst, int16 srcWidth, int16 srcHeight) { - int newWidth = srcWidth * 2; - byte *srcPtr = src; - - for (int y = 0; y < srcHeight; y++) { - for (int x = 0; x < srcWidth; x++) { - int destOffset = y * 2 * newWidth + x * 2; - dst[destOffset] = *srcPtr; - dst[destOffset + 1] = *srcPtr; - dst[destOffset + newWidth] = *srcPtr; - dst[destOffset + newWidth + 1] = *srcPtr; - srcPtr++; - } - } -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_screen.h b/engines/sci/graphics/gui_screen.h deleted file mode 100644 index 8a54e88829..0000000000 --- a/engines/sci/graphics/gui_screen.h +++ /dev/null @@ -1,130 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_SCREEN_H -#define SCI_GUI_SCREEN_H - -#include "sci/sci.h" -#include "sci/graphics/gui_helpers.h" - -namespace Sci { - -#define SCI_SCREEN_MAXHEIGHT 400 - -#define SCI_SCREEN_MASK_VISUAL 1 -#define SCI_SCREEN_MASK_PRIORITY 2 -#define SCI_SCREEN_MASK_CONTROL 4 -#define SCI_SCREEN_MASK_DISPLAY 8 // not official sierra sci -#define SCI_SCREEN_MASK_ALL SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL - -#define SCI_SCREEN_UNDITHERMEMORIAL_SIZE 256 - -class SciGuiScreen { -public: - SciGuiScreen(ResourceManager *resMan, int16 width = 320, int16 height = 200, bool upscaledHires = false); - ~SciGuiScreen(); - - void copyToScreen(); - void copyFromScreen(byte *buffer); - void copyRectToScreen(const Common::Rect &rect); - void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y); - - byte getDrawingMask(byte color, byte prio, byte control); - void putPixel(int x, int y, byte drawMask, byte color, byte prio, byte control); - void putPixelOnDisplay(int x, int y, byte color); - void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control); - void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) { - drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control); - } - bool getUpscaledHires() { - return _upscaledHires; - } - byte getVisual(int x, int y); - byte getPriority(int x, int y); - byte getControl(int x, int y); - byte isFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con); - - int bitsGetDataSize(Common::Rect rect, byte mask); - void bitsSave(Common::Rect rect, byte mask, byte *memoryPtr); - void bitsGetRect(byte *memoryPtr, Common::Rect *destRect); - void bitsRestore(byte *memoryPtr); - - void setPalette(GuiPalette*pal); - - void setVerticalShakePos(uint16 shakePos); - - void scale2x(byte *src, byte *dst, int16 srcWidth, int16 srcHeight); - - void dither(bool addToFlag); - void unditherSetState(bool flag); - int16 *unditherGetMemorial(); - - void debugShowMap(int mapNo); - - uint16 _width; - uint16 _height; - uint _pixels; - uint16 _displayWidth; - uint16 _displayHeight; - uint _displayPixels; - - int _picNotValid; // possible values 0, 1 and 2 - int _picNotValidSci11; // another variable that is used by kPicNotValid in sci1.1 - - byte _colorWhite; - byte _colorDefaultVectorData; - -private: - void bitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *screen); - void bitsRestoreDisplayScreen(Common::Rect rect, byte *&memoryPtr); - void bitsSaveScreen(Common::Rect rect, byte *screen, byte *&memoryPtr); - void bitsSaveDisplayScreen(Common::Rect rect, byte *&memoryPtr); - - bool _unditherState; - int16 _unditherMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; - -public: // HACK. TODO: make private - // these screens have the real resolution of the game engine (320x200 for SCI0/SCI1/SCI11 games, 640x480 for SCI2 games) - // SCI0 games will be dithered in here at any time - byte *_visualScreen; - byte *_priorityScreen; - byte *_controlScreen; - - // this screen is the one that is actually displayed to the user. It may be 640x480 for japanese SCI1 games - // SCI0 games may be undithered in here. Only read from this buffer for Save/ShowBits usage. - byte *_displayScreen; -private: - Common::Rect getScaledRect(Common::Rect rect); - - ResourceManager *_resMan; - - // this is a pointer to the currently active screen (changing it only required for debug purposes) - byte *_activeScreen; - bool _upscaledHires; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_text.cpp b/engines/sci/graphics/gui_text.cpp deleted file mode 100644 index 430877001e..0000000000 --- a/engines/sci/graphics/gui_text.cpp +++ /dev/null @@ -1,410 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" -#include "common/stack.h" -#include "graphics/primitives.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_font.h" -#include "sci/graphics/gui_text.h" - -namespace Sci { - -SciGuiText::SciGuiText(ResourceManager *resMan, SciGuiGfx *gfx, SciGuiScreen *screen) - : _resMan(resMan), _gfx(gfx), _screen(screen) { - init(); -} - -SciGuiText::~SciGuiText() { - delete _font; -} - -void SciGuiText::init() { - _font = NULL; - _codeFonts = NULL; - _codeFontsCount = 0; - _codeColors = NULL; - _codeColorsCount = 0; -} - -GuiResourceId SciGuiText::GetFontId() { - return _gfx->_curPort->fontId; -} - -SciGuiFont *SciGuiText::GetFont() { - if ((_font == NULL) || (_font->getResourceId() != _gfx->_curPort->fontId)) - _font = new SciGuiFont(_resMan, _gfx->_curPort->fontId); - - return _font; -} - -void SciGuiText::SetFont(GuiResourceId fontId) { - if ((_font == NULL) || (_font->getResourceId() != fontId)) - _font = new SciGuiFont(_resMan, fontId); - - _gfx->_curPort->fontId = _font->getResourceId(); - _gfx->_curPort->fontHeight = _font->getHeight(); -} - -void SciGuiText::CodeSetFonts(int argc, reg_t *argv) { - int i; - - delete _codeFonts; - _codeFontsCount = argc; - _codeFonts = new GuiResourceId[argc]; - for (i = 0; i < argc; i++) { - _codeFonts[i] = (GuiResourceId)argv[i].toUint16(); - } -} - -void SciGuiText::CodeSetColors(int argc, reg_t *argv) { - int i; - - delete _codeColors; - _codeColorsCount = argc; - _codeColors = new uint16[argc]; - for (i = 0; i < argc; i++) { - _codeColors[i] = argv[i].toUint16(); - } -} - -void SciGuiText::ClearChar(int16 chr) { - if (_gfx->_curPort->penMode != 1) - return; - Common::Rect rect; - rect.top = _gfx->_curPort->curTop; - rect.bottom = rect.top + _gfx->_curPort->fontHeight; - rect.left = _gfx->_curPort->curLeft; - rect.right = rect.left + GetFont()->getCharWidth(chr); - _gfx->EraseRect(rect); -} - -void SciGuiText::DrawChar(int16 chr) { - chr = chr & 0xFF; - ClearChar(chr); - StdChar(chr); - _gfx->_curPort->curLeft += GetFont()->getCharWidth(chr); -} - -void SciGuiText::StdChar(int16 chr) { -#if 0 - CResFont*res = getResFont(); - if (res) - res->Draw(chr, _curPort->top + _curPort->curTop, _curPort->left - + _curPort->curLeft, _vSeg, 320, _curPort->penClr, - _curPort->textFace); -#endif -} - -// This internal function gets called as soon as a '|' is found in a text -// It will process the encountered code and set new font/set color -// We only support one-digit codes currently, don't know if multi-digit codes are possible -// Returns textcode character count -int16 SciGuiText::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor) { - const char *textCode = text; - int16 textCodeSize = 0; - char curCode; - unsigned char curCodeParm; - - // Find the end of the textcode - while ((++textCodeSize) && (*text != 0) && (*text++ != 0x7C)) { } - - // possible TextCodes: - // c -> sets textColor to current port pen color - // cX -> sets textColor to _textColors[X-1] - curCode = textCode[0]; - curCodeParm = textCode[1]; - if (isdigit(curCodeParm)) { - curCodeParm -= '0'; - } else { - curCodeParm = 0; - } - switch (curCode) { - case 'c': // set text color - if (curCodeParm == 0) { - _gfx->_curPort->penClr = orgPenColor; - } else { - if (curCodeParm < _codeColorsCount) { - _gfx->_curPort->penClr = _codeColors[curCodeParm]; - } - } - break; - case 'f': - if (curCodeParm == 0) { - SetFont(orgFontId); - } else { - if (curCodeParm < _codeFontsCount) { - SetFont(_codeFonts[curCodeParm]); - } - } - break; - } - return textCodeSize; -} - -// return max # of chars to fit maxwidth with full words -int16 SciGuiText::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId) { - char curChar; - int16 maxChars = 0, curCharCount = 0; - uint16 width = 0; - GuiResourceId oldFontId = GetFontId(); - int16 oldPenColor = _gfx->_curPort->penClr; - - GetFont(); - if (!_font) - return 0; - - while (width <= maxWidth) { - curChar = *text++; - switch (curChar) { - case 0x7C: - if (getSciVersion() >= SCI_VERSION_1_1) { - curCharCount++; - curCharCount += CodeProcessing(text, orgFontId, oldPenColor); - continue; - } - break; - - case 0xD: - curCharCount++; - continue; - - case 0xA: - curCharCount++; - case 0: - SetFont(oldFontId); - _gfx->PenColor(oldPenColor); - return curCharCount; - - case ' ': - maxChars = curCharCount + 1; - break; - } - width += _font->getCharWidth(curChar); - curCharCount++; - } - SetFont(oldFontId); - _gfx->PenColor(oldPenColor); - return maxChars; -} - -void SciGuiText::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight) { - unsigned char curChar; - GuiResourceId oldFontId = GetFontId(); - int16 oldPenColor = _gfx->_curPort->penClr; - - textWidth = 0; textHeight = 0; - - GetFont(); - if (_font) { - text += from; - while (len--) { - curChar = *text++; - switch (curChar) { - case 0x0A: - case 0x0D: - textHeight = MAX (textHeight, _gfx->_curPort->fontHeight); - break; - case 0x7C: - if (getSciVersion() >= SCI_VERSION_1_1) { - len -= CodeProcessing(text, orgFontId, 0); - break; - } - default: - textHeight = MAX (textHeight, _gfx->_curPort->fontHeight); - textWidth += _font->getCharWidth(curChar); - } - } - } - SetFont(oldFontId); - _gfx->PenColor(oldPenColor); - return; -} - -void SciGuiText::StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight) { - Width(str, 0, (int16)strlen(str), orgFontId, textWidth, textHeight); -} - -void SciGuiText::ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor) { - Show(str, 0, (int16)strlen(str), orgFontId, orgPenColor); -} -void SciGuiText::DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor) { - Draw(str, 0, (int16)strlen(str), orgFontId, orgPenColor); -} - -int16 SciGuiText::Size(Common::Rect &rect, const char *str, GuiResourceId fontId, int16 maxWidth) { - GuiResourceId oldFontId = GetFontId(); - int16 oldPenColor = _gfx->_curPort->penClr; - int16 charCount; - int16 maxTextWidth = 0, textWidth; - int16 totalHeight = 0, textHeight; - - if (fontId != -1) - SetFont(fontId); - rect.top = rect.left = 0; - - if (maxWidth < 0) { // force output as single line - StringWidth(str, oldFontId, textWidth, textHeight); - rect.bottom = textHeight; - rect.right = textWidth; - } else { - // rect.right=found widest line with RTextWidth and GetLongest - // rect.bottom=num. lines * GetPointSize - rect.right = (maxWidth ? maxWidth : 192); - const char*p = str; - while (*p) { - //if (*p == 0xD || *p == 0xA) { - // p++; - // continue; - //} - charCount = GetLongest(p, rect.right, oldFontId); - if (charCount == 0) - break; - Width(p, 0, charCount, oldFontId, textWidth, textHeight); - maxTextWidth = MAX(textWidth, maxTextWidth); - totalHeight += textHeight; - p += charCount; - } - rect.bottom = totalHeight; - rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); - } - SetFont(oldFontId); - _gfx->PenColor(oldPenColor); - return rect.right; -} - -// returns maximum font height used -void SciGuiText::Draw(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor) { - int16 curChar, charWidth; - Common::Rect rect; - - GetFont(); - if (!_font) - return; - - rect.top = _gfx->_curPort->curTop; - rect.bottom = rect.top + _gfx->_curPort->fontHeight; - text += from; - while (len--) { - curChar = (*text++); - switch (curChar) { - case 0x0A: - case 0x0D: - case 0: - break; - case 0x7C: - if (getSciVersion() >= SCI_VERSION_1_1) { - len -= CodeProcessing(text, orgFontId, orgPenColor); - break; - } - default: - charWidth = _font->getCharWidth(curChar); - // clear char - if (_gfx->_curPort->penMode == 1) { - rect.left = _gfx->_curPort->curLeft; - rect.right = rect.left + charWidth; - _gfx->EraseRect(rect); - } - // CharStd - _font->draw(_screen, curChar, _gfx->_curPort->top + _gfx->_curPort->curTop, _gfx->_curPort->left + _gfx->_curPort->curLeft, _gfx->_curPort->penClr, _gfx->_curPort->greyedOutput); - _gfx->_curPort->curLeft += charWidth; - } - } -} - -// returns maximum font height used -void SciGuiText::Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor) { - Common::Rect rect; - - rect.top = _gfx->_curPort->curTop; - rect.bottom = rect.top + _gfx->GetPointSize(); - rect.left = _gfx->_curPort->curLeft; - Draw(text, from, len, orgFontId, orgPenColor); - rect.right = _gfx->_curPort->curLeft; - _gfx->BitsShow(rect); -} - -// Draws a text in rect. -void SciGuiText::Box(const char *text, int16 bshow, const Common::Rect &rect, GuiTextAlignment alignment, GuiResourceId fontId) { - int16 textWidth, textHeight, charCount; - int16 offset = 0; - int16 hline = 0; - GuiResourceId orgFontId = GetFontId(); - int16 orgPenColor = _gfx->_curPort->penClr; - - if (fontId != -1) - SetFont(fontId); - - while (*text) { -// if (*text == 0xD || *text == 0xA) { -// text++; -// continue; -// } - charCount = GetLongest(text, rect.width(), orgFontId); - if (charCount == 0) - break; - Width(text, 0, charCount, orgFontId, textWidth, textHeight); - switch (alignment) { - case SCI_TEXT_ALIGNMENT_RIGHT: - offset = rect.width() - textWidth; - break; - case SCI_TEXT_ALIGNMENT_CENTER: - offset = (rect.width() - textWidth) / 2; - break; - case SCI_TEXT_ALIGNMENT_LEFT: - offset = 0; - break; - - default: // left-aligned - warning("Invalid alignment %d used in TextBox()", alignment); - } - _gfx->MoveTo(rect.left + offset, rect.top + hline); - - if (bshow) { - Show(text, 0, charCount, orgFontId, orgPenColor); - } else { - Draw(text, 0, charCount, orgFontId, orgPenColor); - } - - hline += textHeight; - text += charCount; - } - SetFont(orgFontId); - _gfx->PenColor(orgPenColor); -} - -void SciGuiText::Draw_String(const char *text) { - GuiResourceId orgFontId = GetFontId(); - int16 orgPenColor = _gfx->_curPort->penClr; - - Draw(text, 0, strlen(text), orgFontId, orgPenColor); - SetFont(orgFontId); - _gfx->PenColor(orgPenColor); -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_text.h b/engines/sci/graphics/gui_text.h deleted file mode 100644 index 8002cdcf0c..0000000000 --- a/engines/sci/graphics/gui_text.h +++ /dev/null @@ -1,83 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_TEXT_H -#define SCI_GUI_TEXT_H - -namespace Sci { - -#define SCI_TEXT_ALIGNMENT_RIGHT -1 -#define SCI_TEXT_ALIGNMENT_CENTER 1 -#define SCI_TEXT_ALIGNMENT_LEFT 0 - -class SciGuiGfx; -class SciGuiScreen; -class SciGuiFont; -class SciGuiText { -public: - SciGuiText(ResourceManager *_resMan, SciGuiGfx *gfx, SciGuiScreen *screen); - ~SciGuiText(); - - GuiResourceId GetFontId(); - SciGuiFont *GetFont(); - void SetFont(GuiResourceId fontId); - - void CodeSetFonts(int argc, reg_t *argv); - void CodeSetColors(int argc, reg_t *argv); - int16 CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor); - - void ClearChar(int16 chr); - void DrawChar(int16 chr); - void StdChar(int16 chr); - - int16 GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId); - void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); - void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); - void ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor); - void DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor); - int16 Size(Common::Rect &rect, const char *str, GuiResourceId fontId, int16 maxWidth); - void Draw(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); - void Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); - void Box(const char *text, int16 bshow, const Common::Rect &rect, GuiTextAlignment alignment, GuiResourceId fontId); - void Draw_String(const char *text); - - SciGuiFont *_font; - -private: - void init(); - - ResourceManager *_resMan; - SciGuiGfx *_gfx; - SciGuiScreen *_screen; - - int _codeFontsCount; - GuiResourceId *_codeFonts; - int _codeColorsCount; - uint16 *_codeColors; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_transitions.cpp b/engines/sci/graphics/gui_transitions.cpp deleted file mode 100644 index 063f497d71..0000000000 --- a/engines/sci/graphics/gui_transitions.cpp +++ /dev/null @@ -1,576 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/events.h" -#include "common/util.h" -#include "common/stack.h" -#include "graphics/surface.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_transitions.h" - -namespace Sci { - -SciGuiTransitions::SciGuiTransitions(SciGui *gui, SciGuiScreen *screen, SciGuiPalette *palette, bool isVGA) - : _gui(gui), _screen(screen), _palette(palette), _isVGA(isVGA) { - init(); -} - -SciGuiTransitions::~SciGuiTransitions() { - delete[] _oldScreen; -} - -// This table contains a mapping between oldIDs (prior SCI1LATE) and newIDs -static const GuiTransitionTranslateEntry oldTransitionIDs[] = { - { 0, SCI_TRANSITIONS_VERTICALROLL_FROMCENTER, false }, - { 1, SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER, false }, - { 2, SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, false }, - { 3, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, false }, - { 4, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, false }, - { 5, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, false }, - { 6, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, false }, - { 7, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, false }, - { 8, SCI_TRANSITIONS_BLOCKS, false }, - { 9, SCI_TRANSITIONS_VERTICALROLL_TOCENTER, false }, - { 10, SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, false }, - { 11, SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, true }, - { 12, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, true }, - { 13, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, true }, - { 14, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, true }, - { 15, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, true }, - { 16, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, true }, - { 17, SCI_TRANSITIONS_BLOCKS, true }, - { 18, SCI_TRANSITIONS_PIXELATION, false }, - { 27, SCI_TRANSITIONS_PIXELATION , true }, - { 30, SCI_TRANSITIONS_FADEPALETTE, false }, - { 40, SCI_TRANSITIONS_SCROLL_RIGHT, false }, - { 41, SCI_TRANSITIONS_SCROLL_LEFT, false }, - { 42, SCI_TRANSITIONS_SCROLL_UP, false }, - { 43, SCI_TRANSITIONS_SCROLL_DOWN, false }, - { 100, SCI_TRANSITIONS_NONE, false }, - { 255, 255, false } -}; - -// this table defines the blackout-transition that needs to be done prior doing the actual transition -static const GuiTransitionTranslateEntry blackoutTransitionIDs[] = { - { SCI_TRANSITIONS_VERTICALROLL_FROMCENTER, SCI_TRANSITIONS_VERTICALROLL_TOCENTER, true }, - { SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER, SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, true }, - { SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, true }, - { SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, true }, - { SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, true }, - { SCI_TRANSITIONS_STRAIGHT_FROM_TOP, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, true }, - { SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, true }, - { SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, true }, - { SCI_TRANSITIONS_BLOCKS, SCI_TRANSITIONS_BLOCKS, true }, - { SCI_TRANSITIONS_PIXELATION, SCI_TRANSITIONS_PIXELATION, true }, - { SCI_TRANSITIONS_FADEPALETTE, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_SCROLL_RIGHT, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_SCROLL_LEFT, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_SCROLL_UP, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_SCROLL_DOWN, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_NONE_LONGBOW, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_NONE, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_VERTICALROLL_TOCENTER, SCI_TRANSITIONS_NONE, true }, - { SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, SCI_TRANSITIONS_NONE, true }, - { 255, 255, true } -}; - -void SciGuiTransitions::init() { - _oldScreen = new byte[_screen->_displayHeight * _screen->_displayWidth]; - - if (getSciVersion() >= SCI_VERSION_1_LATE) - _translationTable = NULL; - else - _translationTable = oldTransitionIDs; - - // setup default transition - _number = SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER; - _blackoutFlag = false; -} - -void SciGuiTransitions::setup(int16 number, bool blackoutFlag) { - if (number != -1) { - _number = number; - _blackoutFlag = blackoutFlag; - } -} - -void SciGuiTransitions::updateScreenAndWait(int msec) { - Common::Event ev; - g_system->updateScreen(); - g_system->delayMillis(msec); - while (g_system->getEventManager()->pollEvent(ev)) {} // discard all events -} - -// will translate a number and return corresponding translationEntry -const GuiTransitionTranslateEntry *SciGuiTransitions::translateNumber (int16 number, const GuiTransitionTranslateEntry *tablePtr) { - while (1) { - if (tablePtr->orgId == 255) - return NULL; - if (tablePtr->orgId == number) - return tablePtr; - tablePtr++; - } -} - -void SciGuiTransitions::doit(Common::Rect picRect) { - const GuiTransitionTranslateEntry *translationEntry = _translationTable; - - _picRect = picRect; - - if (_translationTable) { - // We need to translate the ID - translationEntry = translateNumber(_number, _translationTable); - if (translationEntry) { - _number = translationEntry->newId; - _blackoutFlag = translationEntry->blackoutFlag; - } else { - warning("SciGuiTransitions: old ID %d not supported", _number); - _number = SCI_TRANSITIONS_NONE; - _blackoutFlag = false; - } - } - - if (_blackoutFlag) { - // We need to find out what transition we are supposed to use for blackout - translationEntry = translateNumber(_number, blackoutTransitionIDs); - if (translationEntry) { - doTransition(translationEntry->newId, true); - } else { - warning("SciGuiTransitions: ID %d not listed in blackoutTransitionIDs", _number); - } - } - - // Now we do the actual transition to the new screen - doTransition(_number, false); - - if (picRect.bottom != 320) { - // TODO: this is a workaround for lsl6 not showing menubar when playing - // There is some new code in the sierra sci in ShowPic that seems to do something similar to this - _screen->copyToScreen(); - g_system->updateScreen(); - } - - _screen->_picNotValid = 0; -} - -// This may get called twice, if blackoutFlag is set. It will get once called with blackoutFlag set and another time -// with no blackoutFlag. -void SciGuiTransitions::doTransition(int16 number, bool blackoutFlag) { - if (number != SCI_TRANSITIONS_FADEPALETTE) { - setNewPalette(blackoutFlag); - } - - switch (number) { - case SCI_TRANSITIONS_VERTICALROLL_FROMCENTER: - verticalRollFromCenter(blackoutFlag); - break; - case SCI_TRANSITIONS_VERTICALROLL_TOCENTER: - verticalRollFromCenter(blackoutFlag); - break; - case SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER: - horizontalRollFromCenter(blackoutFlag); - break; - case SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER: - horizontalRollToCenter(blackoutFlag); - break; - case SCI_TRANSITIONS_DIAGONALROLL_TOCENTER: - diagonalRollToCenter(blackoutFlag); - break; - case SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER: - diagonalRollFromCenter(blackoutFlag); - break; - - case SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT: - case SCI_TRANSITIONS_STRAIGHT_FROM_LEFT: - case SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM: - case SCI_TRANSITIONS_STRAIGHT_FROM_TOP: - straight(number, blackoutFlag); - break; - - case SCI_TRANSITIONS_PIXELATION: - pixelation(blackoutFlag); - break; - - case SCI_TRANSITIONS_BLOCKS: - blocks(blackoutFlag); - break; - - case SCI_TRANSITIONS_FADEPALETTE: - if (!blackoutFlag) { - fadeOut(); setNewScreen(blackoutFlag); fadeIn(); - } - break; - - case SCI_TRANSITIONS_SCROLL_RIGHT: - case SCI_TRANSITIONS_SCROLL_LEFT: - case SCI_TRANSITIONS_SCROLL_UP: - case SCI_TRANSITIONS_SCROLL_DOWN: - scroll(number); - break; - - case SCI_TRANSITIONS_NONE_LONGBOW: - case SCI_TRANSITIONS_NONE: - setNewScreen(blackoutFlag); - break; - - default: - warning("SciGuiTransitions: ID %d not implemented", number); - setNewScreen(blackoutFlag); - } -} - -void SciGuiTransitions::setNewPalette(bool blackoutFlag) { - if (!blackoutFlag) - if (_isVGA) - _palette->setOnScreen(); -} - -void SciGuiTransitions::setNewScreen(bool blackoutFlag) { - if (!blackoutFlag) { - _screen->copyRectToScreen(_picRect); - g_system->updateScreen(); - } -} - -void SciGuiTransitions::copyRectToScreen(const Common::Rect rect, bool blackoutFlag) { - if (!blackoutFlag) { - _screen->copyRectToScreen(rect); - } else { - Graphics::Surface *surface = g_system->lockScreen(); - surface->fillRect(rect, 0); - g_system->unlockScreen(); - } -} - -// Note: dont do too many steps in here, otherwise cpu will crap out because of the load -void SciGuiTransitions::fadeOut() { - byte oldPalette[4 * 256], workPalette[4 * 256]; - int16 stepNr, colorNr; - - g_system->grabPalette(oldPalette, 0, 256); - - for (stepNr = 100; stepNr >= 0; stepNr -= 10) { - for (colorNr = 1; colorNr < 255; colorNr++){ - workPalette[colorNr * 4 + 0] = oldPalette[colorNr * 4] * stepNr / 100; - workPalette[colorNr * 4 + 1] = oldPalette[colorNr * 4 + 1] * stepNr / 100; - workPalette[colorNr * 4 + 2] = oldPalette[colorNr * 4 + 2] * stepNr / 100; - } - g_system->setPalette(workPalette + 4, 1, 254); - _gui->wait(2); - } -} - -// Note: dont do too many steps in here, otherwise cpu will crap out because of the load -void SciGuiTransitions::fadeIn() { - int16 stepNr; - - for (stepNr = 0; stepNr <= 100; stepNr += 10) { - _palette->setIntensity(1, 255, stepNr, true); - _gui->wait(2); - } -} - -// pixelates the new picture over the old one - works against the whole screen -// TODO: it seems this needs to get applied on _picRect only if possible -void SciGuiTransitions::pixelation (bool blackoutFlag) { - uint16 mask = 0x40, stepNr = 0; - Common::Rect pixelRect; - - do { - mask = (mask & 1) ? (mask >> 1) ^ 0xB400 : mask >> 1; - if (mask >= 320 * 200) - continue; - pixelRect.left = mask % 320; pixelRect.right = pixelRect.left + 1; - pixelRect.top = mask / 320; pixelRect.bottom = pixelRect.top + 1; - pixelRect.clip(_picRect); - if (!pixelRect.isEmpty()) - copyRectToScreen(pixelRect, blackoutFlag); - if ((stepNr & 0x3FF) == 0) { - updateScreenAndWait(5); - } - stepNr++; - } while (mask != 0x40); -} - -// like pixelation but uses 8x8 blocks - works against the whole screen -// TODO: it seems this needs to get applied on _picRect only if possible -void SciGuiTransitions::blocks(bool blackoutFlag) { - uint16 mask = 0x40, stepNr = 0; - Common::Rect blockRect; - - do { - mask = (mask & 1) ? (mask >> 1) ^ 0x240 : mask >> 1; - if (mask >= 40 * 25) - continue; - blockRect.left = (mask % 40) << 3; blockRect.right = blockRect.left + 8; - blockRect.top = (mask / 40) << 3; blockRect.bottom = blockRect.top + 8; - blockRect.clip(_picRect); - if (!blockRect.isEmpty()) - copyRectToScreen(blockRect, blackoutFlag); - if ((stepNr & 7) == 0) { - updateScreenAndWait(4); - } - stepNr++; - } while (mask != 0x40); -} - -// directly shows new screen starting up/down/left/right and going to the opposite direction - works on _picRect area only -void SciGuiTransitions::straight(int16 number, bool blackoutFlag) { - int16 stepNr = 0; - Common::Rect newScreenRect = _picRect; - - switch (number) { - case SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT: - newScreenRect.left = newScreenRect.right - 1; - while (newScreenRect.left >= _picRect.left) { - copyRectToScreen(newScreenRect, blackoutFlag); - if ((stepNr & 1) == 0) { - updateScreenAndWait(1); - } - stepNr++; - newScreenRect.translate(-1, 0); - } - break; - - case SCI_TRANSITIONS_STRAIGHT_FROM_LEFT: - newScreenRect.right = newScreenRect.left + 1; - while (newScreenRect.right <= _picRect.right) { - copyRectToScreen(newScreenRect, blackoutFlag); - if ((stepNr & 1) == 0) { - updateScreenAndWait(1); - } - stepNr++; - newScreenRect.translate(1, 0); - } - break; - - case SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM: - newScreenRect.top = newScreenRect.bottom - 1; - while (newScreenRect.top >= _picRect.top) { - copyRectToScreen(newScreenRect, blackoutFlag); - updateScreenAndWait(3); - stepNr++; - newScreenRect.translate(0, -1); - } - break; - - case SCI_TRANSITIONS_STRAIGHT_FROM_TOP: - newScreenRect.bottom = newScreenRect.top + 1; - while (newScreenRect.bottom <= _picRect.bottom) { - copyRectToScreen(newScreenRect, blackoutFlag); - updateScreenAndWait(3); - stepNr++; - newScreenRect.translate(0, 1); - } - break; - } -} - -// scroll old screen (up/down/left/right) and insert new screen that way - works on _picRect area only -void SciGuiTransitions::scroll(int16 number) { - int16 screenWidth, screenHeight; - byte *oldScreenPtr; - int16 stepNr = 0; - Common::Rect oldMoveRect = _picRect; - Common::Rect newMoveRect = _picRect; - Common::Rect newScreenRect = _picRect; - - _screen->copyFromScreen(_oldScreen); - screenWidth = _screen->_displayWidth; screenHeight = _screen->_displayHeight; - - oldScreenPtr = _oldScreen + _picRect.left + _picRect.top * screenWidth; - - switch (number) { - case SCI_TRANSITIONS_SCROLL_LEFT: - newScreenRect.right = newScreenRect.left; - newMoveRect.left = newMoveRect.right; - while (oldMoveRect.left < oldMoveRect.right) { - oldScreenPtr++; oldMoveRect.right--; - if (oldMoveRect.right > oldMoveRect.left) - g_system->copyRectToScreen(oldScreenPtr, screenWidth, oldMoveRect.left, oldMoveRect.top, oldMoveRect.width(), oldMoveRect.height()); - newScreenRect.right++; newMoveRect.left--; - _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top); - if ((stepNr & 1) == 0) { - updateScreenAndWait(1); - } - stepNr++; - } - if ((stepNr & 1) == 0) - g_system->updateScreen(); - break; - - case SCI_TRANSITIONS_SCROLL_RIGHT: - newScreenRect.left = newScreenRect.right; - while (oldMoveRect.left < oldMoveRect.right) { - oldMoveRect.left++; - if (oldMoveRect.right > oldMoveRect.left) - g_system->copyRectToScreen(oldScreenPtr, screenWidth, oldMoveRect.left, oldMoveRect.top, oldMoveRect.width(), oldMoveRect.height()); - newScreenRect.left--; - _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top); - if ((stepNr & 1) == 0) { - updateScreenAndWait(1); - } - stepNr++; - } - if ((stepNr & 1) == 0) - g_system->updateScreen(); - break; - - case SCI_TRANSITIONS_SCROLL_UP: - newScreenRect.bottom = newScreenRect.top; - newMoveRect.top = newMoveRect.bottom; - while (oldMoveRect.top < oldMoveRect.bottom) { - oldScreenPtr += screenWidth; oldMoveRect.top++; - if (oldMoveRect.top < oldMoveRect.bottom) - g_system->copyRectToScreen(oldScreenPtr, screenWidth, _picRect.left, _picRect.top, oldMoveRect.width(), oldMoveRect.height()); - newScreenRect.bottom++; newMoveRect.top--; - _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top); - updateScreenAndWait(3); - } - break; - - case SCI_TRANSITIONS_SCROLL_DOWN: - newScreenRect.top = newScreenRect.bottom; - while (oldMoveRect.top < oldMoveRect.bottom) { - oldMoveRect.top++; - if (oldMoveRect.top < oldMoveRect.bottom) - g_system->copyRectToScreen(oldScreenPtr, screenWidth, oldMoveRect.left, oldMoveRect.top, oldMoveRect.width(), oldMoveRect.height()); - newScreenRect.top--; - _screen->copyRectToScreen(newScreenRect, _picRect.left, _picRect.top); - updateScreenAndWait(3); - } - break; - } -} - -// vertically displays new screen starting from center - works on _picRect area only -void SciGuiTransitions::verticalRollFromCenter(bool blackoutFlag) { - Common::Rect leftRect = Common::Rect(_picRect.left + (_picRect.width() / 2) -1, _picRect.top, _picRect.left + (_picRect.width() / 2), _picRect.bottom); - Common::Rect rightRect = Common::Rect(leftRect.right, _picRect.top, leftRect.right + 1, _picRect.bottom); - - while ((leftRect.left >= _picRect.left) || (rightRect.right <= _picRect.right)) { - if (leftRect.left < _picRect.left) - leftRect.translate(1, 0); - if (rightRect.right > _picRect.right) - rightRect.translate(-1, 0); - copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0); - copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0); - updateScreenAndWait(2); - } -} - -// vertically displays new screen starting from edges - works on _picRect area only -void SciGuiTransitions::verticalRollToCenter(bool blackoutFlag) { - Common::Rect leftRect = Common::Rect(_picRect.left, _picRect.top, _picRect.left + 1, _picRect.bottom); - Common::Rect rightRect = Common::Rect(leftRect.right - 1, _picRect.top, leftRect.right, _picRect.bottom); - - while (leftRect.left < rightRect.right) { - copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0); - copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0); - updateScreenAndWait(2); - } -} - -// horizontally displays new screen starting from center - works on _picRect area only -void SciGuiTransitions::horizontalRollFromCenter(bool blackoutFlag) { - Common::Rect upperRect = Common::Rect(_picRect.left, _picRect.top + (_picRect.height() / 2) - 1, _picRect.right, _picRect.top + (_picRect.height() / 2)); - Common::Rect lowerRect = Common::Rect(upperRect.left, upperRect.bottom, upperRect.right, upperRect.bottom + 1); - - while ((upperRect.top >= _picRect.top) || (lowerRect.bottom <= _picRect.bottom)) { - if (upperRect.top < _picRect.top) - upperRect.translate(0, 1); - if (lowerRect.bottom > _picRect.bottom) - lowerRect.translate(0, -1); - copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, -1); - copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1); - updateScreenAndWait(3); - } -} - -// horizontally displays new screen starting from upper and lower edge - works on _picRect area only -void SciGuiTransitions::horizontalRollToCenter(bool blackoutFlag) { - Common::Rect upperRect = Common::Rect(_picRect.left, _picRect.top, _picRect.right, _picRect.top + 1); - Common::Rect lowerRect = Common::Rect(upperRect.left, _picRect.bottom - 1, upperRect.right, _picRect.bottom); - - while (upperRect.top < lowerRect.bottom) { - copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1); - copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1); - updateScreenAndWait(3); - } -} - -// diagonally displays new screen starting from center - works on _picRect area only -// assumes that height of rect is larger than width -void SciGuiTransitions::diagonalRollFromCenter(bool blackoutFlag) { - int16 halfHeight = _picRect.height() / 2; - Common::Rect upperRect(_picRect.left + halfHeight - 2, _picRect.top + halfHeight, _picRect.right - halfHeight + 1, _picRect.top + halfHeight + 1); - Common::Rect lowerRect(upperRect.left, upperRect.top, upperRect.right, upperRect.bottom); - Common::Rect leftRect(upperRect.left, upperRect.top, upperRect.left + 1, lowerRect.bottom); - Common::Rect rightRect(upperRect.right, upperRect.top, upperRect.right + 1, lowerRect.bottom); - - while ((upperRect.top >= _picRect.top) || (lowerRect.bottom <= _picRect.bottom)) { - if (upperRect.top < _picRect.top) { - upperRect.translate(0, 1); leftRect.top++; rightRect.top++; - } - if (lowerRect.bottom > _picRect.bottom) { - lowerRect.translate(0, -1); leftRect.bottom--; rightRect.bottom--; - } - if (leftRect.left < _picRect.left) { - leftRect.translate(1, 0); upperRect.left++; lowerRect.left++; - } - if (rightRect.right > _picRect.right) { - rightRect.translate(-1, 0); upperRect.right--; lowerRect.right--; - } - copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, -1); upperRect.left--; upperRect.right++; - copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1); lowerRect.left--; lowerRect.right++; - copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0); leftRect.top--; leftRect.bottom++; - copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0); rightRect.top--; rightRect.bottom++; - updateScreenAndWait(3); - } -} - -// diagonally displays new screen starting from edges - works on _picRect area only -// assumes that height of rect is larger than width -void SciGuiTransitions::diagonalRollToCenter(bool blackoutFlag) { - Common::Rect upperRect(_picRect.left, _picRect.top, _picRect.right, _picRect.top + 1); - Common::Rect lowerRect(_picRect.left, _picRect.bottom - 1, _picRect.right, _picRect.bottom); - Common::Rect leftRect(_picRect.left, _picRect.top, _picRect.left + 1, _picRect.bottom); - Common::Rect rightRect(_picRect.right - 1, _picRect.top, _picRect.right, _picRect.bottom); - - while (upperRect.top < lowerRect.bottom) { - copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1); upperRect.left++; upperRect.right--; - copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1); lowerRect.left++; lowerRect.right--; - copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0); - copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0); - updateScreenAndWait(3); - } -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_transitions.h b/engines/sci/graphics/gui_transitions.h deleted file mode 100644 index 691a71af91..0000000000 --- a/engines/sci/graphics/gui_transitions.h +++ /dev/null @@ -1,106 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_TRANSITIONS_H -#define SCI_GUI_TRANSITIONS_H - -#include "sci/graphics/gui_helpers.h" - -namespace Sci { - -struct GuiTransitionTranslateEntry { - int16 orgId; - int16 newId; - bool blackoutFlag; -}; - -enum { - SCI_TRANSITIONS_VERTICALROLL_FROMCENTER = 0, - SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER = 1, - SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT = 2, - SCI_TRANSITIONS_STRAIGHT_FROM_LEFT = 3, - SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM = 4, - SCI_TRANSITIONS_STRAIGHT_FROM_TOP = 5, - SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER = 6, - SCI_TRANSITIONS_DIAGONALROLL_TOCENTER = 7, - SCI_TRANSITIONS_BLOCKS = 8, - SCI_TRANSITIONS_PIXELATION = 9, - SCI_TRANSITIONS_FADEPALETTE = 10, - SCI_TRANSITIONS_SCROLL_RIGHT = 11, - SCI_TRANSITIONS_SCROLL_LEFT = 12, - SCI_TRANSITIONS_SCROLL_UP = 13, - SCI_TRANSITIONS_SCROLL_DOWN = 14, - SCI_TRANSITIONS_NONE_LONGBOW = 15, - SCI_TRANSITIONS_NONE = 100, - // here are transitions that are used by the old tableset, but are not included anymore in the new tableset - SCI_TRANSITIONS_VERTICALROLL_TOCENTER = 300, - SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER = 301 -}; - -class SciGuiScreen; -class SciGuiTransitions { -public: - SciGuiTransitions(SciGui *gui, SciGuiScreen *screen, SciGuiPalette *palette, bool isVGA); - ~SciGuiTransitions(); - - void setup(int16 number, bool blackoutFlag); - void doit(Common::Rect picRect); - -private: - void init(); - const GuiTransitionTranslateEntry *translateNumber(int16 number, const GuiTransitionTranslateEntry *tablePtr); - void doTransition(int16 number, bool blackout); - void setNewPalette(bool blackoutFlag); - void setNewScreen(bool blackoutFlag); - void copyRectToScreen(const Common::Rect rect, bool blackoutFlag); - void fadeOut(); - void fadeIn(); - void pixelation(bool blackoutFlag); - void blocks(bool blackoutFlag); - void straight(int16 number, bool blackoutFlag); - void scroll(int16 number); - void verticalRollFromCenter(bool blackoutFlag); - void verticalRollToCenter(bool blackoutFlag); - void horizontalRollFromCenter(bool blackoutFlag); - void horizontalRollToCenter(bool blackoutFlag); - void diagonalRollFromCenter(bool blackoutFlag); - void diagonalRollToCenter(bool blackoutFlag); - void updateScreenAndWait(int msec); - - SciGui *_gui; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - - bool _isVGA; - const GuiTransitionTranslateEntry *_translationTable; - int16 _number; - bool _blackoutFlag; - Common::Rect _picRect; - byte *_oldScreen; // buffer for saving current active screen data to, has dimenions of _screen->_displayScreen -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_view.cpp b/engines/sci/graphics/gui_view.cpp deleted file mode 100644 index 0aeaeb3d96..0000000000 --- a/engines/sci/graphics/gui_view.cpp +++ /dev/null @@ -1,513 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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 "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_view.h" - -namespace Sci { - -SciGuiView::SciGuiView(ResourceManager *resMan, SciGuiScreen *screen, SciGuiPalette *palette, GuiResourceId resourceId) - : _resMan(resMan), _screen(screen), _palette(palette), _resourceId(resourceId) { - assert(resourceId != -1); - initData(resourceId); -} - -SciGuiView::~SciGuiView() { - // Iterate through the loops - for (uint16 loopNum = 0; loopNum < _loopCount; loopNum++) { - // and through the cells of each loop - for (uint16 celNum = 0; celNum < _loop[loopNum].celCount; celNum++) { - delete[] _loop[loopNum].cel[celNum].rawBitmap; - } - delete[] _loop[loopNum].cel; - } - delete[] _loop; - - _resMan->unlockResource(_resource); -} - -static const byte EGAmappingStraight[SCI_VIEW_EGAMAPPING_SIZE] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 -}; - -void SciGuiView::initData(GuiResourceId resourceId) { - _resource = _resMan->findResource(ResourceId(kResourceTypeView, resourceId), true); - if (!_resource) { - error("view resource %d not found", resourceId); - } - _resourceData = _resource->data; - - byte *celData, *loopData; - uint16 celOffset; - sciViewCelInfo *cel; - uint16 celCount = 0; - uint16 mirrorBits = 0; - uint16 palOffset = 0; - uint16 headerSize = 0; - uint16 loopSize = 0, celSize = 0; - int loopNo, celNo, EGAmapNr; - byte seekEntry; - bool isEGA = false; - bool isCompressed = true; - - _loopCount = 0; - _embeddedPal = false; - _EGAmapping = NULL; - - switch (_resMan->getViewType()) { - case kViewEga: // View-format SCI0 (and Amiga 16 colors) - isEGA = true; - case kViewAmiga: // View-format Amiga (32 colors) - case kViewVga: // View-format SCI1 - // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... - - _loopCount = _resourceData[0]; - // bit 0x8000 of _resourceData[1] means palette is set - if (_resourceData[1] & 0x40) - isCompressed = false; - mirrorBits = READ_LE_UINT16(_resourceData + 2); - palOffset = READ_LE_UINT16(_resourceData + 6); - - if (palOffset && palOffset != 0x100) { - // Some SCI0/SCI01 games also have an offset set. It seems that it points to a 16-byte mapping table - // but on those games using that mapping will actually screw things up. - // On the other side: vga sci1 games have this pointing to a VGA palette - // and ega sci1 games have this pointing to a 8x16 byte mapping table that needs to get applied then - if (!isEGA) { - _palette->createFromData(&_resourceData[palOffset], &_viewPalette); - _embeddedPal = true; - } else { - // Only use the EGA-mapping, when being SCI1 - if (getSciVersion() >= SCI_VERSION_1_EGA) { - _EGAmapping = &_resourceData[palOffset]; - for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) { - if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE)!=0) - break; - _EGAmapping += SCI_VIEW_EGAMAPPING_SIZE; - } - // If all mappings are "straight", then we actually ignore the mapping - if (EGAmapNr == SCI_VIEW_EGAMAPPING_COUNT) - _EGAmapping = NULL; - else - _EGAmapping = &_resourceData[palOffset]; - } - } - } - - _loop = new sciViewLoopInfo[_loopCount]; - for (loopNo = 0; loopNo < _loopCount; loopNo++) { - loopData = _resourceData + READ_LE_UINT16(_resourceData + 8 + loopNo * 2); - // CelCount:WORD Unknown:WORD CelOffset0:WORD CelOffset1:WORD... - - celCount = READ_LE_UINT16(loopData); - _loop[loopNo].celCount = celCount; - _loop[loopNo].mirrorFlag = mirrorBits & 1 ? true : false; - mirrorBits >>= 1; - - // read cel info - _loop[loopNo].cel = new sciViewCelInfo[celCount]; - for (celNo = 0; celNo < celCount; celNo++) { - celOffset = READ_LE_UINT16(loopData + 4 + celNo * 2); - celData = _resourceData + celOffset; - - // For VGA - // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE Unknown:BYTE RLEData starts now directly - // For EGA - // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE EGAData starts now directly - cel = &_loop[loopNo].cel[celNo]; - cel->width = READ_LE_UINT16(celData); - cel->height = READ_LE_UINT16(celData + 2); - cel->displaceX = celData[4]; - cel->displaceY = celData[5]; - cel->clearKey = celData[6]; - if (isEGA) { - cel->offsetEGA = celOffset + 7; - cel->offsetRLE = 0; - cel->offsetLiteral = 0; - } else { - cel->offsetEGA = 0; - if (isCompressed) { - cel->offsetRLE = celOffset + 8; - cel->offsetLiteral = 0; - } else { - cel->offsetRLE = 0; - cel->offsetLiteral = celOffset + 8; - } - } - cel->rawBitmap = 0; - if (_loop[loopNo].mirrorFlag) - cel->displaceX = -cel->displaceX; - } - } - break; - - case kViewVga11: // View-format SCI1.1 - // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... - // HeaderSize:WORD LoopCount:BYTE Unknown:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD - headerSize = READ_LE_UINT16(_resourceData + 0); - _loopCount = _resourceData[2]; - palOffset = READ_LE_UINT16(_resourceData + 8); - // FIXME: After LoopCount there is another byte and its set for view 50 within Laura Bow 2 CD, check what it means - - loopData = _resourceData + headerSize; - loopSize = _resourceData[12]; - celSize = _resourceData[13]; - - if (palOffset) { - _palette->createFromData(&_resourceData[palOffset], &_viewPalette); - _embeddedPal = true; - } - - _loop = new sciViewLoopInfo[_loopCount]; - for (loopNo = 0; loopNo < _loopCount; loopNo++) { - loopData = _resourceData + headerSize + (loopNo * loopSize); - - seekEntry = loopData[2]; - if (seekEntry != 255) { - if (seekEntry >= _loopCount) - error("Bad loop-pointer in sci 1.1 view"); - _loop[loopNo].mirrorFlag = true; - loopData = _resourceData + headerSize + (seekEntry * loopSize); - } else { - _loop[loopNo].mirrorFlag = false; - } - - celCount = loopData[4]; - _loop[loopNo].celCount = celCount; - - celData = _resourceData + READ_LE_UINT16(loopData + 14); - - // read cel info - _loop[loopNo].cel = new sciViewCelInfo[celCount]; - for (celNo = 0; celNo < celCount; celNo++) { - cel = &_loop[loopNo].cel[celNo]; - cel->width = READ_LE_UINT16(celData); - cel->height = READ_LE_UINT16(celData + 2); - cel->displaceX = READ_LE_UINT16(celData + 4); - cel->displaceY = READ_LE_UINT16(celData + 6); - cel->clearKey = celData[8]; - cel->offsetEGA = 0; - cel->offsetRLE = READ_LE_UINT16(celData + 24); - cel->offsetLiteral = READ_LE_UINT16(celData + 28); - cel->rawBitmap = 0; - if (_loop[loopNo].mirrorFlag) - cel->displaceX = -cel->displaceX; - - celData += celSize; - } - } - break; - - default: - error("ViewType was not detected, can't continue"); - } -} - -GuiResourceId SciGuiView::getResourceId() { - return _resourceId; -} - -int16 SciGuiView::getWidth(GuiViewLoopNo loopNo, GuiViewCelNo celNo) { - loopNo = CLIP(loopNo, 0, _loopCount - 1); - celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); - return _loopCount ? _loop[loopNo].cel[celNo].width : 0; -} - -int16 SciGuiView::getHeight(GuiViewLoopNo loopNo, GuiViewCelNo celNo) { - loopNo = CLIP(loopNo, 0, _loopCount -1); - celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); - return _loopCount ? _loop[loopNo].cel[celNo].height : 0; -} - -sciViewCelInfo *SciGuiView::getCelInfo(GuiViewLoopNo loopNo, GuiViewCelNo celNo) { - loopNo = CLIP(loopNo, 0, _loopCount - 1); - celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); - return _loopCount ? &_loop[loopNo].cel[celNo] : NULL; -} - -sciViewLoopInfo *SciGuiView::getLoopInfo(GuiViewLoopNo loopNo) { - loopNo = CLIP(loopNo, 0, _loopCount - 1); - return _loopCount ? &_loop[loopNo] : NULL; -} - -void SciGuiView::getCelRect(GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 x, int16 y, int16 z, Common::Rect *outRect) { - sciViewCelInfo *celInfo = getCelInfo(loopNo, celNo); - if (celInfo) { - outRect->left = x + celInfo->displaceX - (celInfo->width >> 1); - outRect->right = outRect->left + celInfo->width; - outRect->bottom = y + celInfo->displaceY - z + 1; - outRect->top = outRect->bottom - celInfo->height; - } -} - -void SciGuiView::unpackCel(GuiViewLoopNo loopNo, GuiViewCelNo celNo, byte *outPtr, uint16 pixelCount) { - sciViewCelInfo *celInfo = getCelInfo(loopNo, celNo); - byte *rlePtr; - byte *literalPtr; - uint16 pixelNo = 0, runLength; - byte pixel; - - if (celInfo->offsetEGA) { - // decompression for EGA views - literalPtr = _resourceData + _loop[loopNo].cel[celNo].offsetEGA; - while (pixelNo < pixelCount) { - pixel = *literalPtr++; - runLength = pixel >> 4; - memset(outPtr + pixelNo, pixel & 0x0F, MIN(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - } - return; - } - - rlePtr = _resourceData + celInfo->offsetRLE; - if (!celInfo->offsetLiteral) { // no additional literal data - if (_resMan->getViewType() == kViewAmiga) { - // decompression for amiga views - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - if (pixel & 0x07) { // fill with color - runLength = pixel & 0x07; - pixel = pixel >> 3; - while (runLength-- && pixelNo < pixelCount) { - outPtr[pixelNo++] = pixel; - } - } else { // fill with transparent - runLength = pixel >> 3; - pixelNo += runLength; - } - } - return; - } else { - // decompression for data that has just one combined stream - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - runLength = pixel & 0x3F; - switch (pixel & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *rlePtr++; - break; - case 0x80: // fill with color - memset(outPtr + pixelNo, *rlePtr++, MIN(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - break; - case 0xC0: // fill with transparent - pixelNo += runLength; - break; - } - } - return; - } - } else { - literalPtr = _resourceData + celInfo->offsetLiteral; - if (celInfo->offsetRLE) { - // decompression for data that has separate rle and literal streams - while (pixelNo < pixelCount) { - pixel = *rlePtr++; - runLength = pixel & 0x3F; - switch (pixel & 0xC0) { - case 0: // copy bytes as-is - while (runLength-- && pixelNo < pixelCount) - outPtr[pixelNo++] = *literalPtr++; - break; - case 0x80: // fill with color - memset(outPtr + pixelNo, *literalPtr++, MIN(runLength, pixelCount - pixelNo)); - pixelNo += runLength; - break; - case 0xC0: // fill with transparent - pixelNo += runLength; - break; - } - } - } else { - // literal stream only, so no compression - memcpy(outPtr, literalPtr, pixelCount); - } - return; - } - error("Unable to decompress view"); -} - -byte *SciGuiView::getBitmap(GuiViewLoopNo loopNo, GuiViewCelNo celNo) { - loopNo = CLIP(loopNo, 0, _loopCount -1); - celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); - if (_loop[loopNo].cel[celNo].rawBitmap) - return _loop[loopNo].cel[celNo].rawBitmap; - - uint16 width = _loop[loopNo].cel[celNo].width; - uint16 height = _loop[loopNo].cel[celNo].height; - // allocating memory to store cel's bitmap - assert(width * height <= 64000); - uint16 pixelCount = width * height; - _loop[loopNo].cel[celNo].rawBitmap = new byte[pixelCount]; - byte *pBitmap = _loop[loopNo].cel[celNo].rawBitmap; - - // Some RLE compressed cels end with the last non-transparent pixel, thats why we fill it up here - // FIXME: change this to fill the remaining bytes within unpackCel() - memset(pBitmap, _loop[loopNo].cel[celNo].clearKey, pixelCount); - unpackCel(loopNo, celNo, pBitmap, pixelCount); - - if (!_resMan->isVGA()) { - unditherBitmap(pBitmap, width, height, _loop[loopNo].cel[celNo].clearKey); - } - - // mirroring the cel if needed - if (_loop[loopNo].mirrorFlag) { - for (int i = 0; i < height; i++, pBitmap += width) - for (int j = 0; j < width / 2; j++) - SWAP(pBitmap[j], pBitmap[width - j - 1]); - } - return _loop[loopNo].cel[celNo].rawBitmap; -} - -// Called after unpacking an EGA cel, this will try to undither (parts) of the cel if the dithering in here -// matches dithering used by the current picture -void SciGuiView::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte clearKey) { - int16 *unditherMemorial = _screen->unditherGetMemorial(); - - // It makes no sense to go further, if no memorial data from current picture is available - if (!unditherMemorial) - return; - - // Makes no sense to process bitmaps that are 3 pixels wide or less - if (width <= 3) return; - - // If EGA mapping is used for this view, dont do undithering as well - if (_EGAmapping) - return; - - // Walk through the bitmap and remember all combinations of colors - int16 bitmapMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; - byte *curPtr; - byte color1, color2; - int16 y, x; - - memset(&bitmapMemorial, 0, sizeof(bitmapMemorial)); - - // Count all seemingly dithered pixel-combinations as soon as at least 4 pixels are adjacent - curPtr = bitmapPtr; - for (y = 0; y < height; y++) { - color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2]; - curPtr += 3; - for (x = 3; x < width; x++) { - color1 = (color1 << 4) | (color2 >> 4); - color2 = (color2 << 4) | *curPtr++; - if (color1 == color2) - bitmapMemorial[color1]++; - } - } - - // Now compare both memorial tables to find out matching dithering-combinations - bool unditherTable[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; - byte color, unditherCount = 0; - memset(&unditherTable, false, sizeof(unditherTable)); - for (color = 0; color < 255; color++) { - if ((bitmapMemorial[color] > 5) && (unditherMemorial[color] > 200)) { - // match found, check if colorKey is contained -> if so, we ignore of course - color1 = color & 0x0F; color2 = color >> 4; - if ((color1 != clearKey) && (color2 != clearKey) && (color1 != color2)) { - // so set this and the reversed color-combination for undithering - unditherTable[color] = true; unditherTable[(color1 << 4) | color2] = true; - unditherCount++; - } - } - } - - // Nothing found to undither -> exit straight away - if (!unditherCount) - return; - - // We now need to replace color-combinations - curPtr = bitmapPtr; - for (y = 0; y < height; y++) { - color = *curPtr; - for (x = 1; x < width; x++) { - color = (color << 4) | curPtr[1]; - if (unditherTable[color]) { - // some color with black? turn colors around otherwise it wont be the right color at all - if ((color & 0xF0)==0) - color = (color << 4) | (color >> 4); - curPtr[0] = color; curPtr[1] = color; - } - curPtr++; - } - curPtr++; - } -} - -void SciGuiView::draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRectTranslated, GuiViewLoopNo loopNo, GuiViewCelNo celNo, byte priority, uint16 EGAmappingNr, int16 origHeight) { - GuiPalette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette; - sciViewCelInfo *celInfo = getCelInfo(loopNo, celNo); - byte *bitmap = getBitmap(loopNo, celNo); - int16 celHeight = celInfo->height, celWidth = celInfo->width; - int16 width, height; - byte clearKey = celInfo->clearKey; - byte color; - byte drawMask = priority == 255 ? SCI_SCREEN_MASK_VISUAL : SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY; - int x, y; - - if (_embeddedPal) { - // Merge view palette in... - _palette->set(&_viewPalette, 1); - } - - width = MIN(clipRect.width(), celWidth); - height = MIN(clipRect.height(), celHeight); - - bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left); - - if (!_EGAmapping) { - for (y = clipRectTranslated.top; y < clipRectTranslated.top + height; y++, bitmap += celWidth) { - for (x = 0; x < width; x++) { - color = bitmap[x]; - if (color != clearKey && priority >= _screen->getPriority(clipRectTranslated.left + x, y)) { - if (origHeight == -1) // HACK: this parameter is passed for already scaled views, but we're not actually using it - _screen->putPixel(clipRectTranslated.left + x, y, drawMask, palette->mapping[color], priority, 0); - else - _screen->putPixelOnDisplay(clipRectTranslated.left + x, y, palette->mapping[color]); - } - } - } - } else { - byte *EGAmapping = _EGAmapping + (EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE); - for (y = clipRectTranslated.top; y < clipRectTranslated.top + height; y++, bitmap += celWidth) { - for (x = 0; x < width; x++) { - color = EGAmapping[bitmap[x]]; - if (color != clearKey && priority >= _screen->getPriority(clipRectTranslated.left + x, y)) - _screen->putPixel(clipRectTranslated.left + x, y, drawMask, color, priority, 0); - } - } - } -} - -GuiPalette *SciGuiView::getPalette() { - return _embeddedPal ? &_viewPalette : &_palette->_sysPalette; -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_view.h b/engines/sci/graphics/gui_view.h deleted file mode 100644 index c4ed3db2b0..0000000000 --- a/engines/sci/graphics/gui_view.h +++ /dev/null @@ -1,91 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_VIEW_H -#define SCI_GUI_VIEW_H - -namespace Sci { - -struct sciViewCelInfo { - int16 width, height; - char displaceX; - byte displaceY; - byte clearKey; - uint16 offsetEGA; - uint16 offsetRLE; - uint16 offsetLiteral; - byte *rawBitmap; -}; - -struct sciViewLoopInfo { - bool mirrorFlag; - uint16 celCount; - sciViewCelInfo *cel; -}; - -#define SCI_VIEW_EGAMAPPING_SIZE 16 -#define SCI_VIEW_EGAMAPPING_COUNT 8 - -class SciGuiView { -public: - SciGuiView(ResourceManager *resMan, SciGuiScreen *screen, SciGuiPalette *palette, GuiResourceId resourceId); - ~SciGuiView(); - - GuiResourceId getResourceId(); - int16 getWidth(GuiViewLoopNo loopNo, GuiViewCelNo celNo); - int16 getHeight(GuiViewLoopNo loopNo, GuiViewCelNo celNo); - sciViewCelInfo *getCelInfo(GuiViewLoopNo loopNo, GuiViewCelNo celNo); - sciViewLoopInfo *getLoopInfo(GuiViewLoopNo loopNo); - void getCelRect(GuiViewLoopNo loopNo, GuiViewCelNo celNo, int16 x, int16 y, int16 z, Common::Rect *outRect); - byte *getBitmap(GuiViewLoopNo loopNo, GuiViewCelNo celNo); - void draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRectTranslated, GuiViewLoopNo loopNo, GuiViewCelNo celNo, byte priority, uint16 EGAmappingNr, int16 origHeight = -1); - uint16 getLoopCount() const { return _loopCount; } - uint16 getCelCount(GuiViewLoopNo loopNo) { return _loop[loopNo].celCount; } - GuiPalette *getPalette(); - -private: - void initData(GuiResourceId resourceId); - void unpackCel(GuiViewLoopNo loopNo, GuiViewCelNo celNo, byte *outPtr, uint16 pixelCount); - void unditherBitmap(byte *bitmap, int16 width, int16 height, byte clearKey); - - ResourceManager *_resMan; - SciGuiScreen *_screen; - SciGuiPalette *_palette; - - GuiResourceId _resourceId; - Resource *_resource; - byte *_resourceData; - - uint16 _loopCount; - sciViewLoopInfo *_loop; - bool _embeddedPal; - GuiPalette _viewPalette; - - byte *_EGAmapping; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/gui_windowmgr.cpp b/engines/sci/graphics/gui_windowmgr.cpp deleted file mode 100644 index a77b5c3944..0000000000 --- a/engines/sci/graphics/gui_windowmgr.cpp +++ /dev/null @@ -1,286 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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/util.h" - -#include "sci/sci.h" -#include "sci/engine/state.h" -#include "sci/graphics/gui_screen.h" -#include "sci/graphics/gui_gfx.h" -#include "sci/graphics/gui_animate.h" -#include "sci/graphics/gui_text.h" -#include "sci/graphics/gui_windowmgr.h" - -namespace Sci { - -// window styles -enum { - SCI_WINDOWMGR_STYLE_TRANSPARENT = (1 << 0), - SCI_WINDOWMGR_STYLE_NOFRAME = (1 << 1), - SCI_WINDOWMGR_STYLE_TITLE = (1 << 2), - SCI_WINDOWMGR_STYLE_TOPMOST = (1 << 3), - SCI_WINDOWMGR_STYLE_USER = (1 << 7) -}; - -SciGuiWindowMgr::SciGuiWindowMgr(SciGui *gui, SciGuiScreen *screen, SciGuiGfx *gfx, SciGuiText *text) - : _gui(gui), _screen(screen), _gfx(gfx), _text(text) { -} - -SciGuiWindowMgr::~SciGuiWindowMgr() { - // TODO: Clear _windowList and delete all stuff in it? -} - -void SciGuiWindowMgr::init(Common::String gameId) { - int16 offTop = 10; - - _wmgrPort = new GuiPort(1); - _windowsById.resize(2); - _windowsById[0] = _wmgrPort; // wmgrPort is supposed to be accessible via id 0 - _windowsById[1] = _wmgrPort; // but wmgrPort may not actually have id 0, so we assign id 1 (as well) - // Background: sierra sci replies with the offset of curPort on kGetPort calls. If we reply with 0 there most games - // will work, but some scripts seem to check for 0 and initialize the variable again in that case - // resulting in problems. - - // Jones sierra sci was called with parameter -Nw 0 0 200 320 - // this actually meant not skipping the first 10 pixellines in windowMgrPort - if (gameId == "jones") - offTop = 0; - - _gfx->OpenPort(_wmgrPort); - _gfx->SetPort(_wmgrPort); - _gfx->SetOrigin(0, offTop); - _wmgrPort->rect.bottom = 200 - offTop; - _wmgrPort->rect.right = 320; - _wmgrPort->rect.moveTo(0, 0); - _wmgrPort->curTop = 0; - _wmgrPort->curLeft = 0; - _windowList.push_front(_wmgrPort); - - _picWind = NewWindow(Common::Rect(0, offTop, _screen->_width, _screen->_height), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true); -} - -int16 SciGuiWindowMgr::isFrontWindow(GuiWindow *pWnd) { - return _windowList.back() == pWnd; -} - -void SciGuiWindowMgr::BeginUpdate(GuiWindow *wnd) { - GuiPort *oldPort = _gfx->SetPort(_wmgrPort); - PortList::iterator it = _windowList.reverse_begin(); - const PortList::iterator end = Common::find(_windowList.begin(), _windowList.end(), wnd); - while (it != end) { - // FIXME: We also store GuiPort objects in the window list. - // We should add a check that we really only pass windows here... - UpdateWindow((GuiWindow *)*it); - --it; - } - _gfx->SetPort(oldPort); -} - -void SciGuiWindowMgr::EndUpdate(GuiWindow *wnd) { - GuiPort *oldPort = _gfx->SetPort(_wmgrPort); - const PortList::iterator end = _windowList.end(); - PortList::iterator it = Common::find(_windowList.begin(), end, wnd); - - // wnd has to be in _windowList - assert(it != end); - - while (++it != end) { - // FIXME: We also store GuiPort objects in the window list. - // We should add a check that we really only pass windows here... - UpdateWindow((GuiWindow *)*it); - } - - _gfx->SetPort(oldPort); -} - -GuiWindow *SciGuiWindowMgr::NewWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw) { - // Find an unused window/port id - uint id = 1; - while (id < _windowsById.size() && _windowsById[id]) { - ++id; - } - if (id == _windowsById.size()) - _windowsById.push_back(0); - assert(0 < id && id < 0xFFFF); - - GuiWindow *pwnd = new GuiWindow(id); - Common::Rect r; - - if (!pwnd) { - warning("Can't open window!"); - return 0; - } - - _windowsById[id] = pwnd; - if (style & SCI_WINDOWMGR_STYLE_TOPMOST) - _windowList.push_front(pwnd); - else - _windowList.push_back(pwnd); - _gfx->OpenPort(pwnd); - r = dims; - pwnd->rect = dims; - if (restoreRect) - pwnd->restoreRect = *restoreRect; - - pwnd->wndStyle = style; - pwnd->hSaved1 = pwnd->hSaved2 = NULL_REG; - pwnd->bDrawn = false; - if ((style & SCI_WINDOWMGR_STYLE_TRANSPARENT) == 0) - pwnd->saveScreenMask = (priority == -1 ? SCI_SCREEN_MASK_VISUAL : SCI_SCREEN_MASK_VISUAL | SCI_SCREEN_MASK_PRIORITY); - - if (title && (style & SCI_WINDOWMGR_STYLE_TITLE)) { - pwnd->title = title; - } - - r = dims; - if (style == SCI_WINDOWMGR_STYLE_USER || !(style & SCI_WINDOWMGR_STYLE_NOFRAME)) { - r.grow(1); - if (style & SCI_WINDOWMGR_STYLE_TITLE) { - r.top -= 10; - r.bottom++; - } - } - - // FIXME: it seems as if shadows may result in the window getting moved one upwards - // so that the shadow is visible (lsl5) - - pwnd->dims = r; - const Common::Rect *wmprect = &_wmgrPort->rect; - int16 oldtop = pwnd->dims.top; - int16 oldleft = pwnd->dims.left; - if (wmprect->top > pwnd->dims.top) - pwnd->dims.moveTo(pwnd->dims.left, wmprect->top); - - if (wmprect->bottom < pwnd->dims.bottom) - pwnd->dims.moveTo(pwnd->dims.left, wmprect->bottom - pwnd->dims.bottom + pwnd->dims.top); - - if (wmprect->right < pwnd->dims.right) - pwnd->dims.moveTo(wmprect->right + pwnd->dims.left - pwnd->dims.right, pwnd->dims.top); - - if (wmprect->left > pwnd->dims.left) - pwnd->dims.moveTo(wmprect->left, pwnd->dims.top); - - pwnd->rect.moveTo(pwnd->rect.left + pwnd->dims.left - oldleft, pwnd->rect.top + pwnd->dims.top - oldtop); - if (restoreRect == 0) - pwnd->restoreRect = pwnd->dims; - - if (!(pwnd->wndStyle & (SCI_WINDOWMGR_STYLE_USER | SCI_WINDOWMGR_STYLE_NOFRAME))) { - // The shadow is drawn slightly outside the window. - // Enlarge restoreRect to cover that. - pwnd->restoreRect.bottom++; - pwnd->restoreRect.right++; - } - - if (draw) - DrawWindow(pwnd); - _gfx->SetPort((GuiPort *)pwnd); - _gfx->SetOrigin(pwnd->rect.left, pwnd->rect.top + _wmgrPort->top); - pwnd->rect.moveTo(0, 0); - return pwnd; -} - -void SciGuiWindowMgr::DrawWindow(GuiWindow *pWnd) { - if (pWnd->bDrawn) - return; - Common::Rect r; - int16 wndStyle = pWnd->wndStyle; - - pWnd->bDrawn = true; - GuiPort *oldport = _gfx->SetPort(_wmgrPort); - _gfx->PenColor(0); - if ((wndStyle & SCI_WINDOWMGR_STYLE_TRANSPARENT) == 0) { - pWnd->hSaved1 = _gfx->BitsSave(pWnd->restoreRect, SCI_SCREEN_MASK_VISUAL); - if (pWnd->saveScreenMask & SCI_SCREEN_MASK_PRIORITY) { - pWnd->hSaved2 = _gfx->BitsSave(pWnd->restoreRect, SCI_SCREEN_MASK_PRIORITY); - if ((wndStyle & SCI_WINDOWMGR_STYLE_USER) == 0) - _gfx->FillRect(pWnd->restoreRect, SCI_SCREEN_MASK_PRIORITY, 0, 15); - } - } - - // drawing frame,shadow and title - if (!(wndStyle & SCI_WINDOWMGR_STYLE_USER)) { - r = pWnd->dims; - if (!(wndStyle & SCI_WINDOWMGR_STYLE_NOFRAME)) { - r.translate(1, 1); - _gfx->FrameRect(r);// shadow - r.translate(-1, -1); - _gfx->FrameRect(r);// window frame - - if (wndStyle & SCI_WINDOWMGR_STYLE_TITLE) { - _gfx->FrameRect(r); - r.grow(-1); - _gfx->FillRect(r, SCI_SCREEN_MASK_VISUAL, 0); - if (!pWnd->title.empty()) { - int16 oldcolor = _gfx->GetPort()->penClr; - _gfx->PenColor(255); - _text->Box(pWnd->title.c_str(), 1, r, SCI_TEXT_ALIGNMENT_CENTER, 0); - _gfx->PenColor(oldcolor); - } - - r = pWnd->dims; - r.top += 9; - } - - r.grow(-1); - } - - if (!(wndStyle & SCI_WINDOWMGR_STYLE_TRANSPARENT)) - _gfx->FillRect(r, SCI_SCREEN_MASK_VISUAL, pWnd->backClr); - - _gfx->BitsShow(pWnd->restoreRect); - } - _gfx->SetPort(oldport); -} - -void SciGuiWindowMgr::DisposeWindow(GuiWindow *pWnd, bool reanimate) { - _gfx->SetPort(_wmgrPort); - _gfx->BitsRestore(pWnd->hSaved1); - _gfx->BitsRestore(pWnd->hSaved2); - if (!reanimate) - _gfx->BitsShow(pWnd->restoreRect); - else - _gui->graphRedrawBox(pWnd->restoreRect); - _windowList.remove(pWnd); - _gfx->SetPort(_windowList.back()); - _windowsById[pWnd->id] = 0; - delete pWnd; -} - -void SciGuiWindowMgr::UpdateWindow(GuiWindow *wnd) { - GuiMemoryHandle handle; - - if (wnd->saveScreenMask && wnd->bDrawn) { - handle = _gfx->BitsSave(wnd->restoreRect, SCI_SCREEN_MASK_VISUAL); - _gfx->BitsRestore(wnd->hSaved1); - wnd->hSaved1 = handle; - if (wnd->saveScreenMask & SCI_SCREEN_MASK_PRIORITY) { - handle = _gfx->BitsSave(wnd->restoreRect, SCI_SCREEN_MASK_PRIORITY); - _gfx->BitsRestore(wnd->hSaved2); - wnd->hSaved2 = handle; - } - } -} - -} // End of namespace Sci diff --git a/engines/sci/graphics/gui_windowmgr.h b/engines/sci/graphics/gui_windowmgr.h deleted file mode 100644 index 483df9efc5..0000000000 --- a/engines/sci/graphics/gui_windowmgr.h +++ /dev/null @@ -1,71 +0,0 @@ -/* ScummVM - Graphic Adventure Engine - * - * ScummVM is the legal property of its developers, whose names - * are too numerous to list here. Please refer to the COPYRIGHT - * file distributed with this source distribution. - * - * 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$ - * - */ - -#ifndef SCI_GUI_WINDOWMGR_H -#define SCI_GUI_WINDOWMGR_H - -#include "common/list.h" -#include "common/array.h" - -namespace Sci { - -class SciGuiWindowMgr { -public: - SciGuiWindowMgr(SciGui *gui, SciGuiScreen *screen, SciGuiGfx *gfx, SciGuiText *text); - ~SciGuiWindowMgr(); - - void init(Common::String gameId); - - int16 isFrontWindow(GuiWindow *wnd); - void BeginUpdate(GuiWindow *wnd); - void EndUpdate(GuiWindow *wnd); - GuiWindow *NewWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw); - void DrawWindow(GuiWindow *wnd); - void DisposeWindow(GuiWindow *pWnd, bool reanimate); - void UpdateWindow(GuiWindow *wnd); - - GuiPort *getPortById(uint16 id) const { return _windowsById[id]; } - - GuiPort *_wmgrPort; - GuiWindow *_picWind; - -private: - typedef Common::List PortList; - - SciGui *_gui; - SciGuiScreen *_screen; - SciGuiGfx *_gfx; - SciGuiText *_text; - - /** The list of open 'windows' (and ports), in visual order. */ - PortList _windowList; - - /** The list of all open 'windows' (and ports), ordered by their id. */ - Common::Array _windowsById; -}; - -} // End of namespace Sci - -#endif diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h new file mode 100644 index 0000000000..27fa3f0b69 --- /dev/null +++ b/engines/sci/graphics/helpers.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_HELPERS_H +#define SCI_GRAPHICS_HELPERS_H + +#include "common/endian.h" // for READ_LE_UINT16 +#include "common/rect.h" +#include "sci/engine/vm_types.h" + +namespace Sci { + +#define SCI_SHAKE_DIRECTION_VERTICAL 1 +#define SCI_SHAKE_DIRECTION_HORIZONTAL 2 + +typedef int GuiResourceId; // is a resource-number and -1 means no parameter given +typedef reg_t MemoryHandle; +typedef int16 LoopNo; +typedef int16 CelNo; + +typedef int16 TextAlignment; + +struct Port { + uint16 id; + int16 top, left; + Common::Rect rect; + int16 curTop, curLeft; + int16 fontHeight; + GuiResourceId fontId; + bool greyedOutput; + int16 penClr, backClr; + int16 penMode; + + Port(uint16 theId) : id(theId), top(0), left(0), + curTop(0), curLeft(0), + fontHeight(0), fontId(0), greyedOutput(false), + penClr(0), backClr(0xFF), penMode(0) { + } +}; + +struct Window : public Port { + Common::Rect dims; // client area of window + Common::Rect restoreRect; // total area of window including borders + uint16 wndStyle; + uint16 saveScreenMask; + reg_t hSaved1; + reg_t hSaved2; + Common::String title; + bool bDrawn; + + Window(uint16 theId) : Port(theId), + wndStyle(0), saveScreenMask(0), + hSaved1(NULL_REG), hSaved2(NULL_REG), + bDrawn(false) { + } +}; + +struct AnimateEntry { + reg_t object; + GuiResourceId viewId; + LoopNo loopNo; + CelNo celNo; + int16 paletteNo; + int16 x, y, z; + int16 priority; + uint16 signal; + Common::Rect celRect; + bool showBitsFlag; + MemoryHandle castHandle; +}; +typedef Common::List AnimateList; + +struct Color { + byte used; + byte r, g, b; +}; + +struct Palette { + byte mapping[256]; + uint32 timestamp; + Color colors[256]; + byte intensity[256]; +}; + +struct PalSchedule { + byte from; + uint32 schedule; +}; + +/** Button and frame control flags. */ +enum controlStateFlags { + kControlStateEnabled = 0x0001, ///< 0001 - enabled buttons (used by the interpreter) + kControlStateDisabled = 0x0004, ///< 0010 - grayed out buttons (used by the interpreter) + kControlStateFramed = 0x0008, ///< 1000 - widgets surrounded by a frame (used by the interpreter) + kControlStateDitherFramed = 0x1000 ///< 0001 0000 0000 0000 - widgets surrounded by a dithered frame (used in kgraphics) +}; + +enum ViewType { + kViewUnknown, + kViewEga, + kViewVga, + kViewVga11, + kViewAmiga +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/menu.cpp b/engines/sci/graphics/menu.cpp new file mode 100644 index 0000000000..719b52fec1 --- /dev/null +++ b/engines/sci/graphics/menu.cpp @@ -0,0 +1,648 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/event.h" +#include "sci/engine/state.h" +#include "sci/graphics/helpers.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/cursor.h" +#include "sci/graphics/font.h" +#include "sci/graphics/text.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/menu.h" + +namespace Sci { + +SciGuiMenu::SciGuiMenu(SciEvent *event, SegManager *segMan, Gfx *gfx, Text *text, Screen *screen, Cursor *cursor) + : _event(event), _segMan(segMan), _gfx(gfx), _text(text), _screen(screen), _cursor(cursor) { + + _listCount = 0; + // We actually set active item in here and remember last selection of the user + // sierra sci always defaulted to first item every time menu was called via ESC, we dont follow that logic + _curMenuId = 1; + _curItemId = 1; + + _menuSaveHandle = NULL_REG; + _barSaveHandle = NULL_REG; + _oldPort = NULL; +} + +SciGuiMenu::~SciGuiMenu() { + // TODO: deallocate _list and _itemList +} + +void SciGuiMenu::add(Common::String title, Common::String content, reg_t contentVmPtr) { + GuiMenuEntry *menuEntry; + uint16 itemCount = 0; + GuiMenuItemEntry *itemEntry; + int contentSize = content.size(); + int separatorCount; + int curPos, beginPos, endPos, tempPos; + int tagPos, rightAlignedPos, functionPos, altPos, controlPos; + + // Sierra SCI starts with id 1, so we do so as well + _listCount++; + menuEntry = new GuiMenuEntry(_listCount); + menuEntry->text = title; + _list.push_back(menuEntry); + + curPos = 0; + do { + itemCount++; + itemEntry = new GuiMenuItemEntry(_listCount, itemCount); + + beginPos = curPos; + + // Now go through the content till we find end-marker and collect data about it + // ':' is an end-marker for each item + tagPos = 0; rightAlignedPos = 0; + controlPos = 0; altPos = 0; functionPos = 0; + while ((curPos < contentSize) && (content[curPos] != ':')) { + switch (content[curPos]) { + case '=': // Set tag + if (tagPos) + error("multiple tag markers within one menu-item"); + tagPos = curPos; + break; + case '`': // Right-aligned + if (rightAlignedPos) + error("multiple right-aligned markers within one menu-item"); + rightAlignedPos = curPos; + break; + case '^': // Ctrl-prefix + if (controlPos) + error("multiple control markers within one menu-item"); + controlPos = curPos; + break; + case '@': // Alt-prefix + if (altPos) + error("multiple alt markers within one menu-item"); + altPos = curPos; + break; + case '#': // Function-prefix + if (functionPos) + error("multiple function markers within one menu-item"); + functionPos = curPos; + break; + } + curPos++; + } + endPos = curPos; + + // Control/Alt/Function key mapping... + if (controlPos) { + content.setChar(SCI_MENU_REPLACE_ONCONTROL, controlPos); + itemEntry->keyModifier = SCI_KEYMOD_CTRL; + tempPos = controlPos + 1; + if (tempPos >= contentSize) + error("control marker at end of item"); + itemEntry->keyPress = tolower(content[tempPos]); + content.setChar(toupper(content[tempPos]), tempPos); + } + if (altPos) { + content.setChar(SCI_MENU_REPLACE_ONALT, altPos); + itemEntry->keyModifier = SCI_KEYMOD_ALT; + tempPos = altPos + 1; + if (tempPos >= contentSize) + error("alt marker at end of item"); + itemEntry->keyPress = tolower(content[tempPos]); + content.setChar(toupper(content[tempPos]), tempPos); + } + if (functionPos) { + content.setChar(SCI_MENU_REPLACE_ONFUNCTION, functionPos); + tempPos = functionPos + 1; + if (tempPos >= contentSize) + error("function marker at end of item"); + itemEntry->keyPress = content[tempPos]; + switch (content[functionPos + 1]) { + case '1': itemEntry->keyPress = SCI_KEY_F1; break; + case '2': itemEntry->keyPress = SCI_KEY_F2; break; + case '3': itemEntry->keyPress = SCI_KEY_F3; break; + case '4': itemEntry->keyPress = SCI_KEY_F4; break; + case '5': itemEntry->keyPress = SCI_KEY_F5; break; + case '6': itemEntry->keyPress = SCI_KEY_F6; break; + case '7': itemEntry->keyPress = SCI_KEY_F7; break; + case '8': itemEntry->keyPress = SCI_KEY_F8; break; + case '9': itemEntry->keyPress = SCI_KEY_F9; break; + case '0': itemEntry->keyPress = SCI_KEY_F10; break; + default: + error("illegal function key specified"); + } + } + + // Now get all strings + tempPos = endPos; + if (rightAlignedPos) { + tempPos = rightAlignedPos; + } else if (tagPos) { + tempPos = tagPos; + } + curPos = beginPos; + separatorCount = 0; + while (curPos < tempPos) { + switch (content[curPos]) { + case '!': + case '-': + case ' ': + separatorCount++; + } + curPos++; + } + if (separatorCount == tempPos - beginPos) { + itemEntry->separatorLine = true; + } else { + EngineState *s = ((SciEngine *)g_engine)->getEngineState(); // HACK: needed for strSplit() + itemEntry->text = s->strSplit(Common::String(content.c_str() + beginPos, tempPos - beginPos).c_str()); + } + itemEntry->textVmPtr = contentVmPtr; + itemEntry->textVmPtr.offset += beginPos; + + if (rightAlignedPos) { + rightAlignedPos++; + tempPos = endPos; + // Shouldnt be needed at all, cause right aligned occurs after tag (hopefully) + // If no game is found that causes problems, remove this line (29.11.2009) + //if (tagPos && tagPos >= rightAlignedPos) + // tempPos = tagPos; + itemEntry->textRightAligned = Common::String(content.c_str() + rightAlignedPos, tempPos - rightAlignedPos); + } + + if (tagPos) { + tempPos = functionPos + 1; + if (tempPos >= contentSize) + error("tag marker at end of item"); + itemEntry->tag = atoi(content.c_str() + tempPos); + } + + curPos = endPos + 1; + + _itemList.push_back(itemEntry); + } while (curPos < contentSize); +} + +GuiMenuItemEntry *SciGuiMenu::findItem(uint16 menuId, uint16 itemId) { + GuiMenuItemList::iterator listIterator; + GuiMenuItemList::iterator listEnd = _itemList.end(); + GuiMenuItemEntry *listEntry; + + listIterator = _itemList.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + if ((listEntry->menuId == menuId) && (listEntry->id == itemId)) + return listEntry; + + listIterator++; + } + return NULL; +} + +void SciGuiMenu::setAttribute(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value) { + EngineState *s = ((SciEngine *)g_engine)->getEngineState(); // HACK: needed for strSplit() + GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); + if (!itemEntry) + error("Tried to setAttribute() on non-existant menu-item %d:%d", menuId, itemId); + switch (attributeId) { + case SCI_MENU_ATTRIBUTE_ENABLED: + itemEntry->enabled = value.isNull() ? false : true; + break; + case SCI_MENU_ATTRIBUTE_SAID: + itemEntry->saidVmPtr = value; + break; + case SCI_MENU_ATTRIBUTE_TEXT: + itemEntry->text = s->strSplit(_segMan->getString(value).c_str()); + itemEntry->textVmPtr = value; + // We assume here that no script ever creates a separatorLine dynamically + break; + case SCI_MENU_ATTRIBUTE_KEYPRESS: + itemEntry->keyPress = tolower(value.offset); + itemEntry->keyModifier = 0; + // TODO: Find out how modifier is handled + printf("setAttr keypress %X %X\n", value.segment, value.offset); + break; + case SCI_MENU_ATTRIBUTE_TAG: + itemEntry->tag = value.offset; + break; + default: + // Happens when loading a game in LSL3 - attribute 1A + warning("setAttribute() called with unsupported attributeId %X", attributeId); + } +} + +reg_t SciGuiMenu::getAttribute(uint16 menuId, uint16 itemId, uint16 attributeId) { + GuiMenuItemEntry *itemEntry = findItem(menuId, itemId); + if (!itemEntry) + error("Tried to getAttribute() on non-existant menu-item %d:%d", menuId, itemId); + switch (attributeId) { + case SCI_MENU_ATTRIBUTE_ENABLED: + if (itemEntry->enabled) + return make_reg(0, 1); + break; + case SCI_MENU_ATTRIBUTE_SAID: + return itemEntry->saidVmPtr; + case SCI_MENU_ATTRIBUTE_TEXT: + return itemEntry->textVmPtr; + case SCI_MENU_ATTRIBUTE_KEYPRESS: + // TODO: Find out how modifier is handled + return make_reg(0, itemEntry->keyPress); + case SCI_MENU_ATTRIBUTE_TAG: + return make_reg(0, itemEntry->tag); + default: + error("getAttribute() called with unsupported attributeId %X", attributeId); + } + return NULL_REG; +} + +void SciGuiMenu::drawBar() { + GuiMenuEntry *listEntry; + GuiMenuList::iterator listIterator; + GuiMenuList::iterator listEnd = _list.end(); + + // Hardcoded black on white + _gfx->FillRect(_gfx->_menuBarRect, 1, _screen->_colorWhite); + _gfx->PenColor(0); + _gfx->MoveTo(8, 1); + + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + _text->Draw_String(listEntry->text.c_str()); + + listIterator++; + } +} + +// This helper calculates all text widths for all menus/items +void SciGuiMenu::calculateTextWidth() { + GuiMenuList::iterator menuIterator; + GuiMenuList::iterator menuEnd = _list.end(); + GuiMenuEntry *menuEntry; + GuiMenuItemList::iterator itemIterator; + GuiMenuItemList::iterator itemEnd = _itemList.end(); + GuiMenuItemEntry *itemEntry; + int16 dummyHeight; + + menuIterator = _list.begin(); + while (menuIterator != menuEnd) { + menuEntry = *menuIterator; + _text->StringWidth(menuEntry->text.c_str(), 0, menuEntry->textWidth, dummyHeight); + + menuIterator++; + } + + itemIterator = _itemList.begin(); + while (itemIterator != itemEnd) { + itemEntry = *itemIterator; + _text->StringWidth(itemEntry->text.c_str(), 0, itemEntry->textWidth, dummyHeight); + _text->StringWidth(itemEntry->textRightAligned.c_str(), 0, itemEntry->textRightAlignedWidth, dummyHeight); + + itemIterator++; + } +} + +reg_t SciGuiMenu::select(reg_t eventObject) { + int16 eventType = GET_SEL32V(_segMan, eventObject, type); + int16 keyPress, keyModifier; + Common::Point mousePosition; + GuiMenuItemList::iterator itemIterator = _itemList.begin(); + GuiMenuItemList::iterator itemEnd = _itemList.end(); + GuiMenuItemEntry *itemEntry = NULL; + bool forceClaimed = false; + EngineState *s; + byte saidSpec[64]; + + switch (eventType) { + case SCI_EVENT_KEYBOARD: + keyPress = GET_SEL32V(_segMan, eventObject, message); + keyModifier = GET_SEL32V(_segMan, eventObject, modifiers); + switch (keyPress) { + case 0: + break; + case SCI_KEY_ESC: + itemEntry = interactiveWithKeyboard(); + forceClaimed = true; + break; + default: + while (itemIterator != itemEnd) { + itemEntry = *itemIterator; + if ((itemEntry->keyPress == keyPress) && (itemEntry->keyModifier == keyModifier)) + break; + itemIterator++; + } + if (itemIterator == itemEnd) + itemEntry = NULL; + } + break; + + case SCI_EVENT_SAID: + // HACK: should be removed as soon as said() is cleaned up + s = ((SciEngine *)g_engine)->getEngineState(); + while (itemIterator != itemEnd) { + itemEntry = *itemIterator; + + if (!itemEntry->saidVmPtr.isNull()) { + // TODO: get a pointer to saidVmPtr or make said() work on VmPtrs + _segMan->memcpy(saidSpec, itemEntry->saidVmPtr, 64); + if (said(s, saidSpec, 0) != SAID_NO_MATCH) + break; + } + itemIterator++; + } + if (itemIterator == itemEnd) + itemEntry = NULL; + break; + + case SCI_EVENT_MOUSE_PRESS: + mousePosition = _cursor->getPosition(); + if (mousePosition.y < 10) { + itemEntry = interactiveWithMouse(); + forceClaimed = true; + } + break; + } + + if (!_menuSaveHandle.isNull()) { + _gfx->BitsRestore(_menuSaveHandle); + _gfx->BitsShow(_menuRect); + _menuSaveHandle = NULL_REG; + // TODO: Change to ReAnimate() + } + if (!_barSaveHandle.isNull()) { + _gfx->BitsRestore(_barSaveHandle); + _gfx->BitsShow(_gfx->_menuBarRect); + _barSaveHandle = NULL_REG; + } + if (_oldPort) + _gfx->SetPort(_oldPort); + + if ((itemEntry) || (forceClaimed)) + PUT_SEL32(_segMan, eventObject, claimed, make_reg(0, 1)); + if (itemEntry) + return make_reg(0, (itemEntry->menuId << 8) | (itemEntry->id)); + return NULL_REG; +} + +GuiMenuItemEntry *SciGuiMenu::interactiveGetItem(uint16 menuId, uint16 itemId, bool menuChanged) { + GuiMenuItemList::iterator itemIterator = _itemList.begin(); + GuiMenuItemList::iterator itemEnd = _itemList.end(); + GuiMenuItemEntry *itemEntry; + GuiMenuItemEntry *firstItemEntry = NULL; + GuiMenuItemEntry *lastItemEntry = NULL; + + // Fixup menuId if needed + if (menuId > _listCount) + menuId = 1; + if (menuId == 0) + menuId = _listCount; + while (itemIterator != itemEnd) { + itemEntry = *itemIterator; + if (itemEntry->menuId == menuId) { + if (itemEntry->id == itemId) + return itemEntry; + if (!firstItemEntry) + firstItemEntry = itemEntry; + if ((!lastItemEntry) || (itemEntry->id > lastItemEntry->id)) + lastItemEntry = itemEntry; + } + itemIterator++; + } + if ((itemId == 0) || (menuChanged)) + return lastItemEntry; + return firstItemEntry; +} + +void SciGuiMenu::drawMenu(uint16 oldMenuId, uint16 newMenuId) { + GuiMenuEntry *listEntry; + GuiMenuList::iterator listIterator; + GuiMenuList::iterator listEnd = _list.end(); + GuiMenuItemEntry *listItemEntry; + GuiMenuItemList::iterator listItemIterator; + GuiMenuItemList::iterator listItemEnd = _itemList.end(); + Common::Rect menuTextRect; + uint16 listNr = 0; + int16 maxTextWidth = 0, maxTextRightAlignedWidth = 0; + int16 topPos; + Common::Point pixelPos; + + // Remove menu, if one is displayed + if (!_menuSaveHandle.isNull()) { + _gfx->BitsRestore(_menuSaveHandle); + _gfx->BitsShow(_menuRect); + // TODO: Change to ReAnimate() + } + + // First calculate rect of menu and also invert old and new menu text + _menuRect.top = _gfx->_menuBarRect.bottom; + menuTextRect.top = _gfx->_menuBarRect.top; + menuTextRect.bottom = _gfx->_menuBarRect.bottom; + menuTextRect.left = menuTextRect.right = 7; + listIterator = _list.begin(); + while (listIterator != listEnd) { + listEntry = *listIterator; + listNr++; + menuTextRect.left = menuTextRect.right; + menuTextRect.right += listEntry->textWidth; + if (listNr == newMenuId) + _menuRect.left = menuTextRect.left; + if ((listNr == newMenuId) || (listNr == oldMenuId)) { + menuTextRect.translate(1, 0); + _gfx->InvertRect(menuTextRect); + menuTextRect.translate(-1, 0); + } + + listIterator++; + } + if (oldMenuId != 0) + _gfx->BitsShow(_gfx->_menuBarRect); + + _menuRect.bottom = _menuRect.top + 2; + listItemIterator = _itemList.begin(); + while (listItemIterator != listItemEnd) { + listItemEntry = *listItemIterator; + if (listItemEntry->menuId == newMenuId) { + _menuRect.bottom += _gfx->_curPort->fontHeight; + maxTextWidth = MAX(maxTextWidth, listItemEntry->textWidth); + maxTextRightAlignedWidth = MAX(maxTextRightAlignedWidth, listItemEntry->textRightAlignedWidth); + } + listItemIterator++; + } + _menuRect.right = _menuRect.left + 16 + 4 + 2; + _menuRect.right += maxTextWidth + maxTextRightAlignedWidth; + if (!maxTextRightAlignedWidth) + _menuRect.right -= 5; + + // Save background + _menuSaveHandle = _gfx->BitsSave(_menuRect, SCI_SCREEN_MASK_VISUAL); + + // Do the drawing + _gfx->FillRect(_menuRect, SCI_SCREEN_MASK_VISUAL, 0); + _menuRect.left++; _menuRect.right--; _menuRect.bottom--; + _gfx->FillRect(_menuRect, SCI_SCREEN_MASK_VISUAL, _screen->_colorWhite); + + _menuRect.left += 8; + topPos = _menuRect.top + 1; + listItemIterator = _itemList.begin(); + while (listItemIterator != listItemEnd) { + listItemEntry = *listItemIterator; + if (listItemEntry->menuId == newMenuId) { + if (!listItemEntry->separatorLine) { + _gfx->TextGreyedOutput(listItemEntry->enabled ? false : true); + _gfx->MoveTo(_menuRect.left, topPos); + _text->Draw_String(listItemEntry->text.c_str()); + _gfx->MoveTo(_menuRect.right - listItemEntry->textRightAlignedWidth - 5, topPos); + _text->Draw_String(listItemEntry->textRightAligned.c_str()); + } else { + // We dont 100% follow sierra here, we draw the line from left to right. Looks better + // BTW. SCI1.1 seems to put 2 pixels and then skip one, we don't do this at all (lsl6) + pixelPos.y = topPos + (_gfx->_curPort->fontHeight >> 1) - 1; + pixelPos.x = _menuRect.left - 7; + while (pixelPos.x < (_menuRect.right - 1)) { + _screen->putPixel(pixelPos.x, pixelPos.y, SCI_SCREEN_MASK_VISUAL, 0, 0, 0); + pixelPos.x += 2; + } + } + topPos += _gfx->_curPort->fontHeight; + } + listItemIterator++; + } + _gfx->TextGreyedOutput(false); + + + _menuRect.left -= 8; + _menuRect.left--; _menuRect.right++; _menuRect.bottom++; + _gfx->BitsShow(_menuRect); +} + +void SciGuiMenu::invertMenuSelection(uint16 itemId) { + Common::Rect itemRect = _menuRect; + + itemRect.top += (itemId - 1) * _gfx->_curPort->fontHeight; + itemRect.bottom = itemRect.top + _gfx->_curPort->fontHeight + 1; + itemRect.left++; itemRect.right--; + + _gfx->InvertRect(itemRect); + _gfx->BitsShow(itemRect); +} + +GuiMenuItemEntry *SciGuiMenu::interactiveWithKeyboard() { + sciEvent curEvent; + uint16 newMenuId = _curMenuId; + uint16 newItemId = _curItemId; + GuiMenuItemEntry *curItemEntry = findItem(_curMenuId, _curItemId); + GuiMenuItemEntry *newItemEntry = curItemEntry; + + // We don't 100% follow sierra here: we select last item instead of selecting first item of first menu everytime + + calculateTextWidth(); + _oldPort = _gfx->SetPort(_gfx->_menuPort); + _barSaveHandle = _gfx->BitsSave(_gfx->_menuBarRect, SCI_SCREEN_MASK_VISUAL); + + _gfx->PenColor(0); + _gfx->BackColor(_screen->_colorWhite); + + drawBar(); + drawMenu(0, curItemEntry->menuId); + invertMenuSelection(curItemEntry->id); + _gfx->BitsShow(_gfx->_menuBarRect); + _gfx->BitsShow(_menuRect); + + while (true) { + curEvent = _event->get(SCI_EVENT_ANY); + + switch (curEvent.type) { + case SCI_EVENT_KEYBOARD: + // We don't 100% follow sierra here: - sierra didn't wrap around when changing item id + // - sierra allowed item id to be 0, which didnt make any sense + do { + switch (curEvent.data) { + case SCI_KEY_ESC: + _curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id; + return NULL; + case SCI_KEY_ENTER: + if (curItemEntry->enabled) { + _curMenuId = curItemEntry->menuId; _curItemId = curItemEntry->id; + return curItemEntry; + } + break; + case SCI_KEY_LEFT: + newMenuId--; newItemId = 1; + break; + case SCI_KEY_RIGHT: + newMenuId++; newItemId = 1; + break; + case SCI_KEY_UP: + newItemId--; + break; + case SCI_KEY_DOWN: + newItemId++; + break; + } + if ((newMenuId != curItemEntry->menuId) || (newItemId != curItemEntry->id)) { + // Selection changed, fix up new selection if required + newItemEntry = interactiveGetItem(newMenuId, newItemId, newMenuId != curItemEntry->menuId); + newMenuId = newItemEntry->menuId; newItemId = newItemEntry->id; + + // if we do this step again because of a separator line -> don't repeat left/right, but go down + switch (curEvent.data) { + case SCI_KEY_LEFT: + case SCI_KEY_RIGHT: + curEvent.data = SCI_KEY_DOWN; + } + } + } while (newItemEntry->separatorLine); + if ((newMenuId != curItemEntry->menuId) || (newItemId != curItemEntry->id)) { + // paint old and new + if (newMenuId != curItemEntry->menuId) { + // Menu changed, remove cur menu and paint new menu + drawMenu(curItemEntry->menuId, newMenuId); + } else { + invertMenuSelection(curItemEntry->id); + } + invertMenuSelection(newItemId); + + curItemEntry = newItemEntry; + } + break; + + case SCI_EVENT_NONE: + kernel_sleep(_event, 2500 / 1000); + break; + } + } +} + +GuiMenuItemEntry *SciGuiMenu::interactiveWithMouse() { + calculateTextWidth(); + + // TODO + + return NULL; +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/menu.h b/engines/sci/graphics/menu.h new file mode 100644 index 0000000000..590c40e2e4 --- /dev/null +++ b/engines/sci/graphics/menu.h @@ -0,0 +1,123 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_MENU_H +#define SCI_GRAPHICS_MENU_H + +namespace Sci { + +enum { + SCI_MENU_ATTRIBUTE_SAID = 0x6d, + SCI_MENU_ATTRIBUTE_TEXT = 0x6e, + SCI_MENU_ATTRIBUTE_KEYPRESS = 0x6f, + SCI_MENU_ATTRIBUTE_ENABLED = 0x70, + SCI_MENU_ATTRIBUTE_TAG = 0x71 +}; + +enum { + SCI_MENU_REPLACE_ONCONTROL = 0x03, + SCI_MENU_REPLACE_ONALT = 0x02, + SCI_MENU_REPLACE_ONFUNCTION = 'F' +}; + +struct GuiMenuEntry { + uint16 id; + Common::String text; + int16 textWidth; + + GuiMenuEntry(uint16 curId) + : id(curId), textWidth(0) { } +}; +typedef Common::List GuiMenuList; + +struct GuiMenuItemEntry { + uint16 menuId; + uint16 id; + bool enabled; + uint16 tag; + uint16 keyPress; + uint16 keyModifier; + bool separatorLine; + reg_t saidVmPtr; + Common::String text; + reg_t textVmPtr; + int16 textWidth; + Common::String textRightAligned; + int16 textRightAlignedWidth; + + GuiMenuItemEntry(uint16 curMenuId, uint16 curId) + : menuId(curMenuId), id(curId), + enabled(true), tag(0), keyPress(0), keyModifier(0), separatorLine(false), textWidth(0), textRightAlignedWidth(0) { + saidVmPtr = NULL_REG; + textVmPtr = NULL_REG; + } +}; +typedef Common::List GuiMenuItemList; + +class SciGuiMenu { +public: + SciGuiMenu(SciEvent *event, SegManager *segMan, Gfx *gfx, Text *text, Screen *screen, Cursor *cursor); + ~SciGuiMenu(); + + void reset(); + void add(Common::String title, Common::String content, reg_t contentVmPtr); + void setAttribute(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value); + reg_t getAttribute(uint16 menuId, uint16 itemId, uint16 attributeId); + + void drawBar(); + reg_t select(reg_t eventObject); + +private: + GuiMenuItemEntry *findItem(uint16 menuId, uint16 itemId); + void calculateTextWidth(); + void drawMenu(uint16 oldMenuId, uint16 newMenuId); + void invertMenuSelection(uint16 itemId); + GuiMenuItemEntry *interactiveWithKeyboard(); + GuiMenuItemEntry *interactiveWithMouse(); + GuiMenuItemEntry *interactiveGetItem(uint16 menuId, uint16 itemId, bool menuChanged); + + SciEvent *_event; + SegManager *_segMan; + Gfx *_gfx; + Text *_text; + Screen *_screen; + Cursor *_cursor; + + uint16 _listCount; + GuiMenuList _list; + GuiMenuItemList _itemList; + + uint16 _curMenuId; + uint16 _curItemId; + + Port *_oldPort; + MemoryHandle _barSaveHandle; + MemoryHandle _menuSaveHandle; + Common::Rect _menuRect; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp new file mode 100644 index 0000000000..ed2fa0c003 --- /dev/null +++ b/engines/sci/graphics/palette.cpp @@ -0,0 +1,380 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/timer.h" +#include "common/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" + +namespace Sci { + +SciPalette::SciPalette(ResourceManager *resMan, Screen *screen, bool autoSetPalette) + : _resMan(resMan), _screen(screen) { + int16 color; + + _sysPalette.timestamp = 0; + for (color = 0; color < 256; color++) { + _sysPalette.colors[color].used = 0; + _sysPalette.colors[color].r = 0; + _sysPalette.colors[color].g = 0; + _sysPalette.colors[color].b = 0; + _sysPalette.intensity[color] = 100; + _sysPalette.mapping[color] = color; + } + // Black and white are hardcoded + _sysPalette.colors[0].used = 1; + _sysPalette.colors[255].used = 1; + _sysPalette.colors[255].r = 255; + _sysPalette.colors[255].g = 255; + _sysPalette.colors[255].b = 255; + + if (autoSetPalette) { + if (_resMan->getViewType() == kViewEga) + setEGA(); + else if (_resMan->getViewType() == kViewAmiga) + setAmiga(); + else + setFromResource(999, 2); + } +} + +SciPalette::~SciPalette() { +} + +#define SCI_PAL_FORMAT_CONSTANT 1 +#define SCI_PAL_FORMAT_VARIABLE 0 + +void SciPalette::createFromData(byte *data, Palette *paletteOut) { + int palFormat = 0; + int palOffset = 0; + int palColorStart = 0; + int palColorCount = 0; + int colorNo = 0; + + memset(paletteOut, 0, sizeof(Palette)); + // Setup default mapping + for (colorNo = 0; colorNo < 256; colorNo++) { + paletteOut->mapping[colorNo] = colorNo; + } + if ((data[0] == 0 && data[1] == 1) || (data[0] == 0 && data[1] == 0 && READ_LE_UINT16(data + 29) == 0)) { + // SCI0/SCI1 palette + palFormat = SCI_PAL_FORMAT_VARIABLE; // CONSTANT; + palOffset = 260; + palColorStart = 0; palColorCount = 256; + //memcpy(&paletteOut->mapping, data, 256); + } else { + // SCI1.1 palette + palFormat = data[32]; + palOffset = 37; + palColorStart = READ_LE_UINT16(data + 25); palColorCount = READ_LE_UINT16(data + 29); + } + switch (palFormat) { + case SCI_PAL_FORMAT_CONSTANT: + for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + paletteOut->colors[colorNo].used = 1; + paletteOut->colors[colorNo].r = data[palOffset++]; + paletteOut->colors[colorNo].g = data[palOffset++]; + paletteOut->colors[colorNo].b = data[palOffset++]; + } + break; + case SCI_PAL_FORMAT_VARIABLE: + for (colorNo = palColorStart; colorNo < palColorStart + palColorCount; colorNo++) { + paletteOut->colors[colorNo].used = data[palOffset++]; + paletteOut->colors[colorNo].r = data[palOffset++]; + paletteOut->colors[colorNo].g = data[palOffset++]; + paletteOut->colors[colorNo].b = data[palOffset++]; + } + break; + } +} + + +// Will try to set amiga palette by using "spal" file. If not found, we return false +bool SciPalette::setAmiga() { + Common::File file; + int curColor, byte1, byte2; + + if (file.open("spal")) { + for (curColor = 0; curColor < 32; curColor++) { + byte1 = file.readByte(); + byte2 = file.readByte(); + if ((byte1 == EOF) || (byte2 == EOF)) + error("Amiga palette file ends prematurely"); + _sysPalette.colors[curColor].used = 1; + _sysPalette.colors[curColor].r = (byte1 & 0x0F) * 0x11; + _sysPalette.colors[curColor].g = ((byte2 & 0xF0) >> 4) * 0x11; + _sysPalette.colors[curColor].b = (byte2 & 0x0F) * 0x11; + } + file.close(); + setOnScreen(); + return true; + } + return false; +} + +void SciPalette::setEGA() { + int i; + byte color1, color2; + _sysPalette.colors[1].r = 0x000; _sysPalette.colors[1].g = 0x000; _sysPalette.colors[1].b = 0x0AA; + _sysPalette.colors[2].r = 0x000; _sysPalette.colors[2].g = 0x0AA; _sysPalette.colors[2].b = 0x000; + _sysPalette.colors[3].r = 0x000; _sysPalette.colors[3].g = 0x0AA; _sysPalette.colors[3].b = 0x0AA; + _sysPalette.colors[4].r = 0x0AA; _sysPalette.colors[4].g = 0x000; _sysPalette.colors[4].b = 0x000; + _sysPalette.colors[5].r = 0x0AA; _sysPalette.colors[5].g = 0x000; _sysPalette.colors[5].b = 0x0AA; + _sysPalette.colors[6].r = 0x0AA; _sysPalette.colors[6].g = 0x055; _sysPalette.colors[6].b = 0x000; + _sysPalette.colors[7].r = 0x0AA; _sysPalette.colors[7].g = 0x0AA; _sysPalette.colors[7].b = 0x0AA; + _sysPalette.colors[8].r = 0x055; _sysPalette.colors[8].g = 0x055; _sysPalette.colors[8].b = 0x055; + _sysPalette.colors[9].r = 0x055; _sysPalette.colors[9].g = 0x055; _sysPalette.colors[9].b = 0x0FF; + _sysPalette.colors[10].r = 0x055; _sysPalette.colors[10].g = 0x0FF; _sysPalette.colors[10].b = 0x055; + _sysPalette.colors[11].r = 0x055; _sysPalette.colors[11].g = 0x0FF; _sysPalette.colors[11].b = 0x0FF; + _sysPalette.colors[12].r = 0x0FF; _sysPalette.colors[12].g = 0x055; _sysPalette.colors[12].b = 0x055; + _sysPalette.colors[13].r = 0x0FF; _sysPalette.colors[13].g = 0x055; _sysPalette.colors[13].b = 0x0FF; + _sysPalette.colors[14].r = 0x0FF; _sysPalette.colors[14].g = 0x0FF; _sysPalette.colors[14].b = 0x055; + _sysPalette.colors[15].r = 0x0FF; _sysPalette.colors[15].g = 0x0FF; _sysPalette.colors[15].b = 0x0FF; + for (i = 0; i <= 15; i++) { + _sysPalette.colors[i].used = 1; + } + // Now setting colors 16-254 to the correct mix colors that occur when not doing a dithering run on + // finished pictures + for (i = 0x10; i <= 0xFE; i++) { + _sysPalette.colors[i].used = 1; + color1 = i & 0x0F; color2 = i >> 4; + _sysPalette.colors[i].r = (_sysPalette.colors[color1].r >> 1) + (_sysPalette.colors[color2].r >> 1); + _sysPalette.colors[i].g = (_sysPalette.colors[color1].g >> 1) + (_sysPalette.colors[color2].g >> 1); + _sysPalette.colors[i].b = (_sysPalette.colors[color1].b >> 1) + (_sysPalette.colors[color2].b >> 1); + } + setOnScreen(); +} + +bool SciPalette::setFromResource(GuiResourceId resourceId, uint16 flag) { + Resource *palResource = _resMan->findResource(ResourceId(kResourceTypePalette, resourceId), 0); + Palette palette; + + if (palResource) { + createFromData(palResource->data, &palette); + set(&palette, 2); + return true; + } + return false; +} + +void SciPalette::set(Palette *sciPal, uint16 flag) { + uint32 systime = _sysPalette.timestamp; + if (flag == 2 || sciPal->timestamp != systime) { + merge(sciPal, &_sysPalette, flag); + sciPal->timestamp = _sysPalette.timestamp; + if (_screen->_picNotValid == 0 && systime != _sysPalette.timestamp) + setOnScreen(); + } +} + +void SciPalette::merge(Palette *pFrom, Palette *pTo, uint16 flag) { + uint16 res; + int i,j; + // colors 0 (black) and 255 (white) are not affected by merging + for (i = 1 ; i < 255; i++) { + if (!pFrom->colors[i].used)// color is not used - so skip it + continue; + // forced palette merging or dest color is not used yet + if (flag == 2 || (!pTo->colors[i].used)) { + pTo->colors[i].used = pFrom->colors[i].used; + pTo->colors[i].r = pFrom->colors[i].r; + pTo->colors[i].g = pFrom->colors[i].g; + pTo->colors[i].b = pFrom->colors[i].b; + pFrom->mapping[i] = i; + continue; + } + // is the same color already at the same position? -> match it directly w/o lookup + // this fixes games like lsl1demo/sq5 where the same rgb color exists multiple times and where we would + // otherwise match the wrong one (which would result into the pixels affected (or not) by palette changes) + if ((pTo->colors[i].r == pFrom->colors[i].r) && (pTo->colors[i].g == pFrom->colors[i].g) && (pTo->colors[i].b == pFrom->colors[i].b)) { + pFrom->mapping[i] = i; + continue; + } + // check if exact color could be matched + res = matchColor(pTo, pFrom->colors[i].r, pFrom->colors[i].g, pFrom->colors[i].b); + if (res & 0x8000) { // exact match was found + pFrom->mapping[i] = res & 0xFF; + continue; + } + // no exact match - see if there is an unused color + for (j = 1; j < 256; j++) + if (!pTo->colors[j].used) { + pTo->colors[j].used = pFrom->colors[i].used; + pTo->colors[j].r = pFrom->colors[i].r; + pTo->colors[j].g = pFrom->colors[i].g; + pTo->colors[j].b = pFrom->colors[i].b; + pFrom->mapping[i] = j; + break; + } + // if still no luck - set an approximate color + if (j == 256) { + pFrom->mapping[i] = res & 0xFF; + pTo->colors[res & 0xFF].used |= 0x10; + } + } + pTo->timestamp = g_system->getMillis() * 60 / 1000; +} + +uint16 SciPalette::matchColor(Palette *pPal, byte r, byte g, byte b) { + byte found = 0xFF; + int diff = 0x2FFFF, cdiff; + int16 dr,dg,db; + + for (int i = 1; i < 255; i++) { + if ((!pPal->colors[i].used)) + continue; + dr = pPal->colors[i].r - r; + dg = pPal->colors[i].g - g; + db = pPal->colors[i].b - b; +// minimum squares match + cdiff = (dr*dr) + (dg*dg) + (db*db); +// minimum sum match (Sierra's) +// cdiff = ABS(dr) + ABS(dg) + ABS(db); + if (cdiff < diff) { + if (cdiff == 0) + return i | 0x8000; // setting this flag to indicate exact match + found = i; + diff = cdiff; + } + } + return found; +} + +void SciPalette::getSys(Palette *pal) { + if (pal != &_sysPalette) + memcpy(pal, &_sysPalette,sizeof(Palette)); +} + +void SciPalette::setOnScreen() { +// if (pal != &_sysPalette) +// memcpy(&_sysPalette,pal,sizeof(Palette)); + _screen->setPalette(&_sysPalette); +} + +void SciPalette::setFlag(uint16 fromColor, uint16 toColor, uint16 flag) { + uint16 colorNr; + for (colorNr = fromColor; colorNr < toColor; colorNr++) { + _sysPalette.colors[colorNr].used |= flag; + } +} + +void SciPalette::unsetFlag(uint16 fromColor, uint16 toColor, uint16 flag) { + uint16 colorNr; + for (colorNr = fromColor; colorNr < toColor; colorNr++) { + _sysPalette.colors[colorNr].used &= ~flag; + } +} + +void SciPalette::setIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette) { + memset(&_sysPalette.intensity[0] + fromColor, intensity, toColor - fromColor); + if (setPalette) + setOnScreen(); +} + +// Returns true, if palette got changed +bool SciPalette::animate(byte fromColor, byte toColor, int speed) { + Color col; + //byte colorNr; + int16 colorCount; + uint32 now = g_system->getMillis() * 60 / 1000; + + // search for sheduled animations with the same 'from' value + // schedule animation... + int scheduleCount = _schedules.size(); + int scheduleNr; + for (scheduleNr = 0; scheduleNr < scheduleCount; scheduleNr++) { + if (_schedules[scheduleNr].from == fromColor) + break; + } + if (scheduleNr == scheduleCount) { + // adding a new schedule + PalSchedule newSchedule; + newSchedule.from = fromColor; + newSchedule.schedule = now + ABS(speed); + _schedules.push_back(newSchedule); + scheduleCount++; + } + + for (scheduleNr = 0; scheduleNr < scheduleCount; scheduleNr++) { + if (_schedules[scheduleNr].from == fromColor) { + if (_schedules[scheduleNr].schedule <= now) { + if (speed > 0) { + // TODO: Not really sure about this, sierra sci seems to do exactly this here + col = _sysPalette.colors[fromColor]; + if (fromColor < toColor) { + colorCount = toColor - fromColor - 1; + memmove(&_sysPalette.colors[fromColor], &_sysPalette.colors[fromColor + 1], colorCount * sizeof(Color)); + } + _sysPalette.colors[toColor - 1] = col; + } else { + col = _sysPalette.colors[toColor - 1]; + if (fromColor < toColor) { + colorCount = toColor - fromColor - 1; + memmove(&_sysPalette.colors[fromColor + 1], &_sysPalette.colors[fromColor], colorCount * sizeof(Color)); + } + _sysPalette.colors[fromColor] = col; + } + // removing schedule + _schedules[scheduleNr].schedule = now + ABS(speed); + // TODO: Not sure when sierra actually removes a schedule + //_schedules.remove_at(scheduleNr); + return true; + } + return false; + } + } + return false; +} + +// palVary +// init - only does, if palVaryOn == false +// target, start, new palette allocation +// palVaryOn = true +// palDirection = 1 +// palStop = 64 +// palTime = from caller +// copy resource palette to target +// init target palette (used = 1 on all colors, color 0 = RGB 0, 0, 0 color 255 = RGB 0xFF, 0xFF, 0xFF +// copy sysPalette to startPalette +// init new palette like target palette +// palPercent = 1 +// do various things +// return 1 +// deinit - unloads target palette, kills timer hook, disables palVaryOn +// pause - counts up or down, if counter != 0 -> signal wont get counted up by timer +// will only count down to 0 +// +// Restarting game +// palVary = false +// palPercent = 0 +// call palVary deinit +// +// Saving/restoring +// need to save start and target-palette, when palVaryOn = true + +} // End of namespace Sci diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h new file mode 100644 index 0000000000..94f5007468 --- /dev/null +++ b/engines/sci/graphics/palette.h @@ -0,0 +1,66 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_PALETTE_H +#define SCI_GRAPHICS_PALETTE_H + +#include "sci/graphics/helpers.h" + +namespace Sci { + +class Screen; +class SciPalette { +public: + SciPalette(ResourceManager *resMan, Screen *screen, bool autoSetPalette = true); + ~SciPalette(); + + void createFromData(byte *data, Palette *paletteOut); + bool setAmiga(); + void setEGA(); + bool setFromResource(GuiResourceId resourceId, uint16 flag); + void set(Palette *sciPal, uint16 flag); + void merge(Palette *pFrom, Palette *pTo, uint16 flag); + uint16 matchColor(Palette *pPal, byte r, byte g, byte b); + void getSys(Palette *pal); + + void setOnScreen(); + + void setFlag(uint16 fromColor, uint16 toColor, uint16 flag); + void unsetFlag(uint16 fromColor, uint16 toColor, uint16 flag); + void setIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette); + bool animate(byte fromColor, byte toColor, int speed); + + Palette _sysPalette; + +private: + Screen *_screen; + ResourceManager *_resMan; + + Common::Array _schedules; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp new file mode 100644 index 0000000000..a86fffcb0a --- /dev/null +++ b/engines/sci/graphics/picture.cpp @@ -0,0 +1,973 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/stack.h" +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/picture.h" + +namespace Sci { + +SciGuiPicture::SciGuiPicture(ResourceManager *resMan, Gfx *gfx, Screen *screen, SciPalette *palette, GuiResourceId resourceId) + : _resMan(resMan), _gfx(gfx), _screen(screen), _palette(palette), _resourceId(resourceId) { + assert(resourceId != -1); + initData(resourceId); +} + +SciGuiPicture::~SciGuiPicture() { +} + +void SciGuiPicture::initData(GuiResourceId resourceId) { + _resource = _resMan->findResource(ResourceId(kResourceTypePic, resourceId), false); + if (!_resource) { + error("picture resource %d not found", resourceId); + } +} + +GuiResourceId SciGuiPicture::getResourceId() { + return _resourceId; +} + +// TODO: subclass this +void SciGuiPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) { + uint16 headerSize; + + _animationNr = animationNr; + _mirroredFlag = mirroredFlag; + _addToFlag = addToFlag; + _EGApaletteNo = EGApaletteNo; + _priority = 0; + + headerSize = READ_LE_UINT16(_resource->data); + switch (headerSize) { + case 0x26: // SCI 1.1 VGA picture + drawSci11Vga(); + break; +#ifdef ENABLE_SCI32 + case 0x0e: // SCI32 VGA picture + drawSci32Vga(); + break; +#endif + default: + // VGA, EGA or Amiga vector data + drawVectorData(_resource->data, _resource->size); + } +} + +void SciGuiPicture::reset() { + int16 x, y; + for (y = _gfx->GetPort()->top; y < _screen->_height; y++) { + for (x = 0; x < _screen->_width; x++) { + _screen->putPixel(x, y, SCI_SCREEN_MASK_ALL, 255, 0, 0); + } + } +} + +void SciGuiPicture::drawSci11Vga() { + byte *inbuffer = _resource->data; + int size = _resource->size; + int has_cel = READ_LE_UINT16(inbuffer + 4); + int vector_dataPos = READ_LE_UINT16(inbuffer + 16); + int vector_size = size - vector_dataPos; + int palette_data_ptr = READ_LE_UINT16(inbuffer + 28); + int cel_headerPos = READ_LE_UINT16(inbuffer + 32); + int cel_RlePos = READ_LE_UINT16(inbuffer + cel_headerPos + 24); + int cel_LiteralPos = READ_LE_UINT16(inbuffer + cel_headerPos + 28); + Palette palette; + + // Create palette and set it + _palette->createFromData(inbuffer + palette_data_ptr, &palette); + _palette->set(&palette, 2); + + // display Cel-data + if (has_cel) { + drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, false); + } + + // process vector data + drawVectorData(inbuffer + vector_dataPos, vector_size); +} + +#ifdef ENABLE_SCI32 +void SciGuiPicture::drawSci32Vga() { + byte *inbuffer = _resource->data; + int size = _resource->size; + int header_size = READ_LE_UINT16(inbuffer); + int palette_data_ptr = READ_LE_UINT16(inbuffer + 6); + int cel_headerPos = header_size; + int cel_RlePos = READ_LE_UINT16(inbuffer + cel_headerPos + 24); + int cel_LiteralPos = READ_LE_UINT16(inbuffer + cel_headerPos + 28); + Palette palette; + + // Create palette and set it + _palette->createFromData(inbuffer + palette_data_ptr, &palette); + _palette->set(&palette, 2); + + drawCelData(inbuffer, size, cel_headerPos, cel_RlePos, cel_LiteralPos, 0, 0, true); + + // TODO: find out where priority map is stored +} +#endif + +void SciGuiPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header) { + byte *celBitmap = NULL; + byte *ptr = NULL; + byte *headerPtr = inbuffer + headerPos; + byte *rlePtr = inbuffer + rlePos; + byte *literalPtr = inbuffer + literalPos; + uint16 width = READ_LE_UINT16(headerPtr + 0); + uint16 height = READ_LE_UINT16(headerPtr + 2); + int16 displaceX, displaceY; + byte priority = _addToFlag ? _priority : 0; + byte clearColor; + bool compression = true; + byte curByte, runLength; + int16 y, lastY, x, leftX, rightX; + uint16 pixelNr, pixelCount; + +#ifdef ENABLE_SCI32 + if (!hasSci32Header) { +#endif + displaceX = (signed char)headerPtr[4]; + displaceY = (unsigned char)headerPtr[5]; + clearColor = headerPtr[6]; +#ifdef ENABLE_SCI32 + } else { + displaceX = READ_LE_UINT16(headerPtr + 4); // probably signed?!? + displaceY = READ_LE_UINT16(headerPtr + 6); // probably signed?!? + clearColor = headerPtr[8]; + if (headerPtr[9] == 0) + compression = false; + } +#endif + + if (displaceX || displaceY) + error("unsupported embedded cel-data in picture"); + + pixelCount = width * height; + celBitmap = new byte[pixelCount]; + if (!celBitmap) + error("Unable to allocate temporary memory for picture drawing"); + + if (compression) { + // We will unpack cel-data into a temporary buffer and then plot it to screen + // That needs to be done cause a mirrored picture may be requested + memset(celBitmap, clearColor, pixelCount); + pixelNr = 0; + ptr = celBitmap; + if (literalPos == 0) { + // decompression for data that has only one stream (vecor embedded view data) + switch (_resMan->getViewType()) { + case kViewEga: + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte >> 4; + memset(ptr + pixelNr, curByte & 0x0F, MIN(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + } + break; + case kViewVga: + case kViewVga11: + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte & 0x3F; + switch (curByte & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNr < pixelCount) + ptr[pixelNr++] = *rlePtr++; + break; + case 0x80: // fill with color + memset(ptr + pixelNr, *rlePtr++, MIN(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + break; + case 0xC0: // fill with transparent + pixelNr += runLength; + break; + } + } + break; + case kViewAmiga: + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + if (curByte & 0x07) { // fill with color + runLength = curByte & 0x07; + curByte = curByte >> 3; + while (runLength-- && pixelNr < pixelCount) { + ptr[pixelNr++] = curByte; + } + } else { // fill with transparent + runLength = curByte >> 3; + pixelNr += runLength; + } + } + break; + + default: + error("Unsupported picture viewtype"); + } + } else { + // decompression for data that has two separate streams (probably SCI 1.1 picture) + while (pixelNr < pixelCount) { + curByte = *rlePtr++; + runLength = curByte & 0x3F; + switch (curByte & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNr < pixelCount) + ptr[pixelNr++] = *literalPtr++; + break; + case 0x80: // fill with color + memset(ptr + pixelNr, *literalPtr++, MIN(runLength, pixelCount - pixelNr)); + pixelNr += runLength; + break; + case 0xC0: // fill with transparent + pixelNr += runLength; + break; + } + } + } + } else { + // No compression (some SCI32 pictures) + memcpy(celBitmap, rlePtr, pixelCount); + } + + // Set initial vertical coordinate by using current port + y = callerY + _gfx->GetPort()->top; + lastY = MIN(height + y, _gfx->GetPort()->rect.bottom + _gfx->GetPort()->top); + leftX = callerX + _gfx->GetPort()->left; + rightX = MIN(width + leftX, _gfx->GetPort()->rect.right + _gfx->GetPort()->left); + + // Change clearcolor to white, if we dont add to an existing picture. That way we will paint everything on screen + // but white and that wont matter because the screen is supposed to be already white. It seems that most (if not all) + // SCI1.1 games use color 0 as transparency and SCI1 games use color 255 as transparency. Sierra SCI seems to paint + // the whole data to screen and wont skip over transparent pixels. So this will actually make it work like Sierra + if (!_addToFlag) + clearColor = _screen->_colorWhite; + + ptr = celBitmap; + if (!_mirroredFlag) { + // Draw bitmap to screen + x = leftX; + while (y < lastY) { + curByte = *ptr++; + if ((curByte != clearColor) && (priority >= _screen->getPriority(x, y))) + _screen->putPixel(x, y, SCI_SCREEN_MASK_VISUAL | SCI_SCREEN_MASK_PRIORITY, curByte, priority, 0); + x++; + if (x >= rightX) { + x = leftX; y++; + } + } + } else { + // Draw bitmap to screen (mirrored) + x = rightX - 1; + while (y < lastY) { + curByte = *ptr++; + if ((curByte != clearColor) && (priority >= _screen->getPriority(x, y))) + _screen->putPixel(x, y, SCI_SCREEN_MASK_VISUAL | SCI_SCREEN_MASK_PRIORITY, curByte, priority, 0); + if (x == leftX) { + x = rightX; y++; + } + x--; + } + } + delete[] celBitmap; +} + +enum { + PIC_OP_SET_COLOR = 0xf0, + PIC_OP_DISABLE_VISUAL = 0xf1, + PIC_OP_SET_PRIORITY = 0xf2, + PIC_OP_DISABLE_PRIORITY = 0xf3, + PIC_OP_SHORT_PATTERNS = 0xf4, + PIC_OP_MEDIUM_LINES = 0xf5, + PIC_OP_LONG_LINES = 0xf6, + PIC_OP_SHORT_LINES = 0xf7, + PIC_OP_FILL = 0xf8, + PIC_OP_SET_PATTERN = 0xf9, + PIC_OP_ABSOLUTE_PATTERN = 0xfa, + PIC_OP_SET_CONTROL = 0xfb, + PIC_OP_DISABLE_CONTROL = 0xfc, + PIC_OP_MEDIUM_PATTERNS = 0xfd, + PIC_OP_OPX = 0xfe, + PIC_OP_TERMINATE = 0xff +}; +#define PIC_OP_FIRST PIC_OP_SET_COLOR + +enum { + PIC_OPX_EGA_SET_PALETTE_ENTRIES = 0, + PIC_OPX_EGA_SET_PALETTE = 1, + PIC_OPX_EGA_MONO0 = 2, + PIC_OPX_EGA_MONO1 = 3, + PIC_OPX_EGA_MONO2 = 4, + PIC_OPX_EGA_MONO3 = 5, + PIC_OPX_EGA_MONO4 = 6, + PIC_OPX_EGA_EMBEDDED_VIEW = 7, + PIC_OPX_EGA_SET_PRIORITY_TABLE = 8 +}; + +enum { + PIC_OPX_VGA_SET_PALETTE_ENTRIES = 0, + PIC_OPX_VGA_EMBEDDED_VIEW = 1, + PIC_OPX_VGA_SET_PALETTE = 2, + PIC_OPX_VGA_PRIORITY_TABLE_EQDIST = 3, + PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT = 4 +}; + +#define PIC_EGAPALETTE_COUNT 4 +#define PIC_EGAPALETTE_SIZE 40 +#define PIC_EGAPALETTE_TOTALSIZE PIC_EGAPALETTE_COUNT*PIC_EGAPALETTE_SIZE +#define PIC_EGAPRIORITY_SIZE PIC_EGAPALETTE_SIZE + +static const byte vector_defaultEGApalette[PIC_EGAPALETTE_SIZE] = { + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, + 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0x88, + 0x88, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x88, + 0x88, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff, + 0x08, 0x91, 0x2a, 0x3b, 0x4c, 0x5d, 0x6e, 0x88 +}; + +static const byte vector_defaultEGApriority[PIC_EGAPRIORITY_SIZE] = { + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 +}; + +void SciGuiPicture::drawVectorData(byte *data, int dataSize) { + byte pic_op; + byte pic_color = _screen->_colorDefaultVectorData; + byte pic_priority = 255, pic_control = 255; + int16 x = 0, y = 0, oldx, oldy; + byte EGApalettes[PIC_EGAPALETTE_TOTALSIZE] = {0}; + byte *EGApalette = &EGApalettes[_EGApaletteNo * PIC_EGAPALETTE_SIZE]; + byte EGApriority[PIC_EGAPRIORITY_SIZE] = {0}; + bool isEGA = false; + int curPos = 0; + uint16 size; + byte pixel; + int i; + Palette palette; + int16 pattern_Code = 0, pattern_Texture = 0; + + memset(&palette, 0, sizeof(palette)); + + if (_EGApaletteNo >= PIC_EGAPALETTE_COUNT) + _EGApaletteNo = 0; + + if (_resMan->getViewType() == kViewEga) { + isEGA = true; + // setup default mapping tables + for (i = 0; i < PIC_EGAPALETTE_TOTALSIZE; i += PIC_EGAPALETTE_SIZE) + memcpy(&EGApalettes[i], &vector_defaultEGApalette, sizeof(vector_defaultEGApalette)); + memcpy(&EGApriority, &vector_defaultEGApriority, sizeof(vector_defaultEGApriority)); + } + + // Drawing + while (curPos < dataSize) { + //warning("%X at %d", data[curPos], curPos); + switch (pic_op = data[curPos++]) { + case PIC_OP_SET_COLOR: + pic_color = data[curPos++]; + if (isEGA) { + pic_color = EGApalette[pic_color]; + pic_color ^= pic_color << 4; + } + break; + case PIC_OP_DISABLE_VISUAL: + pic_color = 0xFF; + break; + + case PIC_OP_SET_PRIORITY: + pic_priority = data[curPos++] & 0x0F; + if (isEGA) { + pic_priority = EGApriority[pic_priority]; + } + break; + case PIC_OP_DISABLE_PRIORITY: + pic_priority = 255; + break; + + case PIC_OP_SET_CONTROL: + pic_control = data[curPos++] & 0x0F; + break; + case PIC_OP_DISABLE_CONTROL: + pic_control = 255; + break; + + case PIC_OP_SHORT_LINES: // short line + vectorGetAbsCoords(data, curPos, x, y); + while (vectorIsNonOpcode(data[curPos])) { + oldx = x; oldy = y; + vectorGetRelCoords(data, curPos, x, y); + Common::Point startPoint(oldx, oldy); + Common::Point endPoint(x, y); + _gfx->OffsetLine(startPoint, endPoint); + _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); + } + break; + case PIC_OP_MEDIUM_LINES: // medium line + vectorGetAbsCoords(data, curPos, x, y); + while (vectorIsNonOpcode(data[curPos])) { + oldx = x; oldy = y; + vectorGetRelCoordsMed(data, curPos, x, y); + Common::Point startPoint(oldx, oldy); + Common::Point endPoint(x, y); + _gfx->OffsetLine(startPoint, endPoint); + _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); + } + break; + case PIC_OP_LONG_LINES: // long line + vectorGetAbsCoords(data, curPos, x, y); + while (vectorIsNonOpcode(data[curPos])) { + oldx = x; oldy = y; + vectorGetAbsCoords(data, curPos, x, y); + Common::Point startPoint(oldx, oldy); + Common::Point endPoint(x, y); + _gfx->OffsetLine(startPoint, endPoint); + _screen->drawLine(startPoint, endPoint, pic_color, pic_priority, pic_control); + } + break; + + case PIC_OP_FILL: //fill + while (vectorIsNonOpcode(data[curPos])) { + vectorGetAbsCoords(data, curPos, x, y); + vectorFloodFill(x, y, pic_color, pic_priority, pic_control); + } + break; + + case PIC_OP_SET_PATTERN: + pattern_Code = data[curPos++]; + break; + case PIC_OP_SHORT_PATTERNS: + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetAbsCoords(data, curPos, x, y); + vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetRelCoords(data, curPos, x, y); + vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + } + break; + case PIC_OP_MEDIUM_PATTERNS: + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetAbsCoords(data, curPos, x, y); + vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + while (vectorIsNonOpcode(data[curPos])) { + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetRelCoordsMed(data, curPos, x, y); + vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + } + break; + case PIC_OP_ABSOLUTE_PATTERN: + while (vectorIsNonOpcode(data[curPos])) { + vectorGetPatternTexture(data, curPos, pattern_Code, pattern_Texture); + vectorGetAbsCoords(data, curPos, x, y); + vectorPattern(x, y, pic_color, pic_priority, pic_control, pattern_Code, pattern_Texture); + } + break; + + case PIC_OP_OPX: // Extended functions + if (isEGA) { + switch (pic_op = data[curPos++]) { + case PIC_OPX_EGA_SET_PALETTE_ENTRIES: + while (vectorIsNonOpcode(data[curPos])) { + pixel = data[curPos++]; + if (pixel >= PIC_EGAPALETTE_TOTALSIZE) { + error("picture trying to write to invalid EGA-palette"); + } + EGApalettes[pixel] = data[curPos++]; + } + break; + case PIC_OPX_EGA_SET_PALETTE: + pixel = data[curPos++]; + if (pixel >= PIC_EGAPALETTE_COUNT) { + error("picture trying to write to invalid palette %d", (int)pixel); + } + pixel *= PIC_EGAPALETTE_SIZE; + for (i = 0; i < PIC_EGAPALETTE_SIZE; i++) { + EGApalettes[pixel + i] = data[curPos++]; + } + break; + case PIC_OPX_EGA_MONO0: + curPos += 41; + break; + case PIC_OPX_EGA_MONO1: + case PIC_OPX_EGA_MONO3: + curPos++; + break; + case PIC_OPX_EGA_MONO2: + case PIC_OPX_EGA_MONO4: + break; + case PIC_OPX_EGA_EMBEDDED_VIEW: + vectorGetAbsCoordsNoMirror(data, curPos, x, y); + size = READ_LE_UINT16(data + curPos); curPos += 2; + _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well + drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false); + curPos += size; + break; + case PIC_OPX_EGA_SET_PRIORITY_TABLE: + _gfx->PriorityBandsInit(data + curPos); + curPos += 14; + break; + default: + error("Unsupported sci1 extended pic-operation %X", pic_op); + } + } else { + switch (pic_op = data[curPos++]) { + case PIC_OPX_VGA_SET_PALETTE_ENTRIES: + while (vectorIsNonOpcode(data[curPos])) { + curPos++; // skip commands + } + break; + case PIC_OPX_VGA_SET_PALETTE: + curPos += 256 + 4; // Skip over mapping and timestamp + for (i = 0; i < 256; i++) { + palette.colors[i].used = data[curPos++]; + palette.colors[i].r = data[curPos++]; palette.colors[i].g = data[curPos++]; palette.colors[i].b = data[curPos++]; + } + _palette->set(&palette, 2); + break; + case PIC_OPX_VGA_EMBEDDED_VIEW: // draw cel + vectorGetAbsCoordsNoMirror(data, curPos, x, y); + size = READ_LE_UINT16(data + curPos); curPos += 2; + _priority = pic_priority; // set global priority so the cel gets drawn using current priority as well + drawCelData(data, _resource->size, curPos, curPos + 8, 0, x, y, false); + curPos += size; + break; + case PIC_OPX_VGA_PRIORITY_TABLE_EQDIST: + _gfx->PriorityBandsInit(-1, READ_LE_UINT16(data + curPos), READ_LE_UINT16(data + curPos + 2)); + curPos += 4; + break; + case PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT: + _gfx->PriorityBandsInit(data + curPos); + curPos += 14; + break; + default: + error("Unsupported sci1 extended pic-operation %X", pic_op); + } + } + break; + case PIC_OP_TERMINATE: + _priority = pic_priority; + // Dithering EGA pictures + if (isEGA) { + _screen->dither(_addToFlag); + } + return; + default: + error("Unsupported pic-operation %X", pic_op); + } + //printf("picop %X\n", pic_op); + // for debug purposes + //_screen->copyToScreen(); + //g_system->updateScreen(); + //g_system->delayMillis(500); + } + error("picture vector data without terminator"); +} + +bool SciGuiPicture::vectorIsNonOpcode(byte pixel) { + if (pixel >= PIC_OP_FIRST) + return false; + return true; +} + +void SciGuiPicture::vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y) { + byte pixel = data[curPos++]; + x = data[curPos++] + ((pixel & 0xF0) << 4); + y = data[curPos++] + ((pixel & 0x0F) << 8); + if (_mirroredFlag) x = 319 - x; +} + +void SciGuiPicture::vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y) { + byte pixel = data[curPos++]; + x = data[curPos++] + ((pixel & 0xF0) << 4); + y = data[curPos++] + ((pixel & 0x0F) << 8); +} + +void SciGuiPicture::vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y) { + byte pixel = data[curPos++]; + if (pixel & 0x80) { + x -= ((pixel >> 4) & 7) * (_mirroredFlag ? -1 : 1); + } else { + x += (pixel >> 4) * (_mirroredFlag ? -1 : 1); + } + if (pixel & 0x08) { + y -= (pixel & 7); + } else { + y += (pixel & 7); + } +} + +void SciGuiPicture::vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y) { + byte pixel = data[curPos++]; + if (pixel & 0x80) { + y -= (pixel & 0x7F); + } else { + y += pixel; + } + pixel = data[curPos++]; + if (pixel & 0x80) { + x -= (128 - (pixel & 0x7F)) * (_mirroredFlag ? -1 : 1); + } else { + x += pixel * (_mirroredFlag ? -1 : 1); + } +} + +void SciGuiPicture::vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture) { + if (pattern_Code & SCI_PATTERN_CODE_USE_TEXTURE) { + pattern_Texture = (data[curPos++] >> 1) & 0x7f; + } +} + +// Do not replace w/ some generic code. This algo really needs to behave exactly as the one from sierra +void SciGuiPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, byte control) { + Port *curPort = _gfx->GetPort(); + Common::Stack stack; + Common::Point p, p1; + byte screenMask = _screen->getDrawingMask(color, priority, control); + byte matchedMask, matchMask; + int16 w, e, a_set, b_set; + + p.x = x + curPort->left; + p.y = y + curPort->top; + stack.push(p); + + byte searchColor = _screen->getVisual(p.x, p.y); + byte searchPriority = _screen->getPriority(p.x, p.y); + byte searchControl = _screen->getControl(p.x, p.y); + + // This logic was taken directly from sierra sci, floodfill will get aborted on various occations + if (screenMask & SCI_SCREEN_MASK_VISUAL) { + if ((color == _screen->_colorWhite) || (searchColor != _screen->_colorWhite)) + return; + } else if (screenMask & SCI_SCREEN_MASK_PRIORITY) { + if ((priority == 0) || (searchPriority != 0)) + return; + } else if (screenMask & SCI_SCREEN_MASK_CONTROL) { + if ((control == 0) || (searchControl != 0)) + return; + } + + // Now remove screens, that already got the right color/priority/control + if ((screenMask & SCI_SCREEN_MASK_VISUAL) && (searchColor == color)) + screenMask ^= SCI_SCREEN_MASK_VISUAL; + if ((screenMask & SCI_SCREEN_MASK_PRIORITY) && (searchPriority == priority)) + screenMask ^= SCI_SCREEN_MASK_PRIORITY; + if ((screenMask & SCI_SCREEN_MASK_CONTROL) && (searchControl == control)) + screenMask ^= SCI_SCREEN_MASK_CONTROL; + + // Exit, if no screens left + if (!screenMask) + return; + + if (screenMask & SCI_SCREEN_MASK_VISUAL) { + matchMask = SCI_SCREEN_MASK_VISUAL; + } else if (screenMask & SCI_SCREEN_MASK_PRIORITY) { + matchMask = SCI_SCREEN_MASK_PRIORITY; + } else { + matchMask = SCI_SCREEN_MASK_CONTROL; + } + + // hard borders for filling + int l = curPort->rect.left + curPort->left; + int t = curPort->rect.top + curPort->top; + int r = curPort->rect.right + curPort->left - 1; + int b = curPort->rect.bottom + curPort->top - 1; + while (stack.size()) { + p = stack.pop(); + if ((matchedMask = _screen->isFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl)) == 0) // already filled + continue; + _screen->putPixel(p.x, p.y, screenMask, color, priority, control); + w = p.x; + e = p.x; + // moving west and east pointers as long as there is a matching color to fill + while (w > l && (matchedMask = _screen->isFillMatch(w - 1, p.y, matchMask, searchColor, searchPriority, searchControl))) + _screen->putPixel(--w, p.y, screenMask, color, priority, control); + while (e < r && (matchedMask = _screen->isFillMatch(e + 1, p.y, matchMask, searchColor, searchPriority, searchControl))) + _screen->putPixel(++e, p.y, screenMask, color, priority, control); + // checking lines above and below for possible flood targets + a_set = b_set = 0; + while (w <= e) { + if (p.y > t && (matchedMask = _screen->isFillMatch(w, p.y - 1, matchMask, searchColor, searchPriority, searchControl))) { // one line above + if (a_set == 0) { + p1.x = w; + p1.y = p.y - 1; + stack.push(p1); + a_set = 1; + } + } else + a_set = 0; + + if (p.y < b && (matchedMask = _screen->isFillMatch(w, p.y + 1, matchMask, searchColor, searchPriority, searchControl))) { // one line below + if (b_set == 0) { + p1.x = w; + p1.y = p.y + 1; + stack.push(p1); + b_set = 1; + } + } else + b_set = 0; + w++; + } + } +} + +// Bitmap for drawing sierra circles +static const byte vectorPatternCircles[8][30] = { + { 0x01 }, + { 0x72, 0x02 }, + { 0xCE, 0xF7, 0x7D, 0x0E }, + { 0x1C, 0x3E, 0x7F, 0x7F, 0x7F, 0x3E, 0x1C, 0x00 }, + { 0x38, 0xF8, 0xF3, 0xDF, 0x7F, 0xFF, 0xFD, 0xF7, 0x9F, 0x3F, 0x38 }, + { 0x70, 0xC0, 0x1F, 0xFE, 0xE3, 0x3F, 0xFF, 0xF7, 0x7F, 0xFF, 0xE7, 0x3F, 0xFE, 0xC3, 0x1F, 0xF8, 0x00 }, + { 0xF0, 0x01, 0xFF, 0xE1, 0xFF, 0xF8, 0x3F, 0xFF, 0xDF, 0xFF, 0xF7, 0xFF, 0xFD, 0x7F, 0xFF, 0x9F, 0xFF, + 0xE3, 0xFF, 0xF0, 0x1F, 0xF0, 0x01 }, + { 0xE0, 0x03, 0xF8, 0x0F, 0xFC, 0x1F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, 0x7F, 0xFF, + 0x7F, 0xFF, 0x7F, 0xFE, 0x3F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8, 0x0F, 0xE0, 0x03 } +// { 0x01 }; +// { 0x03, 0x03, 0x03 }, +// { 0x02, 0x07, 0x07, 0x07, 0x02 }, +// { 0x06, 0x06, 0x0F, 0x0F, 0x0F, 0x06, 0x06 }, +// { 0x04, 0x0E, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x04 }, +// { 0x0C, 0x1E, 0x1E, 0x1E, 0x3F, 0x3F, 0x3F, 0x1E, 0x1E, 0x1E, 0x0C }, +// { 0x1C, 0x3E, 0x3E, 0x3E, 0x7F, 0x7F, 0x7F, 0x7F, 0x7F, 0x3E, 0x3E, 0x3E, 0x1C }, +// { 0x18, 0x3C, 0x7E, 0x7E, 0x7E, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7E, 0x7E, 0x7E, 0x3C, 0x18 } +}; + +// TODO: perhaps this is a better way to set the s_patternTextures array below? +// in that case one would need to adjust bits of secondary table. Bit 256 is ignored by original interpreter +#if 0 +static const byte patternTextures[32 * 2] = { + 0x04, 0x29, 0x40, 0x24, 0x09, 0x41, 0x25, 0x45, + 0x41, 0x90, 0x50, 0x44, 0x48, 0x08, 0x42, 0x28, + 0x89, 0x52, 0x89, 0x88, 0x10, 0x48, 0xA4, 0x08, + 0x44, 0x15, 0x28, 0x24, 0x00, 0x0A, 0x24, 0x20, + // Now the table is actually duplicated, so we won't need to wrap around + 0x04, 0x29, 0x40, 0x24, 0x09, 0x41, 0x25, 0x45, + 0x41, 0x90, 0x50, 0x44, 0x48, 0x08, 0x42, 0x28, + 0x89, 0x52, 0x89, 0x88, 0x10, 0x48, 0xA4, 0x08, + 0x44, 0x15, 0x28, 0x24, 0x00, 0x0A, 0x24, 0x20, +}; +#endif + +// This table is bitwise upwards (from bit0 to bit7), sierras original table went down the bits (bit7 to bit0) +// this was done to simplify things, so we can just run through the table w/o worrying too much about clipping +static const bool vectorPatternTextures[32 * 8 * 2] = { + false, false, true, false, false, false, false, false, // 0x04 + true, false, false, true, false, true, false, false, // 0x29 + false, false, false, false, false, false, true, false, // 0x40 + false, false, true, false, false, true, false, false, // 0x24 + true, false, false, true, false, false, false, false, // 0x09 + true, false, false, false, false, false, true, false, // 0x41 + true, false, true, false, false, true, false, false, // 0x25 + true, false, true, false, false, false, true, false, // 0x45 + true, false, false, false, false, false, true, false, // 0x41 + false, false, false, false, true, false, false, true, // 0x90 + false, false, false, false, true, false, true, false, // 0x50 + false, false, true, false, false, false, true, false, // 0x44 + false, false, false, true, false, false, true, false, // 0x48 + false, false, false, true, false, false, false, false, // 0x08 + false, true, false, false, false, false, true, false, // 0x42 + false, false, false, true, false, true, false, false, // 0x28 + true, false, false, true, false, false, false, true, // 0x89 + false, true, false, false, true, false, true, false, // 0x52 + true, false, false, true, false, false, false, true, // 0x89 + false, false, false, true, false, false, false, true, // 0x88 + false, false, false, false, true, false, false, false, // 0x10 + false, false, false, true, false, false, true, false, // 0x48 + false, false, true, false, false, true, false, true, // 0xA4 + false, false, false, true, false, false, false, false, // 0x08 + false, false, true, false, false, false, true, false, // 0x44 + true, false, true, false, true, false, false, false, // 0x15 + false, false, false, true, false, true, false, false, // 0x28 + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, false, false, false, false, // 0x00 + false, true, false, true, false, false, false, false, // 0x0A + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, false, true, false, // 0x20 (last bit is not mentioned cause original interpreter also ignores that bit) + // Now the table is actually duplicated, so we won't need to wrap around + false, false, true, false, false, false, false, false, // 0x04 + true, false, false, true, false, true, false, false, // 0x29 + false, false, false, false, false, false, true, false, // 0x40 + false, false, true, false, false, true, false, false, // 0x24 + true, false, false, true, false, false, false, false, // 0x09 + true, false, false, false, false, false, true, false, // 0x41 + true, false, true, false, false, true, false, false, // 0x25 + true, false, true, false, false, false, true, false, // 0x45 + true, false, false, false, false, false, true, false, // 0x41 + false, false, false, false, true, false, false, true, // 0x90 + false, false, false, false, true, false, true, false, // 0x50 + false, false, true, false, false, false, true, false, // 0x44 + false, false, false, true, false, false, true, false, // 0x48 + false, false, false, true, false, false, false, false, // 0x08 + false, true, false, false, false, false, true, false, // 0x42 + false, false, false, true, false, true, false, false, // 0x28 + true, false, false, true, false, false, false, true, // 0x89 + false, true, false, false, true, false, true, false, // 0x52 + true, false, false, true, false, false, false, true, // 0x89 + false, false, false, true, false, false, false, true, // 0x88 + false, false, false, false, true, false, false, false, // 0x10 + false, false, false, true, false, false, true, false, // 0x48 + false, false, true, false, false, true, false, true, // 0xA4 + false, false, false, true, false, false, false, false, // 0x08 + false, false, true, false, false, false, true, false, // 0x44 + true, false, true, false, true, false, false, false, // 0x15 + false, false, false, true, false, true, false, false, // 0x28 + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, false, false, false, false, // 0x00 + false, true, false, true, false, false, false, false, // 0x0A + false, false, true, false, false, true, false, false, // 0x24 + false, false, false, false, false, true, false, // 0x20 (last bit is not mentioned cause original interpreter also ignores that bit) +}; + +// Bit offsets into pattern_textures +static const byte vectorPatternTextureOffset[128] = { + 0x00, 0x18, 0x30, 0xc4, 0xdc, 0x65, 0xeb, 0x48, + 0x60, 0xbd, 0x89, 0x05, 0x0a, 0xf4, 0x7d, 0x7d, + 0x85, 0xb0, 0x8e, 0x95, 0x1f, 0x22, 0x0d, 0xdf, + 0x2a, 0x78, 0xd5, 0x73, 0x1c, 0xb4, 0x40, 0xa1, + 0xb9, 0x3c, 0xca, 0x58, 0x92, 0x34, 0xcc, 0xce, + 0xd7, 0x42, 0x90, 0x0f, 0x8b, 0x7f, 0x32, 0xed, + 0x5c, 0x9d, 0xc8, 0x99, 0xad, 0x4e, 0x56, 0xa6, + 0xf7, 0x68, 0xb7, 0x25, 0x82, 0x37, 0x3a, 0x51, + 0x69, 0x26, 0x38, 0x52, 0x9e, 0x9a, 0x4f, 0xa7, + 0x43, 0x10, 0x80, 0xee, 0x3d, 0x59, 0x35, 0xcf, + 0x79, 0x74, 0xb5, 0xa2, 0xb1, 0x96, 0x23, 0xe0, + 0xbe, 0x05, 0xf5, 0x6e, 0x19, 0xc5, 0x66, 0x49, + 0xf0, 0xd1, 0x54, 0xa9, 0x70, 0x4b, 0xa4, 0xe2, + 0xe6, 0xe5, 0xab, 0xe4, 0xd2, 0xaa, 0x4c, 0xe3, + 0x06, 0x6f, 0xc6, 0x4a, 0xa4, 0x75, 0x97, 0xe1 +}; + +void SciGuiPicture::vectorPatternBox(Common::Rect box, byte color, byte prio, byte control) { + byte flag = _screen->getDrawingMask(color, prio, control); + int y, x; + + for (y = box.top; y < box.bottom; y++) { + for (x = box.left; x < box.right; x++) { + _screen->putPixel(x, y, flag, color, prio, control); + } + } +} + +void SciGuiPicture::vectorPatternTexturedBox(Common::Rect box, byte color, byte prio, byte control, byte texture) { + byte flag = _screen->getDrawingMask(color, prio, control); + const bool *textureData = &vectorPatternTextures[vectorPatternTextureOffset[texture]]; + int y, x; + + for (y = box.top; y < box.bottom; y++) { + for (x = box.left; x < box.right; x++) { + if (*textureData) { + _screen->putPixel(x, y, flag, color, prio, control); + } + textureData++; + } + } +} + +void SciGuiPicture::vectorPatternCircle(Common::Rect box, byte size, byte color, byte prio, byte control) { + byte flag = _screen->getDrawingMask(color, prio, control); + const byte *circleData = vectorPatternCircles[size]; + byte bitmap = *circleData; + byte bitNo = 0; + int y, x; + + for (y = box.top; y < box.bottom; y++) { + for (x = box.left; x < box.right; x++) { + if (bitmap & 1) { + _screen->putPixel(x, y, flag, color, prio, control); + } + bitNo++; + if (bitNo == 8) { + circleData++; bitmap = *circleData; bitNo = 0; + } else { + bitmap = bitmap >> 1; + } + } + } +} + +void SciGuiPicture::vectorPatternTexturedCircle(Common::Rect box, byte size, byte color, byte prio, byte control, byte texture) { + byte flag = _screen->getDrawingMask(color, prio, control); + const byte *circleData = vectorPatternCircles[size]; + byte bitmap = *circleData; + byte bitNo = 0; + const bool *textureData = &vectorPatternTextures[vectorPatternTextureOffset[texture]]; + int y, x; + + for (y = box.top; y < box.bottom; y++) { + for (x = box.left; x < box.right; x++) { + if (bitmap & 1) { + if (*textureData) { + _screen->putPixel(x, y, flag, color, prio, control); + } + textureData++; + } + bitNo++; + if (bitNo == 8) { + circleData++; bitmap = *circleData; bitNo = 0; + } else { + bitmap = bitmap >> 1; + } + } + } +} + +void SciGuiPicture::vectorPattern(int16 x, int16 y, byte color, byte priority, byte control, byte code, byte texture) { + byte size = code & SCI_PATTERN_CODE_PENSIZE; + Common::Rect rect; + + // We need to adjust the given coordinates, because the ones given us do not define upper left but somewhat middle + y -= size; if (y < 0) y = 0; + x -= size; if (x < 0) x = 0; + + rect.top = y; rect.left = x; + rect.setHeight((size*2)+1); rect.setWidth((size*2)+2); + _gfx->OffsetRect(rect); + rect.clip(_screen->_width, _screen->_height); + + if (code & SCI_PATTERN_CODE_RECTANGLE) { + // Rectangle + if (code & SCI_PATTERN_CODE_USE_TEXTURE) { + vectorPatternTexturedBox(rect, color, priority, control, texture); + } else { + vectorPatternBox(rect, color, priority, control); + } + + } else { + // Circle + if (code & SCI_PATTERN_CODE_USE_TEXTURE) { + vectorPatternTexturedCircle(rect, size, color, priority, control, texture); + } else { + vectorPatternCircle(rect, size, color, priority, control); + } + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/picture.h b/engines/sci/graphics/picture.h new file mode 100644 index 0000000000..fcab244a36 --- /dev/null +++ b/engines/sci/graphics/picture.h @@ -0,0 +1,82 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_PICTURE_H +#define SCI_GRAPHICS_PICTURE_H + +namespace Sci { + +#define SCI_PATTERN_CODE_RECTANGLE 0x10 +#define SCI_PATTERN_CODE_USE_TEXTURE 0x20 +#define SCI_PATTERN_CODE_PENSIZE 0x07 + +class SciGuiPicture { +public: + SciGuiPicture(ResourceManager *resMan, Gfx *gfx, Screen *screen, SciPalette *palette, GuiResourceId resourceId); + ~SciGuiPicture(); + + GuiResourceId getResourceId(); + void draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo); + +private: + void initData(GuiResourceId resourceId); + void reset(); + void drawSci11Vga(); +#ifdef ENABLE_SCI32 + void drawSci32Vga(); +#endif + void drawCelData(byte *inbuffer, int size, int headerPos, int rlePos, int literalPos, int16 callerX, int16 callerY, bool hasSci32Header); + void drawVectorData(byte *data, int size); + bool vectorIsNonOpcode(byte pixel); + void vectorGetAbsCoords(byte *data, int &curPos, int16 &x, int16 &y); + void vectorGetAbsCoordsNoMirror(byte *data, int &curPos, int16 &x, int16 &y); + void vectorGetRelCoords(byte *data, int &curPos, int16 &x, int16 &y); + void vectorGetRelCoordsMed(byte *data, int &curPos, int16 &x, int16 &y); + void vectorGetPatternTexture(byte *data, int &curPos, int16 pattern_Code, int16 &pattern_Texture); + void vectorFloodFill(int16 x, int16 y, byte color, byte prio, byte control); + void vectorPattern(int16 x, int16 y, byte pic_color, byte pic_priority, byte pic_control, byte code, byte texture); + void vectorPatternBox(Common::Rect box, byte color, byte prio, byte control); + void vectorPatternTexturedBox(Common::Rect box, byte color, byte prio, byte control, byte texture); + void vectorPatternCircle(Common::Rect box, byte size, byte color, byte prio, byte control); + void vectorPatternTexturedCircle(Common::Rect box, byte size, byte color, byte prio, byte control, byte texture); + + ResourceManager *_resMan; + Gfx *_gfx; + Screen *_screen; + SciPalette *_palette; + + int16 _resourceId; + Resource *_resource; + + int16 _animationNr; + bool _mirroredFlag; + bool _addToFlag; + int16 _EGApaletteNo; + byte _priority; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp new file mode 100644 index 0000000000..e348ec2dda --- /dev/null +++ b/engines/sci/graphics/portrait.cpp @@ -0,0 +1,66 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/portrait.h" + +namespace Sci { + +Portrait::Portrait(ResourceManager *resMan, Screen *screen, SciPalette *palette, Common::String resourceName) + : _resMan(resMan), _screen(screen), _palette(palette), _resourceName(resourceName) { + init(); +} + +Portrait::~Portrait() { +} + +void Portrait::init() { + // .BIN files are loaded from actors directory and from .\ directory + // header: + // 3 bytes "WIN" + // 2 bytes main height (should be the same as first bitmap header height) + // 2 bytes main width (should be the same as first bitmap header width) + // 2 bytes animation count + // 2 bytes unknown + // 2 bytes unknown + // 4 bytes paletteSize (base 1) + // paletteSize bytes paletteData + // 14 bytes bitmap header + // -> 4 bytes unknown + // -> 2 bytes height + // -> 2 bytes width + // -> 6 bytes unknown + // height * width bitmap data + // another animation count times bitmap header and data +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/portrait.h b/engines/sci/graphics/portrait.h new file mode 100644 index 0000000000..18a23ad189 --- /dev/null +++ b/engines/sci/graphics/portrait.h @@ -0,0 +1,49 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_PORTRAITS_H +#define SCI_GRAPHICS_PORTRAITS_H + +namespace Sci { + +class Portrait { +public: + Portrait(ResourceManager *resMan, Screen *screen, SciPalette *palette, Common::String resourceName); + ~Portrait(); + +private: + void init(); + + ResourceManager *_resMan; + Screen *_screen; + SciPalette *_palette; + + Common::String _resourceName; + byte *_resourceData; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp new file mode 100644 index 0000000000..fce6827d43 --- /dev/null +++ b/engines/sci/graphics/screen.cpp @@ -0,0 +1,513 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/timer.h" +#include "common/util.h" +#include "graphics/surface.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/screen.h" + +namespace Sci { + +Screen::Screen(ResourceManager *resMan, int16 width, int16 height, bool upscaledHires) : + _resMan(resMan), _width(width), _height(height), _upscaledHires(upscaledHires) { + + _pixels = _width * _height; + + _displayWidth = _width; + _displayHeight = _height; + if (_upscaledHires) { + _displayWidth *= 2; + _displayHeight *= 2; + } + _displayPixels = _displayWidth * _displayHeight; + + _visualScreen = (byte *)calloc(_pixels, 1); + _priorityScreen = (byte *)calloc(_pixels, 1); + _controlScreen = (byte *)calloc(_pixels, 1); + _displayScreen = (byte *)calloc(_displayPixels, 1); + + // Sets display screen to be actually displayed + _activeScreen = _displayScreen; + + _picNotValid = 0; + _picNotValidSci11 = 0; + _unditherState = true; + + if (_resMan->isVGA()) { + _colorWhite = 255; + if (getSciVersion() >= SCI_VERSION_1_1) + _colorDefaultVectorData = 255; + else + _colorDefaultVectorData = 0; + } else { + _colorWhite = 15; + _colorDefaultVectorData = 0; + } + + // Initialize the actual screen + initGraphics(_displayWidth, _displayHeight, _displayWidth > 320); +} + +Screen::~Screen() { + free(_visualScreen); + free(_priorityScreen); + free(_controlScreen); + free(_displayScreen); +} + +void Screen::copyToScreen() { + g_system->copyRectToScreen(_activeScreen, _displayWidth, 0, 0, _displayWidth, _displayHeight); +} + +void Screen::copyFromScreen(byte *buffer) { + Graphics::Surface *screen; + screen = g_system->lockScreen(); + memcpy(buffer, screen->pixels, _displayWidth * _displayHeight); + g_system->unlockScreen(); +} + +void Screen::copyRectToScreen(const Common::Rect &rect) { + if (!_upscaledHires) { + g_system->copyRectToScreen(_activeScreen + rect.top * _displayWidth + rect.left, _displayWidth, rect.left, rect.top, rect.width(), rect.height()); + } else { + g_system->copyRectToScreen(_activeScreen + rect.top * 2 * _displayWidth + rect.left * 2, _displayWidth, rect.left * 2, rect.top * 2, rect.width() * 2, rect.height() * 2); + } +} + +void Screen::copyRectToScreen(const Common::Rect &rect, int16 x, int16 y) { + if (!_upscaledHires) { + g_system->copyRectToScreen(_activeScreen + rect.top * _displayWidth + rect.left, _displayWidth, x, y, rect.width(), rect.height()); + } else { + g_system->copyRectToScreen(_activeScreen + rect.top * 2 * _displayWidth + rect.left * 2, _displayWidth, x * 2, y * 2, rect.width() * 2, rect.height() * 2); + } +} + +byte Screen::getDrawingMask(byte color, byte prio, byte control) { + byte flag = 0; + if (color != 255) + flag |= SCI_SCREEN_MASK_VISUAL; + if (prio != 255) + flag |= SCI_SCREEN_MASK_PRIORITY; + if (control != 255) + flag |= SCI_SCREEN_MASK_CONTROL; + return flag; +} + +void Screen::putPixel(int x, int y, byte drawMask, byte color, byte priority, byte control) { + int offset = y * _width + x; + + if (drawMask & SCI_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + if (!_upscaledHires) { + _displayScreen[offset] = color; + } else { + int displayOffset = y * 2 * _displayWidth + x * 2; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + _displayScreen[displayOffset + _displayWidth] = color; + _displayScreen[displayOffset + _displayWidth + 1] = color; + } + } + if (drawMask & SCI_SCREEN_MASK_PRIORITY) + _priorityScreen[offset] = priority; + if (drawMask & SCI_SCREEN_MASK_CONTROL) + _controlScreen[offset] = control; +} + +// This will just change a pixel directly on displayscreen. Its supposed to get only used on upscaled-Hires games where +// hires content needs to get drawn ONTO the upscaled display screen (like japanese fonts, hires portraits, etc.) +void Screen::putPixelOnDisplay(int x, int y, byte color) { + int offset = y * _width + x; + _displayScreen[offset] = color; +} + +// Sierra's Bresenham line drawing +// WARNING: Do not just blindly replace this with Graphics::drawLine(), as it seems to create issues with flood fill +void Screen::drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) { + int16 left = startPoint.x; + int16 top = startPoint.y; + int16 right = endPoint.x; + int16 bottom = endPoint.y; + + //set_drawing_flag + byte drawMask = getDrawingMask(color, priority, control); + + // horizontal line + if (top == bottom) { + if (right < left) + SWAP(right, left); + for (int i = left; i <= right; i++) + putPixel(i, top, drawMask, color, priority, control); + return; + } + // vertical line + if (left == right) { + if (top > bottom) + SWAP(top, bottom); + for (int i = top; i <= bottom; i++) + putPixel(left, i, drawMask, color, priority, control); + return; + } + // sloped line - draw with Bresenham algorithm + int dy = bottom - top; + int dx = right - left; + int stepy = dy < 0 ? -1 : 1; + int stepx = dx < 0 ? -1 : 1; + dy = ABS(dy) << 1; + dx = ABS(dx) << 1; + + // setting the 1st and last pixel + putPixel(left, top, drawMask, color, priority, control); + putPixel(right, bottom, drawMask, color, priority, control); + // drawing the line + if (dx > dy) { // going horizontal + int fraction = dy - (dx >> 1); + while (left != right) { + if (fraction >= 0) { + top += stepy; + fraction -= dx; + } + left += stepx; + fraction += dy; + putPixel(left, top, drawMask, color, priority, control); + } + } else { // going vertical + int fraction = dx - (dy >> 1); + while (top != bottom) { + if (fraction >= 0) { + left += stepx; + fraction -= dy; + } + top += stepy; + fraction += dx; + putPixel(left, top, drawMask, color, priority, control); + } + } +} + +byte Screen::getVisual(int x, int y) { + return _visualScreen[y * _width + x]; +} + +byte Screen::getPriority(int x, int y) { + return _priorityScreen[y * _width + x]; +} + +byte Screen::getControl(int x, int y) { + return _controlScreen[y * _width + x]; +} + +byte Screen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con) { + int offset = y * _width + x; + byte match = 0; + + if (screenMask & SCI_SCREEN_MASK_VISUAL && *(_visualScreen + offset) == t_color) + match |= SCI_SCREEN_MASK_VISUAL; + if (screenMask & SCI_SCREEN_MASK_PRIORITY && *(_priorityScreen + offset) == t_pri) + match |= SCI_SCREEN_MASK_PRIORITY; + if (screenMask & SCI_SCREEN_MASK_CONTROL && *(_controlScreen + offset) == t_con) + match |= SCI_SCREEN_MASK_CONTROL; + return match; +} + +int Screen::bitsGetDataSize(Common::Rect rect, byte mask) { + int byteCount = sizeof(rect) + sizeof(mask); + int pixels = rect.width() * rect.height(); + if (mask & SCI_SCREEN_MASK_VISUAL) { + byteCount += pixels; // _visualScreen + if (!_upscaledHires) { + byteCount += pixels; // _displayScreen + } else { + byteCount += pixels * 4; // _displayScreen (upscaled hires) + } + } + if (mask & SCI_SCREEN_MASK_PRIORITY) { + byteCount += pixels; // _priorityScreen + } + if (mask & SCI_SCREEN_MASK_CONTROL) { + byteCount += pixels; // _controlScreen + } + if (mask & SCI_SCREEN_MASK_DISPLAY) { + if (!_upscaledHires) + error("bitsGetDataSize() called w/o being in upscaled hires mode"); + byteCount += pixels; // _displayScreen (coordinates actually are given to us for hires displayScreen) + } + + return byteCount; +} + +void Screen::bitsSave(Common::Rect rect, byte mask, byte *memoryPtr) { + memcpy(memoryPtr, (void *)&rect, sizeof(rect)); memoryPtr += sizeof(rect); + memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask); + + if (mask & SCI_SCREEN_MASK_VISUAL) { + bitsSaveScreen(rect, _visualScreen, memoryPtr); + bitsSaveDisplayScreen(rect, memoryPtr); + } + if (mask & SCI_SCREEN_MASK_PRIORITY) { + bitsSaveScreen(rect, _priorityScreen, memoryPtr); + } + if (mask & SCI_SCREEN_MASK_CONTROL) { + bitsSaveScreen(rect, _controlScreen, memoryPtr); + } + if (mask & SCI_SCREEN_MASK_DISPLAY) { + if (!_upscaledHires) + error("bitsSave() called w/o being in upscaled hires mode"); + bitsSaveScreen(rect, _displayScreen, memoryPtr); + } +} + +void Screen::bitsSaveScreen(Common::Rect rect, byte *screen, byte *&memoryPtr) { + int width = rect.width(); + int y; + + screen += (rect.top * _width) + rect.left; + + for (y = rect.top; y < rect.bottom; y++) { + memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; + screen += _width; + } +} + +void Screen::bitsSaveDisplayScreen(Common::Rect rect, byte *&memoryPtr) { + byte *screen = _displayScreen; + int width = rect.width(); + int y; + + if (!_upscaledHires) { + screen += (rect.top * _displayWidth) + rect.left; + } else { + screen += (rect.top * 2 * _displayWidth) + rect.left * 2; + width *= 2; + rect.top *= 2; rect.bottom *= 2; + } + + for (y = rect.top; y < rect.bottom; y++) { + memcpy(memoryPtr, (void*)screen, width); memoryPtr += width; + screen += _displayWidth; + } +} + +void Screen::bitsGetRect(byte *memoryPtr, Common::Rect *destRect) { + memcpy((void *)destRect, memoryPtr, sizeof(Common::Rect)); +} + +void Screen::bitsRestore(byte *memoryPtr) { + Common::Rect rect; + byte mask; + + memcpy((void *)&rect, memoryPtr, sizeof(rect)); memoryPtr += sizeof(rect); + memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask); + + if (mask & SCI_SCREEN_MASK_VISUAL) { + bitsRestoreScreen(rect, memoryPtr, _visualScreen); + bitsRestoreDisplayScreen(rect, memoryPtr); + } + if (mask & SCI_SCREEN_MASK_PRIORITY) { + bitsRestoreScreen(rect, memoryPtr, _priorityScreen); + } + if (mask & SCI_SCREEN_MASK_CONTROL) { + bitsRestoreScreen(rect, memoryPtr, _controlScreen); + } + if (mask & SCI_SCREEN_MASK_DISPLAY) { + if (!_upscaledHires) + error("bitsRestore() called w/o being in upscaled hires mode"); + bitsRestoreScreen(rect, memoryPtr, _displayScreen); + } +} + +void Screen::bitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *screen) { + int width = rect.width(); + int y; + + screen += (rect.top * _width) + rect.left; + + for (y = rect.top; y < rect.bottom; y++) { + memcpy((void*) screen, memoryPtr, width); memoryPtr += width; + screen += _width; + } +} + +void Screen::bitsRestoreDisplayScreen(Common::Rect rect, byte *&memoryPtr) { + byte *screen = _displayScreen; + int width = rect.width(); + int y; + + if (!_upscaledHires) { + screen += (rect.top * _displayWidth) + rect.left; + } else { + screen += (rect.top * 2 * _displayWidth) + rect.left * 2; + width *= 2; + rect.top *= 2; rect.bottom *= 2; + } + + for (y = rect.top; y < rect.bottom; y++) { + memcpy((void*) screen, memoryPtr, width); memoryPtr += width; + screen += _displayWidth; + } +} + +void Screen::setPalette(Palette*pal) { + // just copy palette to system + byte bpal[4 * 256]; + // Get current palette, update it and put back + g_system->grabPalette(bpal, 0, 256); + for (int16 i = 0; i < 256; i++) { + if (!pal->colors[i].used) + continue; + bpal[i * 4] = pal->colors[i].r * pal->intensity[i] / 100; + bpal[i * 4 + 1] = pal->colors[i].g * pal->intensity[i] / 100; + bpal[i * 4 + 2] = pal->colors[i].b * pal->intensity[i] / 100; + bpal[i * 4 + 3] = 100; + } + g_system->setPalette(bpal, 0, 256); +} + +void Screen::setVerticalShakePos(uint16 shakePos) { + if (!_upscaledHires) + g_system->setShakePos(shakePos); + else + g_system->setShakePos(shakePos * 2); +} + +void Screen::dither(bool addToFlag) { + int y, x; + byte color, ditheredColor; + byte *visualPtr = _visualScreen; + byte *displayPtr = _displayScreen; + + if (!_unditherState) { + // Do dithering on visual and display-screen + for (y = 0; y < _height; y++) { + for (x = 0; x < _width; x++) { + color = *visualPtr; + if (color & 0xF0) { + color ^= color << 4; + color = ((x^y) & 1) ? color >> 4 : color & 0x0F; + *displayPtr = color; + if (_upscaledHires) { + *(displayPtr + 1) = color; + *(displayPtr + _displayWidth) = color; + *(displayPtr + _displayWidth + 1) = color; + } + *visualPtr = color; + } + visualPtr++; displayPtr++; + if (_upscaledHires) + displayPtr++; + } + if (_upscaledHires) + displayPtr += _displayWidth; + } + } else { + if (!addToFlag) + memset(&_unditherMemorial, 0, sizeof(_unditherMemorial)); + // Do dithering on visual screen and put decoded but undithered byte onto display-screen + for (y = 0; y < _height; y++) { + for (x = 0; x < _width; x++) { + color = *visualPtr; + if (color & 0xF0) { + color ^= color << 4; + // remember dither combination for cel-undithering + _unditherMemorial[color]++; + // if decoded color wants do dither with black on left side, we turn it around + // otherwise the normal ega color would get used for display + if (color & 0xF0) { + ditheredColor = color; + } else { + ditheredColor = color << 4; + } + *displayPtr = ditheredColor; + if (_upscaledHires) { + *(displayPtr + 1) = ditheredColor; + *(displayPtr + _displayWidth) = ditheredColor; + *(displayPtr + _displayWidth + 1) = ditheredColor; + } + color = ((x^y) & 1) ? color >> 4 : color & 0x0F; + *visualPtr = color; + } + visualPtr++; displayPtr++; + if (_upscaledHires) + displayPtr++; + } + if (_upscaledHires) + displayPtr += _displayWidth; + } + } +} + +void Screen::unditherSetState(bool flag) { + _unditherState = flag; +} + +int16 *Screen::unditherGetMemorial() { + if (_unditherState) + return (int16 *)&_unditherMemorial; + else + return NULL; +} + +void Screen::debugShowMap(int mapNo) { + // We cannot really support changing maps when in upscaledHires mode + if (_upscaledHires) + return; + + switch (mapNo) { + case 0: + _activeScreen = _visualScreen; + break; + case 1: + _activeScreen = _priorityScreen; + break; + case 2: + _activeScreen = _controlScreen; + break; + case 3: + _activeScreen = _displayScreen; + break; + } + copyToScreen(); +} + +void Screen::scale2x(byte *src, byte *dst, int16 srcWidth, int16 srcHeight) { + int newWidth = srcWidth * 2; + byte *srcPtr = src; + + for (int y = 0; y < srcHeight; y++) { + for (int x = 0; x < srcWidth; x++) { + int destOffset = y * 2 * newWidth + x * 2; + dst[destOffset] = *srcPtr; + dst[destOffset + 1] = *srcPtr; + dst[destOffset + newWidth] = *srcPtr; + dst[destOffset + newWidth + 1] = *srcPtr; + srcPtr++; + } + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h new file mode 100644 index 0000000000..efcfa17e03 --- /dev/null +++ b/engines/sci/graphics/screen.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_SCREEN_H +#define SCI_GRAPHICS_SCREEN_H + +#include "sci/sci.h" +#include "sci/graphics/helpers.h" + +namespace Sci { + +#define SCI_SCREEN_MAXHEIGHT 400 + +#define SCI_SCREEN_MASK_VISUAL 1 +#define SCI_SCREEN_MASK_PRIORITY 2 +#define SCI_SCREEN_MASK_CONTROL 4 +#define SCI_SCREEN_MASK_DISPLAY 8 // not official sierra sci +#define SCI_SCREEN_MASK_ALL SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY|SCI_SCREEN_MASK_CONTROL + +#define SCI_SCREEN_UNDITHERMEMORIAL_SIZE 256 + +class Screen { +public: + Screen(ResourceManager *resMan, int16 width = 320, int16 height = 200, bool upscaledHires = false); + ~Screen(); + + void copyToScreen(); + void copyFromScreen(byte *buffer); + void copyRectToScreen(const Common::Rect &rect); + void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y); + + byte getDrawingMask(byte color, byte prio, byte control); + void putPixel(int x, int y, byte drawMask, byte color, byte prio, byte control); + void putPixelOnDisplay(int x, int y, byte color); + void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control); + void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) { + drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control); + } + bool getUpscaledHires() { + return _upscaledHires; + } + byte getVisual(int x, int y); + byte getPriority(int x, int y); + byte getControl(int x, int y); + byte isFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con); + + int bitsGetDataSize(Common::Rect rect, byte mask); + void bitsSave(Common::Rect rect, byte mask, byte *memoryPtr); + void bitsGetRect(byte *memoryPtr, Common::Rect *destRect); + void bitsRestore(byte *memoryPtr); + + void setPalette(Palette*pal); + + void setVerticalShakePos(uint16 shakePos); + + void scale2x(byte *src, byte *dst, int16 srcWidth, int16 srcHeight); + + void dither(bool addToFlag); + void unditherSetState(bool flag); + int16 *unditherGetMemorial(); + + void debugShowMap(int mapNo); + + uint16 _width; + uint16 _height; + uint _pixels; + uint16 _displayWidth; + uint16 _displayHeight; + uint _displayPixels; + + int _picNotValid; // possible values 0, 1 and 2 + int _picNotValidSci11; // another variable that is used by kPicNotValid in sci1.1 + + byte _colorWhite; + byte _colorDefaultVectorData; + +private: + void bitsRestoreScreen(Common::Rect rect, byte *&memoryPtr, byte *screen); + void bitsRestoreDisplayScreen(Common::Rect rect, byte *&memoryPtr); + void bitsSaveScreen(Common::Rect rect, byte *screen, byte *&memoryPtr); + void bitsSaveDisplayScreen(Common::Rect rect, byte *&memoryPtr); + + bool _unditherState; + int16 _unditherMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; + +public: // HACK. TODO: make private + // these screens have the real resolution of the game engine (320x200 for SCI0/SCI1/SCI11 games, 640x480 for SCI2 games) + // SCI0 games will be dithered in here at any time + byte *_visualScreen; + byte *_priorityScreen; + byte *_controlScreen; + + // this screen is the one that is actually displayed to the user. It may be 640x480 for japanese SCI1 games + // SCI0 games may be undithered in here. Only read from this buffer for Save/ShowBits usage. + byte *_displayScreen; +private: + Common::Rect getScaledRect(Common::Rect rect); + + ResourceManager *_resMan; + + // this is a pointer to the currently active screen (changing it only required for debug purposes) + byte *_activeScreen; + bool _upscaledHires; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/text.cpp b/engines/sci/graphics/text.cpp new file mode 100644 index 0000000000..c0bb8d8e00 --- /dev/null +++ b/engines/sci/graphics/text.cpp @@ -0,0 +1,410 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/font.h" +#include "sci/graphics/text.h" + +namespace Sci { + +Text::Text(ResourceManager *resMan, Gfx *gfx, Screen *screen) + : _resMan(resMan), _gfx(gfx), _screen(screen) { + init(); +} + +Text::~Text() { + delete _font; +} + +void Text::init() { + _font = NULL; + _codeFonts = NULL; + _codeFontsCount = 0; + _codeColors = NULL; + _codeColorsCount = 0; +} + +GuiResourceId Text::GetFontId() { + return _gfx->_curPort->fontId; +} + +Font *Text::GetFont() { + if ((_font == NULL) || (_font->getResourceId() != _gfx->_curPort->fontId)) + _font = new Font(_resMan, _gfx->_curPort->fontId); + + return _font; +} + +void Text::SetFont(GuiResourceId fontId) { + if ((_font == NULL) || (_font->getResourceId() != fontId)) + _font = new Font(_resMan, fontId); + + _gfx->_curPort->fontId = _font->getResourceId(); + _gfx->_curPort->fontHeight = _font->getHeight(); +} + +void Text::CodeSetFonts(int argc, reg_t *argv) { + int i; + + delete _codeFonts; + _codeFontsCount = argc; + _codeFonts = new GuiResourceId[argc]; + for (i = 0; i < argc; i++) { + _codeFonts[i] = (GuiResourceId)argv[i].toUint16(); + } +} + +void Text::CodeSetColors(int argc, reg_t *argv) { + int i; + + delete _codeColors; + _codeColorsCount = argc; + _codeColors = new uint16[argc]; + for (i = 0; i < argc; i++) { + _codeColors[i] = argv[i].toUint16(); + } +} + +void Text::ClearChar(int16 chr) { + if (_gfx->_curPort->penMode != 1) + return; + Common::Rect rect; + rect.top = _gfx->_curPort->curTop; + rect.bottom = rect.top + _gfx->_curPort->fontHeight; + rect.left = _gfx->_curPort->curLeft; + rect.right = rect.left + GetFont()->getCharWidth(chr); + _gfx->EraseRect(rect); +} + +void Text::DrawChar(int16 chr) { + chr = chr & 0xFF; + ClearChar(chr); + StdChar(chr); + _gfx->_curPort->curLeft += GetFont()->getCharWidth(chr); +} + +void Text::StdChar(int16 chr) { +#if 0 + CResFont*res = getResFont(); + if (res) + res->Draw(chr, _curPort->top + _curPort->curTop, _curPort->left + + _curPort->curLeft, _vSeg, 320, _curPort->penClr, + _curPort->textFace); +#endif +} + +// This internal function gets called as soon as a '|' is found in a text +// It will process the encountered code and set new font/set color +// We only support one-digit codes currently, don't know if multi-digit codes are possible +// Returns textcode character count +int16 Text::CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor) { + const char *textCode = text; + int16 textCodeSize = 0; + char curCode; + unsigned char curCodeParm; + + // Find the end of the textcode + while ((++textCodeSize) && (*text != 0) && (*text++ != 0x7C)) { } + + // possible TextCodes: + // c -> sets textColor to current port pen color + // cX -> sets textColor to _textColors[X-1] + curCode = textCode[0]; + curCodeParm = textCode[1]; + if (isdigit(curCodeParm)) { + curCodeParm -= '0'; + } else { + curCodeParm = 0; + } + switch (curCode) { + case 'c': // set text color + if (curCodeParm == 0) { + _gfx->_curPort->penClr = orgPenColor; + } else { + if (curCodeParm < _codeColorsCount) { + _gfx->_curPort->penClr = _codeColors[curCodeParm]; + } + } + break; + case 'f': + if (curCodeParm == 0) { + SetFont(orgFontId); + } else { + if (curCodeParm < _codeFontsCount) { + SetFont(_codeFonts[curCodeParm]); + } + } + break; + } + return textCodeSize; +} + +// return max # of chars to fit maxwidth with full words +int16 Text::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId) { + char curChar; + int16 maxChars = 0, curCharCount = 0; + uint16 width = 0; + GuiResourceId oldFontId = GetFontId(); + int16 oldPenColor = _gfx->_curPort->penClr; + + GetFont(); + if (!_font) + return 0; + + while (width <= maxWidth) { + curChar = *text++; + switch (curChar) { + case 0x7C: + if (getSciVersion() >= SCI_VERSION_1_1) { + curCharCount++; + curCharCount += CodeProcessing(text, orgFontId, oldPenColor); + continue; + } + break; + + case 0xD: + curCharCount++; + continue; + + case 0xA: + curCharCount++; + case 0: + SetFont(oldFontId); + _gfx->PenColor(oldPenColor); + return curCharCount; + + case ' ': + maxChars = curCharCount + 1; + break; + } + width += _font->getCharWidth(curChar); + curCharCount++; + } + SetFont(oldFontId); + _gfx->PenColor(oldPenColor); + return maxChars; +} + +void Text::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight) { + unsigned char curChar; + GuiResourceId oldFontId = GetFontId(); + int16 oldPenColor = _gfx->_curPort->penClr; + + textWidth = 0; textHeight = 0; + + GetFont(); + if (_font) { + text += from; + while (len--) { + curChar = *text++; + switch (curChar) { + case 0x0A: + case 0x0D: + textHeight = MAX (textHeight, _gfx->_curPort->fontHeight); + break; + case 0x7C: + if (getSciVersion() >= SCI_VERSION_1_1) { + len -= CodeProcessing(text, orgFontId, 0); + break; + } + default: + textHeight = MAX (textHeight, _gfx->_curPort->fontHeight); + textWidth += _font->getCharWidth(curChar); + } + } + } + SetFont(oldFontId); + _gfx->PenColor(oldPenColor); + return; +} + +void Text::StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight) { + Width(str, 0, (int16)strlen(str), orgFontId, textWidth, textHeight); +} + +void Text::ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor) { + Show(str, 0, (int16)strlen(str), orgFontId, orgPenColor); +} +void Text::DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor) { + Draw(str, 0, (int16)strlen(str), orgFontId, orgPenColor); +} + +int16 Text::Size(Common::Rect &rect, const char *str, GuiResourceId fontId, int16 maxWidth) { + GuiResourceId oldFontId = GetFontId(); + int16 oldPenColor = _gfx->_curPort->penClr; + int16 charCount; + int16 maxTextWidth = 0, textWidth; + int16 totalHeight = 0, textHeight; + + if (fontId != -1) + SetFont(fontId); + rect.top = rect.left = 0; + + if (maxWidth < 0) { // force output as single line + StringWidth(str, oldFontId, textWidth, textHeight); + rect.bottom = textHeight; + rect.right = textWidth; + } else { + // rect.right=found widest line with RTextWidth and GetLongest + // rect.bottom=num. lines * GetPointSize + rect.right = (maxWidth ? maxWidth : 192); + const char*p = str; + while (*p) { + //if (*p == 0xD || *p == 0xA) { + // p++; + // continue; + //} + charCount = GetLongest(p, rect.right, oldFontId); + if (charCount == 0) + break; + Width(p, 0, charCount, oldFontId, textWidth, textHeight); + maxTextWidth = MAX(textWidth, maxTextWidth); + totalHeight += textHeight; + p += charCount; + } + rect.bottom = totalHeight; + rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); + } + SetFont(oldFontId); + _gfx->PenColor(oldPenColor); + return rect.right; +} + +// returns maximum font height used +void Text::Draw(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor) { + int16 curChar, charWidth; + Common::Rect rect; + + GetFont(); + if (!_font) + return; + + rect.top = _gfx->_curPort->curTop; + rect.bottom = rect.top + _gfx->_curPort->fontHeight; + text += from; + while (len--) { + curChar = (*text++); + switch (curChar) { + case 0x0A: + case 0x0D: + case 0: + break; + case 0x7C: + if (getSciVersion() >= SCI_VERSION_1_1) { + len -= CodeProcessing(text, orgFontId, orgPenColor); + break; + } + default: + charWidth = _font->getCharWidth(curChar); + // clear char + if (_gfx->_curPort->penMode == 1) { + rect.left = _gfx->_curPort->curLeft; + rect.right = rect.left + charWidth; + _gfx->EraseRect(rect); + } + // CharStd + _font->draw(_screen, curChar, _gfx->_curPort->top + _gfx->_curPort->curTop, _gfx->_curPort->left + _gfx->_curPort->curLeft, _gfx->_curPort->penClr, _gfx->_curPort->greyedOutput); + _gfx->_curPort->curLeft += charWidth; + } + } +} + +// returns maximum font height used +void Text::Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor) { + Common::Rect rect; + + rect.top = _gfx->_curPort->curTop; + rect.bottom = rect.top + _gfx->GetPointSize(); + rect.left = _gfx->_curPort->curLeft; + Draw(text, from, len, orgFontId, orgPenColor); + rect.right = _gfx->_curPort->curLeft; + _gfx->BitsShow(rect); +} + +// Draws a text in rect. +void Text::Box(const char *text, int16 bshow, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) { + int16 textWidth, textHeight, charCount; + int16 offset = 0; + int16 hline = 0; + GuiResourceId orgFontId = GetFontId(); + int16 orgPenColor = _gfx->_curPort->penClr; + + if (fontId != -1) + SetFont(fontId); + + while (*text) { +// if (*text == 0xD || *text == 0xA) { +// text++; +// continue; +// } + charCount = GetLongest(text, rect.width(), orgFontId); + if (charCount == 0) + break; + Width(text, 0, charCount, orgFontId, textWidth, textHeight); + switch (alignment) { + case SCI_TEXT_ALIGNMENT_RIGHT: + offset = rect.width() - textWidth; + break; + case SCI_TEXT_ALIGNMENT_CENTER: + offset = (rect.width() - textWidth) / 2; + break; + case SCI_TEXT_ALIGNMENT_LEFT: + offset = 0; + break; + + default: // left-aligned + warning("Invalid alignment %d used in TextBox()", alignment); + } + _gfx->MoveTo(rect.left + offset, rect.top + hline); + + if (bshow) { + Show(text, 0, charCount, orgFontId, orgPenColor); + } else { + Draw(text, 0, charCount, orgFontId, orgPenColor); + } + + hline += textHeight; + text += charCount; + } + SetFont(orgFontId); + _gfx->PenColor(orgPenColor); +} + +void Text::Draw_String(const char *text) { + GuiResourceId orgFontId = GetFontId(); + int16 orgPenColor = _gfx->_curPort->penClr; + + Draw(text, 0, strlen(text), orgFontId, orgPenColor); + SetFont(orgFontId); + _gfx->PenColor(orgPenColor); +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/text.h b/engines/sci/graphics/text.h new file mode 100644 index 0000000000..56f789598c --- /dev/null +++ b/engines/sci/graphics/text.h @@ -0,0 +1,83 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_TEXT_H +#define SCI_GRAPHICS_TEXT_H + +namespace Sci { + +#define SCI_TEXT_ALIGNMENT_RIGHT -1 +#define SCI_TEXT_ALIGNMENT_CENTER 1 +#define SCI_TEXT_ALIGNMENT_LEFT 0 + +class Gfx; +class Screen; +class Font; +class Text { +public: + Text(ResourceManager *_resMan, Gfx *gfx, Screen *screen); + ~Text(); + + GuiResourceId GetFontId(); + Font *GetFont(); + void SetFont(GuiResourceId fontId); + + void CodeSetFonts(int argc, reg_t *argv); + void CodeSetColors(int argc, reg_t *argv); + int16 CodeProcessing(const char *&text, GuiResourceId orgFontId, int16 orgPenColor); + + void ClearChar(int16 chr); + void DrawChar(int16 chr); + void StdChar(int16 chr); + + int16 GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId); + void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); + void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight); + void ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor); + void DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor); + int16 Size(Common::Rect &rect, const char *str, GuiResourceId fontId, int16 maxWidth); + void Draw(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); + void Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); + void Box(const char *text, int16 bshow, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId); + void Draw_String(const char *text); + + Font *_font; + +private: + void init(); + + ResourceManager *_resMan; + Gfx *_gfx; + Screen *_screen; + + int _codeFontsCount; + GuiResourceId *_codeFonts; + int _codeColorsCount; + uint16 *_codeColors; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp new file mode 100644 index 0000000000..565d628a67 --- /dev/null +++ b/engines/sci/graphics/transitions.cpp @@ -0,0 +1,576 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/events.h" +#include "common/util.h" +#include "common/stack.h" +#include "graphics/surface.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/gui.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/transitions.h" + +namespace Sci { + +Transitions::Transitions(SciGui *gui, Screen *screen, SciPalette *palette, bool isVGA) + : _gui(gui), _screen(screen), _palette(palette), _isVGA(isVGA) { + init(); +} + +Transitions::~Transitions() { + delete[] _oldScreen; +} + +// This table contains a mapping between oldIDs (prior SCI1LATE) and newIDs +static const GuiTransitionTranslateEntry oldTransitionIDs[] = { + { 0, SCI_TRANSITIONS_VERTICALROLL_FROMCENTER, false }, + { 1, SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER, false }, + { 2, SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, false }, + { 3, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, false }, + { 4, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, false }, + { 5, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, false }, + { 6, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, false }, + { 7, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, false }, + { 8, SCI_TRANSITIONS_BLOCKS, false }, + { 9, SCI_TRANSITIONS_VERTICALROLL_TOCENTER, false }, + { 10, SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, false }, + { 11, SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, true }, + { 12, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, true }, + { 13, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, true }, + { 14, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, true }, + { 15, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, true }, + { 16, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, true }, + { 17, SCI_TRANSITIONS_BLOCKS, true }, + { 18, SCI_TRANSITIONS_PIXELATION, false }, + { 27, SCI_TRANSITIONS_PIXELATION , true }, + { 30, SCI_TRANSITIONS_FADEPALETTE, false }, + { 40, SCI_TRANSITIONS_SCROLL_RIGHT, false }, + { 41, SCI_TRANSITIONS_SCROLL_LEFT, false }, + { 42, SCI_TRANSITIONS_SCROLL_UP, false }, + { 43, SCI_TRANSITIONS_SCROLL_DOWN, false }, + { 100, SCI_TRANSITIONS_NONE, false }, + { 255, 255, false } +}; + +// this table defines the blackout-transition that needs to be done prior doing the actual transition +static const GuiTransitionTranslateEntry blackoutTransitionIDs[] = { + { SCI_TRANSITIONS_VERTICALROLL_FROMCENTER, SCI_TRANSITIONS_VERTICALROLL_TOCENTER, true }, + { SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER, SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, true }, + { SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, true }, + { SCI_TRANSITIONS_STRAIGHT_FROM_LEFT, SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT, true }, + { SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, SCI_TRANSITIONS_STRAIGHT_FROM_TOP, true }, + { SCI_TRANSITIONS_STRAIGHT_FROM_TOP, SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM, true }, + { SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, true }, + { SCI_TRANSITIONS_DIAGONALROLL_TOCENTER, SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER, true }, + { SCI_TRANSITIONS_BLOCKS, SCI_TRANSITIONS_BLOCKS, true }, + { SCI_TRANSITIONS_PIXELATION, SCI_TRANSITIONS_PIXELATION, true }, + { SCI_TRANSITIONS_FADEPALETTE, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_SCROLL_RIGHT, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_SCROLL_LEFT, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_SCROLL_UP, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_SCROLL_DOWN, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_NONE_LONGBOW, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_NONE, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_VERTICALROLL_TOCENTER, SCI_TRANSITIONS_NONE, true }, + { SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER, SCI_TRANSITIONS_NONE, true }, + { 255, 255, true } +}; + +void Transitions::init() { + _oldScreen = new byte[_screen->_displayHeight * _screen->_displayWidth]; + + if (getSciVersion() >= SCI_VERSION_1_LATE) + _translationTable = NULL; + else + _translationTable = oldTransitionIDs; + + // setup default transition + _number = SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER; + _blackoutFlag = false; +} + +void Transitions::setup(int16 number, bool blackoutFlag) { + if (number != -1) { + _number = number; + _blackoutFlag = blackoutFlag; + } +} + +void Transitions::updateScreenAndWait(int msec) { + Common::Event ev; + g_system->updateScreen(); + g_system->delayMillis(msec); + while (g_system->getEventManager()->pollEvent(ev)) {} // discard all events +} + +// will translate a number and return corresponding translationEntry +const GuiTransitionTranslateEntry *Transitions::translateNumber (int16 number, const GuiTransitionTranslateEntry *tablePtr) { + while (1) { + if (tablePtr->orgId == 255) + return NULL; + if (tablePtr->orgId == number) + return tablePtr; + tablePtr++; + } +} + +void Transitions::doit(Common::Rect picRect) { + const GuiTransitionTranslateEntry *translationEntry = _translationTable; + + _picRect = picRect; + + if (_translationTable) { + // We need to translate the ID + translationEntry = translateNumber(_number, _translationTable); + if (translationEntry) { + _number = translationEntry->newId; + _blackoutFlag = translationEntry->blackoutFlag; + } else { + warning("Transitions: old ID %d not supported", _number); + _number = SCI_TRANSITIONS_NONE; + _blackoutFlag = false; + } + } + + if (_blackoutFlag) { + // We need to find out what transition we are supposed to use for blackout + translationEntry = translateNumber(_number, blackoutTransitionIDs); + if (translationEntry) { + doTransition(translationEntry->newId, true); + } else { + warning("Transitions: ID %d not listed in blackoutTransitionIDs", _number); + } + } + + // Now we do the actual transition to the new screen + doTransition(_number, false); + + if (picRect.bottom != 320) { + // TODO: this is a workaround for lsl6 not showing menubar when playing + // There is some new code in the sierra sci in ShowPic that seems to do something similar to this + _screen->copyToScreen(); + g_system->updateScreen(); + } + + _screen->_picNotValid = 0; +} + +// This may get called twice, if blackoutFlag is set. It will get once called with blackoutFlag set and another time +// with no blackoutFlag. +void Transitions::doTransition(int16 number, bool blackoutFlag) { + if (number != SCI_TRANSITIONS_FADEPALETTE) { + setNewPalette(blackoutFlag); + } + + switch (number) { + case SCI_TRANSITIONS_VERTICALROLL_FROMCENTER: + verticalRollFromCenter(blackoutFlag); + break; + case SCI_TRANSITIONS_VERTICALROLL_TOCENTER: + verticalRollFromCenter(blackoutFlag); + break; + case SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER: + horizontalRollFromCenter(blackoutFlag); + break; + case SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER: + horizontalRollToCenter(blackoutFlag); + break; + case SCI_TRANSITIONS_DIAGONALROLL_TOCENTER: + diagonalRollToCenter(blackoutFlag); + break; + case SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER: + diagonalRollFromCenter(blackoutFlag); + break; + + case SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT: + case SCI_TRANSITIONS_STRAIGHT_FROM_LEFT: + case SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM: + case SCI_TRANSITIONS_STRAIGHT_FROM_TOP: + straight(number, blackoutFlag); + break; + + case SCI_TRANSITIONS_PIXELATION: + pixelation(blackoutFlag); + break; + + case SCI_TRANSITIONS_BLOCKS: + blocks(blackoutFlag); + break; + + case SCI_TRANSITIONS_FADEPALETTE: + if (!blackoutFlag) { + fadeOut(); setNewScreen(blackoutFlag); fadeIn(); + } + break; + + case SCI_TRANSITIONS_SCROLL_RIGHT: + case SCI_TRANSITIONS_SCROLL_LEFT: + case SCI_TRANSITIONS_SCROLL_UP: + case SCI_TRANSITIONS_SCROLL_DOWN: + scroll(number); + break; + + case SCI_TRANSITIONS_NONE_LONGBOW: + case SCI_TRANSITIONS_NONE: + setNewScreen(blackoutFlag); + break; + + default: + warning("Transitions: ID %d not implemented", number); + setNewScreen(blackoutFlag); + } +} + +void Transitions::setNewPalette(bool blackoutFlag) { + if (!blackoutFlag) + if (_isVGA) + _palette->setOnScreen(); +} + +void Transitions::setNewScreen(bool blackoutFlag) { + if (!blackoutFlag) { + _screen->copyRectToScreen(_picRect); + g_system->updateScreen(); + } +} + +void Transitions::copyRectToScreen(const Common::Rect rect, bool blackoutFlag) { + if (!blackoutFlag) { + _screen->copyRectToScreen(rect); + } else { + Graphics::Surface *surface = g_system->lockScreen(); + surface->fillRect(rect, 0); + g_system->unlockScreen(); + } +} + +// Note: dont do too many steps in here, otherwise cpu will crap out because of the load +void Transitions::fadeOut() { + byte oldPalette[4 * 256], workPalette[4 * 256]; + int16 stepNr, colorNr; + + g_system->grabPalette(oldPalette, 0, 256); + + for (stepNr = 100; stepNr >= 0; stepNr -= 10) { + for (colorNr = 1; colorNr < 255; colorNr++){ + workPalette[colorNr * 4 + 0] = oldPalette[colorNr * 4] * stepNr / 100; + workPalette[colorNr * 4 + 1] = oldPalette[colorNr * 4 + 1] * stepNr / 100; + workPalette[colorNr * 4 + 2] = oldPalette[colorNr * 4 + 2] * stepNr / 100; + } + g_system->setPalette(workPalette + 4, 1, 254); + _gui->wait(2); + } +} + +// Note: dont do too many steps in here, otherwise cpu will crap out because of the load +void Transitions::fadeIn() { + int16 stepNr; + + for (stepNr = 0; stepNr <= 100; stepNr += 10) { + _palette->setIntensity(1, 255, stepNr, true); + _gui->wait(2); + } +} + +// pixelates the new picture over the old one - works against the whole screen +// TODO: it seems this needs to get applied on _picRect only if possible +void Transitions::pixelation (bool blackoutFlag) { + uint16 mask = 0x40, stepNr = 0; + Common::Rect pixelRect; + + do { + mask = (mask & 1) ? (mask >> 1) ^ 0xB400 : mask >> 1; + if (mask >= 320 * 200) + continue; + pixelRect.left = mask % 320; pixelRect.right = pixelRect.left + 1; + pixelRect.top = mask / 320; pixelRect.bottom = pixelRect.top + 1; + pixelRect.clip(_picRect); + if (!pixelRect.isEmpty()) + copyRectToScreen(pixelRect, blackoutFlag); + if ((stepNr & 0x3FF) == 0) { + updateScreenAndWait(5); + } + stepNr++; + } while (mask != 0x40); +} + +// like pixelation but uses 8x8 blocks - works against the whole screen +// TODO: it seems this needs to get applied on _picRect only if possible +void Transitions::blocks(bool blackoutFlag) { + uint16 mask = 0x40, stepNr = 0; + Common::Rect blockRect; + + do { + mask = (mask & 1) ? (mask >> 1) ^ 0x240 : mask >> 1; + if (mask >= 40 * 25) + continue; + blockRect.left = (mask % 40) << 3; blockRect.right = blockRect.left + 8; + blockRect.top = (mask / 40) << 3; blockRect.bottom = blockRect.top + 8; + blockRect.clip(_picRect); + if (!blockRect.isEmpty()) + copyRectToScreen(blockRect, blackoutFlag); + if ((stepNr & 7) == 0) { + updateScreenAndWait(4); + } + stepNr++; + } while (mask != 0x40); +} + +// directly shows new screen starting up/down/left/right and going to the opposite direction - works on _picRect area only +void Transitions::straight(int16 number, bool blackoutFlag) { + int16 stepNr = 0; + Common::Rect newScreenRect = _picRect; + + switch (number) { + case SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT: + newScreenRect.left = newScreenRect.right - 1; + while (newScreenRect.left >= _picRect.left) { + copyRectToScreen(newScreenRect, blackoutFlag); + if ((stepNr & 1) == 0) { + updateScreenAndWait(1); + } + stepNr++; + newScreenRect.translate(-1, 0); + } + break; + + case SCI_TRANSITIONS_STRAIGHT_FROM_LEFT: + newScreenRect.right = newScreenRect.left + 1; + while (newScreenRect.right <= _picRect.right) { + copyRectToScreen(newScreenRect, blackoutFlag); + if ((stepNr & 1) == 0) { + updateScreenAndWait(1); + } + stepNr++; + newScreenRect.translate(1, 0); + } + break; + + case SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM: + newScreenRect.top = newScreenRect.bottom - 1; + while (newScreenRect.top >= _picRect.top) { + copyRectToScreen(newScreenRect, blackoutFlag); + updateScreenAndWait(3); + stepNr++; + newScreenRect.translate(0, -1); + } + break; + + case SCI_TRANSITIONS_STRAIGHT_FROM_TOP: + newScreenRect.bottom = newScreenRect.top + 1; + while (newScreenRect.bottom <= _picRect.bottom) { + copyRectToScreen(newScreenRect, blackoutFlag); + updateScreenAndWait(3); + stepNr++; + newScreenRect.translate(0, 1); + } + break; + } +} + +// scroll old screen (up/down/left/right) and insert new screen that way - works on _picRect area only +void Transitions::scroll(int16 number) { + int16 screenWidth, screenHeight; + byte *oldScreenPtr; + int16 stepNr = 0; + Common::Rect oldMoveRect = _picRect; + Common::Rect newMoveRect = _picRect; + Common::Rect newScreenRect = _picRect; + + _screen->copyFromScreen(_oldScreen); + screenWidth = _screen->_displayWidth; screenHeight = _screen->_displayHeight; + + oldScreenPtr = _oldScreen + _picRect.left + _picRect.top * screenWidth; + + switch (number) { + case SCI_TRANSITIONS_SCROLL_LEFT: + newScreenRect.right = newScreenRect.left; + newMoveRect.left = newMoveRect.right; + while (oldMoveRect.left < oldMoveRect.right) { + oldScreenPtr++; oldMoveRect.right--; + if (oldMoveRect.right > oldMoveRect.left) + g_system->copyRectToScreen(oldScreenPtr, screenWidth, oldMoveRect.left, oldMoveRect.top, oldMoveRect.width(), oldMoveRect.height()); + newScreenRect.right++; newMoveRect.left--; + _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top); + if ((stepNr & 1) == 0) { + updateScreenAndWait(1); + } + stepNr++; + } + if ((stepNr & 1) == 0) + g_system->updateScreen(); + break; + + case SCI_TRANSITIONS_SCROLL_RIGHT: + newScreenRect.left = newScreenRect.right; + while (oldMoveRect.left < oldMoveRect.right) { + oldMoveRect.left++; + if (oldMoveRect.right > oldMoveRect.left) + g_system->copyRectToScreen(oldScreenPtr, screenWidth, oldMoveRect.left, oldMoveRect.top, oldMoveRect.width(), oldMoveRect.height()); + newScreenRect.left--; + _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top); + if ((stepNr & 1) == 0) { + updateScreenAndWait(1); + } + stepNr++; + } + if ((stepNr & 1) == 0) + g_system->updateScreen(); + break; + + case SCI_TRANSITIONS_SCROLL_UP: + newScreenRect.bottom = newScreenRect.top; + newMoveRect.top = newMoveRect.bottom; + while (oldMoveRect.top < oldMoveRect.bottom) { + oldScreenPtr += screenWidth; oldMoveRect.top++; + if (oldMoveRect.top < oldMoveRect.bottom) + g_system->copyRectToScreen(oldScreenPtr, screenWidth, _picRect.left, _picRect.top, oldMoveRect.width(), oldMoveRect.height()); + newScreenRect.bottom++; newMoveRect.top--; + _screen->copyRectToScreen(newScreenRect, newMoveRect.left, newMoveRect.top); + updateScreenAndWait(3); + } + break; + + case SCI_TRANSITIONS_SCROLL_DOWN: + newScreenRect.top = newScreenRect.bottom; + while (oldMoveRect.top < oldMoveRect.bottom) { + oldMoveRect.top++; + if (oldMoveRect.top < oldMoveRect.bottom) + g_system->copyRectToScreen(oldScreenPtr, screenWidth, oldMoveRect.left, oldMoveRect.top, oldMoveRect.width(), oldMoveRect.height()); + newScreenRect.top--; + _screen->copyRectToScreen(newScreenRect, _picRect.left, _picRect.top); + updateScreenAndWait(3); + } + break; + } +} + +// vertically displays new screen starting from center - works on _picRect area only +void Transitions::verticalRollFromCenter(bool blackoutFlag) { + Common::Rect leftRect = Common::Rect(_picRect.left + (_picRect.width() / 2) -1, _picRect.top, _picRect.left + (_picRect.width() / 2), _picRect.bottom); + Common::Rect rightRect = Common::Rect(leftRect.right, _picRect.top, leftRect.right + 1, _picRect.bottom); + + while ((leftRect.left >= _picRect.left) || (rightRect.right <= _picRect.right)) { + if (leftRect.left < _picRect.left) + leftRect.translate(1, 0); + if (rightRect.right > _picRect.right) + rightRect.translate(-1, 0); + copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0); + copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0); + updateScreenAndWait(2); + } +} + +// vertically displays new screen starting from edges - works on _picRect area only +void Transitions::verticalRollToCenter(bool blackoutFlag) { + Common::Rect leftRect = Common::Rect(_picRect.left, _picRect.top, _picRect.left + 1, _picRect.bottom); + Common::Rect rightRect = Common::Rect(leftRect.right - 1, _picRect.top, leftRect.right, _picRect.bottom); + + while (leftRect.left < rightRect.right) { + copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0); + copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0); + updateScreenAndWait(2); + } +} + +// horizontally displays new screen starting from center - works on _picRect area only +void Transitions::horizontalRollFromCenter(bool blackoutFlag) { + Common::Rect upperRect = Common::Rect(_picRect.left, _picRect.top + (_picRect.height() / 2) - 1, _picRect.right, _picRect.top + (_picRect.height() / 2)); + Common::Rect lowerRect = Common::Rect(upperRect.left, upperRect.bottom, upperRect.right, upperRect.bottom + 1); + + while ((upperRect.top >= _picRect.top) || (lowerRect.bottom <= _picRect.bottom)) { + if (upperRect.top < _picRect.top) + upperRect.translate(0, 1); + if (lowerRect.bottom > _picRect.bottom) + lowerRect.translate(0, -1); + copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, -1); + copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1); + updateScreenAndWait(3); + } +} + +// horizontally displays new screen starting from upper and lower edge - works on _picRect area only +void Transitions::horizontalRollToCenter(bool blackoutFlag) { + Common::Rect upperRect = Common::Rect(_picRect.left, _picRect.top, _picRect.right, _picRect.top + 1); + Common::Rect lowerRect = Common::Rect(upperRect.left, _picRect.bottom - 1, upperRect.right, _picRect.bottom); + + while (upperRect.top < lowerRect.bottom) { + copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1); + copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1); + updateScreenAndWait(3); + } +} + +// diagonally displays new screen starting from center - works on _picRect area only +// assumes that height of rect is larger than width +void Transitions::diagonalRollFromCenter(bool blackoutFlag) { + int16 halfHeight = _picRect.height() / 2; + Common::Rect upperRect(_picRect.left + halfHeight - 2, _picRect.top + halfHeight, _picRect.right - halfHeight + 1, _picRect.top + halfHeight + 1); + Common::Rect lowerRect(upperRect.left, upperRect.top, upperRect.right, upperRect.bottom); + Common::Rect leftRect(upperRect.left, upperRect.top, upperRect.left + 1, lowerRect.bottom); + Common::Rect rightRect(upperRect.right, upperRect.top, upperRect.right + 1, lowerRect.bottom); + + while ((upperRect.top >= _picRect.top) || (lowerRect.bottom <= _picRect.bottom)) { + if (upperRect.top < _picRect.top) { + upperRect.translate(0, 1); leftRect.top++; rightRect.top++; + } + if (lowerRect.bottom > _picRect.bottom) { + lowerRect.translate(0, -1); leftRect.bottom--; rightRect.bottom--; + } + if (leftRect.left < _picRect.left) { + leftRect.translate(1, 0); upperRect.left++; lowerRect.left++; + } + if (rightRect.right > _picRect.right) { + rightRect.translate(-1, 0); upperRect.right--; lowerRect.right--; + } + copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, -1); upperRect.left--; upperRect.right++; + copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, 1); lowerRect.left--; lowerRect.right++; + copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(-1, 0); leftRect.top--; leftRect.bottom++; + copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(1, 0); rightRect.top--; rightRect.bottom++; + updateScreenAndWait(3); + } +} + +// diagonally displays new screen starting from edges - works on _picRect area only +// assumes that height of rect is larger than width +void Transitions::diagonalRollToCenter(bool blackoutFlag) { + Common::Rect upperRect(_picRect.left, _picRect.top, _picRect.right, _picRect.top + 1); + Common::Rect lowerRect(_picRect.left, _picRect.bottom - 1, _picRect.right, _picRect.bottom); + Common::Rect leftRect(_picRect.left, _picRect.top, _picRect.left + 1, _picRect.bottom); + Common::Rect rightRect(_picRect.right - 1, _picRect.top, _picRect.right, _picRect.bottom); + + while (upperRect.top < lowerRect.bottom) { + copyRectToScreen(upperRect, blackoutFlag); upperRect.translate(0, 1); upperRect.left++; upperRect.right--; + copyRectToScreen(lowerRect, blackoutFlag); lowerRect.translate(0, -1); lowerRect.left++; lowerRect.right--; + copyRectToScreen(leftRect, blackoutFlag); leftRect.translate(1, 0); + copyRectToScreen(rightRect, blackoutFlag); rightRect.translate(-1, 0); + updateScreenAndWait(3); + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/transitions.h b/engines/sci/graphics/transitions.h new file mode 100644 index 0000000000..43d94dec9e --- /dev/null +++ b/engines/sci/graphics/transitions.h @@ -0,0 +1,106 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_TRANSITIONS_H +#define SCI_GRAPHICS_TRANSITIONS_H + +#include "sci/graphics/helpers.h" + +namespace Sci { + +struct GuiTransitionTranslateEntry { + int16 orgId; + int16 newId; + bool blackoutFlag; +}; + +enum { + SCI_TRANSITIONS_VERTICALROLL_FROMCENTER = 0, + SCI_TRANSITIONS_HORIZONTALROLL_FROMCENTER = 1, + SCI_TRANSITIONS_STRAIGHT_FROM_RIGHT = 2, + SCI_TRANSITIONS_STRAIGHT_FROM_LEFT = 3, + SCI_TRANSITIONS_STRAIGHT_FROM_BOTTOM = 4, + SCI_TRANSITIONS_STRAIGHT_FROM_TOP = 5, + SCI_TRANSITIONS_DIAGONALROLL_FROMCENTER = 6, + SCI_TRANSITIONS_DIAGONALROLL_TOCENTER = 7, + SCI_TRANSITIONS_BLOCKS = 8, + SCI_TRANSITIONS_PIXELATION = 9, + SCI_TRANSITIONS_FADEPALETTE = 10, + SCI_TRANSITIONS_SCROLL_RIGHT = 11, + SCI_TRANSITIONS_SCROLL_LEFT = 12, + SCI_TRANSITIONS_SCROLL_UP = 13, + SCI_TRANSITIONS_SCROLL_DOWN = 14, + SCI_TRANSITIONS_NONE_LONGBOW = 15, + SCI_TRANSITIONS_NONE = 100, + // here are transitions that are used by the old tableset, but are not included anymore in the new tableset + SCI_TRANSITIONS_VERTICALROLL_TOCENTER = 300, + SCI_TRANSITIONS_HORIZONTALROLL_TOCENTER = 301 +}; + +class Screen; +class Transitions { +public: + Transitions(SciGui *gui, Screen *screen, SciPalette *palette, bool isVGA); + ~Transitions(); + + void setup(int16 number, bool blackoutFlag); + void doit(Common::Rect picRect); + +private: + void init(); + const GuiTransitionTranslateEntry *translateNumber(int16 number, const GuiTransitionTranslateEntry *tablePtr); + void doTransition(int16 number, bool blackout); + void setNewPalette(bool blackoutFlag); + void setNewScreen(bool blackoutFlag); + void copyRectToScreen(const Common::Rect rect, bool blackoutFlag); + void fadeOut(); + void fadeIn(); + void pixelation(bool blackoutFlag); + void blocks(bool blackoutFlag); + void straight(int16 number, bool blackoutFlag); + void scroll(int16 number); + void verticalRollFromCenter(bool blackoutFlag); + void verticalRollToCenter(bool blackoutFlag); + void horizontalRollFromCenter(bool blackoutFlag); + void horizontalRollToCenter(bool blackoutFlag); + void diagonalRollFromCenter(bool blackoutFlag); + void diagonalRollToCenter(bool blackoutFlag); + void updateScreenAndWait(int msec); + + SciGui *_gui; + Screen *_screen; + SciPalette *_palette; + + bool _isVGA; + const GuiTransitionTranslateEntry *_translationTable; + int16 _number; + bool _blackoutFlag; + Common::Rect _picRect; + byte *_oldScreen; // buffer for saving current active screen data to, has dimenions of _screen->_displayScreen +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp new file mode 100644 index 0000000000..068ff24b02 --- /dev/null +++ b/engines/sci/graphics/view.cpp @@ -0,0 +1,513 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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 "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/view.h" + +namespace Sci { + +View::View(ResourceManager *resMan, Screen *screen, SciPalette *palette, GuiResourceId resourceId) + : _resMan(resMan), _screen(screen), _palette(palette), _resourceId(resourceId) { + assert(resourceId != -1); + initData(resourceId); +} + +View::~View() { + // Iterate through the loops + for (uint16 loopNum = 0; loopNum < _loopCount; loopNum++) { + // and through the cells of each loop + for (uint16 celNum = 0; celNum < _loop[loopNum].celCount; celNum++) { + delete[] _loop[loopNum].cel[celNum].rawBitmap; + } + delete[] _loop[loopNum].cel; + } + delete[] _loop; + + _resMan->unlockResource(_resource); +} + +static const byte EGAmappingStraight[SCI_VIEW_EGAMAPPING_SIZE] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 +}; + +void View::initData(GuiResourceId resourceId) { + _resource = _resMan->findResource(ResourceId(kResourceTypeView, resourceId), true); + if (!_resource) { + error("view resource %d not found", resourceId); + } + _resourceData = _resource->data; + + byte *celData, *loopData; + uint16 celOffset; + CelInfo *cel; + uint16 celCount = 0; + uint16 mirrorBits = 0; + uint16 palOffset = 0; + uint16 headerSize = 0; + uint16 loopSize = 0, celSize = 0; + int loopNo, celNo, EGAmapNr; + byte seekEntry; + bool isEGA = false; + bool isCompressed = true; + + _loopCount = 0; + _embeddedPal = false; + _EGAmapping = NULL; + + switch (_resMan->getViewType()) { + case kViewEga: // View-format SCI0 (and Amiga 16 colors) + isEGA = true; + case kViewAmiga: // View-format Amiga (32 colors) + case kViewVga: // View-format SCI1 + // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... + + _loopCount = _resourceData[0]; + // bit 0x8000 of _resourceData[1] means palette is set + if (_resourceData[1] & 0x40) + isCompressed = false; + mirrorBits = READ_LE_UINT16(_resourceData + 2); + palOffset = READ_LE_UINT16(_resourceData + 6); + + if (palOffset && palOffset != 0x100) { + // Some SCI0/SCI01 games also have an offset set. It seems that it points to a 16-byte mapping table + // but on those games using that mapping will actually screw things up. + // On the other side: vga sci1 games have this pointing to a VGA palette + // and ega sci1 games have this pointing to a 8x16 byte mapping table that needs to get applied then + if (!isEGA) { + _palette->createFromData(&_resourceData[palOffset], &_viewPalette); + _embeddedPal = true; + } else { + // Only use the EGA-mapping, when being SCI1 + if (getSciVersion() >= SCI_VERSION_1_EGA) { + _EGAmapping = &_resourceData[palOffset]; + for (EGAmapNr = 0; EGAmapNr < SCI_VIEW_EGAMAPPING_COUNT; EGAmapNr++) { + if (memcmp(_EGAmapping, EGAmappingStraight, SCI_VIEW_EGAMAPPING_SIZE)!=0) + break; + _EGAmapping += SCI_VIEW_EGAMAPPING_SIZE; + } + // If all mappings are "straight", then we actually ignore the mapping + if (EGAmapNr == SCI_VIEW_EGAMAPPING_COUNT) + _EGAmapping = NULL; + else + _EGAmapping = &_resourceData[palOffset]; + } + } + } + + _loop = new LoopInfo[_loopCount]; + for (loopNo = 0; loopNo < _loopCount; loopNo++) { + loopData = _resourceData + READ_LE_UINT16(_resourceData + 8 + loopNo * 2); + // CelCount:WORD Unknown:WORD CelOffset0:WORD CelOffset1:WORD... + + celCount = READ_LE_UINT16(loopData); + _loop[loopNo].celCount = celCount; + _loop[loopNo].mirrorFlag = mirrorBits & 1 ? true : false; + mirrorBits >>= 1; + + // read cel info + _loop[loopNo].cel = new CelInfo[celCount]; + for (celNo = 0; celNo < celCount; celNo++) { + celOffset = READ_LE_UINT16(loopData + 4 + celNo * 2); + celData = _resourceData + celOffset; + + // For VGA + // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE Unknown:BYTE RLEData starts now directly + // For EGA + // Width:WORD Height:WORD DisplaceX:BYTE DisplaceY:BYTE ClearKey:BYTE EGAData starts now directly + cel = &_loop[loopNo].cel[celNo]; + cel->width = READ_LE_UINT16(celData); + cel->height = READ_LE_UINT16(celData + 2); + cel->displaceX = celData[4]; + cel->displaceY = celData[5]; + cel->clearKey = celData[6]; + if (isEGA) { + cel->offsetEGA = celOffset + 7; + cel->offsetRLE = 0; + cel->offsetLiteral = 0; + } else { + cel->offsetEGA = 0; + if (isCompressed) { + cel->offsetRLE = celOffset + 8; + cel->offsetLiteral = 0; + } else { + cel->offsetRLE = 0; + cel->offsetLiteral = celOffset + 8; + } + } + cel->rawBitmap = 0; + if (_loop[loopNo].mirrorFlag) + cel->displaceX = -cel->displaceX; + } + } + break; + + case kViewVga11: // View-format SCI1.1 + // LoopCount:WORD MirrorMask:WORD Version:WORD PaletteOffset:WORD LoopOffset0:WORD LoopOffset1:WORD... + // HeaderSize:WORD LoopCount:BYTE Unknown:BYTE Version:WORD Unknown:WORD PaletteOffset:WORD + headerSize = READ_LE_UINT16(_resourceData + 0); + _loopCount = _resourceData[2]; + palOffset = READ_LE_UINT16(_resourceData + 8); + // FIXME: After LoopCount there is another byte and its set for view 50 within Laura Bow 2 CD, check what it means + + loopData = _resourceData + headerSize; + loopSize = _resourceData[12]; + celSize = _resourceData[13]; + + if (palOffset) { + _palette->createFromData(&_resourceData[palOffset], &_viewPalette); + _embeddedPal = true; + } + + _loop = new LoopInfo[_loopCount]; + for (loopNo = 0; loopNo < _loopCount; loopNo++) { + loopData = _resourceData + headerSize + (loopNo * loopSize); + + seekEntry = loopData[2]; + if (seekEntry != 255) { + if (seekEntry >= _loopCount) + error("Bad loop-pointer in sci 1.1 view"); + _loop[loopNo].mirrorFlag = true; + loopData = _resourceData + headerSize + (seekEntry * loopSize); + } else { + _loop[loopNo].mirrorFlag = false; + } + + celCount = loopData[4]; + _loop[loopNo].celCount = celCount; + + celData = _resourceData + READ_LE_UINT16(loopData + 14); + + // read cel info + _loop[loopNo].cel = new CelInfo[celCount]; + for (celNo = 0; celNo < celCount; celNo++) { + cel = &_loop[loopNo].cel[celNo]; + cel->width = READ_LE_UINT16(celData); + cel->height = READ_LE_UINT16(celData + 2); + cel->displaceX = READ_LE_UINT16(celData + 4); + cel->displaceY = READ_LE_UINT16(celData + 6); + cel->clearKey = celData[8]; + cel->offsetEGA = 0; + cel->offsetRLE = READ_LE_UINT16(celData + 24); + cel->offsetLiteral = READ_LE_UINT16(celData + 28); + cel->rawBitmap = 0; + if (_loop[loopNo].mirrorFlag) + cel->displaceX = -cel->displaceX; + + celData += celSize; + } + } + break; + + default: + error("ViewType was not detected, can't continue"); + } +} + +GuiResourceId View::getResourceId() { + return _resourceId; +} + +int16 View::getWidth(LoopNo loopNo, CelNo celNo) { + loopNo = CLIP(loopNo, 0, _loopCount - 1); + celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); + return _loopCount ? _loop[loopNo].cel[celNo].width : 0; +} + +int16 View::getHeight(LoopNo loopNo, CelNo celNo) { + loopNo = CLIP(loopNo, 0, _loopCount -1); + celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); + return _loopCount ? _loop[loopNo].cel[celNo].height : 0; +} + +CelInfo *View::getCelInfo(LoopNo loopNo, CelNo celNo) { + loopNo = CLIP(loopNo, 0, _loopCount - 1); + celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); + return _loopCount ? &_loop[loopNo].cel[celNo] : NULL; +} + +LoopInfo *View::getLoopInfo(LoopNo loopNo) { + loopNo = CLIP(loopNo, 0, _loopCount - 1); + return _loopCount ? &_loop[loopNo] : NULL; +} + +void View::getCelRect(LoopNo loopNo, CelNo celNo, int16 x, int16 y, int16 z, Common::Rect *outRect) { + CelInfo *celInfo = getCelInfo(loopNo, celNo); + if (celInfo) { + outRect->left = x + celInfo->displaceX - (celInfo->width >> 1); + outRect->right = outRect->left + celInfo->width; + outRect->bottom = y + celInfo->displaceY - z + 1; + outRect->top = outRect->bottom - celInfo->height; + } +} + +void View::unpackCel(LoopNo loopNo, CelNo celNo, byte *outPtr, uint16 pixelCount) { + CelInfo *celInfo = getCelInfo(loopNo, celNo); + byte *rlePtr; + byte *literalPtr; + uint16 pixelNo = 0, runLength; + byte pixel; + + if (celInfo->offsetEGA) { + // decompression for EGA views + literalPtr = _resourceData + _loop[loopNo].cel[celNo].offsetEGA; + while (pixelNo < pixelCount) { + pixel = *literalPtr++; + runLength = pixel >> 4; + memset(outPtr + pixelNo, pixel & 0x0F, MIN(runLength, pixelCount - pixelNo)); + pixelNo += runLength; + } + return; + } + + rlePtr = _resourceData + celInfo->offsetRLE; + if (!celInfo->offsetLiteral) { // no additional literal data + if (_resMan->getViewType() == kViewAmiga) { + // decompression for amiga views + while (pixelNo < pixelCount) { + pixel = *rlePtr++; + if (pixel & 0x07) { // fill with color + runLength = pixel & 0x07; + pixel = pixel >> 3; + while (runLength-- && pixelNo < pixelCount) { + outPtr[pixelNo++] = pixel; + } + } else { // fill with transparent + runLength = pixel >> 3; + pixelNo += runLength; + } + } + return; + } else { + // decompression for data that has just one combined stream + while (pixelNo < pixelCount) { + pixel = *rlePtr++; + runLength = pixel & 0x3F; + switch (pixel & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNo < pixelCount) + outPtr[pixelNo++] = *rlePtr++; + break; + case 0x80: // fill with color + memset(outPtr + pixelNo, *rlePtr++, MIN(runLength, pixelCount - pixelNo)); + pixelNo += runLength; + break; + case 0xC0: // fill with transparent + pixelNo += runLength; + break; + } + } + return; + } + } else { + literalPtr = _resourceData + celInfo->offsetLiteral; + if (celInfo->offsetRLE) { + // decompression for data that has separate rle and literal streams + while (pixelNo < pixelCount) { + pixel = *rlePtr++; + runLength = pixel & 0x3F; + switch (pixel & 0xC0) { + case 0: // copy bytes as-is + while (runLength-- && pixelNo < pixelCount) + outPtr[pixelNo++] = *literalPtr++; + break; + case 0x80: // fill with color + memset(outPtr + pixelNo, *literalPtr++, MIN(runLength, pixelCount - pixelNo)); + pixelNo += runLength; + break; + case 0xC0: // fill with transparent + pixelNo += runLength; + break; + } + } + } else { + // literal stream only, so no compression + memcpy(outPtr, literalPtr, pixelCount); + } + return; + } + error("Unable to decompress view"); +} + +byte *View::getBitmap(LoopNo loopNo, CelNo celNo) { + loopNo = CLIP(loopNo, 0, _loopCount -1); + celNo = CLIP(celNo, 0, _loop[loopNo].celCount - 1); + if (_loop[loopNo].cel[celNo].rawBitmap) + return _loop[loopNo].cel[celNo].rawBitmap; + + uint16 width = _loop[loopNo].cel[celNo].width; + uint16 height = _loop[loopNo].cel[celNo].height; + // allocating memory to store cel's bitmap + assert(width * height <= 64000); + uint16 pixelCount = width * height; + _loop[loopNo].cel[celNo].rawBitmap = new byte[pixelCount]; + byte *pBitmap = _loop[loopNo].cel[celNo].rawBitmap; + + // Some RLE compressed cels end with the last non-transparent pixel, thats why we fill it up here + // FIXME: change this to fill the remaining bytes within unpackCel() + memset(pBitmap, _loop[loopNo].cel[celNo].clearKey, pixelCount); + unpackCel(loopNo, celNo, pBitmap, pixelCount); + + if (!_resMan->isVGA()) { + unditherBitmap(pBitmap, width, height, _loop[loopNo].cel[celNo].clearKey); + } + + // mirroring the cel if needed + if (_loop[loopNo].mirrorFlag) { + for (int i = 0; i < height; i++, pBitmap += width) + for (int j = 0; j < width / 2; j++) + SWAP(pBitmap[j], pBitmap[width - j - 1]); + } + return _loop[loopNo].cel[celNo].rawBitmap; +} + +// Called after unpacking an EGA cel, this will try to undither (parts) of the cel if the dithering in here +// matches dithering used by the current picture +void View::unditherBitmap(byte *bitmapPtr, int16 width, int16 height, byte clearKey) { + int16 *unditherMemorial = _screen->unditherGetMemorial(); + + // It makes no sense to go further, if no memorial data from current picture is available + if (!unditherMemorial) + return; + + // Makes no sense to process bitmaps that are 3 pixels wide or less + if (width <= 3) return; + + // If EGA mapping is used for this view, dont do undithering as well + if (_EGAmapping) + return; + + // Walk through the bitmap and remember all combinations of colors + int16 bitmapMemorial[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; + byte *curPtr; + byte color1, color2; + int16 y, x; + + memset(&bitmapMemorial, 0, sizeof(bitmapMemorial)); + + // Count all seemingly dithered pixel-combinations as soon as at least 4 pixels are adjacent + curPtr = bitmapPtr; + for (y = 0; y < height; y++) { + color1 = curPtr[0]; color2 = (curPtr[1] << 4) | curPtr[2]; + curPtr += 3; + for (x = 3; x < width; x++) { + color1 = (color1 << 4) | (color2 >> 4); + color2 = (color2 << 4) | *curPtr++; + if (color1 == color2) + bitmapMemorial[color1]++; + } + } + + // Now compare both memorial tables to find out matching dithering-combinations + bool unditherTable[SCI_SCREEN_UNDITHERMEMORIAL_SIZE]; + byte color, unditherCount = 0; + memset(&unditherTable, false, sizeof(unditherTable)); + for (color = 0; color < 255; color++) { + if ((bitmapMemorial[color] > 5) && (unditherMemorial[color] > 200)) { + // match found, check if colorKey is contained -> if so, we ignore of course + color1 = color & 0x0F; color2 = color >> 4; + if ((color1 != clearKey) && (color2 != clearKey) && (color1 != color2)) { + // so set this and the reversed color-combination for undithering + unditherTable[color] = true; unditherTable[(color1 << 4) | color2] = true; + unditherCount++; + } + } + } + + // Nothing found to undither -> exit straight away + if (!unditherCount) + return; + + // We now need to replace color-combinations + curPtr = bitmapPtr; + for (y = 0; y < height; y++) { + color = *curPtr; + for (x = 1; x < width; x++) { + color = (color << 4) | curPtr[1]; + if (unditherTable[color]) { + // some color with black? turn colors around otherwise it wont be the right color at all + if ((color & 0xF0)==0) + color = (color << 4) | (color >> 4); + curPtr[0] = color; curPtr[1] = color; + } + curPtr++; + } + curPtr++; + } +} + +void View::draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRectTranslated, LoopNo loopNo, CelNo celNo, byte priority, uint16 EGAmappingNr, int16 origHeight) { + Palette *palette = _embeddedPal ? &_viewPalette : &_palette->_sysPalette; + CelInfo *celInfo = getCelInfo(loopNo, celNo); + byte *bitmap = getBitmap(loopNo, celNo); + int16 celHeight = celInfo->height, celWidth = celInfo->width; + int16 width, height; + byte clearKey = celInfo->clearKey; + byte color; + byte drawMask = priority == 255 ? SCI_SCREEN_MASK_VISUAL : SCI_SCREEN_MASK_VISUAL|SCI_SCREEN_MASK_PRIORITY; + int x, y; + + if (_embeddedPal) { + // Merge view palette in... + _palette->set(&_viewPalette, 1); + } + + width = MIN(clipRect.width(), celWidth); + height = MIN(clipRect.height(), celHeight); + + bitmap += (clipRect.top - rect.top) * celWidth + (clipRect.left - rect.left); + + if (!_EGAmapping) { + for (y = clipRectTranslated.top; y < clipRectTranslated.top + height; y++, bitmap += celWidth) { + for (x = 0; x < width; x++) { + color = bitmap[x]; + if (color != clearKey && priority >= _screen->getPriority(clipRectTranslated.left + x, y)) { + if (origHeight == -1) // HACK: this parameter is passed for already scaled views, but we're not actually using it + _screen->putPixel(clipRectTranslated.left + x, y, drawMask, palette->mapping[color], priority, 0); + else + _screen->putPixelOnDisplay(clipRectTranslated.left + x, y, palette->mapping[color]); + } + } + } + } else { + byte *EGAmapping = _EGAmapping + (EGAmappingNr * SCI_VIEW_EGAMAPPING_SIZE); + for (y = clipRectTranslated.top; y < clipRectTranslated.top + height; y++, bitmap += celWidth) { + for (x = 0; x < width; x++) { + color = EGAmapping[bitmap[x]]; + if (color != clearKey && priority >= _screen->getPriority(clipRectTranslated.left + x, y)) + _screen->putPixel(clipRectTranslated.left + x, y, drawMask, color, priority, 0); + } + } + } +} + +Palette *View::getPalette() { + return _embeddedPal ? &_viewPalette : &_palette->_sysPalette; +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/view.h b/engines/sci/graphics/view.h new file mode 100644 index 0000000000..109a37f065 --- /dev/null +++ b/engines/sci/graphics/view.h @@ -0,0 +1,91 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_VIEW_H +#define SCI_GRAPHICS_VIEW_H + +namespace Sci { + +struct CelInfo { + int16 width, height; + char displaceX; + byte displaceY; + byte clearKey; + uint16 offsetEGA; + uint16 offsetRLE; + uint16 offsetLiteral; + byte *rawBitmap; +}; + +struct LoopInfo { + bool mirrorFlag; + uint16 celCount; + CelInfo *cel; +}; + +#define SCI_VIEW_EGAMAPPING_SIZE 16 +#define SCI_VIEW_EGAMAPPING_COUNT 8 + +class View { +public: + View(ResourceManager *resMan, Screen *screen, SciPalette *palette, GuiResourceId resourceId); + ~View(); + + GuiResourceId getResourceId(); + int16 getWidth(LoopNo loopNo, CelNo celNo); + int16 getHeight(LoopNo loopNo, CelNo celNo); + CelInfo *getCelInfo(LoopNo loopNo, CelNo celNo); + LoopInfo *getLoopInfo(LoopNo loopNo); + void getCelRect(LoopNo loopNo, CelNo celNo, int16 x, int16 y, int16 z, Common::Rect *outRect); + byte *getBitmap(LoopNo loopNo, CelNo celNo); + void draw(Common::Rect rect, Common::Rect clipRect, Common::Rect clipRectTranslated, LoopNo loopNo, CelNo celNo, byte priority, uint16 EGAmappingNr, int16 origHeight = -1); + uint16 getLoopCount() const { return _loopCount; } + uint16 getCelCount(LoopNo loopNo) { return _loop[loopNo].celCount; } + Palette *getPalette(); + +private: + void initData(GuiResourceId resourceId); + void unpackCel(LoopNo loopNo, CelNo celNo, byte *outPtr, uint16 pixelCount); + void unditherBitmap(byte *bitmap, int16 width, int16 height, byte clearKey); + + ResourceManager *_resMan; + Screen *_screen; + SciPalette *_palette; + + GuiResourceId _resourceId; + Resource *_resource; + byte *_resourceData; + + uint16 _loopCount; + LoopInfo *_loop; + bool _embeddedPal; + Palette _viewPalette; + + byte *_EGAmapping; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/graphics/windowmgr.cpp b/engines/sci/graphics/windowmgr.cpp new file mode 100644 index 0000000000..6e599ae0a4 --- /dev/null +++ b/engines/sci/graphics/windowmgr.cpp @@ -0,0 +1,286 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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/util.h" + +#include "sci/sci.h" +#include "sci/engine/state.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/gfx.h" +#include "sci/graphics/animate.h" +#include "sci/graphics/text.h" +#include "sci/graphics/windowmgr.h" + +namespace Sci { + +// window styles +enum { + SCI_WINDOWMGR_STYLE_TRANSPARENT = (1 << 0), + SCI_WINDOWMGR_STYLE_NOFRAME = (1 << 1), + SCI_WINDOWMGR_STYLE_TITLE = (1 << 2), + SCI_WINDOWMGR_STYLE_TOPMOST = (1 << 3), + SCI_WINDOWMGR_STYLE_USER = (1 << 7) +}; + +WindowMgr::WindowMgr(SciGui *gui, Screen *screen, Gfx *gfx, Text *text) + : _gui(gui), _screen(screen), _gfx(gfx), _text(text) { +} + +WindowMgr::~WindowMgr() { + // TODO: Clear _windowList and delete all stuff in it? +} + +void WindowMgr::init(Common::String gameId) { + int16 offTop = 10; + + _wmgrPort = new Port(1); + _windowsById.resize(2); + _windowsById[0] = _wmgrPort; // wmgrPort is supposed to be accessible via id 0 + _windowsById[1] = _wmgrPort; // but wmgrPort may not actually have id 0, so we assign id 1 (as well) + // Background: sierra sci replies with the offset of curPort on kGetPort calls. If we reply with 0 there most games + // will work, but some scripts seem to check for 0 and initialize the variable again in that case + // resulting in problems. + + // Jones sierra sci was called with parameter -Nw 0 0 200 320 + // this actually meant not skipping the first 10 pixellines in windowMgrPort + if (gameId == "jones") + offTop = 0; + + _gfx->OpenPort(_wmgrPort); + _gfx->SetPort(_wmgrPort); + _gfx->SetOrigin(0, offTop); + _wmgrPort->rect.bottom = 200 - offTop; + _wmgrPort->rect.right = 320; + _wmgrPort->rect.moveTo(0, 0); + _wmgrPort->curTop = 0; + _wmgrPort->curLeft = 0; + _windowList.push_front(_wmgrPort); + + _picWind = NewWindow(Common::Rect(0, offTop, _screen->_width, _screen->_height), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true); +} + +int16 WindowMgr::isFrontWindow(Window *pWnd) { + return _windowList.back() == pWnd; +} + +void WindowMgr::BeginUpdate(Window *wnd) { + Port *oldPort = _gfx->SetPort(_wmgrPort); + PortList::iterator it = _windowList.reverse_begin(); + const PortList::iterator end = Common::find(_windowList.begin(), _windowList.end(), wnd); + while (it != end) { + // FIXME: We also store Port objects in the window list. + // We should add a check that we really only pass windows here... + UpdateWindow((Window *)*it); + --it; + } + _gfx->SetPort(oldPort); +} + +void WindowMgr::EndUpdate(Window *wnd) { + Port *oldPort = _gfx->SetPort(_wmgrPort); + const PortList::iterator end = _windowList.end(); + PortList::iterator it = Common::find(_windowList.begin(), end, wnd); + + // wnd has to be in _windowList + assert(it != end); + + while (++it != end) { + // FIXME: We also store Port objects in the window list. + // We should add a check that we really only pass windows here... + UpdateWindow((Window *)*it); + } + + _gfx->SetPort(oldPort); +} + +Window *WindowMgr::NewWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw) { + // Find an unused window/port id + uint id = 1; + while (id < _windowsById.size() && _windowsById[id]) { + ++id; + } + if (id == _windowsById.size()) + _windowsById.push_back(0); + assert(0 < id && id < 0xFFFF); + + Window *pwnd = new Window(id); + Common::Rect r; + + if (!pwnd) { + warning("Can't open window!"); + return 0; + } + + _windowsById[id] = pwnd; + if (style & SCI_WINDOWMGR_STYLE_TOPMOST) + _windowList.push_front(pwnd); + else + _windowList.push_back(pwnd); + _gfx->OpenPort(pwnd); + r = dims; + pwnd->rect = dims; + if (restoreRect) + pwnd->restoreRect = *restoreRect; + + pwnd->wndStyle = style; + pwnd->hSaved1 = pwnd->hSaved2 = NULL_REG; + pwnd->bDrawn = false; + if ((style & SCI_WINDOWMGR_STYLE_TRANSPARENT) == 0) + pwnd->saveScreenMask = (priority == -1 ? SCI_SCREEN_MASK_VISUAL : SCI_SCREEN_MASK_VISUAL | SCI_SCREEN_MASK_PRIORITY); + + if (title && (style & SCI_WINDOWMGR_STYLE_TITLE)) { + pwnd->title = title; + } + + r = dims; + if (style == SCI_WINDOWMGR_STYLE_USER || !(style & SCI_WINDOWMGR_STYLE_NOFRAME)) { + r.grow(1); + if (style & SCI_WINDOWMGR_STYLE_TITLE) { + r.top -= 10; + r.bottom++; + } + } + + // FIXME: it seems as if shadows may result in the window getting moved one upwards + // so that the shadow is visible (lsl5) + + pwnd->dims = r; + const Common::Rect *wmprect = &_wmgrPort->rect; + int16 oldtop = pwnd->dims.top; + int16 oldleft = pwnd->dims.left; + if (wmprect->top > pwnd->dims.top) + pwnd->dims.moveTo(pwnd->dims.left, wmprect->top); + + if (wmprect->bottom < pwnd->dims.bottom) + pwnd->dims.moveTo(pwnd->dims.left, wmprect->bottom - pwnd->dims.bottom + pwnd->dims.top); + + if (wmprect->right < pwnd->dims.right) + pwnd->dims.moveTo(wmprect->right + pwnd->dims.left - pwnd->dims.right, pwnd->dims.top); + + if (wmprect->left > pwnd->dims.left) + pwnd->dims.moveTo(wmprect->left, pwnd->dims.top); + + pwnd->rect.moveTo(pwnd->rect.left + pwnd->dims.left - oldleft, pwnd->rect.top + pwnd->dims.top - oldtop); + if (restoreRect == 0) + pwnd->restoreRect = pwnd->dims; + + if (!(pwnd->wndStyle & (SCI_WINDOWMGR_STYLE_USER | SCI_WINDOWMGR_STYLE_NOFRAME))) { + // The shadow is drawn slightly outside the window. + // Enlarge restoreRect to cover that. + pwnd->restoreRect.bottom++; + pwnd->restoreRect.right++; + } + + if (draw) + DrawWindow(pwnd); + _gfx->SetPort((Port *)pwnd); + _gfx->SetOrigin(pwnd->rect.left, pwnd->rect.top + _wmgrPort->top); + pwnd->rect.moveTo(0, 0); + return pwnd; +} + +void WindowMgr::DrawWindow(Window *pWnd) { + if (pWnd->bDrawn) + return; + Common::Rect r; + int16 wndStyle = pWnd->wndStyle; + + pWnd->bDrawn = true; + Port *oldport = _gfx->SetPort(_wmgrPort); + _gfx->PenColor(0); + if ((wndStyle & SCI_WINDOWMGR_STYLE_TRANSPARENT) == 0) { + pWnd->hSaved1 = _gfx->BitsSave(pWnd->restoreRect, SCI_SCREEN_MASK_VISUAL); + if (pWnd->saveScreenMask & SCI_SCREEN_MASK_PRIORITY) { + pWnd->hSaved2 = _gfx->BitsSave(pWnd->restoreRect, SCI_SCREEN_MASK_PRIORITY); + if ((wndStyle & SCI_WINDOWMGR_STYLE_USER) == 0) + _gfx->FillRect(pWnd->restoreRect, SCI_SCREEN_MASK_PRIORITY, 0, 15); + } + } + + // drawing frame,shadow and title + if (!(wndStyle & SCI_WINDOWMGR_STYLE_USER)) { + r = pWnd->dims; + if (!(wndStyle & SCI_WINDOWMGR_STYLE_NOFRAME)) { + r.translate(1, 1); + _gfx->FrameRect(r);// shadow + r.translate(-1, -1); + _gfx->FrameRect(r);// window frame + + if (wndStyle & SCI_WINDOWMGR_STYLE_TITLE) { + _gfx->FrameRect(r); + r.grow(-1); + _gfx->FillRect(r, SCI_SCREEN_MASK_VISUAL, 0); + if (!pWnd->title.empty()) { + int16 oldcolor = _gfx->GetPort()->penClr; + _gfx->PenColor(255); + _text->Box(pWnd->title.c_str(), 1, r, SCI_TEXT_ALIGNMENT_CENTER, 0); + _gfx->PenColor(oldcolor); + } + + r = pWnd->dims; + r.top += 9; + } + + r.grow(-1); + } + + if (!(wndStyle & SCI_WINDOWMGR_STYLE_TRANSPARENT)) + _gfx->FillRect(r, SCI_SCREEN_MASK_VISUAL, pWnd->backClr); + + _gfx->BitsShow(pWnd->restoreRect); + } + _gfx->SetPort(oldport); +} + +void WindowMgr::DisposeWindow(Window *pWnd, bool reanimate) { + _gfx->SetPort(_wmgrPort); + _gfx->BitsRestore(pWnd->hSaved1); + _gfx->BitsRestore(pWnd->hSaved2); + if (!reanimate) + _gfx->BitsShow(pWnd->restoreRect); + else + _gui->graphRedrawBox(pWnd->restoreRect); + _windowList.remove(pWnd); + _gfx->SetPort(_windowList.back()); + _windowsById[pWnd->id] = 0; + delete pWnd; +} + +void WindowMgr::UpdateWindow(Window *wnd) { + MemoryHandle handle; + + if (wnd->saveScreenMask && wnd->bDrawn) { + handle = _gfx->BitsSave(wnd->restoreRect, SCI_SCREEN_MASK_VISUAL); + _gfx->BitsRestore(wnd->hSaved1); + wnd->hSaved1 = handle; + if (wnd->saveScreenMask & SCI_SCREEN_MASK_PRIORITY) { + handle = _gfx->BitsSave(wnd->restoreRect, SCI_SCREEN_MASK_PRIORITY); + _gfx->BitsRestore(wnd->hSaved2); + wnd->hSaved2 = handle; + } + } +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/windowmgr.h b/engines/sci/graphics/windowmgr.h new file mode 100644 index 0000000000..30d854c518 --- /dev/null +++ b/engines/sci/graphics/windowmgr.h @@ -0,0 +1,71 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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$ + * + */ + +#ifndef SCI_GRAPHICS_WINDOWMGR_H +#define SCI_GRAPHICS_WINDOWMGR_H + +#include "common/list.h" +#include "common/array.h" + +namespace Sci { + +class WindowMgr { +public: + WindowMgr(SciGui *gui, Screen *screen, Gfx *gfx, Text *text); + ~WindowMgr(); + + void init(Common::String gameId); + + int16 isFrontWindow(Window *wnd); + void BeginUpdate(Window *wnd); + void EndUpdate(Window *wnd); + Window *NewWindow(const Common::Rect &dims, const Common::Rect *restoreRect, const char *title, uint16 style, int16 priority, bool draw); + void DrawWindow(Window *wnd); + void DisposeWindow(Window *pWnd, bool reanimate); + void UpdateWindow(Window *wnd); + + Port *getPortById(uint16 id) const { return _windowsById[id]; } + + Port *_wmgrPort; + Window *_picWind; + +private: + typedef Common::List PortList; + + SciGui *_gui; + Screen *_screen; + Gfx *_gfx; + Text *_text; + + /** The list of open 'windows' (and ports), in visual order. */ + PortList _windowList; + + /** The list of all open 'windows' (and ports), ordered by their id. */ + Common::Array _windowsById; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/module.mk b/engines/sci/module.mk index bb2a2eea1e..c607703089 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -36,20 +36,20 @@ MODULE_OBJS := \ engine/state.o \ engine/vm.o \ graphics/gui.o \ - graphics/gui_animate.o \ - graphics/gui_controls.o \ - graphics/gui_cursor.o \ - graphics/gui_font.o \ - graphics/gui_gfx.o \ - graphics/gui_menu.o \ - graphics/gui_palette.o \ - graphics/gui_picture.o \ - graphics/gui_portrait.o \ - graphics/gui_screen.o \ - graphics/gui_text.o \ - graphics/gui_transitions.o \ - graphics/gui_view.o \ - graphics/gui_windowmgr.o \ + graphics/animate.o \ + graphics/controls.o \ + graphics/cursor.o \ + graphics/font.o \ + graphics/gfx.o \ + graphics/menu.o \ + graphics/palette.o \ + graphics/picture.o \ + graphics/portrait.o \ + graphics/screen.o \ + graphics/text.o \ + graphics/transitions.o \ + graphics/view.o \ + graphics/windowmgr.o \ sound/audio.o \ sound/midiparser_sci.o \ sound/music.o \ diff --git a/engines/sci/resource.h b/engines/sci/resource.h index dac5c0a634..ab3363db0f 100644 --- a/engines/sci/resource.h +++ b/engines/sci/resource.h @@ -34,7 +34,7 @@ #include "sound/audiostream.h" #include "sound/mixer.h" // for SoundHandle -#include "graphics/gui_helpers.h" // for ViewType +#include "graphics/helpers.h" // for ViewType #include "sci/decompressor.h" #include "sci/sci.h" diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 914ea52a1d..8ae054655b 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -39,9 +39,9 @@ #include "sci/sound/audio.h" #include "sci/sound/soundcmd.h" #include "sci/graphics/gui.h" -#include "sci/graphics/gui_palette.h" -#include "sci/graphics/gui_cursor.h" -#include "sci/graphics/gui_screen.h" +#include "sci/graphics/palette.h" +#include "sci/graphics/cursor.h" +#include "sci/graphics/screen.h" namespace Sci { @@ -118,9 +118,9 @@ Common::Error SciEngine::run() { // TODO: Possibly look at first picture resource and determine if its hires or not // Initialize graphics-related parts - SciGuiScreen *screen = new SciGuiScreen(_resMan, 320, 200, upscaledHires); // invokes initGraphics() - SciGuiPalette *palette = new SciGuiPalette(_resMan, screen); - SciGuiCursor *cursor = new SciGuiCursor(_resMan, palette, screen); + Screen *screen = new Screen(_resMan, 320, 200, upscaledHires); // invokes initGraphics() + SciPalette *palette = new SciPalette(_resMan, screen); + Cursor *cursor = new Cursor(_resMan, palette, screen); // Create debugger console. It requires GFX to be initialized _console = new Console(this); -- cgit v1.2.3