void GfxCursor32::setRestrictedArea(const Common::Rect &rect) { _restrictedArea = rect; const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; mulru(_restrictedArea, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight), 0); if (_position.x < rect.left) { _position.x = rect.left; } if (_position.x >= rect.right) { _position.x = rect.right - 1; } if (_position.y < rect.top) { _position.y = rect.top; } if (_position.y >= rect.bottom) { _position.y = rect.bottom - 1; } g_system->warpMouse(_position.x, _position.y); }
reg_t kCelWide32(EngineState *s, int argc, reg_t *argv) { GuiResourceId resourceId = argv[0].toUint16(); int16 loopNo = argv[1].toSint16(); int16 celNo = argv[2].toSint16(); CelObjView celObj(resourceId, loopNo, celNo); return make_reg(0, mulru(celObj._width, Ratio(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth, celObj._scaledWidth))); }
void ScreenItem::calcRects(const Plane &plane) { const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; const CelObj &celObj = getCelObj(); Common::Rect celRect(celObj._width, celObj._height); if (_useInsetRect) { if (_insetRect.intersects(celRect)) { _insetRect.clip(celRect); } else { _insetRect = Common::Rect(); } } else { _insetRect = celRect; } Ratio scaleX, scaleY; if (_scale.signal & kScaleSignalDoScaling32) { if (_scale.signal & kScaleSignalUseVanishingPoint) { int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y); scaleX = Ratio(num, 128); scaleY = Ratio(num, 128); } else { scaleX = Ratio(_scale.x, 128); scaleY = Ratio(_scale.y, 128); } } if (scaleX.getNumerator() && scaleY.getNumerator()) { _screenItemRect = _insetRect; const Ratio celToScreenX(screenWidth, celObj._scaledWidth); const Ratio celToScreenY(screenHeight, celObj._scaledHeight); // Cel may use a coordinate system that is not the same size as the // script coordinate system (usually this means high-resolution // pictures with low-resolution scripts) if (celObj._scaledWidth != kLowResX || celObj._scaledHeight != kLowResY) { // high resolution coordinates if (_useInsetRect) { const Ratio scriptToCelX(celObj._scaledWidth, scriptWidth); const Ratio scriptToCelY(celObj._scaledHeight, scriptHeight); mulru(_screenItemRect, scriptToCelX, scriptToCelY, 0); if (_screenItemRect.intersects(celRect)) { _screenItemRect.clip(celRect); } else { _screenItemRect = Common::Rect(); } } int displaceX = celObj._displace.x; int displaceY = celObj._displace.y; if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { displaceX = celObj._width - celObj._displace.x - 1; } if (!scaleX.isOne() || !scaleY.isOne()) { // Different games use a different cel scaling mode, but the // difference isn't consistent across SCI versions; instead, // it seems to be related to an update that happened during // SCI2.1mid where games started using hi-resolution game // scripts if (scriptWidth == kLowResX) { mulinc(_screenItemRect, scaleX, scaleY); } else { _screenItemRect.left = (_screenItemRect.left * scaleX).toInt(); _screenItemRect.top = (_screenItemRect.top * scaleY).toInt(); if (scaleX.getNumerator() > scaleX.getDenominator()) { _screenItemRect.right = (_screenItemRect.right * scaleX).toInt(); } else { _screenItemRect.right = ((_screenItemRect.right - 1) * scaleX).toInt() + 1; } if (scaleY.getNumerator() > scaleY.getDenominator()) { _screenItemRect.bottom = (_screenItemRect.bottom * scaleY).toInt(); } else { _screenItemRect.bottom = ((_screenItemRect.bottom - 1) * scaleY).toInt() + 1; } } displaceX = (displaceX * scaleX).toInt(); displaceY = (displaceY * scaleY).toInt(); } mulinc(_screenItemRect, celToScreenX, celToScreenY); displaceX = (displaceX * celToScreenX).toInt(); displaceY = (displaceY * celToScreenY).toInt(); const Ratio scriptToScreenX = Ratio(screenWidth, scriptWidth); const Ratio scriptToScreenY = Ratio(screenHeight, scriptHeight); if (/* TODO: dword_C6288 */ false && _celInfo.type == kCelTypePic) { _scaledPosition.x = _position.x; _scaledPosition.y = _position.y; } else { _scaledPosition.x = (_position.x * scriptToScreenX).toInt() - displaceX; _scaledPosition.y = (_position.y * scriptToScreenY).toInt() - displaceY; } _screenItemRect.translate(_scaledPosition.x, _scaledPosition.y); if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) { Common::Rect temp(_insetRect); if (!scaleX.isOne()) { mulinc(temp, scaleX, Ratio()); } mulinc(temp, celToScreenX, Ratio()); CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj); if (celObjPic == nullptr) { error("Expected a CelObjPic"); } temp.translate((celObjPic->_relativePosition.x * scriptToScreenX).toInt() - displaceX, 0); // TODO: This is weird. int deltaX = plane._planeRect.width() - temp.right - 1 - temp.left; _scaledPosition.x += deltaX; _screenItemRect.translate(deltaX, 0); } _scaledPosition.x += plane._planeRect.left; _scaledPosition.y += plane._planeRect.top; _screenItemRect.translate(plane._planeRect.left, plane._planeRect.top); _ratioX = scaleX * celToScreenX; _ratioY = scaleY * celToScreenY; } else { // low resolution coordinates int displaceX = celObj._displace.x; if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { displaceX = celObj._width - celObj._displace.x - 1; } if (!scaleX.isOne() || !scaleY.isOne()) { mulinc(_screenItemRect, scaleX, scaleY); // TODO: This was in the original code, baked into the // multiplication though it is not immediately clear // why this is the only one that reduces the BR corner _screenItemRect.right -= 1; _screenItemRect.bottom -= 1; } _scaledPosition.x = _position.x - (displaceX * scaleX).toInt(); _scaledPosition.y = _position.y - (celObj._displace.y * scaleY).toInt(); _screenItemRect.translate(_scaledPosition.x, _scaledPosition.y); if (_mirrorX != celObj._mirrorX && _celInfo.type == kCelTypePic) { Common::Rect temp(_insetRect); if (!scaleX.isOne()) { mulinc(temp, scaleX, Ratio()); temp.right -= 1; } CelObjPic *celObjPic = dynamic_cast<CelObjPic *>(_celObj); if (celObjPic == nullptr) { error("Expected a CelObjPic"); } temp.translate(celObjPic->_relativePosition.x - (displaceX * scaleX).toInt(), celObjPic->_relativePosition.y - (celObj._displace.y * scaleY).toInt()); // TODO: This is weird. int deltaX = plane._gameRect.width() - temp.right - 1 - temp.left; _scaledPosition.x += deltaX; _screenItemRect.translate(deltaX, 0); } _scaledPosition.x += plane._gameRect.left; _scaledPosition.y += plane._gameRect.top; _screenItemRect.translate(plane._gameRect.left, plane._gameRect.top); if (celObj._scaledWidth != screenWidth || celObj._scaledHeight != screenHeight) { mulru(_scaledPosition, celToScreenX, celToScreenY); mulru(_screenItemRect, celToScreenX, celToScreenY, 1); } _ratioX = scaleX * celToScreenX; _ratioY = scaleY * celToScreenY; } _screenRect = _screenItemRect; if (_screenRect.intersects(plane._screenRect)) { _screenRect.clip(plane._screenRect); } else { _screenRect.right = 0; _screenRect.bottom = 0; _screenRect.left = 0; _screenRect.top = 0; } if (!_fixedPriority) { _priority = _z + _position.y; } } else { _screenRect.left = 0; _screenRect.top = 0; _screenRect.right = 0; _screenRect.bottom = 0; } }
Common::Rect ScreenItem::getNowSeenRect(const Plane &plane) const { CelObj &celObj = getCelObj(); Common::Rect celObjRect(celObj._width, celObj._height); Common::Rect nsRect; if (_useInsetRect) { if (_insetRect.intersects(celObjRect)) { nsRect = _insetRect; nsRect.clip(celObjRect); } else { nsRect = Common::Rect(); } } else { nsRect = celObjRect; } const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; Ratio scaleX, scaleY; if (_scale.signal & kScaleSignalDoScaling32) { if (_scale.signal & kScaleSignalUseVanishingPoint) { int num = _scale.max * (_position.y - plane._vanishingPoint.y) / (scriptWidth - plane._vanishingPoint.y); scaleX = Ratio(num, 128); scaleY = Ratio(num, 128); } else { scaleX = Ratio(_scale.x, 128); scaleY = Ratio(_scale.y, 128); } } if (scaleX.getNumerator() == 0 || scaleY.getNumerator() == 0) { return Common::Rect(); } int16 displaceX = celObj._displace.x; int16 displaceY = celObj._displace.y; if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { displaceX = celObj._width - displaceX - 1; } if (celObj._scaledWidth != kLowResX || celObj._scaledHeight != kLowResY) { // high resolution coordinates if (_useInsetRect) { Ratio scriptToCelX(celObj._scaledWidth, scriptWidth); Ratio scriptToCelY(celObj._scaledHeight, scriptHeight); mulru(nsRect, scriptToCelX, scriptToCelY, 0); if (nsRect.intersects(celObjRect)) { nsRect.clip(celObjRect); } else { nsRect = Common::Rect(); } } if (!scaleX.isOne() || !scaleY.isOne()) { // Different games use a different cel scaling mode, but the // difference isn't consistent across SCI versions; instead, // it seems to be related to an update that happened during // SCI2.1mid where games started using hi-resolution game // scripts if (scriptWidth == kLowResX) { mulinc(nsRect, scaleX, scaleY); // TODO: This was in the original code, baked into the // multiplication though it is not immediately clear // why this is the only one that reduces the BR corner nsRect.right -= 1; nsRect.bottom -= 1; } else { nsRect.left = (nsRect.left * scaleX).toInt(); nsRect.top = (nsRect.top * scaleY).toInt(); if (scaleX.getNumerator() > scaleX.getDenominator()) { nsRect.right = (nsRect.right * scaleX).toInt(); } else { nsRect.right = ((nsRect.right - 1) * scaleX).toInt() + 1; } if (scaleY.getNumerator() > scaleY.getDenominator()) { nsRect.bottom = (nsRect.bottom * scaleY).toInt(); } else { nsRect.bottom = ((nsRect.bottom - 1) * scaleY).toInt() + 1; } } } Ratio celToScriptX(scriptWidth, celObj._scaledWidth); Ratio celToScriptY(scriptHeight, celObj._scaledHeight); displaceX = (displaceX * scaleX * celToScriptX).toInt(); displaceY = (displaceY * scaleY * celToScriptY).toInt(); mulinc(nsRect, celToScriptX, celToScriptY); nsRect.translate(_position.x - displaceX, _position.y - displaceY); } else { // low resolution coordinates if (!scaleX.isOne() || !scaleY.isOne()) { mulinc(nsRect, scaleX, scaleY); // TODO: This was in the original code, baked into the // multiplication though it is not immediately clear // why this is the only one that reduces the BR corner nsRect.right -= 1; nsRect.bottom -= 1; } displaceX = (displaceX * scaleX).toInt(); displaceY = (displaceY * scaleY).toInt(); nsRect.translate(_position.x - displaceX, _position.y - displaceY); if (_mirrorX != celObj._mirrorX && _celInfo.type != kCelTypePic) { nsRect.translate(plane._gameRect.width() - nsRect.width(), 0); } } return nsRect; }
SciEvent EventManager::getScummVMEvent() { #ifdef ENABLE_SCI32 SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point(), Common::Point() }; #else SciEvent input = { SCI_EVENT_NONE, 0, 0, Common::Point() }; SciEvent noEvent = { SCI_EVENT_NONE, 0, 0, Common::Point() }; #endif Common::EventManager *em = g_system->getEventManager(); Common::Event ev; bool found = em->pollEvent(ev); // Don't generate events for mouse movement while (found && ev.type == Common::EVENT_MOUSEMOVE) found = em->pollEvent(ev); // Save the mouse position // // We call getMousePos of the event manager here, since we also want to // store the mouse position in case of keyboard events, which do not feature // any mouse position information itself. // This should be safe, since the mouse position in the event manager should // only be updated when a mouse related event has been taken from the queue // via pollEvent. // We also adjust the position based on the scaling of the screen. Common::Point mousePos = em->getMousePos(); #if ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2) { Buffer &screen = g_sci->_gfxFrameout->getCurrentBuffer(); Common::Point mousePosSci = mousePos; mulru(mousePosSci, Ratio(screen.scriptWidth, screen.screenWidth), Ratio(screen.scriptHeight, screen.screenHeight)); noEvent.mousePosSci = input.mousePosSci = mousePosSci; } else { #endif g_sci->_gfxScreen->adjustBackUpscaledCoordinates(mousePos.y, mousePos.x); #if ENABLE_SCI32 } #endif noEvent.mousePos = input.mousePos = mousePos; if (!found || ev.type == Common::EVENT_MOUSEMOVE) { int modifiers = em->getModifierState(); noEvent.modifiers = ((modifiers & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) | ((modifiers & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) | ((modifiers & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0); return noEvent; } if (ev.type == Common::EVENT_QUIT) { input.type = SCI_EVENT_QUIT; return input; } int scummVMKeyFlags; switch (ev.type) { case Common::EVENT_KEYDOWN: case Common::EVENT_KEYUP: // Use keyboard modifiers directly in case this is a keyboard event scummVMKeyFlags = ev.kbd.flags; break; default: // Otherwise get them from EventManager scummVMKeyFlags = em->getModifierState(); break; } input.modifiers = ((scummVMKeyFlags & Common::KBD_ALT) ? SCI_KEYMOD_ALT : 0) | ((scummVMKeyFlags & Common::KBD_CTRL) ? SCI_KEYMOD_CTRL : 0) | ((scummVMKeyFlags & Common::KBD_SHIFT) ? SCI_KEYMOD_LSHIFT | SCI_KEYMOD_RSHIFT : 0); // Caps lock and Scroll lock have been removed, cause we already handle upper // case keys and Scroll lock doesn't seem to be used anywhere //((ourModifiers & Common::KBD_CAPS) ? SCI_KEYMOD_CAPSLOCK : 0) | //((ourModifiers & Common::KBD_SCRL) ? SCI_KEYMOD_SCRLOCK : 0) | // Handle mouse events for (int i = 0; i < ARRAYSIZE(mouseEventMappings); i++) { if (mouseEventMappings[i].commonType == ev.type) { input.type = mouseEventMappings[i].sciType; // Sierra passed keyboard modifiers for mouse events, too. // Sierra also set certain modifiers within their mouse interrupt handler // This whole thing was probably meant for people using a mouse, that only featured 1 button // So the user was able to press Ctrl and click the mouse button to create a right click. switch (ev.type) { case Common::EVENT_RBUTTONDOWN: // right button case Common::EVENT_RBUTTONUP: input.modifiers |= (SCI_KEYMOD_RSHIFT | SCI_KEYMOD_LSHIFT); // this value was hardcoded in the mouse interrupt handler break; case Common::EVENT_MBUTTONDOWN: // middle button case Common::EVENT_MBUTTONUP: input.modifiers |= SCI_KEYMOD_CTRL; // this value was hardcoded in the mouse interrupt handler break; default: break; } return input; } } // If we reached here, make sure that it's a keydown event if (ev.type != Common::EVENT_KEYDOWN) return noEvent; // Check for Control-Shift-D (debug console) if (ev.kbd.hasFlags(Common::KBD_CTRL | Common::KBD_SHIFT) && ev.kbd.keycode == Common::KEYCODE_d) { // Open debug console Console *con = g_sci->getSciDebugger(); con->attach(); return noEvent; } // Process keyboard events bool numlockOn = (ev.kbd.flags & Common::KBD_NUM); Common::KeyCode scummVMKeycode = ev.kbd.keycode; input.character = ev.kbd.ascii; input.type = SCI_EVENT_KEYBOARD; if (scummVMKeycode >= Common::KEYCODE_KP0 && scummVMKeycode <= Common::KEYCODE_KP9) { if (!(scummVMKeyFlags & Common::KBD_NUM)) { // HACK: Num-Lock not enabled // We shouldn't get a valid ascii code in these cases. We fix it here, so that cursor keys // on the numpad work properly. input.character = 0; } } if ((input.character) && (input.character <= 0xFF)) { // Directly accept most common keys without conversion if ((input.character >= 0x80) && (input.character <= 0xFF)) { // If there is no extended font, we will just clear the // current event. // Sierra SCI actually accepted those characters, but // didn't display them inside text edit controls because // the characters were missing inside the font(s). // We filter them out for non-multilingual games because // of that. if (!_fontIsExtended) return noEvent; // Convert 8859-1 characters to DOS (cp850/437) for // multilingual SCI01 games input.character = codePageMap88591ToDOS[input.character & 0x7f]; } if (scummVMKeycode == Common::KEYCODE_TAB) { input.character = SCI_KEY_TAB; if (scummVMKeyFlags & Common::KBD_SHIFT) input.character = SCI_KEY_SHIFT_TAB; } if (scummVMKeycode == Common::KEYCODE_DELETE) input.character = SCI_KEY_DELETE; } else if ((scummVMKeycode >= Common::KEYCODE_F1) && scummVMKeycode <= Common::KEYCODE_F10) { // SCI_K_F1 == 59 << 8 // SCI_K_SHIFT_F1 == 84 << 8 if (!(scummVMKeyFlags & Common::KBD_SHIFT)) input.character = SCI_KEY_F1 + ((scummVMKeycode - Common::KEYCODE_F1)<<8); else input.character = SCI_KEY_SHIFT_F1 + ((scummVMKeycode - Common::KEYCODE_F1)<<8); } else { // Special keys that need conversion for (int i = 0; i < ARRAYSIZE(keyMappings); i++) { if (keyMappings[i].scummVMKey == scummVMKeycode) { input.character = numlockOn ? keyMappings[i].sciKeyNumlockOn : keyMappings[i].sciKeyNumlockOff; break; } } } // When Ctrl AND Alt are pressed together with a regular key, Linux will give us control-key, Windows will give // us the actual key. My opinion is that windows is right, because under DOS the keys worked the same, anyway // we support the other case as well if ((scummVMKeyFlags & Common::KBD_ALT) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' // Scancodify if appropriate if (scummVMKeyFlags & Common::KBD_ALT) input.character = altify(input.character); if (getSciVersion() <= SCI_VERSION_1_MIDDLE && (scummVMKeyFlags & Common::KBD_CTRL) && input.character > 0 && input.character < 27) input.character += 96; // 0x01 -> 'a' #ifdef ENABLE_SCI32 if (getSciVersion() >= SCI_VERSION_2 && (scummVMKeyFlags & Common::KBD_CTRL) && input.character == 'c') { input.character = SCI_KEY_ETX; } #endif // If no actual key was pressed (e.g. if only a modifier key was pressed), // ignore the event if (!input.character) return noEvent; return input; }