reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, const bool gc) { _borderColor = borderColor; _text = text; _textRect = rect; _foreColor = foreColor; _dimmed = dimmed; setFont(fontId); int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; mulinc(_textRect, Ratio(_xResolution, scriptWidth), Ratio(_yResolution, scriptHeight)); CelObjView view(celInfo.resourceId, celInfo.loopNo, celInfo.celNo); _skipColor = view._skipColor; _width = view._width * _xResolution / view._xResolution; _height = view._height * _yResolution / view._yResolution; Common::Rect bitmapRect(_width, _height); if (_textRect.intersects(bitmapRect)) { _textRect.clip(bitmapRect); } else { _textRect = Common::Rect(); } SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _width, _height, _skipColor, 0, 0, _xResolution, _yResolution, 0, false, gc); // NOTE: The engine filled the bitmap pixels with 11 here, which is silly // because then it just erased the bitmap using the skip color. So we don't // fill the bitmap redundantly here. _backColor = _skipColor; erase(bitmapRect, false); _backColor = backColor; view.draw(bitmap.getBuffer(), bitmapRect, Common::Point(0, 0), false, Ratio(_xResolution, view._xResolution), Ratio(_yResolution, view._yResolution)); if (_backColor != skipColor && _foreColor != skipColor) { erase(_textRect, false); } if (text.size() > 0) { if (_foreColor == skipColor) { error("TODO: Implement transparent text"); } else { if (borderColor != -1) { drawFrame(bitmapRect, 1, _borderColor, false); } drawTextBox(); } } return _bitmap; }
reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling, reg_t *outBitmapObject) { _field_22 = 0; _borderColor = borderColor; _text = text; _textRect = rect; _width = width; _height = height; _foreColor = foreColor; _backColor = backColor; _skipColor = skipColor; _alignment = alignment; _dimmed = dimmed; setFont(fontId); if (doScaling) { int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; Ratio scaleX(_scaledWidth, scriptWidth); Ratio scaleY(_scaledHeight, scriptHeight); _width = (_width * scaleX).toInt(); _height = (_height * scaleY).toInt(); mulinc(_textRect, scaleX, scaleY); } // _textRect represents where text is drawn inside the // bitmap; clipRect is the entire bitmap Common::Rect bitmapRect(_width, _height); if (_textRect.intersects(bitmapRect)) { _textRect.clip(bitmapRect); } else { _textRect = Common::Rect(); } _bitmap = _segMan->allocateHunkEntry("FontBitmap()", _width * _height + BITMAP_HEADER_SIZE); byte *bitmap = _segMan->getHunkPointer(_bitmap); buildBitmapHeader(bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); erase(bitmapRect, false); if (_borderColor > -1) { drawFrame(bitmapRect, 1, _borderColor, false); } drawTextBox(); *outBitmapObject = _bitmap; return _bitmap; }
reg_t GfxText32::createFontBitmap(int16 width, int16 height, const Common::Rect &rect, const Common::String &text, const uint8 foreColor, const uint8 backColor, const uint8 skipColor, const GuiResourceId fontId, const TextAlign alignment, const int16 borderColor, const bool dimmed, const bool doScaling, const bool gc) { _borderColor = borderColor; _text = text; _textRect = rect; _width = width; _height = height; _foreColor = foreColor; _backColor = backColor; _skipColor = skipColor; _alignment = alignment; _dimmed = dimmed; setFont(fontId); if (doScaling) { int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; Ratio scaleX(_xResolution, scriptWidth); Ratio scaleY(_yResolution, scriptHeight); _width = (_width * scaleX).toInt(); _height = (_height * scaleY).toInt(); mulinc(_textRect, scaleX, scaleY); } // _textRect represents where text is drawn inside the // bitmap; clipRect is the entire bitmap Common::Rect bitmapRect(_width, _height); if (_textRect.intersects(bitmapRect)) { _textRect.clip(bitmapRect); } else { _textRect = Common::Rect(); } _segMan->allocateBitmap(&_bitmap, _width, _height, _skipColor, 0, 0, _xResolution, _yResolution, 0, false, gc); erase(bitmapRect, false); if (_borderColor > -1) { drawFrame(bitmapRect, 1, _borderColor, false); } drawTextBox(); return _bitmap; }
ScrollWindow::ScrollWindow(SegManager *segMan, const Common::Rect &gameRect, const Common::Point &position, const reg_t plane, const uint8 defaultForeColor, const uint8 defaultBackColor, const GuiResourceId defaultFontId, const TextAlign defaultAlignment, const int16 defaultBorderColor, const uint16 maxNumEntries) : _segMan(segMan), _gfxText32(segMan, g_sci->_gfxCache), _maxNumEntries(maxNumEntries), _firstVisibleChar(0), _topVisibleLine(0), _lastVisibleChar(0), _bottomVisibleLine(0), _numLines(0), _numVisibleLines(0), _plane(plane), _foreColor(defaultForeColor), _backColor(defaultBackColor), _borderColor(defaultBorderColor), _fontId(defaultFontId), _alignment(defaultAlignment), _visible(false), _position(position), _screenItem(nullptr), _nextEntryId(1) { _entries.reserve(maxNumEntries); _gfxText32.setFont(_fontId); _pointSize = _gfxText32._font->getHeight(); const uint16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const uint16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; Common::Rect bitmapRect(gameRect); mulinc(bitmapRect, Ratio(_gfxText32._scaledWidth, scriptWidth), Ratio(_gfxText32._scaledHeight, scriptHeight)); _textRect.left = 2; _textRect.top = 2; _textRect.right = bitmapRect.width() - 2; _textRect.bottom = bitmapRect.height() - 2; uint8 skipColor = 0; while (skipColor == _foreColor || skipColor == _backColor) { skipColor++; } assert(bitmapRect.width() > 0 && bitmapRect.height() > 0); _bitmap = _gfxText32.createFontBitmap(bitmapRect.width(), bitmapRect.height(), _textRect, "", _foreColor, _backColor, skipColor, _fontId, _alignment, _borderColor, false, false, false); debugC(1, kDebugLevelGraphics, "New ScrollWindow: textRect size: %d x %d, bitmap: %04x:%04x", _textRect.width(), _textRect.height(), PRINT_REG(_bitmap)); }
int16 GfxText32::getTextCount(const Common::String &text, const uint index, const Common::Rect &textRect, const bool doScaling) { const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; Common::Rect scaledRect(textRect); if (doScaling) { mulinc(scaledRect, Ratio(_xResolution, scriptWidth), Ratio(_yResolution, scriptHeight)); } Common::String oldText = _text; _text = text; uint charIndex = index; int16 maxWidth = scaledRect.width(); int16 lineCount = (scaledRect.height() - 2) / _font->getHeight(); while (lineCount--) { getLongest(&charIndex, maxWidth); } _text = oldText; return charIndex - index; }
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; }
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; } }
reg_t GfxText32::createFontBitmap(const CelInfo32 &celInfo, const Common::Rect &rect, const Common::String &text, const int16 foreColor, const int16 backColor, const GuiResourceId fontId, const int16 skipColor, const int16 borderColor, const bool dimmed, reg_t *outBitmapObject) { _field_22 = 0; _borderColor = borderColor; _text = text; _textRect = rect; _foreColor = foreColor; _dimmed = dimmed; setFont(fontId); int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; int borderSize = 1; mulinc(_textRect, Ratio(_scaledWidth, scriptWidth), Ratio(_scaledHeight, scriptHeight)); CelObjView view(celInfo.resourceId, celInfo.loopNo, celInfo.celNo); _skipColor = view._transparentColor; _width = view._width * _scaledWidth / view._scaledWidth; _height = view._height * _scaledHeight / view._scaledHeight; Common::Rect bitmapRect(_width, _height); if (_textRect.intersects(bitmapRect)) { _textRect.clip(bitmapRect); } else { _textRect = Common::Rect(); } _bitmap = _segMan->allocateHunkEntry("FontBitmap()", _width * _height + CelObjMem::getBitmapHeaderSize()); byte *bitmap = _segMan->getHunkPointer(_bitmap); CelObjMem::buildBitmapHeader(bitmap, _width, _height, _skipColor, 0, 0, _scaledWidth, _scaledHeight, 0, false); Buffer buffer(_width, _height, bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28)); // NOTE: The engine filled the bitmap pixels with 11 here, which is silly // because then it just erased the bitmap using the skip color. So we don't // fill the bitmap redundantly here. _backColor = _skipColor; erase(bitmapRect, false); _backColor = backColor; view.draw(buffer, bitmapRect, Common::Point(0, 0), false, Ratio(_scaledWidth, view._scaledWidth), Ratio(_scaledHeight, view._scaledHeight)); if (_backColor != skipColor && _foreColor != skipColor) { erase(_textRect, false); } if (text.size() > 0) { if (_foreColor == skipColor) { error("TODO: Implement transparent text"); } else { if (borderColor != -1) { drawFrame(bitmapRect, borderSize, _borderColor, false); } drawTextBox(); } } *outBitmapObject = _bitmap; return _bitmap; }