SCI: Initial implementation of kScrollWindow, used in some SCI21 games

This is used in LSL6 hires and SQ6. This initial implementation is hackish
and only works in SQ6 (nothing is shown in LSL6)
This commit is contained in:
Filippos Karapetis 2012-06-07 11:26:32 +03:00
parent e73f93e565
commit de3f6a19ed
6 changed files with 168 additions and 75 deletions

View File

@ -564,7 +564,7 @@ static SciKernelMapEntry s_kernelMap[] = {
{ MAP_CALL(GetSierraProfileInt), SIG_EVERYWHERE, "rri", NULL, NULL },
{ MAP_CALL(CelInfo), SIG_EVERYWHERE, "iiiiii", NULL, NULL },
{ MAP_CALL(SetLanguage), SIG_EVERYWHERE, "r", NULL, NULL },
{ MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "(.*)", NULL, NULL },
{ MAP_CALL(ScrollWindow), SIG_EVERYWHERE, "io(.*)", NULL, NULL },
{ MAP_CALL(SetFontRes), SIG_EVERYWHERE, "ii", NULL, NULL },
{ MAP_CALL(Font), SIG_EVERYWHERE, "i(.*)", NULL, NULL },
{ MAP_CALL(Bitmap), SIG_EVERYWHERE, "(.*)", NULL, NULL },

View File

@ -308,103 +308,91 @@ reg_t kCelInfo(EngineState *s, int argc, reg_t *argv) {
}
reg_t kScrollWindow(EngineState *s, int argc, reg_t *argv) {
// Used by Phantasmagoria 1 and SQ6. In SQ6, it is used for the messages
// shown in the scroll window at the bottom of the screen.
// Used by SQ6 and LSL6 hires for the text area in the bottom of the
// screen. The relevant scripts also exist in Phantasmagoria 1, but they're
// unused. This is always called by scripts 64906 (ScrollerWindow) and
// 64907 (ScrollableWindow).
// TODO: This is all a stub/skeleton, thus we're invoking kStub() for now
kStub(s, argc, argv);
switch (argv[0].toUint16()) {
reg_t kWindow = argv[1];
uint16 op = argv[0].toUint16();
switch (op) {
case 0: // Init
// 2 parameters
// argv[1] points to the scroll object (e.g. textScroller in SQ6)
// argv[2] is an integer (e.g. 0x32)
break;
case 1: // Show message
g_sci->_gfxFrameout->initScrollText(argv[2].toUint16()); // maxItems
g_sci->_gfxFrameout->clearScrollTexts();
return argv[1]; // kWindow
case 1: // Show message, called by ScrollableWindow::addString
case 14: // Modify message, called by ScrollableWindow::modifyString
// 5 or 6 parameters
// Seems to be called with 5 parameters when the narrator speaks, and
// with 6 when Roger speaks
// argv[1] unknown (usually 0)
// argv[2] the text to show
// argv[3] a small integer (e.g. 0x32)
// argv[4] a small integer (e.g. 0x54)
// argv[5] optional, unknown (usually 0)
warning("kScrollWindow: '%s'", s->_segMan->getString(argv[2]).c_str());
{
Common::String text = s->_segMan->getString(argv[2]);
uint16 x = 0;//argv[3].toUint16(); // TODO: can't be x (values are all wrong)
uint16 y = 0;//argv[4].toUint16(); // TODO: can't be y (values are all wrong)
// TODO: argv[5] is an optional unknown parameter (an integer set to 0)
g_sci->_gfxFrameout->addScrollTextEntry(text, kWindow, x, y, (op == 14));
}
break;
case 2: // Clear
// 2 parameters
// TODO
case 2: // Clear, called by ScrollableWindow::erase
g_sci->_gfxFrameout->clearScrollTexts();
break;
case 3: // Page up
// 2 parameters
case 3: // Page up, called by ScrollableWindow::scrollTo
// TODO
kStub(s, argc, argv);
break;
case 4: // Page down
// 2 parameters
case 4: // Page down, called by ScrollableWindow::scrollTo
// TODO
kStub(s, argc, argv);
break;
case 5: // Up arrow
// 2 parameters
// TODO
case 5: // Up arrow, called by ScrollableWindow::scrollTo
g_sci->_gfxFrameout->prevScrollText();
break;
case 6: // Down arrow
// 2 parameters
// TODO
case 6: // Down arrow, called by ScrollableWindow::scrollTo
g_sci->_gfxFrameout->nextScrollText();
break;
case 7: // Home
// 2 parameters
// TODO
case 7: // Home, called by ScrollableWindow::scrollTo
g_sci->_gfxFrameout->firstScrollText();
break;
case 8: // End
// 2 parameters
// TODO
case 8: // End, called by ScrollableWindow::scrollTo
g_sci->_gfxFrameout->lastScrollText();
break;
case 9: // Resize
// 3 parameters
case 9: // Resize, called by ScrollableWindow::resize and ScrollerWindow::resize
// TODO
kStub(s, argc, argv);
break;
case 10: // Where
// 3 parameters
case 10: // Where, called by ScrollableWindow::where
// TODO
// argv[2] is an unknown integer
kStub(s, argc, argv);
break;
case 11: // Go
// 4 parameters
case 11: // Go, called by ScrollableWindow::scrollTo
// 2 extra parameters here
// TODO
kStub(s, argc, argv);
break;
case 12: // Insert
// 7 parameters
case 12: // Insert, called by ScrollableWindow::insertString
// 3 extra parameters here
// TODO
kStub(s, argc, argv);
break;
case 13: // Delete
// 3 parameters
// TODO
// case 13 (Delete) is handled below
// case 14 (Modify) is handled above
case 15: // Hide, called by ScrollableWindow::hide
g_sci->_gfxFrameout->toggleScrollText(false);
break;
case 14: // Modify
// 7 or 8 parameters
// TODO
case 16: // Show, called by ScrollableWindow::show
g_sci->_gfxFrameout->toggleScrollText(true);
break;
case 15: // Hide
// 2 parameters
// TODO
case 17: // Destroy, called by ScrollableWindow::dispose
g_sci->_gfxFrameout->clearScrollTexts();
break;
case 16: // Show
// 2 parameters
// TODO
break;
case 17: // Destroy
// 2 parameters
// TODO
break;
case 18: // Text
// 2 parameters
// TODO
break;
case 19: // Reconstruct
// 3 parameters
// TODO
case 13: // Delete, unused
case 18: // Text, unused
case 19: // Reconstruct, unused
error("kScrollWindow: Unused subop %d invoked", op);
break;
default:
error("kScrollWindow: unknown subop %d", argv[0].toUint16());
error("kScrollWindow: unknown subop %d", op);
break;
}

View File

@ -59,6 +59,9 @@ GfxFrameout::GfxFrameout(SegManager *segMan, ResourceManager *resMan, GfxCoordAd
_coordAdjuster = (GfxCoordAdjuster32 *)coordAdjuster;
_scriptsRunningWidth = 320;
_scriptsRunningHeight = 200;
_curScrollText = -1;
_showScrollText = false;
_maxScrollTexts = 0;
}
GfxFrameout::~GfxFrameout() {
@ -69,6 +72,46 @@ void GfxFrameout::clear() {
deletePlaneItems(NULL_REG);
_planes.clear();
deletePlanePictures(NULL_REG);
clearScrollTexts();
}
void GfxFrameout::clearScrollTexts() {
_scrollTexts.clear();
_curScrollText = -1;
}
void GfxFrameout::addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace) {
//reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow);
// HACK: We set the container dimensions manually
reg_t bitmapHandle = g_sci->_gfxText32->createScrollTextBitmap(text, kWindow, 480, 70);
ScrollTextEntry textEntry;
textEntry.bitmapHandle = bitmapHandle;
textEntry.kWindow = kWindow;
textEntry.x = x;
textEntry.y = y;
if (!replace || _scrollTexts.size() == 0) {
if (_scrollTexts.size() > _maxScrollTexts) {
_scrollTexts.remove_at(0);
_curScrollText--;
}
_scrollTexts.push_back(textEntry);
_curScrollText++;
} else {
_scrollTexts.pop_back();
_scrollTexts.push_back(textEntry);
}
}
void GfxFrameout::showCurrentScrollText() {
if (!_showScrollText || _curScrollText < 0)
return;
uint16 size = (uint16)_scrollTexts.size();
if (size > 0) {
assert(_curScrollText < size);
ScrollTextEntry textEntry = _scrollTexts[_curScrollText];
g_sci->_gfxText32->drawScrollTextBitmap(textEntry.kWindow, textEntry.bitmapHandle, textEntry.x, textEntry.y);
}
}
void GfxFrameout::kernelAddPlane(reg_t object) {
@ -673,6 +716,8 @@ void GfxFrameout::kernelFrameout() {
}
}
showCurrentScrollText();
_screen->copyToScreen();
g_sci->getEngineState()->_throttleTrigger = true;

View File

@ -76,6 +76,15 @@ struct PlanePictureEntry {
typedef Common::List<PlanePictureEntry> PlanePictureList;
struct ScrollTextEntry {
reg_t bitmapHandle;
reg_t kWindow;
uint16 x;
uint16 y;
};
typedef Common::Array<ScrollTextEntry> ScrollTextList;
class GfxCache;
class GfxCoordAdjuster32;
class GfxPaint32;
@ -104,6 +113,18 @@ public:
void addPlanePicture(reg_t object, GuiResourceId pictureId, uint16 startX, uint16 startY = 0);
void deletePlanePictures(reg_t object);
void clear();
// Scroll text functions
void addScrollTextEntry(Common::String &text, reg_t kWindow, uint16 x, uint16 y, bool replace);
void showCurrentScrollText();
void initScrollText(uint16 maxItems) { _maxScrollTexts = maxItems; }
void clearScrollTexts();
void firstScrollText() { if (_scrollTexts.size() > 0) _curScrollText = 0; }
void lastScrollText() { if (_scrollTexts.size() > 0) _curScrollText = _scrollTexts.size() - 1; }
void prevScrollText() { if (_curScrollText > 0) _curScrollText--; }
void nextScrollText() { if (_curScrollText + 1 < (uint16)_scrollTexts.size()) _curScrollText++; }
void toggleScrollText(bool show) { _showScrollText = show; }
void printPlaneList(Console *con);
void printPlaneItemList(Console *con, reg_t planeObject);
@ -127,6 +148,10 @@ private:
FrameoutList _screenItems;
PlaneList _planes;
PlanePictureList _planePictures;
ScrollTextList _scrollTexts;
int16 _curScrollText;
bool _showScrollText;
uint16 _maxScrollTexts;
void sortPlanes();

View File

@ -49,9 +49,12 @@ GfxText32::GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen)
GfxText32::~GfxText32() {
}
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));
// 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.
@ -59,6 +62,11 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH
stringObject = readSelector(_segMan, stringObject, SELECTOR(data));
Common::String text = _segMan->getString(stringObject);
return createTextBitmapInternal(text, textObject, maxWidth, maxHeight, prevHunk);
}
reg_t GfxText32::createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t prevHunk) {
// HACK: The character offsets of the up and down arrow buttons are off by one
// in GK1, for some unknown reason. Fix them here.
if (text.size() == 1 && (text[0] == 29 || text[0] == 30)) {
@ -91,7 +99,11 @@ reg_t GfxText32::createTextBitmap(reg_t textObject, uint16 maxWidth, uint16 maxH
reg_t memoryId = NULL_REG;
if (prevHunk.isNull()) {
memoryId = _segMan->allocateHunkEntry("TextBitmap()", entrySize);
writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId);
// Scroll text objects have no bitmap selector!
ObjVarRef varp;
if (lookupSelector(_segMan, textObject, SELECTOR(bitmap), &varp, NULL) == kSelectorVariable)
writeSelector(_segMan, textObject, SELECTOR(bitmap), memoryId);
} else {
memoryId = prevHunk;
}
@ -175,6 +187,24 @@ void GfxText32::disposeTextBitmap(reg_t hunkId) {
void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t textObject) {
reg_t hunkId = readSelector(_segMan, textObject, SELECTOR(bitmap));
drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);
}
void GfxText32::drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y) {
/*reg_t plane = readSelector(_segMan, textObject, SELECTOR(plane));
Common::Rect planeRect;
planeRect.top = readSelectorValue(_segMan, plane, SELECTOR(top));
planeRect.left = readSelectorValue(_segMan, plane, SELECTOR(left));
planeRect.bottom = readSelectorValue(_segMan, plane, SELECTOR(bottom));
planeRect.right = readSelectorValue(_segMan, plane, SELECTOR(right));
drawTextBitmapInternal(x, y, planeRect, textObject, hunkId);*/
// HACK: we pretty much ignore the plane rect and x, y...
drawTextBitmapInternal(0, 0, Common::Rect(20, 390, 600, 460), textObject, hunkId);
}
void GfxText32::drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId) {
uint16 backColor = readSelectorValue(_segMan, textObject, SELECTOR(back));
// Sanity check: Check if the hunk is set. If not, either the game scripts
// didn't set it, or an old saved game has been loaded, where it wasn't set.
@ -188,8 +218,9 @@ void GfxText32::drawTextBitmap(int16 x, int16 y, Common::Rect planeRect, reg_t t
byte *memoryPtr = _segMan->getHunkPointer(hunkId);
if (!memoryPtr) {
// Happens when restoring in some SCI32 games
warning("Attempt to draw an invalid text bitmap");
// Happens when restoring in some SCI32 games (e.g. SQ6).
// Commented out to reduce console spam
//warning("Attempt to draw an invalid text bitmap");
return;
}

View File

@ -33,13 +33,17 @@ public:
GfxText32(SegManager *segMan, GfxCache *fonts, GfxScreen *screen);
~GfxText32();
reg_t createTextBitmap(reg_t textObject, uint16 maxWidth = 0, uint16 maxHeight = 0, reg_t prevHunk = NULL_REG);
void disposeTextBitmap(reg_t hunkId);
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);
void drawScrollTextBitmap(reg_t textObject, reg_t hunkId, uint16 x, uint16 y);
void disposeTextBitmap(reg_t hunkId);
int16 GetLongest(const char *text, int16 maxWidth, GfxFont *font);
void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight);
private:
reg_t createTextBitmapInternal(Common::String &text, reg_t textObject, uint16 maxWidth, uint16 maxHeight, reg_t hunkId);
void drawTextBitmapInternal(int16 x, int16 y, Common::Rect planeRect, reg_t textObject, reg_t hunkId);
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);