aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics
diff options
context:
space:
mode:
authorColin Snover2016-02-14 12:07:30 -0600
committerColin Snover2016-02-18 13:18:02 -0600
commit20ccad80bfb689822be9f70512901557cbf244bf (patch)
tree40a0a63028a9355a1c58c3090c6c043af189e26c /engines/sci/graphics
parent3bddd869abbd6ba6dd88b0911f80aa305c8d464e (diff)
downloadscummvm-rg350-20ccad80bfb689822be9f70512901557cbf244bf.tar.gz
scummvm-rg350-20ccad80bfb689822be9f70512901557cbf244bf.tar.bz2
scummvm-rg350-20ccad80bfb689822be9f70512901557cbf244bf.zip
SCI: WIP GfxText32 code
This at least prevents SQ6 from crashing when going into the introduction
Diffstat (limited to 'engines/sci/graphics')
-rw-r--r--engines/sci/graphics/helpers.h11
-rw-r--r--engines/sci/graphics/text32.cpp248
-rw-r--r--engines/sci/graphics/text32.h137
3 files changed, 373 insertions, 23 deletions
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
@@ -128,6 +128,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);