aboutsummaryrefslogtreecommitdiff
path: root/engines/sci
diff options
context:
space:
mode:
authorFilippos Karapetis2011-10-11 01:24:28 +0300
committerFilippos Karapetis2011-10-11 01:25:08 +0300
commit96ce226967741e65684c8b4d55adfbb5526fa787 (patch)
treefb0ef824d0566157c661ab41798346a1ff3efc27 /engines/sci
parent1402b47674f83a7f021417a4eebb8e132036cdcd (diff)
downloadscummvm-rg350-96ce226967741e65684c8b4d55adfbb5526fa787.tar.gz
scummvm-rg350-96ce226967741e65684c8b4d55adfbb5526fa787.tar.bz2
scummvm-rg350-96ce226967741e65684c8b4d55adfbb5526fa787.zip
SCI: Proper implementation of text drawing for SCI2+
Diffstat (limited to 'engines/sci')
-rw-r--r--engines/sci/engine/kernel.h1
-rw-r--r--engines/sci/engine/kernel_tables.h2
-rw-r--r--engines/sci/engine/kgraphics.cpp5
-rw-r--r--engines/sci/engine/selector.cpp1
-rw-r--r--engines/sci/engine/selector.h1
-rw-r--r--engines/sci/graphics/frameout.cpp11
-rw-r--r--engines/sci/graphics/text32.cpp183
-rw-r--r--engines/sci/graphics/text32.h23
8 files changed, 81 insertions, 146 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h
index e3e3f51f75..e0ab954641 100644
--- a/engines/sci/engine/kernel.h
+++ b/engines/sci/engine/kernel.h
@@ -442,6 +442,7 @@ reg_t kUpdateScreenItem(EngineState *s, int argc, reg_t *argv);
reg_t kDeleteScreenItem(EngineState *s, int argc, reg_t *argv);
// Text
reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv);
+reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv);
// "Planes" in SCI32 are pictures
reg_t kAddPlane(EngineState *s, int argc, reg_t *argv);
reg_t kDeletePlane(EngineState *s, int argc, reg_t *argv);
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h
index 22f9c9556a..d32482d155 100644
--- a/engines/sci/engine/kernel_tables.h
+++ b/engines/sci/engine/kernel_tables.h
@@ -477,6 +477,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(CreateTextBitmap), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
{ MAP_CALL(DeletePlane), SIG_EVERYWHERE, "o", NULL, NULL },
{ MAP_CALL(DeleteScreenItem), SIG_EVERYWHERE, "o", NULL, NULL },
+ { MAP_CALL(DisposeTextBitmap), SIG_EVERYWHERE, "r", NULL, NULL },
{ MAP_CALL(FrameOut), SIG_EVERYWHERE, "", NULL, NULL },
{ MAP_CALL(GetHighPlanePri), SIG_EVERYWHERE, "", NULL, NULL },
{ MAP_CALL(InPolygon), SIG_EVERYWHERE, "iio", NULL, NULL },
@@ -501,7 +502,6 @@ static SciKernelMapEntry s_kernelMap[] = {
// SCI2 unmapped functions - TODO!
// SetScroll - called by script 64909, Styler::doit()
- // DisposeTextBitmap
// PalCycle - called by Game::newRoom. Related to RemapColors.
// VibrateMouse - used in QFG4
// ObjectIntersect - used in QFG4
diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp
index 4b35864268..b1314ef02f 100644
--- a/engines/sci/engine/kgraphics.cpp
+++ b/engines/sci/engine/kgraphics.cpp
@@ -1405,6 +1405,11 @@ reg_t kCreateTextBitmap(EngineState *s, int argc, reg_t *argv) {
}
}
+reg_t kDisposeTextBitmap(EngineState *s, int argc, reg_t *argv) {
+ g_sci->_gfxText32->disposeTextBitmap(argv[0]);
+ return s->r_acc;
+}
+
reg_t kGetWindowsOption(EngineState *s, int argc, reg_t *argv) {
uint16 windowsOption = argv[0].toUint16();
switch (windowsOption) {
diff --git a/engines/sci/engine/selector.cpp b/engines/sci/engine/selector.cpp
index c2f857f319..a9aca9e22f 100644
--- a/engines/sci/engine/selector.cpp
+++ b/engines/sci/engine/selector.cpp
@@ -167,6 +167,7 @@ void Kernel::mapSelectors() {
#ifdef ENABLE_SCI32
FIND_SELECTOR(data);
FIND_SELECTOR(picture);
+ FIND_SELECTOR(bitmap);
FIND_SELECTOR(plane);
FIND_SELECTOR(top);
FIND_SELECTOR(left);
diff --git a/engines/sci/engine/selector.h b/engines/sci/engine/selector.h
index 085dd6e832..bbd86bb03e 100644
--- a/engines/sci/engine/selector.h
+++ b/engines/sci/engine/selector.h
@@ -132,6 +132,7 @@ struct SelectorCache {
#ifdef ENABLE_SCI32
Selector data; // Used by Array()/String()
Selector picture; // Used to hold the picture ID for SCI32 pictures
+ Selector bitmap; // Used to hold the text bitmap for SCI32 texts
Selector plane;
Selector top;
diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp
index 432ad051ca..17b4b015d5 100644
--- a/engines/sci/graphics/frameout.cpp
+++ b/engines/sci/graphics/frameout.cpp
@@ -547,16 +547,7 @@ void GfxFrameout::kernelFrameout() {
} else {
// Most likely a text entry
if (lookupSelector(_segMan, itemEntry->object, SELECTOR(text), NULL, NULL) == kSelectorVariable) {
- 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;
- // Upscale the coordinates/width if the fonts are already upscaled
- if (_screen->fontIsUpscaled()) {
- startX = startX * _screen->getDisplayWidth() / _screen->getWidth();
- startY = startY * _screen->getDisplayHeight() / _screen->getHeight();
- }
-
- g_sci->_gfxText32->drawTextBitmap(itemEntry->object, startX, startY, it->planeRect.width());
+ g_sci->_gfxText32->drawTextBitmap(itemEntry->object);
}
}
}
diff --git a/engines/sci/graphics/text32.cpp b/engines/sci/graphics/text32.cpp
index 7be3874ed0..8337d16fe6 100644
--- a/engines/sci/graphics/text32.cpp
+++ b/engines/sci/graphics/text32.cpp
@@ -43,163 +43,114 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *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();
}
reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxHeight) {
- 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, maxWidth, maxHeight);
+ reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text));
- // TODO: Create a new hunk pointer with the created surface
- return NULL_REG;
-}
+ // 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));
-// TODO: Finish this!
-void GfxText32::drawTextBitmap(reg_t textObject, uint16 textX, uint16 textY, uint16 planeWidth) {
- uint32 textId = (textObject.segment << 16) | textObject.offset;
+ 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));
+ uint16 x = readSelectorValue(_segMan, textObject, SELECTOR(x));
+ uint16 y = readSelectorValue(_segMan, textObject, SELECTOR(y));
- if (!_textCache.contains(textId))
- createTextBitmap(textObject);
+ Common::Rect planeRect = getPlaneRect(textObject);
+ uint16 width = planeRect.width();
+ uint16 height = planeRect.height();
- TextEntry *entry = _textCache[textId];
+ // Limit rectangle dimensions, if requested
+ if (maxWidth > 0)
+ width = maxWidth;
+ if (maxHeight > 0)
+ height = maxHeight;
- // 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));
+ int entrySize = width * height;
+ reg_t memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize);
+ writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId);
+ byte *memoryPtr = _segMan->getHunkPointer(memoryId);
+ memset(memoryPtr, 0, entrySize);
- const char *txt = entry->text.c_str();
- int16 charCount;
- uint16 maxWidth = (planeWidth > 0) ? planeWidth : _screen->getWidth() - textX;
+ int16 charCount = 0;
+ uint16 curX = 0, curY = 0;
+ const char *txt = text.c_str();
while (*txt) {
- charCount = GetLongest(txt, maxWidth, 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, memoryPtr, 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, uint16 maxWidth, uint16 maxHeight) {
- reg_t stringObject = readSelector(_segMan, textObject, SELECTOR(text));
+void GfxText32::drawTextBitmap(reg_t textObject) {
+ reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap));
+ byte *surface = _segMan->getHunkPointer(hunkId);
- // TODO: maxWidth, maxHeight (if > 0)
+ if (!surface)
+ error("Attempt to draw an invalid text bitmap");
- // 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));
+ int curByte = 0;
+ Common::Rect nsRect = getNSRect(textObject);
+ Common::Rect planeRect = getPlaneRect(textObject);
+ uint16 textX = planeRect.left + nsRect.left;
+ uint16 textY = planeRect.top + nsRect.top;
+ uint16 width = nsRect.width();
+ uint16 height = nsRect.height();
- 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));
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ byte pixel = surface[curByte++];
+ if (pixel)
+ _screen->putPixel(x + textX, y + textY, 1, pixel, 0, 0);
+ }
+ }
+}
+
+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 = 0,*/ charCount = 0;
- uint16 curX = 0, curY = 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 planeRect;
+}
- return newEntry;
+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;
+ return nsRect;
}
int16 GfxText32::GetLongest(const char *text, int16 maxWidth, GfxFont *font) {
diff --git a/engines/sci/graphics/text32.h b/engines/sci/graphics/text32.h
index 113fbb46a2..4c1e53d971 100644
--- a/engines/sci/graphics/text32.h
+++ b/engines/sci/graphics/text32.h
@@ -30,20 +30,6 @@
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
*/
@@ -52,22 +38,21 @@ public:
GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen);
~GfxText32();
reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0);
- void drawTextBitmap(reg_t textObject, uint16 textX, uint16 textY, uint16 planeWidth);
+ void disposeTextBitmap(reg_t hunkId);
+ void drawTextBitmap(reg_t textObject);
int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font);
- TextEntry *getTextEntry(reg_t textObject);
void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
private:
- TextEntry *createTextEntry(reg_t textObject, uint16 maxWidth, uint16 maxHeight);
int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth);
void Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont);
void StringWidth(const char *str, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight);
- void purgeCache();
+ Common::Rect getPlaneRect(reg_t textObject);
+ Common::Rect getNSRect(reg_t textObject);
SegManager *_segMan;
GfxCache *_cache;
- TextCache _textCache;
GfxScreen *_screen;
};