diff options
Diffstat (limited to 'engines/sci/graphics/text32.cpp')
-rw-r--r-- | engines/sci/graphics/text32.cpp | 267 |
1 files changed, 158 insertions, 109 deletions
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp index 21372f1502..49e6fe01b8 100644 --- a/engines/sci/graphics/text32.cpp +++ b/engines/sci/graphics/text32.cpp @@ -38,163 +38,139 @@ namespace Sci { +#define BITMAP_HEADER_SIZE 46 + GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen) : _segMan(segMan), _cache(fonts), _screen(screen) { } GfxText32::~GfxText32() { - purgeCache(); -} - -void GfxText32::purgeCache() { - for (TextCache::iterator cacheIterator = _textCache.begin(); cacheIterator != _textCache.end(); cacheIterator++) { - delete[] cacheIterator->_value->surface; - delete cacheIterator->_value; - cacheIterator->_value = 0; - } - - _textCache.clear(); } -void GfxText32::createTextBitmap(reg_t textObject) { - if (_textCache.size() >= MAX_CACHED_TEXTS) - purgeCache(); +reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight) { + reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); - uint32 textId = (textObject.segment << 16) | textObject.offset; + // The object in the text selector of the item can be either a raw string + // or a Str object. In the latter case, we need to access the object's data + // selector to get the raw string. + if (_segMan->isHeapObject(stringObject)) + stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); - if (_textCache.contains(textId)) { - // Delete the old entry - TextEntry *oldEntry = _textCache[textId]; - delete[] oldEntry->surface; - delete oldEntry; - _textCache.erase(textId); - } + Common::String text = _segMan->getString(stringObject); + GfxFont *font = _cache->getFont(readSelectorValue(_segMan, textObject, SELECTOR(font))); + bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed)); + uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); - _textCache[textId] = createTextEntry(textObject); -} + Common::Rect planeRect = getPlaneRect(textObject); + uint16 width = planeRect.width(); + uint16 height = planeRect.height(); -// TODO: Finish this! -void GfxText32::drawTextBitmap(reg_t textObject, uint16 textX, uint16 textY, uint16 w) { - uint32 textId = (textObject.segment << 16) | textObject.offset; + // Limit rectangle dimensions, if requested + if (maxWidth > 0) + width = maxWidth; + if (maxHeight > 0) + height = maxHeight; - if (!_textCache.contains(textId)) - createTextBitmap(textObject); + // Upscale the coordinates/width if the fonts are already upscaled + if (_screen->fontIsUpscaled()) { + width = width * _screen->getDisplayWidth() / _screen->getWidth(); + height = height * _screen->getDisplayHeight() / _screen->getHeight(); + } - TextEntry *entry = _textCache[textId]; + int entrySize = width * height + BITMAP_HEADER_SIZE; + reg_t memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize); + writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId); + byte *memoryPtr = _segMan->getHunkPointer(memoryId); + memset(memoryPtr, 0, entrySize); + byte *bitmap = memoryPtr + BITMAP_HEADER_SIZE; - // This draws text the "SCI0-SCI11" way. In SCI2, text is prerendered in kCreateTextBitmap - // TODO: rewrite this the "SCI2" way (i.e. implement the text buffer to draw inside kCreateTextBitmap) - GfxFont *font = _cache->getFont(readSelectorValue(_segMan, textObject, SELECTOR(font))); - bool dimmed = readSelectorValue(_segMan,textObject, SELECTOR(dimmed)); - uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); - - const char *txt = entry->text.c_str(); - int16 charCount; + int16 charCount = 0; + uint16 curX = 0, curY = 0; + const char *txt = text.c_str(); while (*txt) { - charCount = GetLongest(txt, w, font); + charCount = GetLongest(txt, width, font); if (charCount == 0) break; - uint16 curX = textX; - for (int i = 0; i < charCount; i++) { unsigned char curChar = txt[i]; - font->draw(curChar, textY, curX, foreColor, dimmed); + font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, bitmap, width, height); curX += font->getCharWidth(curChar); } - textY += font->getHeight(); + curX = 0; + curY += font->getHeight(); txt += charCount; while (*txt == ' ') txt++; // skip over breaking spaces } - // TODO: The "SCI2" way of font drawing. Currently buggy - /* - for (int x = textX; x < entry->width; x++) { - for (int y = textY; y < entry->height; y++) { - byte pixel = entry->surface[y * entry->width + x]; - if (pixel) - _screen->putPixel(x, y, 1, pixel, 0, 0); - } - } - */ + return memoryId; } -TextEntry *GfxText32::getTextEntry(reg_t textObject) { - uint32 textId = (textObject.segment << 16) | textObject.offset; - - if (!_textCache.contains(textId)) - createTextBitmap(textObject); - - return _textCache[textId]; +void GfxText32::disposeTextBitmap(reg_t hunkId) { + _segMan->freeHunkEntry(hunkId); } -// TODO: Finish this! Currently buggy. -TextEntry *GfxText32::createTextEntry(reg_t textObject) { - reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); +void GfxText32::drawTextBitmap(reg_t textObject) { + reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap)); + byte *memoryPtr = _segMan->getHunkPointer(hunkId); - // The object in the text selector of the item can be either a raw string - // or a Str object. In the latter case, we need to access the object's data - // selector to get the raw string. - if (_segMan->isHeapObject(stringObject)) - stringObject = readSelector(_segMan, stringObject, SELECTOR(data)); + if (!memoryPtr) + error("Attempt to draw an invalid text bitmap"); - const char *text = _segMan->getString(stringObject).c_str(); - GfxFont *font = _cache->getFont(readSelectorValue(_segMan, textObject, SELECTOR(font))); - bool dimmed = readSelectorValue(_segMan, textObject, SELECTOR(dimmed)); - uint16 foreColor = readSelectorValue(_segMan, textObject, SELECTOR(fore)); + byte *surface = memoryPtr + BITMAP_HEADER_SIZE; + + int curByte = 0; + Common::Rect nsRect = getNSRect(textObject); + Common::Rect planeRect = getPlaneRect(textObject); uint16 x = readSelectorValue(_segMan, textObject, SELECTOR(x)); uint16 y = readSelectorValue(_segMan, textObject, SELECTOR(y)); + uint16 textX = planeRect.left + x; + uint16 textY = planeRect.top + y; + uint16 width = nsRect.width(); + uint16 height = nsRect.height(); + + // Upscale the coordinates/width if the fonts are already upscaled + if (_screen->fontIsUpscaled()) { + textX = textX * _screen->getDisplayWidth() / _screen->getWidth(); + textY = textY * _screen->getDisplayHeight() / _screen->getHeight(); + width = width * _screen->getDisplayWidth() / _screen->getWidth(); + height = height * _screen->getDisplayHeight() / _screen->getHeight(); + } + + for (int curY = 0; curY < height; curY++) { + for (int curX = 0; curX < width; curX++) { + byte pixel = surface[curByte++]; + if (pixel) + _screen->putFontPixel(textY, curX + textX, curY, pixel); + } + } +} + +Common::Rect GfxText32::getPlaneRect(reg_t textObject) { + Common::Rect planeRect(0, 0, _screen->getWidth(), _screen->getHeight()); - // Now get the bounding box from the associated plane reg_t planeObject = readSelector(_segMan, textObject, SELECTOR(plane)); - Common::Rect planeRect; if (!planeObject.isNull()) { planeRect.top = readSelectorValue(_segMan, planeObject, SELECTOR(top)); planeRect.left = readSelectorValue(_segMan, planeObject, SELECTOR(left)); planeRect.bottom = readSelectorValue(_segMan, planeObject, SELECTOR(bottom)) + 1; planeRect.right = readSelectorValue(_segMan, planeObject, SELECTOR(right)) + 1; - } else { - planeRect.top = 0; - planeRect.left = 0; - planeRect.bottom = _screen->getHeight(); - planeRect.right = _screen->getWidth(); } - TextEntry *newEntry = new TextEntry(); - newEntry->object = stringObject; - newEntry->x = x; - newEntry->y = y; - newEntry->width = planeRect.width(); - newEntry->height = planeRect.height(); - newEntry->surface = new byte[newEntry->width * newEntry->height]; - memset(newEntry->surface, 0, newEntry->width * newEntry->height); - newEntry->text = _segMan->getString(stringObject); - - int16 maxTextWidth, charCount; - uint16 curX = 0, curY = 0; + return planeRect; +} - maxTextWidth = 0; - while (*text) { - charCount = GetLongest(text, planeRect.width(), font); - if (charCount == 0) - break; +Common::Rect GfxText32::getNSRect(reg_t textObject) { + Common::Rect nsRect; + nsRect.top = readSelectorValue(_segMan, textObject, SELECTOR(nsTop)); + nsRect.left = readSelectorValue(_segMan, textObject, SELECTOR(nsLeft)); + nsRect.bottom = readSelectorValue(_segMan, textObject, SELECTOR(nsBottom)) + 1; + nsRect.right = readSelectorValue(_segMan, textObject, SELECTOR(nsRight)) + 1; - for (int i = 0; i < charCount; i++) { - unsigned char curChar = text[i]; - font->drawToBuffer(curChar, curY, curX, foreColor, dimmed, newEntry->surface, newEntry->width, newEntry->height); - curX += font->getCharWidth(curChar); - } - - curY += font->getHeight(); - text += charCount; - while (*text == ' ') - text++; // skip over breaking spaces - } - - return newEntry; + return nsRect; } int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) { @@ -235,4 +211,77 @@ int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) { return maxChars; } +void GfxText32::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) { + Common::Rect rect(0, 0, 0, 0); + Size(rect, text, font, maxWidth); + *textWidth = rect.width(); + *textHeight = rect.height(); +} + +void GfxText32::StringWidth(const char *str, GuiResourceId fontId, int16 &textWidth, int16 &textHeight) { + Width(str, 0, (int16)strlen(str), fontId, textWidth, textHeight, true); +} + +void GfxText32::Width(const char *text, int16 from, int16 len, GuiResourceId fontId, int16 &textWidth, int16 &textHeight, bool restoreFont) { + uint16 curChar; + textWidth = 0; textHeight = 0; + + GfxFont *font = _cache->getFont(fontId); + + if (font) { + text += from; + while (len--) { + curChar = (*(const byte *)text++); + switch (curChar) { + case 0x0A: + case 0x0D: + case 0x9781: // this one is used by SQ4/japanese as line break as well + textHeight = MAX<int16> (textHeight, font->getHeight()); + break; + case 0x7C: + warning("Code processing isn't implemented in SCI32"); + break; + default: + textHeight = MAX<int16> (textHeight, font->getHeight()); + textWidth += font->getCharWidth(curChar); + break; + } + } + } +} + +int16 GfxText32::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) { + int16 charCount; + int16 maxTextWidth = 0, textWidth; + int16 totalHeight = 0, textHeight; + + rect.top = rect.left = 0; + GfxFont *font = _cache->getFont(fontId); + + if (maxWidth < 0) { // force output as single line + StringWidth(text, fontId, textWidth, textHeight); + rect.bottom = textHeight; + rect.right = textWidth; + } else { + // rect.right=found widest line with RTextWidth and GetLongest + // rect.bottom=num. lines * GetPointSize + rect.right = (maxWidth ? maxWidth : 192); + const char *curPos = text; + while (*curPos) { + charCount = GetLongest(curPos, rect.right, font); + if (charCount == 0) + break; + Width(curPos, 0, charCount, fontId, textWidth, textHeight, false); + maxTextWidth = MAX(textWidth, maxTextWidth); + totalHeight += textHeight; + curPos += charCount; + while (*curPos == ' ') + curPos++; // skip over breaking spaces + } + rect.bottom = totalHeight; + rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); + } + return rect.right; +} + } // End of namespace Sci |