diff options
author | Filippos Karapetis | 2011-09-03 14:50:58 +0300 |
---|---|---|
committer | Filippos Karapetis | 2011-09-03 14:51:51 +0300 |
commit | 41cc1932d2cc19e6179f54d1b149a245420dba7a (patch) | |
tree | 1c743a35692c61786a9bca4353be2f87b14a964b /engines | |
parent | f85fd9b4f1168bcf0659ef6cf747c6616408921c (diff) | |
download | scummvm-rg350-41cc1932d2cc19e6179f54d1b149a245420dba7a.tar.gz scummvm-rg350-41cc1932d2cc19e6179f54d1b149a245420dba7a.tar.bz2 scummvm-rg350-41cc1932d2cc19e6179f54d1b149a245420dba7a.zip |
SCI32: Added an initial skeleton structure for the SCI2 text drawing code
This includes kCreateTextBitmap, and moves all of the text drawing code
into the new GfxText32 class
Diffstat (limited to 'engines')
-rw-r--r-- | engines/sci/engine/kgraphics.cpp | 18 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 86 | ||||
-rw-r--r-- | engines/sci/graphics/text32.cpp | 238 | ||||
-rw-r--r-- | engines/sci/graphics/text32.h | 71 | ||||
-rw-r--r-- | engines/sci/module.mk | 1 | ||||
-rw-r--r-- | engines/sci/sci.cpp | 4 | ||||
-rw-r--r-- | engines/sci/sci.h | 2 |
7 files changed, 335 insertions, 85 deletions
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index 36de767464..556e5249b6 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -49,6 +49,7 @@ #include "sci/graphics/text16.h" #include "sci/graphics/view.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/text32.h" #include "sci/graphics/frameout.h" #include "sci/video/robot_decoder.h" #endif @@ -1380,15 +1381,19 @@ reg_t kIsOnMe(EngineState *s, int argc, reg_t *argv) { } reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { - // TODO: argument 0 is usually 0, and arguments 1 and 2 are usually 1 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))); + 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()); + // TODO: arguments 1 and 2 + g_sci->_gfxText32->createTextBitmap(object); break; } case 1: { @@ -1396,8 +1401,11 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) { warning("kCreateTextBitmap(0): 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))); + 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()); + g_sci->_gfxText32->createTextBitmap(object); break; } default: diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index 11948d5d38..5499a2d192 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -43,6 +43,7 @@ #include "sci/graphics/paint32.h" #include "sci/graphics/palette.h" #include "sci/graphics/picture.h" +#include "sci/graphics/text32.h" #include "sci/graphics/frameout.h" #include "sci/video/robot_decoder.h" @@ -316,44 +317,6 @@ void GfxFrameout::sortPlanes() { Common::sort(_planes.begin(), _planes.end(), planeSortHelper); } -static int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font) { - uint16 curChar = 0; - int16 maxChars = 0, curCharCount = 0; - uint16 width = 0; - - while (width <= maxWidth) { - curChar = (*(const byte *)text++); - - switch (curChar) { - // We need to add 0xD, 0xA and 0xD 0xA to curCharCount and then exit - // which means, we split text like - // 'Mature, experienced software analyst available.' 0xD 0xA - // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2) - // and 0xA '-------' 0xA (which is the official sierra subtitle separator) - // Sierra did it the same way. - case 0xD: - // Check, if 0xA is following, if so include it as well - if ((*(const unsigned char *)text) == 0xA) - curCharCount++; - // it's meant to pass through here - case 0xA: - curCharCount++; - // and it's also meant to pass through here - case 0: - return curCharCount; - case ' ': - maxChars = curCharCount; // return count up to (but not including) breaking space - break; - } - if (width + font->getCharWidth(curChar) > maxWidth) - break; - width += font->getCharWidth(curChar); - curCharCount++; - } - - return maxChars; -} - void GfxFrameout::kernelFrameout() { if (g_sci->_robotDecoder->isVideoLoaded()) { bool skipVideo = false; @@ -578,62 +541,25 @@ void GfxFrameout::kernelFrameout() { } } else { // Most likely a text entry - // 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) if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) { - reg_t stringObject = readSelector(_segMan, itemEntry->object, SELECTOR(text)); - - // 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)); - - Common::String text = _segMan->getString(stringObject); - GfxFont *font = _cache->getFont(readSelectorValue(_segMan, itemEntry->object, SELECTOR(font))); - bool dimmed = readSelectorValue(_segMan, itemEntry->object, SELECTOR(dimmed)); - uint16 foreColor = readSelectorValue(_segMan, itemEntry->object, SELECTOR(fore)); - - itemEntry->y = ((itemEntry->y * _screen->getHeight()) / scriptsRunningHeight); - itemEntry->x = ((itemEntry->x * _screen->getWidth()) / scriptsRunningWidth); - - uint16 startX = itemEntry->x + it->planeRect.left; - uint16 curY = itemEntry->y + it->planeRect.top; - const char *txt = text.c_str(); + TextEntry *textEntry = g_sci->_gfxText32->getTextEntry(itemEntry->object); + uint16 startX = ((textEntry->x * _screen->getWidth()) / scriptsRunningWidth) + it->planeRect.left; + uint16 startY = ((textEntry->y * _screen->getHeight()) / scriptsRunningHeight) + it->planeRect.top; // HACK. The plane sometimes doesn't contain the correct width. This // hack breaks the dialog options when speaking with Grace, but it's // the best we got up to now. This happens because of the unimplemented // kTextWidth function in SCI32. // TODO: Remove this once kTextWidth has been implemented. uint16 w = it->planeRect.width() >= 20 ? it->planeRect.width() : _screen->getWidth() - 10; - int16 charCount; // Upscale the coordinates/width if the fonts are already upscaled if (_screen->fontIsUpscaled()) { startX = startX * _screen->getDisplayWidth() / _screen->getWidth(); - curY = curY * _screen->getDisplayHeight() / _screen->getHeight(); + startY = startY * _screen->getDisplayHeight() / _screen->getHeight(); w = w * _screen->getDisplayWidth() / _screen->getWidth(); } - while (*txt) { - charCount = GetLongest(txt, w, font); - if (charCount == 0) - break; - - uint16 curX = startX; - - for (int i = 0; i < charCount; i++) { - unsigned char curChar = txt[i]; - font->draw(curChar, curY, curX, foreColor, dimmed); - curX += font->getCharWidth(curChar); - } - - curY += font->getHeight(); - txt += charCount; - while (*txt == ' ') - txt++; // skip over breaking spaces - } - + g_sci->_gfxText32->drawTextBitmap(itemEntry->object, startX, startY, w); } } } diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp new file mode 100644 index 0000000000..21372f1502 --- /dev/null +++ b/engines/sci/graphics/text32.cpp @@ -0,0 +1,238 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/sci/graphics/text16.cpp $ + * $Id: text16.cpp 55178 2011-01-08 23:16:44Z thebluegr $ + * + */ + +#include "common/util.h" +#include "common/stack.h" +#include "graphics/primitives.h" + +#include "sci/sci.h" +#include "sci/engine/kernel.h" +#include "sci/engine/selector.h" +#include "sci/engine/state.h" +#include "sci/graphics/cache.h" +#include "sci/graphics/font.h" +#include "sci/graphics/screen.h" +#include "sci/graphics/text32.h" + +namespace Sci { + +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(); + + uint32 textId = (textObject.segment << 16) | textObject.offset; + + if (_textCache.contains(textId)) { + // Delete the old entry + TextEntry *oldEntry = _textCache[textId]; + delete[] oldEntry->surface; + delete oldEntry; + _textCache.erase(textId); + } + + _textCache[textId] = createTextEntry(textObject); +} + +// TODO: Finish this! +void GfxText32::drawTextBitmap(reg_t textObject, uint16 textX, uint16 textY, uint16 w) { + uint32 textId = (textObject.segment << 16) | textObject.offset; + + if (!_textCache.contains(textId)) + createTextBitmap(textObject); + + TextEntry *entry = _textCache[textId]; + + // 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; + + while (*txt) { + charCount = GetLongest(txt, w, 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); + curX += font->getCharWidth(curChar); + } + + textY += 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); + } + } + */ +} + +TextEntry *GfxText32::getTextEntry(reg_t textObject) { + uint32 textId = (textObject.segment << 16) | textObject.offset; + + if (!_textCache.contains(textId)) + createTextBitmap(textObject); + + return _textCache[textId]; +} + +// TODO: Finish this! Currently buggy. +TextEntry *GfxText32::createTextEntry(reg_t textObject) { + reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text)); + + // 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)); + + 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)); + uint16 x = readSelectorValue(_segMan, textObject, SELECTOR(x)); + uint16 y = readSelectorValue(_segMan, textObject, SELECTOR(y)); + + // 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; + + maxTextWidth = 0; + while (*text) { + charCount = GetLongest(text, planeRect.width(), font); + if (charCount == 0) + break; + + 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; +} + +int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) { + uint16 curChar = 0; + int16 maxChars = 0, curCharCount = 0; + uint16 width = 0; + + while (width <= maxWidth) { + curChar = (*(const byte *)text++); + + switch (curChar) { + // We need to add 0xD, 0xA and 0xD 0xA to curCharCount and then exit + // which means, we split text like + // 'Mature, experienced software analyst available.' 0xD 0xA + // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2) + // and 0xA '-------' 0xA (which is the official sierra subtitle separator) + // Sierra did it the same way. + case 0xD: + // Check, if 0xA is following, if so include it as well + if ((*(const unsigned char *)text) == 0xA) + curCharCount++; + // it's meant to pass through here + case 0xA: + curCharCount++; + // and it's also meant to pass through here + case 0: + return curCharCount; + case ' ': + maxChars = curCharCount; // return count up to (but not including) breaking space + break; + } + if (width + font->getCharWidth(curChar) > maxWidth) + break; + width += font->getCharWidth(curChar); + curCharCount++; + } + + return maxChars; +} + +} // End of namespace Sci diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h new file mode 100644 index 0000000000..39fe710a86 --- /dev/null +++ b/engines/sci/graphics/text32.h @@ -0,0 +1,71 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/trunk/engines/sci/graphics/text16.h $ + * $Id: text16.h 55178 2011-01-08 23:16:44Z thebluegr $ + * + */ + +#ifndef SCI_GRAPHICS_TEXT32_H +#define SCI_GRAPHICS_TEXT32_H + +#include "common/hashmap.h" + +namespace Sci { + +struct TextEntry { + reg_t object; + uint16 x; + uint16 y; + uint16 width; + uint16 height; + byte *surface; + Common::String text; +}; + +// TODO: Move to Cache, perhaps? +#define MAX_CACHED_TEXTS 20 +typedef Common::HashMap<uint32, TextEntry *> TextCache; + +/** + * Text32 class, handles text calculation and displaying of text for SCI2, SCI21 and SCI3 games + */ +class GfxText32 { +public: + GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen); + ~GfxText32(); + void createTextBitmap(reg_t textObject); + void drawTextBitmap(reg_t textObject, uint16 textX, uint16 textY, uint16 w); + int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font); + TextEntry *getTextEntry(reg_t textObject); + +private: + TextEntry *createTextEntry(reg_t textObject); + void purgeCache(); + + SegManager *_segMan; + GfxCache *_cache; + TextCache _textCache; + GfxScreen *_screen; +}; + +} // End of namespace Sci + +#endif diff --git a/engines/sci/module.mk b/engines/sci/module.mk index 2202002e2e..c129ae5439 100644 --- a/engines/sci/module.mk +++ b/engines/sci/module.mk @@ -80,6 +80,7 @@ ifdef ENABLE_SCI32 MODULE_OBJS += \ graphics/frameout.o \ graphics/paint32.o \ + graphics/text32.o \ video/robot_decoder.o endif diff --git a/engines/sci/sci.cpp b/engines/sci/sci.cpp index 792b2b2055..6c1b6e4dd6 100644 --- a/engines/sci/sci.cpp +++ b/engines/sci/sci.cpp @@ -61,6 +61,7 @@ #include "sci/graphics/transitions.h" #ifdef ENABLE_SCI32 +#include "sci/graphics/text32.h" #include "sci/graphics/frameout.h" #include "sci/video/robot_decoder.h" #endif @@ -146,6 +147,7 @@ SciEngine::~SciEngine() { DebugMan.clearAllDebugChannels(); #ifdef ENABLE_SCI32 + delete _gfxText32; delete _robotDecoder; delete _gfxFrameout; #endif @@ -598,6 +600,7 @@ void SciEngine::initGraphics() { _gfxText16 = 0; _gfxTransitions = 0; #ifdef ENABLE_SCI32 + _gfxText32 = 0; _robotDecoder = 0; _gfxFrameout = 0; _gfxPaint32 = 0; @@ -627,6 +630,7 @@ void SciEngine::initGraphics() { _gfxCompare = new GfxCompare(_gamestate->_segMan, _kernel, _gfxCache, _gfxScreen, _gfxCoordAdjuster); _gfxPaint32 = new GfxPaint32(_resMan, _gamestate->_segMan, _kernel, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette); _gfxPaint = _gfxPaint32; + _gfxText32 = new GfxText32(_gamestate->_segMan, _gfxCache, _gfxScreen); _robotDecoder = new RobotDecoder(g_system->getMixer(), getPlatform() == Common::kPlatformMacintosh); _gfxFrameout = new GfxFrameout(_gamestate->_segMan, _resMan, _gfxCoordAdjuster, _gfxCache, _gfxScreen, _gfxPalette, _gfxPaint32); } else { diff --git a/engines/sci/sci.h b/engines/sci/sci.h index b419d862a4..81bbdc51de 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -71,6 +71,7 @@ class GfxPalette; class GfxPorts; class GfxScreen; class GfxText16; +class GfxText32; class GfxTransitions; #ifdef ENABLE_SCI32 @@ -313,6 +314,7 @@ public: GfxPorts *_gfxPorts; // Port managment for 16-bit gfx GfxScreen *_gfxScreen; GfxText16 *_gfxText16; + GfxText32 *_gfxText32; GfxTransitions *_gfxTransitions; // transitions between screens for 16-bit gfx GfxMacIconBar *_gfxMacIconBar; // Mac Icon Bar manager |