scummvm/engines/sci/graphics/gui.cpp
Martin Kiewitz 01fd01122a SCI: fixing cursor in sci32 for clone ;)
svn-id: r47671
2010-01-29 15:46:22 +00:00

1041 lines
31 KiB
C++

/* 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/debug.h" // for g_debug_sleeptime_factor
#include "sci/event.h"
#include "sci/engine/state.h"
#include "sci/engine/selector.h"
#include "sci/graphics/gui.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/portrait.h"
#include "sci/graphics/robot.h"
#include "sci/graphics/text.h"
#include "sci/graphics/transitions.h"
#include "sci/graphics/view.h"
#include "sci/sound/audio.h"
namespace Sci {
SciGui::SciGui(EngineState *state, Screen *screen, SciPalette *palette, Cursor *cursor, AudioPlayer *audio)
: _s(state), _screen(screen), _palette(palette), _cursor(cursor), _audio(audio) {
_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 Text(_s->resMan, _gfx, _screen);
_windowMgr = new WindowMgr(this, _screen, _gfx, _text);
_controls = new Controls(_s->_segMan, _gfx, _text);
_menu = new Menu(_s->_event, _s->_segMan, this, _gfx, _text, _screen, _cursor);
}
SciGui::SciGui() {
}
SciGui::~SciGui() {
delete _menu;
delete _controls;
delete _windowMgr;
delete _text;
delete _animate;
delete _transitions;
delete _gfx;
}
void SciGui::resetEngineState(EngineState *s) {
_s = s;
_animate->resetEngineState(s);
}
void SciGui::init(bool usesOldGfxFunctions) {
_usesOldGfxFunctions = usesOldGfxFunctions;
_gfx->init(_text);
_windowMgr->init(_s->_gameId);
initPriorityBands();
}
void SciGui::initPriorityBands() {
if (_usesOldGfxFunctions) {
_gfx->PriorityBandsInit(15, 42, 200);
} else {
if (getSciVersion() >= SCI_VERSION_1_1)
_gfx->PriorityBandsInit(14, 0, 190);
else
_gfx->PriorityBandsInit(14, 42, 190);
}
}
void SciGui::wait(int16 ticks) {
uint32 time;
time = g_system->getMillis();
_s->r_acc = make_reg(0, ((long)time - (long)_s->last_wait_time) * 60 / 1000);
_s->last_wait_time = time;
ticks *= g_debug_sleeptime_factor;
kernel_sleep(_s->_event, ticks * 1000 / 60);
}
void SciGui::setPort(uint16 portPtr) {
switch (portPtr) {
case 0:
_gfx->SetPort(_windowMgr->_wmgrPort);
break;
case 0xFFFF:
_gfx->SetPort(_gfx->_menuPort);
break;
default:
_gfx->SetPort(_windowMgr->getPortById(portPtr));
};
}
Common::Rect SciGui::getPortPic(int16 &picTop, int16 &picLeft) {
picTop = _windowMgr->_picWind->top;
picLeft = _windowMgr->_picWind->left;
return _windowMgr->_picWind->rect;
}
void SciGui::setPortPic(Common::Rect rect, int16 picTop, int16 picLeft, bool initPriorityBandsFlag) {
_windowMgr->_picWind->rect = rect;
_windowMgr->_picWind->top = picTop;
_windowMgr->_picWind->left = picLeft;
if (initPriorityBandsFlag)
initPriorityBands();
}
reg_t SciGui::getPort() {
return make_reg(0, _gfx->GetPort()->id);
}
void SciGui::globalToLocal(int16 *x, int16 *y) {
Port *curPort = _gfx->GetPort();
*x = *x - curPort->left;
*y = *y - curPort->top;
}
void SciGui::localToGlobal(int16 *x, int16 *y) {
Port *curPort = _gfx->GetPort();
*x = *x + curPort->left;
*y = *y + curPort->top;
}
#ifdef ENABLE_SCI32
void SciGui::globalToLocal(int16 *x, int16 *y, reg_t planeObj) {
*x = *x - GET_SEL32V(_s->_segMan, planeObj, left);
*y = *y - GET_SEL32V(_s->_segMan, planeObj, top);
}
void SciGui::localToGlobal(int16 *x, int16 *y, reg_t planeObj) {
*x = *x + GET_SEL32V(_s->_segMan, planeObj, left);
*y = *y + GET_SEL32V(_s->_segMan, planeObj, top);
}
#endif
int16 SciGui::coordinateToPriority(int16 y) {
return _gfx->CoordinateToPriority(y);
}
int16 SciGui::priorityToCoordinate(int16 priority) {
return _gfx->PriorityToCoordinate(priority);
}
reg_t SciGui::newWindow(Common::Rect dims, Common::Rect restoreRect, uint16 style, int16 priority, int16 colorPen, int16 colorBack, const char *title) {
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);
else
wnd = _windowMgr->NewWindow(dims, NULL, title, style, priority, false);
wnd->penClr = colorPen;
wnd->backClr = colorBack;
_windowMgr->DrawWindow(wnd);
return make_reg(0, wnd->id);
}
void SciGui::disposeWindow(uint16 windowPtr, bool reanimate) {
Window *wnd = (Window *)_windowMgr->getPortById(windowPtr);
_windowMgr->DisposeWindow(wnd, reanimate);
}
#define SCI_DISPLAY_MOVEPEN 100
#define SCI_DISPLAY_SETALIGNMENT 101
#define SCI_DISPLAY_SETPENCOLOR 102
#define SCI_DISPLAY_SETBACKGROUNDCOLOR 103
#define SCI_DISPLAY_SETGREYEDOUTPUT 104
#define SCI_DISPLAY_SETFONT 105
#define SCI_DISPLAY_WIDTH 106
#define SCI_DISPLAY_SAVEUNDER 107
#define SCI_DISPLAY_RESTOREUNDER 108
#define SCI_DISPLAY_DONTSHOWBITS 121
void SciGui::display(const char *text, int argc, reg_t *argv) {
int displayArg;
TextAlignment alignment = SCI_TEXT_ALIGNMENT_LEFT;
int16 colorPen = -1, colorBack = -1, width = -1, bRedraw = 1;
bool doSaveUnder = false;
Common::Rect rect;
// Make a "backup" of the port settings
Port oldPort = *_gfx->GetPort();
// setting defaults
_gfx->PenMode(0);
_gfx->PenColor(0);
_gfx->TextGreyedOutput(false);
// processing codes in argv
while (argc > 0) {
displayArg = argv[0].toUint16();
argc--; argv++;
switch (displayArg) {
case SCI_DISPLAY_MOVEPEN:
_gfx->MoveTo(argv[0].toUint16(), argv[1].toUint16());
argc -= 2; argv += 2;
break;
case SCI_DISPLAY_SETALIGNMENT:
alignment = argv[0].toSint16();
argc--; argv++;
break;
case SCI_DISPLAY_SETPENCOLOR:
colorPen = argv[0].toUint16();
_gfx->PenColor(colorPen);
argc--; argv++;
break;
case SCI_DISPLAY_SETBACKGROUNDCOLOR:
colorBack = argv[0].toUint16();
argc--; argv++;
break;
case SCI_DISPLAY_SETGREYEDOUTPUT:
_gfx->TextGreyedOutput(argv[0].isNull() ? false : true);
argc--; argv++;
break;
case SCI_DISPLAY_SETFONT:
_text->SetFont(argv[0].toUint16());
argc--; argv++;
break;
case SCI_DISPLAY_WIDTH:
width = argv[0].toUint16();
argc--; argv++;
break;
case SCI_DISPLAY_SAVEUNDER:
doSaveUnder = true;
break;
case SCI_DISPLAY_RESTOREUNDER:
_gfx->BitsGetRect(argv[0], &rect);
rect.translate(-_gfx->GetPort()->left, -_gfx->GetPort()->top);
_gfx->BitsRestore(argv[0]);
graphRedrawBox(rect);
// finishing loop
argc = 0;
break;
case SCI_DISPLAY_DONTSHOWBITS:
bRedraw = 0;
break;
default:
warning("Unknown kDisplay argument %X", displayArg);
break;
}
}
// now drawing the text
_text->Size(rect, text, -1, width);
rect.moveTo(_gfx->GetPort()->curLeft, _gfx->GetPort()->curTop);
if (getSciVersion() >= SCI_VERSION_1_LATE) {
int16 leftPos = rect.right <= _screen->getWidth() ? 0 : _screen->getWidth() - rect.right;
int16 topPos = rect.bottom <= _screen->getHeight() ? 0 : _screen->getHeight() - rect.bottom;
_gfx->Move(leftPos, topPos);
rect.moveTo(_gfx->GetPort()->curLeft, _gfx->GetPort()->curTop);
}
if (doSaveUnder)
_s->r_acc = _gfx->BitsSave(rect, SCI_SCREEN_MASK_VISUAL);
if (colorBack != -1)
_gfx->FillRect(rect, SCI_SCREEN_MASK_VISUAL, colorBack, 0, 0);
_text->Box(text, 0, rect, alignment, -1);
if (_screen->_picNotValid == 0 && bRedraw)
_gfx->BitsShow(rect);
// restoring port and cursor pos
Port *currport = _gfx->GetPort();
uint16 tTop = currport->curTop;
uint16 tLeft = currport->curLeft;
*currport = oldPort;
currport->curTop = tTop;
currport->curLeft = tLeft;
}
void SciGui::textSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) {
Common::Rect rect(0, 0, *textWidth, *textHeight);
_text->Size(rect, text, font, maxWidth);
*textWidth = rect.width();
*textHeight = rect.height();
}
// Used SCI1+ for text codes
void SciGui::textFonts(int argc, reg_t *argv) {
_text->CodeSetFonts(argc, argv);
}
// Used SCI1+ for text codes
void SciGui::textColors(int argc, reg_t *argv) {
_text->CodeSetColors(argc, argv);
}
void SciGui::drawStatus(const char *text, int16 colorPen, int16 colorBack) {
Port *oldPort = _gfx->SetPort(_gfx->_menuPort);
_gfx->FillRect(_gfx->_menuBarRect, 1, colorBack);
_gfx->PenColor(colorPen);
_gfx->MoveTo(0, 1);
_text->Draw_String(text);
_gfx->BitsShow(_gfx->_menuBarRect);
_gfx->SetPort(oldPort);
}
void SciGui::drawMenuBar(bool clear) {
if (!clear) {
Port *oldPort = _gfx->SetPort(_gfx->_menuPort);
_menu->drawBar();
_gfx->BitsShow(_gfx->_menuBarRect);
_gfx->SetPort(oldPort);
} else {
drawStatus("", 0, 0);
}
}
void SciGui::menuReset() {
delete _menu;
_menu = new Menu(_s->_event, _s->_segMan, this, _gfx, _text, _screen, _cursor);
}
void SciGui::menuAdd(Common::String title, Common::String content, reg_t contentVmPtr) {
_menu->add(title, content, contentVmPtr);
}
void SciGui::menuSet(uint16 menuId, uint16 itemId, uint16 attributeId, reg_t value) {
_menu->setAttribute(menuId, itemId, attributeId, value);
}
reg_t SciGui::menuGet(uint16 menuId, uint16 itemId, uint16 attributeId) {
return _menu->getAttribute(menuId, itemId, attributeId);
}
reg_t SciGui::menuSelect(reg_t eventObject) {
return _menu->select(eventObject);
}
void SciGui::drawPicture(GuiResourceId pictureId, int16 animationNr, bool animationBlackoutFlag, bool mirroredFlag, bool addToFlag, int16 EGApaletteNo) {
Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind);
if (_windowMgr->isFrontWindow(_windowMgr->_picWind)) {
_screen->_picNotValid = 1;
_gfx->drawPicture(pictureId, animationNr, mirroredFlag, addToFlag, EGApaletteNo);
_transitions->setup(animationNr, animationBlackoutFlag);
} else {
_windowMgr->BeginUpdate(_windowMgr->_picWind);
_gfx->drawPicture(pictureId, animationNr, mirroredFlag, addToFlag, EGApaletteNo);
_windowMgr->EndUpdate(_windowMgr->_picWind);
}
_gfx->SetPort(oldPort);
}
void SciGui::drawCel(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, int16 priority, uint16 paletteNo, bool hiresMode, reg_t upscaledHiresHandle) {
// some calls are hiresMode even under kq6 DOS, that's why we check for upscaled hires here
if ((!hiresMode) || (!_screen->getUpscaledHires())) {
_gfx->drawCelAndShow(viewId, loopNo, celNo, leftPos, topPos, priority, paletteNo);
} else {
_gfx->drawHiresCelAndShow(viewId, loopNo, celNo, leftPos, topPos, priority, paletteNo, upscaledHiresHandle);
}
_palette->setOnScreen();
}
int SciGui::getControlPicNotValid() {
if (getSciVersion() >= SCI_VERSION_1_1)
return _screen->_picNotValidSci11;
return _screen->_picNotValid;
}
void SciGui::drawControlButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite) {
if (!hilite) {
rect.grow(1);
_gfx->EraseRect(rect);
_gfx->FrameRect(rect);
rect.grow(-2);
_gfx->TextGreyedOutput(style & 1 ? false : true);
_text->Box(text, 0, rect, SCI_TEXT_ALIGNMENT_CENTER, fontId);
_gfx->TextGreyedOutput(false);
rect.grow(1);
if (style & 8) // selected
_gfx->FrameRect(rect);
if (!getControlPicNotValid()) {
rect.grow(1);
_gfx->BitsShow(rect);
}
} else {
_gfx->InvertRect(rect);
_gfx->BitsShow(rect);
}
}
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);
rect.grow(-1);
_text->Box(text, 0, rect, alignment, fontId);
if (style & 8) { // selected
_gfx->FrameRect(rect);
}
rect.grow(1);
if (!getControlPicNotValid())
_gfx->BitsShow(rect);
} else {
_gfx->InvertRect(rect);
_gfx->BitsShow(rect);
}
}
void SciGui::drawControlTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) {
Common::Rect textRect = rect;
uint16 oldFontId = _text->GetFontId();
rect.grow(1);
_controls->TexteditCursorErase();
_gfx->EraseRect(rect);
_text->Box(text, 0, textRect, SCI_TEXT_ALIGNMENT_LEFT, fontId);
_gfx->FrameRect(rect);
if (style & 8) {
_text->SetFont(fontId);
rect.grow(-1);
_controls->TexteditCursorDraw(rect, text, cursorPos);
_text->SetFont(oldFontId);
rect.grow(1);
}
if (!getControlPicNotValid())
_gfx->BitsShow(rect);
}
void SciGui::drawControlIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, int16 loopNo, int16 celNo, int16 priority, int16 style, bool hilite) {
if (!hilite) {
_gfx->drawCelAndShow(viewId, loopNo, celNo, rect.left, rect.top, priority, 0);
if (style & 0x20) {
_gfx->FrameRect(rect);
}
if (!getControlPicNotValid())
_gfx->BitsShow(rect);
} else {
_gfx->InvertRect(rect);
_gfx->BitsShow(rect);
}
}
void SciGui::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) {
if (!hilite) {
_controls->drawListControl(rect, obj, maxChars, count, entries, fontId, upperPos, cursorPos, isAlias);
rect.grow(1);
if (isAlias && (style & 8)) {
_gfx->FrameRect(rect);
}
if (!getControlPicNotValid())
_gfx->BitsShow(rect);
}
}
void SciGui::editControl(reg_t controlObject, reg_t eventObject) {
int16 controlType = GET_SEL32V(_s->_segMan, controlObject, type);
switch (controlType) {
case SCI_CONTROLS_TYPE_TEXTEDIT:
// Only process textedit controls in here
_controls->TexteditChange(controlObject, eventObject);
return;
}
}
void SciGui::graphFillBoxForeground(Common::Rect rect) {
_gfx->PaintRect(rect);
}
void SciGui::graphFillBoxBackground(Common::Rect rect) {
_gfx->EraseRect(rect);
}
void SciGui::graphFillBox(Common::Rect rect, uint16 colorMask, int16 color, int16 priority, int16 control) {
_gfx->FillRect(rect, colorMask, color, priority, control);
}
void SciGui::graphFrameBox(Common::Rect rect, int16 color) {
int16 oldColor = _gfx->GetPort()->penClr;
_gfx->PenColor(color);
_gfx->FrameRect(rect);
_gfx->PenColor(oldColor);
}
void SciGui::graphDrawLine(Common::Point startPoint, Common::Point endPoint, int16 color, int16 priority, int16 control) {
_gfx->OffsetLine(startPoint, endPoint);
_screen->drawLine(startPoint.x, startPoint.y, endPoint.x, endPoint.y, color, priority, control);
}
reg_t SciGui::graphSaveBox(Common::Rect rect, uint16 screenMask) {
return _gfx->BitsSave(rect, screenMask);
}
reg_t SciGui::graphSaveUpscaledHiresBox(Common::Rect rect) {
return _gfx->BitsSave(rect, SCI_SCREEN_MASK_DISPLAY);
}
void SciGui::graphRestoreBox(reg_t handle) {
_gfx->BitsRestore(handle);
}
void SciGui::graphUpdateBox(Common::Rect rect, bool hiresMode) {
// some calls are hiresMode even under kq6 DOS, that's why we check for upscaled hires here
if ((!hiresMode) || (!_screen->getUpscaledHires()))
_gfx->BitsShow(rect);
else
_gfx->BitsShowHires(rect);
}
void SciGui::graphRedrawBox(Common::Rect rect) {
localToGlobal(&rect.left, &rect.top);
localToGlobal(&rect.right, &rect.bottom);
Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind);
globalToLocal(&rect.left, &rect.top);
globalToLocal(&rect.right, &rect.bottom);
_animate->reAnimate(rect);
_gfx->SetPort(oldPort);
}
void SciGui::graphAdjustPriority(int top, int bottom) {
if (_usesOldGfxFunctions) {
_gfx->PriorityBandsInit(15, top, bottom);
} else {
_gfx->PriorityBandsInit(14, top, bottom);
}
}
int16 SciGui::picNotValid(int16 newPicNotValid) {
int16 oldPicNotValid;
if (getSciVersion() >= SCI_VERSION_1_1) {
oldPicNotValid = _screen->_picNotValidSci11;
if (newPicNotValid != -1)
_screen->_picNotValidSci11 = newPicNotValid;
} else {
oldPicNotValid = _screen->_picNotValid;
if (newPicNotValid != -1)
_screen->_picNotValid = newPicNotValid;
}
return oldPicNotValid;
}
void SciGui::paletteSet(GuiResourceId resourceId, bool force) {
// we are also called on EGA games as well, this doesnt make sense. doing this would actually break the system EGA palette
if (!_s->resMan->isVGA())
return;
_palette->setFromResource(resourceId, force);
}
void SciGui::paletteSetFlag(uint16 fromColor, uint16 toColor, uint16 flag) {
_palette->setFlag(fromColor, toColor, flag);
}
void SciGui::paletteUnsetFlag(uint16 fromColor, uint16 toColor, uint16 flag) {
_palette->unsetFlag(fromColor, toColor, flag);
}
int16 SciGui::paletteFind(uint16 r, uint16 g, uint16 b) {
return _palette->matchColor(&_palette->_sysPalette, r, g, b) & 0xFF;
}
void SciGui::paletteSetIntensity(uint16 fromColor, uint16 toColor, uint16 intensity, bool setPalette) {
// we are also called on Amiga as well, but for colors above 32, so it doesnt make sense
if (!_s->resMan->isVGA())
return;
_palette->setIntensity(fromColor, toColor, intensity, setPalette);
}
bool SciGui::paletteAnimate(uint16 fromColor, uint16 toColor, int16 speed) {
// we are also called on Amiga as well, but for colors above 32, so it doesnt make sense
if (!_s->resMan->isVGA())
return false;
return _palette->animate(fromColor, toColor, speed);
}
void SciGui::paletteAnimateSet() {
_palette->setOnScreen();
}
void SciGui::shakeScreen(uint16 shakeCount, uint16 directions) {
while (shakeCount--) {
if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
_screen->setVerticalShakePos(10);
// TODO: horizontal shakes
g_system->updateScreen();
wait(3);
if (directions & SCI_SHAKE_DIRECTION_VERTICAL)
_screen->setVerticalShakePos(0);
g_system->updateScreen();
wait(3);
}
}
uint16 SciGui::onControl(byte screenMask, Common::Rect rect) {
Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind);
uint16 result;
result = _gfx->onControl(screenMask, rect);
_gfx->SetPort(oldPort);
return result;
}
void SciGui::animateShowPic() {
Port *picPort = _windowMgr->_picWind;
Common::Rect picRect = picPort->rect;
bool previousCursorState = _cursor->isVisible();
if (previousCursorState)
_cursor->hide();
// Adjust picRect to become relative to screen
picRect.translate(picPort->left, picPort->top);
_transitions->doit(picRect);
if (previousCursorState)
_cursor->show();
// We set SCI1.1 priority band information here
_gfx->PriorityBandsRecall();
}
void SciGui::animate(reg_t listReference, bool cycle, int argc, reg_t *argv) {
byte old_picNotValid = _screen->_picNotValid;
if (listReference.isNull()) {
_animate->disposeLastCast();
if (_screen->_picNotValid)
animateShowPic();
return;
}
List *list = _s->_segMan->lookupList(listReference);
if (!list)
error("kAnimate called with non-list as parameter");
if (cycle) {
if (!_animate->invoke(list, argc, argv))
return;
}
Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind);
_animate->disposeLastCast();
_animate->makeSortedList(list);
_animate->fill(old_picNotValid);
if (old_picNotValid) {
_windowMgr->BeginUpdate(_windowMgr->_picWind);
_animate->update();
_windowMgr->EndUpdate(_windowMgr->_picWind);
}
_animate->drawCels();
if (_screen->_picNotValid)
animateShowPic();
_animate->updateScreen(old_picNotValid);
_animate->restoreAndDelete(argc, argv);
if (_animate->getLastCastCount() > 1)
_s->_throttleTrigger = true;
_gfx->SetPort(oldPort);
}
void SciGui::addToPicSetPicNotValid() {
if (getSciVersion() <= SCI_VERSION_1_EARLY)
_screen->_picNotValid = 1;
else
_screen->_picNotValid = 2;
}
void SciGui::addToPicList(reg_t listReference, int argc, reg_t *argv) {
List *list;
_gfx->SetPort((Port *)_windowMgr->_picWind);
list = _s->_segMan->lookupList(listReference);
if (!list)
error("kAddToPic called with non-list as parameter");
_animate->makeSortedList(list);
_animate->addToPicDrawCels();
addToPicSetPicNotValid();
}
void SciGui::addToPicView(GuiResourceId viewId, int16 loopNo, int16 celNo, int16 leftPos, int16 topPos, int16 priority, int16 control) {
_gfx->SetPort((Port *)_windowMgr->_picWind);
_animate->addToPicDrawView(viewId, loopNo, celNo, leftPos, topPos, priority, control);
addToPicSetPicNotValid();
}
void SciGui::setNowSeen(reg_t objectReference) {
_gfx->SetNowSeen(objectReference);
}
bool SciGui::canBeHere(reg_t curObject, reg_t listReference) {
Port *oldPort = _gfx->SetPort((Port *)_windowMgr->_picWind);
Common::Rect checkRect;
uint16 signal, controlMask;
bool result;
checkRect.left = GET_SEL32V(_s->_segMan, curObject, brLeft);
checkRect.top = GET_SEL32V(_s->_segMan, curObject, brTop);
checkRect.right = GET_SEL32V(_s->_segMan, curObject, brRight);
checkRect.bottom = GET_SEL32V(_s->_segMan, curObject, brBottom);
signal = GET_SEL32V(_s->_segMan, curObject, signal);
controlMask = GET_SEL32V(_s->_segMan, curObject, illegalBits);
result = (_gfx->onControl(SCI_SCREEN_MASK_CONTROL, checkRect) & controlMask) ? false : true;
if ((result) && (signal & (kSignalIgnoreActor | kSignalRemoveView)) == 0) {
List *list = _s->_segMan->lookupList(listReference);
if (!list)
error("kCanBeHere called with non-list as parameter");
result = _gfx->CanBeHereCheckRectList(curObject, checkRect, list);
}
_gfx->SetPort(oldPort);
return result;
}
bool SciGui::isItSkip(GuiResourceId viewId, int16 loopNo, int16 celNo, Common::Point position) {
View *tmpView = _gfx->getView(viewId);
CelInfo *celInfo = tmpView->getCelInfo(loopNo, celNo);
position.x = CLIP<int>(position.x, 0, celInfo->width - 1);
position.y = CLIP<int>(position.y, 0, celInfo->height - 1);
byte *celData = tmpView->getBitmap(loopNo, celNo);
bool result = (celData[position.y * celInfo->width + position.x] == celInfo->clearKey);
return result;
}
void SciGui::baseSetter(reg_t object) {
if (lookup_selector(_s->_segMan, object, _s->_kernel->_selectorCache.brLeft, NULL, NULL) == kSelectorVariable) {
int16 x = GET_SEL32V(_s->_segMan, object, x);
int16 y = GET_SEL32V(_s->_segMan, object, y);
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);
int16 loopNo = GET_SEL32V(_s->_segMan, object, loop);
int16 celNo = GET_SEL32V(_s->_segMan, object, cel);
View *tmpView = _gfx->getView(viewId);
Common::Rect celRect;
tmpView->getCelRect(loopNo, celNo, x, y, z, &celRect);
celRect.bottom = y + 1;
celRect.top = celRect.bottom - yStep;
PUT_SEL32V(_s->_segMan, object, brLeft, celRect.left);
PUT_SEL32V(_s->_segMan, object, brRight, celRect.right);
PUT_SEL32V(_s->_segMan, object, brTop, celRect.top);
PUT_SEL32V(_s->_segMan, object, brBottom, celRect.bottom);
}
}
void SciGui::hideCursor() {
_cursor->hide();
}
void SciGui::showCursor() {
_cursor->show();
}
bool SciGui::isCursorVisible() {
return _cursor->isVisible();
}
void SciGui::setCursorShape(GuiResourceId cursorId) {
_cursor->setShape(cursorId);
}
void SciGui::setCursorView(GuiResourceId viewNum, int loopNum, int cellNum, Common::Point *hotspot) {
_cursor->setView(viewNum, loopNum, cellNum, hotspot);
}
void SciGui::setCursorPos(Common::Point pos) {
pos.y += _gfx->GetPort()->top;
pos.x += _gfx->GetPort()->left;
moveCursor(pos);
}
Common::Point SciGui::getCursorPos() {
return _cursor->getPosition();
}
void SciGui::moveCursor(Common::Point pos) {
pos.y += _windowMgr->_picWind->rect.top;
pos.x += _windowMgr->_picWind->rect.left;
pos.y = CLIP<int16>(pos.y, _windowMgr->_picWind->rect.top, _windowMgr->_picWind->rect.bottom - 1);
pos.x = CLIP<int16>(pos.x, _windowMgr->_picWind->rect.left, _windowMgr->_picWind->rect.right - 1);
if (pos.x > _screen->getWidth() || pos.y > _screen->getHeight()) {
warning("attempt to place cursor at invalid coordinates (%d, %d)", pos.y, pos.x);
return;
}
_cursor->setPosition(pos);
// Trigger event reading to make sure the mouse coordinates will
// actually have changed the next time we read them.
_s->_event->get(SCI_EVENT_PEEK);
}
void SciGui::setCursorZone(Common::Rect zone) {
_cursor->setMoveZone(zone);
}
int16 SciGui::getCelWidth(GuiResourceId viewId, int16 loopNo, int16 celNo) {
return _gfx->getView(viewId)->getCelInfo(loopNo, celNo)->width;
}
int16 SciGui::getCelHeight(GuiResourceId viewId, int16 loopNo, int16 celNo) {
return _gfx->getView(viewId)->getCelInfo(loopNo, celNo)->height;
}
int16 SciGui::getLoopCount(GuiResourceId viewId) {
return _gfx->getView(viewId)->getLoopCount();
}
int16 SciGui::getCelCount(GuiResourceId viewId, int16 loopNo) {
return _gfx->getView(viewId)->getLoopInfo(loopNo)->celCount;
}
void SciGui::syncWithFramebuffer() {
_screen->syncWithFramebuffer();
}
reg_t SciGui::portraitLoad(Common::String resourceName) {
//Portrait *myPortrait = new Portrait(_s->resMan, _screen, _palette, resourceName);
return NULL_REG;
}
void SciGui::portraitShow(Common::String resourceName, Common::Point position, uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq) {
Portrait *myPortrait = new Portrait(_s->resMan, _s->_event, this, _screen, _palette, _audio, resourceName);
// TODO: cache portraits
// adjust given coordinates to curPort (but dont adjust coordinates on upscaledHires_Save_Box and give us hires coordinates
// on kDrawCel, yeah this whole stuff makes sense)
position.x += _gfx->GetPort()->left; position.y += _gfx->GetPort()->top;
position.x *= 2; position.y *= 2;
myPortrait->doit(position, resourceId, noun, verb, cond, seq);
delete myPortrait;
}
void SciGui::portraitUnload(uint16 portraitId) {
}
void SciGui::startPalVary(uint16 paletteId, uint16 ticks) {
if (_palVaryId >= 0) // another palvary is taking place, return
return;
_palVaryId = paletteId;
_palVaryStart = g_system->getMillis();
_palVaryEnd = _palVaryStart + ticks * 1000 / 60;
((SciEngine*)g_engine)->getTimerManager()->installTimerProc(&palVaryCallback, 1000 / 60, this);
}
void SciGui::togglePalVary(bool pause) {
// this call is actually counting states, so calling this 3 times with true will require calling it later
// 3 times with false to actually remove pause
// TODO
}
void SciGui::stopPalVary() {
((SciEngine*)g_engine)->getTimerManager()->removeTimerProc(&palVaryCallback);
_palVaryId = -1; // invalidate the target palette
// HACK: just set the target palette
_palette->setFromResource(_palVaryId, true);
}
void SciGui::palVaryCallback(void *refCon) {
((SciGui *)refCon)->doPalVary();
}
void SciGui::doPalVary() {
// TODO: do palette transition here...
}
#ifdef ENABLE_SCI32
void SciGui::addScreenItem(reg_t object) {
_screenItems.push_back(object);
}
void SciGui::deleteScreenItem(reg_t object) {
for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
if (_screenItems[itemNr] == object) {
_screenItems.remove_at(itemNr);
return;
}
}
}
void SciGui::addPlane(reg_t object) {
_planes.push_back(object);
}
void SciGui::updatePlane(reg_t object) {
int16 picNum = GET_SEL32V(_s->_segMan, object, picture);
if (picNum > -1) {
drawPicture(picNum, 100, false, false, false, 0);
animateShowPic();
}
}
void SciGui::deletePlane(reg_t object) {
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
if (_planes[planeNr] == object) {
_planes.remove_at(planeNr);
return;
}
}
}
void SciGui::frameOut() {
for (uint32 planeNr = 0; planeNr < _planes.size(); planeNr++) {
reg_t planeObj = _planes[planeNr];
int16 priority = GET_SEL32V(_s->_segMan, planeObj, priority);
if (priority == -1)
continue;
int16 picNum = GET_SEL32V(_s->_segMan, planeObj, picture);
if (picNum > -1) {
drawPicture(picNum, 100, false, false, false, 0);
}
// FIXME: This code doesn't currently work properly because of the way we set up the
// view port. We are starting at 10 pixels from the top automatically. The offset should
// be based on the plane's top in SCI32 instead. Here we would be adding 10 to 10 and
// therefore drawing too low. We would need to draw each picture at the correct offset
// which doesn't currently happen.
//int16 planeTop = GET_SEL32V(_s->_segMan, planeObj, top);
//int16 planeLeft = GET_SEL32V(_s->_segMan, planeObj, left);
for (uint32 itemNr = 0; itemNr < _screenItems.size(); itemNr++) {
reg_t viewObj = _screenItems[itemNr];
reg_t planeOfItem = GET_SEL32(_s->_segMan, viewObj, plane);
if (planeOfItem == _planes[planeNr]) {
uint16 viewId = GET_SEL32V(_s->_segMan, viewObj, view);
uint16 loopNo = GET_SEL32V(_s->_segMan, viewObj, loop);
uint16 celNo = GET_SEL32V(_s->_segMan, viewObj, cel);
uint16 leftPos = GET_SEL32V(_s->_segMan, viewObj, x);
uint16 topPos = GET_SEL32V(_s->_segMan, viewObj, y);
priority = GET_SEL32V(_s->_segMan, viewObj, priority);
uint16 scaleX = GET_SEL32V(_s->_segMan, viewObj, scaleX);
uint16 scaleY = GET_SEL32V(_s->_segMan, viewObj, scaleY);
//int16 signal = GET_SEL32V(_s->_segMan, viewObj, signal);
// FIXME: See above
//leftPos += planeLeft;
//topPos += planeTop;
// Theoretically, leftPos and topPos should be sane
// Apparently, sometimes they're not, therefore I'm adding some sanity checks here so that
// the hack underneath does not try and draw cels outside the screen coordinates
if (leftPos >= _screen->getWidth()) {
continue;
}
if (topPos >= _screen->getHeight()) {
continue;
}
if (viewId != 0xffff) {
Common::Rect celRect;
View *view = _gfx->getView(viewId);
// Sometimes x,y are bottom right
celRect.left = leftPos;
celRect.top = topPos;
celRect.right = leftPos + view->getWidth(loopNo, celNo);
celRect.bottom = topPos + view->getHeight(loopNo, celNo);
//celRect.right = leftPos;
//celRect.bottom = topPos;
//celRect.left = celRect.right - view->getWidth(loopNo, celNo);;
//celRect.top = celRect.bottom - view->getHeight(loopNo, celNo);
celRect.clip(_gfx->_curPort->rect);
_gfx->drawCel(view, loopNo, celNo, celRect, priority, 0, scaleX, scaleY);
}
//drawCel(viewId, loopNo, celNo, leftPos, topPos, priority, 0);
}
}
}
_screen->copyToScreen();
//animateShowPic();
}
void SciGui::drawRobot(GuiResourceId robotId) {
Robot *test = new Robot(_s->resMan, _screen, robotId);
test->draw();
delete test;
}
#endif
bool SciGui::debugUndither(bool flag) {
_screen->unditherSetState(flag);
return false;
}
bool SciGui::debugShowMap(int mapNo) {
_screen->debugShowMap(mapNo);
return false;
}
bool SciGui::debugEGAdrawingVisualize(bool state) {
_gfx->setEGAdrawingVisualize(state);
return false;
}
} // End of namespace Sci