From 20ccad80bfb689822be9f70512901557cbf244bf Mon Sep 17 00:00:00 2001 From: Colin Snover Date: Sun, 14 Feb 2016 12:07:30 -0600 Subject: SCI: WIP GfxText32 code This at least prevents SQ6 from crashing when going into the introduction --- engines/sci/engine/kernel_tables.h | 2 +- engines/sci/engine/kgraphics32.cpp | 118 ++++++++++-------- engines/sci/engine/selector.cpp | 5 + engines/sci/engine/selector.h | 2 + engines/sci/graphics/helpers.h | 11 ++ engines/sci/graphics/text32.cpp | 248 +++++++++++++++++++++++++++++++++---- engines/sci/graphics/text32.h | 137 +++++++++++++++++++- engines/sci/sci.cpp | 4 +- engines/sci/util.cpp | 9 ++ engines/sci/util.h | 3 + 10 files changed, 460 insertions(+), 79 deletions(-) (limited to 'engines') diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index ad0b86b8b1..b4a092a25c 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -670,7 +670,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(CelInfo), SIG_EVERYWHERE, "iiiiii", NULL, NULL }, { MAP_CALL(SetLanguage), SIG_EVERYWHERE, "r", NULL, NULL }, { MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "i(.*)", kScrollWindow_subops, NULL }, - { MAP_CALL(SetFontRes), SIG_EVERYWHERE, "ii", NULL, NULL }, + { MAP_DUMMY(SetFontRes), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Font), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, { MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(AddLine), SIG_EVERYWHERE, "oiiiiiiiii", NULL, NULL }, diff --git a/engines/sci/engine/kgraphics32.cpp b/engines/sci/engine/kgraphics32.cpp index 64ef7ca610..a83836b033 100644 --- a/engines/sci/engine/kgraphics32.cpp +++ b/engines/sci/engine/kgraphics32.cpp @@ -174,41 +174,53 @@ reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { } reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { - switch (argv[0].toUint16()) { - case 0: { - if (argc != 4) { - warning("kCreateTextBitmap(0): expected 4 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[3]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 0 (%04x:%04x, %04x:%04x, %04x:%04x)", - PRINT_REG(argv[1]), PRINT_REG(argv[2]), PRINT_REG(argv[3])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - int16 maxWidth = argv[1].toUint16(); - int16 maxHeight = argv[2].toUint16(); - g_sci->_gfxCoordAdjuster->fromScriptToDisplay(maxHeight, maxWidth); - // These values can be larger than the screen in the SQ6 demo, room 100 - // TODO: Find out why. For now, don't show any text in that room. - if (g_sci->getGameId() == GID_SQ6 && g_sci->isDemo() && s->currentRoomNumber() == 100) - return NULL_REG; - return g_sci->_gfxText32->createTextBitmap(object, maxWidth, maxHeight); - } - case 1: { - if (argc != 2) { - warning("kCreateTextBitmap(1): expected 2 arguments, got %i", argc); - return NULL_REG; - } - reg_t object = argv[1]; - Common::String text = s->_segMan->getString(readSelector(s->_segMan, object, SELECTOR(text))); - debugC(kDebugLevelStrings, "kCreateTextBitmap case 1 (%04x:%04x)", PRINT_REG(argv[1])); - debugC(kDebugLevelStrings, "%s", text.c_str()); - return g_sci->_gfxText32->createTextBitmap(object); - } - default: - warning("CreateTextBitmap(%d)", argv[0].toUint16()); + SegManager *segMan = s->_segMan; + + int16 subop = argv[0].toUint16(); + + int16 width; + int16 height; + reg_t object; + + if (subop == 0) { + width = argv[1].toUint16(); + height = argv[2].toUint16(); + object = argv[3]; + } else if (subop == 1) { + object = argv[1]; + } else { + warning("Invalid kCreateTextBitmap subop %d", subop); return NULL_REG; } + + Common::String text = segMan->getString(readSelector(segMan, object, SELECTOR(text))); + int16 foreColor = readSelectorValue(segMan, object, SELECTOR(fore)); + int16 backColor = readSelectorValue(segMan, object, SELECTOR(back)); + int16 skipColor = readSelectorValue(segMan, object, SELECTOR(skip)); + GuiResourceId fontId = (GuiResourceId)readSelectorValue(segMan, object, SELECTOR(font)); + int16 borderColor = readSelectorValue(segMan, object, SELECTOR(borderColor)); + int16 dimmed = readSelectorValue(segMan, object, SELECTOR(dimmed)); + + Common::Rect rect( + readSelectorValue(segMan, object, SELECTOR(textLeft)), + readSelectorValue(segMan, object, SELECTOR(textTop)), + readSelectorValue(segMan, object, SELECTOR(textRight)), + readSelectorValue(segMan, object, SELECTOR(textBottom)) + ); + + if (subop == 0) { + TextAlign alignment = (TextAlign)readSelectorValue(segMan, object, SELECTOR(mode)); + reg_t out; + return g_sci->_gfxText32->createFontBitmap(width, height, rect, text, foreColor, backColor, skipColor, fontId, alignment, borderColor, dimmed, 1, &out); + } else { + CelInfo32 celInfo; + celInfo.type = kCelTypeView; + celInfo.resourceId = readSelectorValue(segMan, object, SELECTOR(view)); + celInfo.loopNo = readSelectorValue(segMan, object, SELECTOR(loop)); + celInfo.celNo = readSelectorValue(segMan, object, SELECTOR(cel)); + reg_t out; + return g_sci->_gfxText32->createTitledFontBitmap(celInfo, rect, text, foreColor, backColor, fontId, skipColor, borderColor, dimmed, &out); + } } reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) { @@ -455,34 +467,26 @@ reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) { } #endif -reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { - // TODO: This defines the resolution that the fonts are supposed to be displayed - // in. Currently, this is only used for showing high-res fonts in GK1 Mac, but - // should be extended to handle other font resolutions such as those - - int xResolution = argv[0].toUint16(); - //int yResolution = argv[1].toUint16(); - - g_sci->_gfxScreen->setFontIsUpscaled(xResolution == 640 && - g_sci->_gfxScreen->getUpscaledHires() != GFX_SCREEN_UPSCALED_DISABLED); - - return s->r_acc; -} - reg_t kFont(EngineState *s, int argc, reg_t *argv) { - // Handle font settings for SCI2.1 + // TODO: Handle font settings for SCI2.1 switch (argv[0].toUint16()) { case 1: - // Set font resolution - return kSetFontRes(s, argc - 1, argv + 1); + g_sci->_gfxText32->_scaledWidth = argv[1].toUint16(); + g_sci->_gfxText32->_scaledHeight = argv[2].toUint16(); + return NULL_REG; default: - warning("kFont: unknown subop %d", argv[0].toUint16()); + error("kFont: unknown subop %d", argv[0].toUint16()); } return s->r_acc; } +// TODO: Is this actually a thing?? +reg_t kSetFontRes(EngineState *s, int argc, reg_t *argv) { + return kStub(s, argc, argv); +} + // TODO: Eventually, all of the kBitmap operations should be put // in a separate class @@ -516,8 +520,16 @@ reg_t kBitmap(EngineState *s, int argc, reg_t *argv) { memset(memoryPtr + BITMAP_HEADER_SIZE, back, width * height); // Save totalWidth, totalHeight // TODO: Save the whole bitmap header, like SSCI does - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); + WRITE_SCI11ENDIAN_UINT16(memoryPtr, width); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 2, height); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 4, 0); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 6, 0); + memoryPtr[8] = 0; + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 10, 0); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 20, BITMAP_HEADER_SIZE); + WRITE_SCI11ENDIAN_UINT32(memoryPtr + 28, 46); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 36, width); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 38, width); return memoryId; } break; diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp index 05a9e6c980..b86e0ffd68 100644 --- a/engines/sci/engine/selector.cpp +++ b/engines/sci/engine/selector.cpp @@ -179,6 +179,7 @@ void Kernel::mapSelectors() { FIND_SELECTOR(fore); FIND_SELECTOR(back); FIND_SELECTOR(skip); + FIND_SELECTOR(borderColor); FIND_SELECTOR(fixPriority); FIND_SELECTOR(mirrored); FIND_SELECTOR(visible); @@ -187,6 +188,10 @@ void Kernel::mapSelectors() { FIND_SELECTOR(inLeft); FIND_SELECTOR(inBottom); FIND_SELECTOR(inRight); + FIND_SELECTOR(textTop); + FIND_SELECTOR(textLeft); + FIND_SELECTOR(textBottom); + FIND_SELECTOR(textRight); FIND_SELECTOR(magnifier); #endif } diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h index a8b195f245..6b724ed271 100644 --- a/engines/sci/engine/selector.h +++ b/engines/sci/engine/selector.h @@ -146,6 +146,7 @@ struct SelectorCache { Selector back; Selector skip; Selector dimmed; + Selector borderColor; Selector fixPriority; Selector mirrored; @@ -153,6 +154,7 @@ struct SelectorCache { Selector useInsetRect; Selector inTop, inLeft, inBottom, inRight; + Selector textTop, textLeft, textBottom, textRight; Selector magnifier; #endif diff --git a/engines/sci/graphics/helpers.h b/engines/sci/graphics/helpers.h index e2fdedb27a..c238e2c87b 100644 --- a/engines/sci/graphics/helpers.h +++ b/engines/sci/graphics/helpers.h @@ -127,6 +127,17 @@ struct Window : public Port, public Common::Serializable { }; #ifdef ENABLE_SCI32 +/** + * Multiplies a rectangle by two ratios with default + * rounding. Modifies the rect directly. + */ +inline void mul(Common::Rect &rect, const Common::Rational &ratioX, const Common::Rational &ratioY) { + rect.left = (rect.left * ratioX).toInt(); + rect.top = (rect.top * ratioY).toInt(); + rect.right = (rect.right * ratioX).toInt(); + rect.bottom = (rect.bottom * ratioY).toInt(); +} + /** * Multiplies a number by a rational number, rounding up to * the nearest whole number. diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 56ce73e8fa..e0fb56b74b 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -31,6 +31,7 @@ #include "sci/graphics/cache.h" #include "sci/graphics/compare.h" #include "sci/graphics/font.h" +#include "sci/graphics/frameout.h" #include "sci/graphics/screen.h" #include "sci/graphics/text32.h" @@ -38,20 +39,220 @@ namespace Sci { #define BITMAP_HEADER_SIZE 46 -#define SCI_TEXT32_ALIGNMENT_RIGHT -1 -#define SCI_TEXT32_ALIGNMENT_CENTER 1 -#define SCI_TEXT32_ALIGNMENT_LEFT 0 +GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) : + _segMan(segMan), + _cache(fonts), + _screen(screen), + _scaledWidth(g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth), + _scaledHeight(g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight), + _bitmap(NULL_REG) {} + +void GfxText32::buildBitmapHeader(byte *bitmap, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool useRemap) const { + + WRITE_SCI11ENDIAN_UINT16(bitmap + 0, width); + WRITE_SCI11ENDIAN_UINT16(bitmap + 2, height); + WRITE_SCI11ENDIAN_UINT16(bitmap + 4, (uint16)displaceX); + WRITE_SCI11ENDIAN_UINT16(bitmap + 6, (uint16)displaceY); + bitmap[8] = skipColor; + bitmap[9] = 0; + WRITE_SCI11ENDIAN_UINT16(bitmap + 10, 0); + + if (useRemap) { + bitmap[10] |= 2; + } + + WRITE_SCI11ENDIAN_UINT32(bitmap + 12, width * height); + WRITE_SCI11ENDIAN_UINT32(bitmap + 16, 0); + + if (hunkPaletteOffset) { + WRITE_SCI11ENDIAN_UINT32(bitmap + 20, hunkPaletteOffset + BITMAP_HEADER_SIZE); + } else { + WRITE_SCI11ENDIAN_UINT32(bitmap + 20, 0); + } + + WRITE_SCI11ENDIAN_UINT32(bitmap + 24, BITMAP_HEADER_SIZE); + WRITE_SCI11ENDIAN_UINT32(bitmap + 28, BITMAP_HEADER_SIZE); + WRITE_SCI11ENDIAN_UINT32(bitmap + 32, 0); + WRITE_SCI11ENDIAN_UINT16(bitmap + 36, scaledWidth); + WRITE_SCI11ENDIAN_UINT16(bitmap + 38, scaledHeight); +} + +int16 GfxText32::_defaultFontId = 0; + +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; + + if (fontId != _fontId) { + _fontId = fontId == -1 ? _defaultFontId : fontId; + _font = _cache->getFont(_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(); + mul(_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(); + + debug("Drawing a bitmap %dx%d, scaled %dx%d, border %d, font %d", width, height, _width, _height, _borderColor, _fontId); -GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) - : _segMan(segMan), _cache(fonts), _screen(screen) { + *outBitmapObject = _bitmap; + return _bitmap; } -GfxText32::~GfxText32() { +reg_t GfxText32::createTitledFontBitmap(CelInfo32 &celInfo, Common::Rect &rect, Common::String &text, int16 foreColor, int16 backColor, int font, int16 skipColor, int16 borderColor, bool dimmed, void *unknown1) { + warning("TODO: createTitledFontBitmap"); + return NULL_REG; +} + +void GfxText32::drawFrame(const Common::Rect &rect, const int size, const uint8 color, const bool doScaling) { + Common::Rect targetRect = doScaling ? scaleRect(rect) : rect; + + byte *bitmap = _segMan->getHunkPointer(_bitmap); + byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); + + // NOTE: Not fully disassembled, but this should be right + // TODO: Implement variable frame size + assert(size == 1); + Buffer buffer(_width, _height, pixels); + buffer.frameRect(targetRect, color); +} + +// TODO: This is not disassembled +void GfxText32::drawTextBox() { + int16 charCount = 0; + uint16 curX = 0, curY = 0; + const char *txt = _text.c_str(); + int16 textWidth, textHeight, totalHeight = 0, offsetX = 0, offsetY = 0; + uint16 start = 0; + + // Calculate total text height + while (*txt) { + charCount = GetLongest(txt, _textRect.width(), _font); + if (charCount == 0) + break; + + Width(txt, 0, (int16)strlen(txt), _fontId, textWidth, textHeight, true); + + totalHeight += textHeight; + txt += charCount; + while (*txt == ' ') { + txt++; // skip over breaking spaces + } + } + + txt = _text.c_str(); + + byte *pixels = _segMan->getHunkPointer(_bitmap); + pixels = pixels + READ_SCI11ENDIAN_UINT32(pixels + 28) + _width * _textRect.top + _textRect.left; + + // Draw text in buffer + while (*txt) { + charCount = GetLongest(txt, _textRect.width(), _font); + if (charCount == 0) + break; + Width(txt, start, charCount, _fontId, textWidth, textHeight, true); + + switch (_alignment) { + case kTextAlignRight: + offsetX = _textRect.width() - textWidth; + break; + case kTextAlignCenter: + // Center text both horizontally and vertically + offsetX = (_textRect.width() - textWidth) / 2; + offsetY = (_textRect.height() - totalHeight) / 2; + break; + case kTextAlignLeft: + offsetX = 0; + break; + + default: + warning("Invalid alignment %d used in TextBox()", _alignment); + } + + byte curChar; + + for (int i = 0; i < charCount; i++) { + curChar = txt[i]; + + switch (curChar) { + case 0x0A: + case 0x0D: + case 0: + break; + case 0x7C: + warning("Code processing isn't implemented in SCI32"); + break; + default: + _font->drawToBuffer(curChar, curY + offsetY, curX + offsetX, _foreColor, _dimmed, pixels, _width, _height); + curX += _font->getCharWidth(curChar); + break; + } + } + + curX = 0; + curY += _font->getHeight(); + txt += charCount; + while (*txt == ' ') { + txt++; // skip over breaking spaces + } + } +} + +void GfxText32::erase(const Common::Rect &rect, const bool doScaling) { + Common::Rect targetRect = doScaling ? rect : scaleRect(rect); + + byte *bitmap = _segMan->getHunkPointer(_bitmap); + byte *pixels = bitmap + READ_SCI11ENDIAN_UINT32(bitmap + 28); + + // NOTE: There is an extra optimisation within the SCI code to + // do a single memset if the scaledRect is the same size as + // the bitmap, not implemented here. + Buffer buffer(_width, _height, pixels); + buffer.fillRect(targetRect, _backColor); } reg_t GfxText32::createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk); - } reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) { reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); @@ -116,8 +317,16 @@ reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject memset(bitmap, backColor, width * height); // Save totalWidth, totalHeight - WRITE_LE_UINT16(memoryPtr, width); - WRITE_LE_UINT16(memoryPtr + 2, height); + WRITE_SCI11ENDIAN_UINT16(memoryPtr, width); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 2, height); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 4, 0); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 6, 0); + memoryPtr[8] = 0; + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 10, 0); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 20, BITMAP_HEADER_SIZE); + WRITE_SCI11ENDIAN_UINT32(memoryPtr + 28, 46); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 36, width); + WRITE_SCI11ENDIAN_UINT16(memoryPtr + 38, height); int16 charCount = 0; uint16 curX = 0, curY = 0; @@ -149,15 +358,15 @@ reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject Width(txt, start, charCount, fontId, textWidth, textHeight, true); switch (alignment) { - case SCI_TEXT32_ALIGNMENT_RIGHT: + case kTextAlignRight: offsetX = width - textWidth; break; - case SCI_TEXT32_ALIGNMENT_CENTER: + case kTextAlignCenter: // Center text both horizontally and vertically offsetX = (width - textWidth) / 2; offsetY = (height - totalHeight) / 2; break; - case SCI_TEXT32_ALIGNMENT_LEFT: + case kTextAlignLeft: offsetX = 0; break; @@ -347,9 +556,10 @@ int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId int16 maxTextWidth = 0, textWidth; int16 totalHeight = 0, textHeight; - // Adjust maxWidth if we're using an upscaled font - if (_screen->fontIsUpscaled()) - maxWidth = maxWidth * _screen->getDisplayWidth() / _screen->getWidth(); + int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + + maxWidth = maxWidth * _scaledWidth / scriptWidth; rect.top = rect.left = 0; GfxFont *font = _cache->getFont(fontId); @@ -378,12 +588,8 @@ int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); } - // Adjust the width/height if we're using an upscaled font - // for the scripts - if (_screen->fontIsUpscaled()) { - rect.right = rect.right * _screen->getWidth() / _screen->getDisplayWidth(); - rect.bottom = rect.bottom * _screen->getHeight() / _screen->getDisplayHeight(); - } + rect.right = rect.right * scriptWidth / _scaledWidth; + rect.bottom = rect.bottom * scriptHeight / _scaledHeight; return rect.right; } diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h index 7ba7df50e4..42804f5670 100644 --- a/engines/sci/graphics/text32.h +++ b/engines/sci/graphics/text32.h @@ -23,15 +23,148 @@ #ifndef SCI_GRAPHICS_TEXT32_H #define SCI_GRAPHICS_TEXT32_H +#include "sci/graphics/celobj32.h" +#include "sci/graphics/frameout.h" + namespace Sci { +enum TextAlign { + kTextAlignLeft = 0, + kTextAlignCenter = 1, + kTextAlignRight = -1 +}; + /** - * Text32 class, handles text calculation and displaying of text for SCI2, SCI21 and SCI3 games + * This class handles text calculation and rendering for + * SCI32 games. The text calculation system in SCI32 is + * nearly the same as SCI16, which means this class behaves + * similarly. Notably, GfxText32 maintains drawing + * parameters across multiple calls. */ class GfxText32 { +private: + /** + * The resource ID of the default font used by the game. + * + * @todo Check all SCI32 games to learn what their + * default font is. + */ + static int16 _defaultFontId; + + /** + * The width and height of the currently active text + * bitmap, in text-system coordinates. + */ + int16 _width, _height; + + /** + * The colour used to draw text. + */ + uint8 _foreColor; + + /** + * The background colour of the text box. + */ + uint8 _backColor; + + /** + * The transparent colour of the text box. Used when + * compositing the bitmap onto the screen. + */ + uint8 _skipColor; + + /** + * The rect where the text is drawn within the bitmap. + * This rect is clipped to the dimensions of the bitmap. + */ + Common::Rect _textRect; + + /** + * The text being drawn to the currently active text + * bitmap. + */ + Common::String _text; + + /** + * The font being used to draw the text. + */ + GuiResourceId _fontId; + + /** + * The colour of the text box border. + */ + int16 _borderColor; + + /** + * TODO: Document + */ + bool _dimmed; + + /** + * The text alignment for the drawn text. + */ + TextAlign _alignment; + + /** + * The memory handle of the currently active bitmap. + */ + reg_t _bitmap; + + /** + * TODO: Document + */ + int _field_22; + + /** + * The currently active font resource used to write text + * into the bitmap. + * + * @note SCI engine builds the font table directly + * inside of FontMgr; we use GfxFont instead. + */ + GfxFont *_font; + + // TODO: This is general for all CelObjMem and should be + // put in a single location, like maybe as a static + // method of CelObjMem?! + void buildBitmapHeader(byte *bitmap, const int16 width, const int16 height, const uint8 skipColor, const int16 displaceX, const int16 displaceY, const int16 scaledWidth, const int16 scaledHeight, const uint32 hunkPaletteOffset, const bool useRemap) const; + + void drawFrame(const Common::Rect &rect, const int size, const uint8 color, const bool doScaling); + void drawTextBox(); + void erase(const Common::Rect &rect, const bool doScaling); + + inline Common::Rect scaleRect(const Common::Rect &rect) { + Common::Rect scaledRect(rect); + int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; + int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; + Ratio scaleX(_scaledWidth, scriptWidth); + Ratio scaleY(_scaledHeight, scriptHeight); + mul(scaledRect, scaleX, scaleY); + return scaledRect; + } + public: GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen); - ~GfxText32(); + + /** + * The size of the x-dimension of the coordinate system + * used by the text renderer. + */ + int16 _scaledWidth; + + /** + * The size of the y-dimension of the coordinate system + * used by the text renderer. + */ + int16 _scaledHeight; + + reg_t 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, TextAlign alignment, const int16 borderColor, bool dimmed, const bool doScaling, reg_t *outBitmapObject); + + reg_t createTitledFontBitmap(CelInfo32 &celInfo, Common::Rect &rect, Common::String &text, int16 foreColor, int16 backColor, int font, int16 skipColor, int16 borderColor, bool dimmed, void *unknown1); + +#pragma mark - +#pragma mark Old stuff + reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); reg_t createScrollTextBitmap(Common::String text, reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG); void drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject); diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 9ef28b214b..49eb31de53 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -690,10 +690,10 @@ void SciEngine::initGraphics() { _gfxCompare = new GfxCompare(_gamestate->_segMan, _gfxCache, _gfxScreen, _gfxCoordAdjuster); _gfxPaint32 = new GfxPaint32(_resMan, _gfxCoordAdjuster, _gfxScreen, _gfxPalette32); _gfxPaint = _gfxPaint32; - _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); - _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); _robotDecoder = new RobotDecoder(getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette32, _gfxPaint32); + _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); + _gfxControls32 = new GfxControls32(_gamestate->_segMan, _gfxCache, _gfxText32); _gfxFrameout->run(); } else { #endif diff --git a/engines/sci/util.cpp b/engines/sci/util.cpp index c72d3beb19..ccec41a1ab 100644 --- a/engines/sci/util.cpp +++ b/engines/sci/util.cpp @@ -69,4 +69,13 @@ void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val) { WRITE_LE_UINT16(ptr, val); } +#ifdef ENABLE_SCI32 +void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val) { + if (g_sci->getPlatform() == Common::kPlatformMacintosh && getSciVersion() >= SCI_VERSION_1_1) + WRITE_BE_UINT32(ptr, val); + else + WRITE_LE_UINT32(ptr, val); +} +#endif + } // End of namespace Sci diff --git a/engines/sci/util.h b/engines/sci/util.h index 378030939c..b0fee5151e 100644 --- a/engines/sci/util.h +++ b/engines/sci/util.h @@ -37,6 +37,9 @@ void WRITE_SCIENDIAN_UINT16(void *ptr, uint16 val); uint16 READ_SCI11ENDIAN_UINT16(const void *ptr); uint32 READ_SCI11ENDIAN_UINT32(const void *ptr); void WRITE_SCI11ENDIAN_UINT16(void *ptr, uint16 val); +#ifdef ENABLE_SCI32 +void WRITE_SCI11ENDIAN_UINT32(void *ptr, uint32 val); +#endif // Wrappers for reading integer values in resources that are // LE in SCI1.1 Mac, but BE in SCI32 Mac -- cgit v1.2.3