diff options
Diffstat (limited to 'engines/sci/graphics')
-rw-r--r-- | engines/sci/graphics/controls16.cpp | 12 | ||||
-rw-r--r-- | engines/sci/graphics/controls16.h | 6 | ||||
-rw-r--r-- | engines/sci/graphics/cursor.cpp | 8 | ||||
-rw-r--r-- | engines/sci/graphics/font.cpp | 8 | ||||
-rw-r--r-- | engines/sci/graphics/font.h | 4 | ||||
-rw-r--r-- | engines/sci/graphics/frameout.cpp | 10 | ||||
-rw-r--r-- | engines/sci/graphics/paint16.cpp | 25 | ||||
-rw-r--r-- | engines/sci/graphics/paint16.h | 2 | ||||
-rw-r--r-- | engines/sci/graphics/paint32.cpp | 2 | ||||
-rw-r--r-- | engines/sci/graphics/palette.cpp | 87 | ||||
-rw-r--r-- | engines/sci/graphics/palette.h | 6 | ||||
-rw-r--r-- | engines/sci/graphics/picture.cpp | 88 | ||||
-rw-r--r-- | engines/sci/graphics/portrait.cpp | 105 | ||||
-rw-r--r-- | engines/sci/graphics/portrait.h | 2 | ||||
-rw-r--r-- | engines/sci/graphics/ports.cpp | 16 | ||||
-rw-r--r-- | engines/sci/graphics/screen.cpp | 399 | ||||
-rw-r--r-- | engines/sci/graphics/screen.h | 95 | ||||
-rw-r--r-- | engines/sci/graphics/text16.cpp | 225 | ||||
-rw-r--r-- | engines/sci/graphics/text16.h | 15 | ||||
-rw-r--r-- | engines/sci/graphics/transitions.cpp | 6 | ||||
-rw-r--r-- | engines/sci/graphics/view.cpp | 3 |
21 files changed, 746 insertions, 378 deletions
diff --git a/engines/sci/graphics/controls16.cpp b/engines/sci/graphics/controls16.cpp index f2b2ccdfe6..e2e250cf9d 100644 --- a/engines/sci/graphics/controls16.cpp +++ b/engines/sci/graphics/controls16.cpp @@ -280,7 +280,7 @@ int GfxControls16::getPicNotValid() { return _screen->_picNotValid; } -void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite) { +void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 style, bool hilite) { int16 sci0EarlyPen = 0, sci0EarlyBack = 0; if (!hilite) { if (getSciVersion() == SCI_VERSION_0_EARLY) { @@ -295,7 +295,7 @@ void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *t _paint16->frameRect(rect); rect.grow(-2); _ports->textGreyedOutput(!(style & SCI_CONTROLS_STYLE_ENABLED)); - _text16->Box(text, false, rect, SCI_TEXT16_ALIGNMENT_CENTER, fontId); + _text16->Box(text, languageSplitter, false, rect, SCI_TEXT16_ALIGNMENT_CENTER, fontId); _ports->textGreyedOutput(false); rect.grow(1); if (style & SCI_CONTROLS_STYLE_SELECTED) @@ -318,12 +318,12 @@ void GfxControls16::kernelDrawButton(Common::Rect rect, reg_t obj, const char *t } } -void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, TextAlignment alignment, int16 style, bool hilite) { +void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, TextAlignment alignment, int16 style, bool hilite) { if (!hilite) { rect.grow(1); _paint16->eraseRect(rect); rect.grow(-1); - _text16->Box(text, false, rect, alignment, fontId); + _text16->Box(text, languageSplitter, false, rect, alignment, fontId); if (style & SCI_CONTROLS_STYLE_SELECTED) { _paint16->frameRect(rect); } @@ -335,7 +335,7 @@ void GfxControls16::kernelDrawText(Common::Rect rect, reg_t obj, const char *tex } } -void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) { +void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite) { Common::Rect textRect = rect; uint16 oldFontId = _text16->GetFontId(); @@ -343,7 +343,7 @@ void GfxControls16::kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char _texteditCursorVisible = false; texteditCursorErase(); _paint16->eraseRect(rect); - _text16->Box(text, false, textRect, SCI_TEXT16_ALIGNMENT_LEFT, fontId); + _text16->Box(text, languageSplitter, false, textRect, SCI_TEXT16_ALIGNMENT_LEFT, fontId); _paint16->frameRect(rect); if (style & SCI_CONTROLS_STYLE_SELECTED) { _text16->SetFont(fontId); diff --git a/engines/sci/graphics/controls16.h b/engines/sci/graphics/controls16.h index 6a70c71aae..39ffa243fb 100644 --- a/engines/sci/graphics/controls16.h +++ b/engines/sci/graphics/controls16.h @@ -55,9 +55,9 @@ public: GfxControls16(SegManager *segMan, GfxPorts *ports, GfxPaint16 *paint16, GfxText16 *text16, GfxScreen *screen); ~GfxControls16(); - void kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 style, bool hilite); - void kernelDrawText(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 alignment, int16 style, bool hilite); - void kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite); + void kernelDrawButton(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 style, bool hilite); + void kernelDrawText(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 alignment, int16 style, bool hilite); + void kernelDrawTextEdit(Common::Rect rect, reg_t obj, const char *text, uint16 languageSplitter, int16 fontId, int16 mode, int16 style, int16 cursorPos, int16 maxChars, bool hilite); void kernelDrawIcon(Common::Rect rect, reg_t obj, GuiResourceId viewId, int16 loopNo, int16 celNo, int16 priority, int16 style, bool hilite); void kernelDrawList(Common::Rect rect, reg_t obj, int16 maxChars, int16 count, const char **entries, GuiResourceId fontId, int16 style, int16 upperPos, int16 cursorPos, bool isAlias, bool hilite); void kernelTexteditChange(reg_t controlObject, reg_t eventObject); diff --git a/engines/sci/graphics/cursor.cpp b/engines/sci/graphics/cursor.cpp index 048ec1e9b9..1a58de073c 100644 --- a/engines/sci/graphics/cursor.cpp +++ b/engines/sci/graphics/cursor.cpp @@ -47,7 +47,7 @@ GfxCursor::GfxCursor(ResourceManager *resMan, GfxPalette *palette, GfxScreen *sc _isVisible = true; // center mouse cursor - setPosition(Common::Point(_screen->getWidth() / 2, _screen->getHeight() / 2)); + setPosition(Common::Point(_screen->getScriptWidth() / 2, _screen->getScriptHeight() / 2)); _moveZoneActive = false; _zoomZoneActive = false; @@ -151,14 +151,14 @@ void GfxCursor::kernelSetShape(GuiResourceId resourceId) { colorMapping[0] = 0; // Black is hardcoded colorMapping[1] = _screen->getColorWhite(); // White is also hardcoded colorMapping[2] = SCI_CURSOR_SCI0_TRANSPARENCYCOLOR; - colorMapping[3] = _palette->matchColor(170, 170, 170); // Grey + colorMapping[3] = _palette->matchColor(170, 170, 170) & SCI_PALETTE_MATCH_COLORMASK; // Grey // TODO: Figure out if the grey color is hardcoded // HACK for the magnifier cursor in LB1, fixes its color (bug #3487092) if (g_sci->getGameId() == GID_LAURABOW && resourceId == 1) colorMapping[3] = _screen->getColorWhite(); // HACK for Longbow cursors, fixes the shade of grey they're using (bug #3489101) if (g_sci->getGameId() == GID_LONGBOW) - colorMapping[3] = _palette->matchColor(223, 223, 223); // Light Grey + colorMapping[3] = _palette->matchColor(223, 223, 223) & SCI_PALETTE_MATCH_COLORMASK; // Light Grey // Seek to actual data resourceData += 4; @@ -481,7 +481,7 @@ void GfxCursor::kernelSetPos(Common::Point pos) { void GfxCursor::kernelMoveCursor(Common::Point pos) { _coordAdjuster->moveCursor(pos); - if (pos.x > _screen->getWidth() || pos.y > _screen->getHeight()) { + if (pos.x > _screen->getScriptWidth() || pos.y > _screen->getScriptHeight()) { warning("attempt to place cursor at invalid coordinates (%d, %d)", pos.y, pos.x); return; } diff --git a/engines/sci/graphics/font.cpp b/engines/sci/graphics/font.cpp index e4684ff134..2268ec0459 100644 --- a/engines/sci/graphics/font.cpp +++ b/engines/sci/graphics/font.cpp @@ -48,8 +48,8 @@ GfxFontFromResource::GfxFontFromResource(ResourceManager *resMan, GfxScreen *scr // filling info for every char for (int16 i = 0; i < _numChars; i++) { _chars[i].offset = READ_SCI32ENDIAN_UINT16(_resourceData + 6 + i * 2); - _chars[i].w = _resourceData[_chars[i].offset]; - _chars[i].h = _resourceData[_chars[i].offset + 1]; + _chars[i].width = _resourceData[_chars[i].offset]; + _chars[i].height = _resourceData[_chars[i].offset + 1]; } } @@ -66,10 +66,10 @@ byte GfxFontFromResource::getHeight() { return _fontHeight; } byte GfxFontFromResource::getCharWidth(uint16 chr) { - return chr < _numChars ? _chars[chr].w : 0; + return chr < _numChars ? _chars[chr].width : 0; } byte GfxFontFromResource::getCharHeight(uint16 chr) { - return chr < _numChars ? _chars[chr].h : 0; + return chr < _numChars ? _chars[chr].height : 0; } byte *GfxFontFromResource::getCharData(uint16 chr) { return chr < _numChars ? _resourceData + _chars[chr].offset + 2 : 0; diff --git a/engines/sci/graphics/font.h b/engines/sci/graphics/font.h index 58b2ba4813..451261f315 100644 --- a/engines/sci/graphics/font.h +++ b/engines/sci/graphics/font.h @@ -71,9 +71,11 @@ private: byte *_resourceData; struct Charinfo { - byte w, h; + byte width; + byte height; int16 offset; }; + byte _fontHeight; uint16 _numChars; Charinfo *_chars; diff --git a/engines/sci/graphics/frameout.cpp b/engines/sci/graphics/frameout.cpp index fafc734895..ccc362dc37 100644 --- a/engines/sci/graphics/frameout.cpp +++ b/engines/sci/graphics/frameout.cpp @@ -524,6 +524,10 @@ void GfxFrameout::showVideo() { RobotDecoder *videoDecoder = g_sci->_robotDecoder; uint16 x = videoDecoder->getPos().x; uint16 y = videoDecoder->getPos().y; + uint16 screenWidth = _screen->getWidth(); + uint16 screenHeight = _screen->getHeight(); + uint16 outputWidth; + uint16 outputHeight; if (videoDecoder->hasDirtyPalette()) g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); @@ -532,7 +536,11 @@ void GfxFrameout::showVideo() { if (videoDecoder->needsUpdate()) { const Graphics::Surface *frame = videoDecoder->decodeNextFrame(); if (frame) { - g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, frame->w, frame->h); + // We need to clip here + // At least Phantasmagoria shows a 640x390 video on a 630x450 screen during the intro + outputWidth = frame->w > screenWidth ? screenWidth : frame->w; + outputHeight = frame->h > screenHeight ? screenHeight : frame->h; + g_system->copyRectToScreen(frame->getPixels(), frame->pitch, x, y, outputWidth, outputHeight); if (videoDecoder->hasDirtyPalette()) g_system->getPaletteManager()->setPalette(videoDecoder->getPalette(), 0, 256); diff --git a/engines/sci/graphics/paint16.cpp b/engines/sci/graphics/paint16.cpp index b835eb92ca..6004e9ce7a 100644 --- a/engines/sci/graphics/paint16.cpp +++ b/engines/sci/graphics/paint16.cpp @@ -471,12 +471,9 @@ void GfxPaint16::kernelGraphRedrawBox(Common::Rect rect) { #define SCI_DISPLAY_WIDTH 106 #define SCI_DISPLAY_SAVEUNDER 107 #define SCI_DISPLAY_RESTOREUNDER 108 -#define SCI_DISPLAY_DUMMY1 114 -#define SCI_DISPLAY_DUMMY2 115 -#define SCI_DISPLAY_DUMMY3 117 #define SCI_DISPLAY_DONTSHOWBITS 121 -reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { +reg_t GfxPaint16::kernelDisplay(const char *text, uint16 languageSplitter, int argc, reg_t *argv) { reg_t displayArg; TextAlignment alignment = SCI_TEXT16_ALIGNMENT_LEFT; int16 colorPen = -1, colorBack = -1, width = -1, bRedraw = 1; @@ -543,22 +540,6 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { bRedraw = 0; break; - // The following three dummy calls are not supported by the Sierra SCI - // interpreter, but are erroneously called in some game scripts. - case SCI_DISPLAY_DUMMY1: // Longbow demo (all rooms) and QFG1 EGA demo (room 11) - case SCI_DISPLAY_DUMMY2: // Longbow demo (all rooms) - case SCI_DISPLAY_DUMMY3: // QFG1 EGA demo (room 11) and PQ2 (room 23) - if (!(g_sci->getGameId() == GID_LONGBOW && g_sci->isDemo()) && - !(g_sci->getGameId() == GID_QFG1 && g_sci->isDemo()) && - !(g_sci->getGameId() == GID_PQ2)) - error("Unknown kDisplay argument %d", displayArg.getOffset()); - - if (displayArg.getOffset() == SCI_DISPLAY_DUMMY2) { - if (!argc) - error("No parameter left for kDisplay(115)"); - argc--; argv++; - } - break; default: SciTrackOriginReply originReply; SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kDisplay_workarounds, &originReply); @@ -572,7 +553,7 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { } // now drawing the text - _text16->Size(rect, text, -1, width); + _text16->Size(rect, text, languageSplitter, -1, width); rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop); // Note: This code has been found in SCI1 middle and newer games. It was // previously only for SCI1 late and newer, but the LSL1 interpreter contains @@ -588,7 +569,7 @@ reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { result = bitsSave(rect, GFX_SCREEN_MASK_VISUAL); if (colorBack != -1) fillRect(rect, GFX_SCREEN_MASK_VISUAL, colorBack, 0, 0); - _text16->Box(text, false, rect, alignment, -1); + _text16->Box(text, languageSplitter, false, rect, alignment, -1); if (_screen->_picNotValid == 0 && bRedraw) bitsShow(rect); // restoring port and cursor pos diff --git a/engines/sci/graphics/paint16.h b/engines/sci/graphics/paint16.h index 882f311a5b..955cfdec8f 100644 --- a/engines/sci/graphics/paint16.h +++ b/engines/sci/graphics/paint16.h @@ -80,7 +80,7 @@ public: void kernelGraphUpdateBox(const Common::Rect &rect, bool hiresMode); void kernelGraphRedrawBox(Common::Rect rect); - reg_t kernelDisplay(const char *text, int argc, reg_t *argv); + reg_t kernelDisplay(const char *text, uint16 languageSplitter, int argc, reg_t *argv); reg_t kernelPortraitLoad(const Common::String &resourceName); void kernelPortraitShow(const Common::String &resourceName, Common::Point position, uint16 resourceNum, uint16 noun, uint16 verb, uint16 cond, uint16 seq); diff --git a/engines/sci/graphics/paint32.cpp b/engines/sci/graphics/paint32.cpp index 7d106b5b02..a210a469f1 100644 --- a/engines/sci/graphics/paint32.cpp +++ b/engines/sci/graphics/paint32.cpp @@ -46,7 +46,7 @@ void GfxPaint32::fillRect(Common::Rect rect, byte color) { Common::Rect clipRect = rect; clipRect.clip(_screen->getWidth(), _screen->getHeight()); - + for (y = clipRect.top; y < clipRect.bottom; y++) { for (x = clipRect.left; x < clipRect.right; x++) { _screen->putPixel(x, y, GFX_SCREEN_MASK_VISUAL, color, 0, 0); diff --git a/engines/sci/graphics/palette.cpp b/engines/sci/graphics/palette.cpp index a3624c7959..59abef5550 100644 --- a/engines/sci/graphics/palette.cpp +++ b/engines/sci/graphics/palette.cpp @@ -65,14 +65,21 @@ GfxPalette::GfxPalette(ResourceManager *resMan, GfxScreen *screen) // the real merging done in earlier games. If we use the copying over, we // will get issues because some views have marked all colors as being used // and those will overwrite the current palette in that case - if (getSciVersion() < SCI_VERSION_1_1) + if (getSciVersion() < SCI_VERSION_1_1) { _useMerging = true; - else if (getSciVersion() == SCI_VERSION_1_1) + _use16bitColorMatch = true; + } else if (getSciVersion() == SCI_VERSION_1_1) { // there are some games that use inbetween SCI1.1 interpreter, so we have // to detect if the current game is merging or copying _useMerging = _resMan->detectPaletteMergingSci11(); - else // SCI32 + _use16bitColorMatch = _useMerging; + // Note: Laura Bow 2 floppy uses the new palette format and is detected + // as 8 bit color matching because of that. + } else { + // SCI32 _useMerging = false; + _use16bitColorMatch = false; // not verified that SCI32 uses 8-bit color matching + } palVaryInit(); @@ -120,6 +127,10 @@ bool GfxPalette::isMerging() { return _useMerging; } +bool GfxPalette::isUsing16bitColorMatch() { + return _use16bitColorMatch; +} + // meant to get called only once during init of engine void GfxPalette::setDefault() { if (_resMan->getViewType() == kViewEga) @@ -464,8 +475,8 @@ bool GfxPalette::merge(Palette *newPalette, bool force, bool forceRealMerge) { // check if exact color could be matched res = matchColor(newPalette->colors[i].r, newPalette->colors[i].g, newPalette->colors[i].b); - if (res & 0x8000) { // exact match was found - newPalette->mapping[i] = res & 0xFF; + if (res & SCI_PALETTE_MATCH_PERFECT) { // exact match was found + newPalette->mapping[i] = res & SCI_PALETTE_MATCH_COLORMASK; continue; } @@ -486,8 +497,8 @@ bool GfxPalette::merge(Palette *newPalette, bool force, bool forceRealMerge) { // if still no luck - set an approximate color if (j == 256) { - newPalette->mapping[i] = res & 0xFF; - _sysPalette.colors[res & 0xFF].used |= 0x10; + newPalette->mapping[i] = res & SCI_PALETTE_MATCH_COLORMASK; + _sysPalette.colors[res & SCI_PALETTE_MATCH_COLORMASK].used |= 0x10; } } @@ -509,29 +520,47 @@ void GfxPalette::drewPicture(GuiResourceId pictureId) { } } -uint16 GfxPalette::matchColor(byte r, byte g, byte b) { - byte found = 0xFF; - int diff = 0x2FFFF, cdiff; - int16 dr,dg,db; - - for (int i = 1; i < 255; i++) { - if ((!_sysPalette.colors[i].used)) - continue; - dr = _sysPalette.colors[i].r - r; - dg = _sysPalette.colors[i].g - g; - db = _sysPalette.colors[i].b - b; -// minimum squares match - cdiff = (dr*dr) + (dg*dg) + (db*db); -// minimum sum match (Sierra's) -// cdiff = ABS(dr) + ABS(dg) + ABS(db); - if (cdiff < diff) { - if (cdiff == 0) - return i | 0x8000; // setting this flag to indicate exact match - found = i; - diff = cdiff; +uint16 GfxPalette::matchColor(byte matchRed, byte matchGreen, byte matchBlue) { + int16 colorNr; + int16 differenceRed, differenceGreen, differenceBlue; + int16 differenceTotal = 0; + int16 bestDifference = 0x7FFF; + uint16 bestColorNr = 255; + + if (_use16bitColorMatch) { + // used by SCI0 to SCI1, also by the first few SCI1.1 games + for (colorNr = 0; colorNr < 256; colorNr++) { + if ((!_sysPalette.colors[colorNr].used)) + continue; + differenceRed = ABS(_sysPalette.colors[colorNr].r - matchRed); + differenceGreen = ABS(_sysPalette.colors[colorNr].g - matchGreen); + differenceBlue = ABS(_sysPalette.colors[colorNr].b - matchBlue); + differenceTotal = differenceRed + differenceGreen + differenceBlue; + if (differenceTotal <= bestDifference) { + bestDifference = differenceTotal; + bestColorNr = colorNr; + } + } + } else { + // SCI1.1, starting with QfG3 introduced a bug in the matching code + // we have to implement it as well, otherwise some colors will be "wrong" in comparison to the original interpreter + // See Space Quest 5 bug #6455 + for (colorNr = 0; colorNr < 256; colorNr++) { + if ((!_sysPalette.colors[colorNr].used)) + continue; + differenceRed = (uint8)ABS<int8>(_sysPalette.colors[colorNr].r - matchRed); + differenceGreen = (uint8)ABS<int8>(_sysPalette.colors[colorNr].g - matchGreen); + differenceBlue = (uint8)ABS<int8>(_sysPalette.colors[colorNr].b - matchBlue); + differenceTotal = differenceRed + differenceGreen + differenceBlue; + if (differenceTotal <= bestDifference) { + bestDifference = differenceTotal; + bestColorNr = colorNr; + } } } - return found; + if (differenceTotal == 0) // original interpreter does not do this, instead it does 2 calls for merges in the worst case + return bestColorNr | SCI_PALETTE_MATCH_PERFECT; // we set this flag, so that we can optimize during palette merge + return bestColorNr; } void GfxPalette::getSys(Palette *pal) { @@ -621,7 +650,7 @@ void GfxPalette::kernelSetIntensity(uint16 fromColor, uint16 toColor, uint16 int } int16 GfxPalette::kernelFindColor(uint16 r, uint16 g, uint16 b) { - return matchColor(r, g, b) & 0xFF; + return matchColor(r, g, b) & SCI_PALETTE_MATCH_COLORMASK; } // Returns true, if palette got changed diff --git a/engines/sci/graphics/palette.h b/engines/sci/graphics/palette.h index 347695deb8..500a45eccf 100644 --- a/engines/sci/graphics/palette.h +++ b/engines/sci/graphics/palette.h @@ -31,6 +31,10 @@ namespace Sci { class ResourceManager; class GfxScreen; +// Special flag implemented by us for optimization in palette merge +#define SCI_PALETTE_MATCH_PERFECT 0x8000 +#define SCI_PALETTE_MATCH_COLORMASK 0xFF + enum ColorRemappingType { kRemappingNone = 0, kRemappingByRange = 1, @@ -46,6 +50,7 @@ public: ~GfxPalette(); bool isMerging(); + bool isUsing16bitColorMatch(); void setDefault(); void createFromData(byte *data, int bytesLeft, Palette *paletteOut); @@ -124,6 +129,7 @@ private: bool _sysPaletteChanged; bool _useMerging; + bool _use16bitColorMatch; Common::Array<PalSchedule> _schedules; diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index 434a490109..d7ef84dc1e 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -88,10 +88,13 @@ void GfxPicture::draw(int16 animationNr, bool mirroredFlag, bool addToFlag, int1 } void GfxPicture::reset() { + int16 startY = _ports->getPort()->top; + int16 startX = 0; int16 x, y; - for (y = _ports->getPort()->top; y < _screen->getHeight(); y++) { - for (x = 0; x < _screen->getWidth(); x++) { - _screen->putPixel(x, y, GFX_SCREEN_MASK_ALL, 255, 0, 0); + _screen->vectorAdjustCoordinate(&startX, &startY); + for (y = startY; y < _screen->getHeight(); y++) { + for (x = startX; x < _screen->getWidth(); x++) { + _screen->vectorPutPixel(x, y, GFX_SCREEN_MASK_ALL, 255, 0, 0); } } } @@ -246,7 +249,7 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos int16 y, lastY, x, leftX, rightX; int pixelCount; uint16 width, height; - + // if the picture is not an overlay and we are also not in EGA mode, use priority 0 if (!isEGA && !_addToFlag) priority = 0; @@ -362,7 +365,7 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos ptr = celBitmap; ptr += skipCelBitmapPixels; ptr += skipCelBitmapLines * width; - + if ((!isEGA) || (priority < 16)) { // VGA + EGA, EGA only checks priority, when given priority is below 16 if (!_mirroredFlag) { @@ -482,6 +485,8 @@ enum { PIC_OPX_VGA_PRIORITY_TABLE_EXPLICIT = 4 }; +//#define DEBUG_PICTURE_DRAW 1 + #ifdef DEBUG_PICTURE_DRAW const char *picOpcodeNames[] = { "Set color", @@ -589,6 +594,9 @@ void GfxPicture::drawVectorData(byte *data, int dataSize) { while (curPos < dataSize) { #ifdef DEBUG_PICTURE_DRAW debug("Picture op: %X (%s) at %d", data[curPos], picOpcodeNames[data[curPos] - 0xF0], curPos); + _screen->copyToScreen(); + g_system->updateScreen(); + g_system->delayMillis(400); #endif switch (pic_op = data[curPos++]) { case PIC_OP_SET_COLOR: @@ -934,17 +942,17 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by Common::Point p, p1; byte screenMask = _screen->getDrawingMask(color, priority, control); byte matchedMask, matchMask; - int16 w, e, a_set, b_set; bool isEGA = (_resMan->getViewType() == kViewEga); p.x = x + curPort->left; p.y = y + curPort->top; - stack.push(p); - byte searchColor = _screen->getVisual(p.x, p.y); - byte searchPriority = _screen->getPriority(p.x, p.y); - byte searchControl = _screen->getControl(p.x, p.y); + _screen->vectorAdjustCoordinate(&p.x, &p.y); + + byte searchColor = _screen->vectorGetVisual(p.x, p.y); + byte searchPriority = _screen->vectorGetPriority(p.x, p.y); + byte searchControl = _screen->vectorGetControl(p.x, p.y); if (isEGA) { // In EGA games a pixel in the framebuffer is only 4 bits. We store @@ -991,22 +999,31 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by } // hard borders for filling - int l = curPort->rect.left + curPort->left; - int t = curPort->rect.top + curPort->top; - int r = curPort->rect.right + curPort->left - 1; - int b = curPort->rect.bottom + curPort->top - 1; + int16 borderLeft = curPort->rect.left + curPort->left; + int16 borderTop = curPort->rect.top + curPort->top; + int16 borderRight = curPort->rect.right + curPort->left - 1; + int16 borderBottom = curPort->rect.bottom + curPort->top - 1; + int16 curToLeft, curToRight, a_set, b_set; + + // Translate coordinates, if required (needed for Macintosh 480x300) + _screen->vectorAdjustCoordinate(&borderLeft, &borderTop); + _screen->vectorAdjustCoordinate(&borderRight, &borderBottom); + //return; + + stack.push(p); + while (stack.size()) { p = stack.pop(); - if ((matchedMask = _screen->isFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)) == 0) // already filled + if ((matchedMask = _screen->vectorIsFillMatch(p.x, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA)) == 0) // already filled continue; - _screen->putPixel(p.x, p.y, screenMask, color, priority, control); - w = p.x; - e = p.x; + _screen->vectorPutPixel(p.x, p.y, screenMask, color, priority, control); + curToLeft = p.x; + curToRight = p.x; // moving west and east pointers as long as there is a matching color to fill - while (w > l && (matchedMask = _screen->isFillMatch(w - 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA))) - _screen->putPixel(--w, p.y, screenMask, color, priority, control); - while (e < r && (matchedMask = _screen->isFillMatch(e + 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA))) - _screen->putPixel(++e, p.y, screenMask, color, priority, control); + while (curToLeft > borderLeft && (matchedMask = _screen->vectorIsFillMatch(curToLeft - 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA))) + _screen->vectorPutPixel(--curToLeft, p.y, screenMask, color, priority, control); + while (curToRight < borderRight && (matchedMask = _screen->vectorIsFillMatch(curToRight + 1, p.y, matchMask, searchColor, searchPriority, searchControl, isEGA))) + _screen->vectorPutPixel(++curToRight, p.y, screenMask, color, priority, control); #if 0 // debug code for floodfill _screen->copyToScreen(); @@ -1015,10 +1032,10 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by #endif // checking lines above and below for possible flood targets a_set = b_set = 0; - while (w <= e) { - if (p.y > t && (matchedMask = _screen->isFillMatch(w, p.y - 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line above + while (curToLeft <= curToRight) { + if (p.y > borderTop && (matchedMask = _screen->vectorIsFillMatch(curToLeft, p.y - 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line above if (a_set == 0) { - p1.x = w; + p1.x = curToLeft; p1.y = p.y - 1; stack.push(p1); a_set = 1; @@ -1026,16 +1043,16 @@ void GfxPicture::vectorFloodFill(int16 x, int16 y, byte color, byte priority, by } else a_set = 0; - if (p.y < b && (matchedMask = _screen->isFillMatch(w, p.y + 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line below + if (p.y < borderBottom && (matchedMask = _screen->vectorIsFillMatch(curToLeft, p.y + 1, matchMask, searchColor, searchPriority, searchControl, isEGA))) { // one line below if (b_set == 0) { - p1.x = w; + p1.x = curToLeft; p1.y = p.y + 1; stack.push(p1); b_set = 1; } } else b_set = 0; - w++; + curToLeft++; } } } @@ -1173,7 +1190,7 @@ void GfxPicture::vectorPatternBox(Common::Rect box, byte color, byte prio, byte for (y = box.top; y < box.bottom; y++) { for (x = box.left; x < box.right; x++) { - _screen->putPixel(x, y, flag, color, prio, control); + _screen->vectorPutPixel(x, y, flag, color, prio, control); } } } @@ -1186,7 +1203,7 @@ void GfxPicture::vectorPatternTexturedBox(Common::Rect box, byte color, byte pri for (y = box.top; y < box.bottom; y++) { for (x = box.left; x < box.right; x++) { if (*textureData) { - _screen->putPixel(x, y, flag, color, prio, control); + _screen->vectorPutPixel(x, y, flag, color, prio, control); } textureData++; } @@ -1203,7 +1220,7 @@ void GfxPicture::vectorPatternCircle(Common::Rect box, byte size, byte color, by for (y = box.top; y < box.bottom; y++) { for (x = box.left; x < box.right; x++) { if (bitmap & 1) { - _screen->putPixel(x, y, flag, color, prio, control); + _screen->vectorPutPixel(x, y, flag, color, prio, control); } bitNo++; if (bitNo == 8) { @@ -1222,12 +1239,12 @@ void GfxPicture::vectorPatternTexturedCircle(Common::Rect box, byte size, byte c byte bitNo = 0; const bool *textureData = &vectorPatternTextures[vectorPatternTextureOffset[texture]]; int y, x; - + for (y = box.top; y < box.bottom; y++) { for (x = box.left; x < box.right; x++) { if (bitmap & 1) { if (*textureData) { - _screen->putPixel(x, y, flag, color, prio, control); + _screen->vectorPutPixel(x, y, flag, color, prio, control); } textureData++; } @@ -1252,7 +1269,10 @@ void GfxPicture::vectorPattern(int16 x, int16 y, byte color, byte priority, byte rect.top = y; rect.left = x; rect.setHeight((size*2)+1); rect.setWidth((size*2)+2); _ports->offsetRect(rect); - rect.clip(_screen->getWidth(), _screen->getHeight()); + rect.clip(_screen->getScriptWidth(), _screen->getScriptHeight()); + + _screen->vectorAdjustCoordinate(&rect.left, &rect.top); + _screen->vectorAdjustCoordinate(&rect.right, &rect.bottom); if (code & SCI_PATTERN_CODE_RECTANGLE) { // Rectangle diff --git a/engines/sci/graphics/portrait.cpp b/engines/sci/graphics/portrait.cpp index 488450485d..cb425f3be9 100644 --- a/engines/sci/graphics/portrait.cpp +++ b/engines/sci/graphics/portrait.cpp @@ -57,13 +57,39 @@ void Portrait::init() { // 4 bytes paletteSize (base 1) // -> 17 bytes // paletteSize bytes paletteData - // 14 bytes bitmap header - // -> 4 bytes unknown - // -> 2 bytes height - // -> 2 bytes width - // -> 6 bytes unknown - // height * width bitmap data - // another animation count times bitmap header and data + // + // bitmap-data follows, total of [animation count] + // 14 bytes bitmap header + // -> 4 bytes unknown + // -> 2 bytes height + // -> 2 bytes width + // -> 6 bytes unknown + // height * width bitmap data + // + // 4 bytes offset table size (may be larger than the actual known entries?!) + // 14 bytes all zeroes (dummy entry?!) + // + // 14 bytes for each entry + // -> 2 bytes displace X + // -> 2 bytes displace Y + // -> 2 bytes height (again) + // -> 2 bytes width (again) + // -> 6 bytes unknown (normally 01 00 00 00 00 00 for delta bitmaps, 00 00 00 00 00 00 for first bitmap) + // random data may be used as filler + // + // 4 bytes lip sync id table size (is [lip sync id count] * 4, should be 0x2E0 for all actors) + // 4 bytes per lip sync id + // -> 1 byte length of ID + // -> 3 bytes actual ID + // + // 4 bytes lip sync id data table size (seems to be the same for all actors, always 0x220 in size) + // 1 byte animation number or 0xFF as terminator + // 1 byte delay, if last byte was not terminator + // one array for every lip sync id + // + // 4 bytes appended, seem to be random + // 9E11120E for alex + // 9E9E9E9E for vizier int32 fileSize = 0; Common::SeekableReadStream *file = SearchMan.createReadStreamForMember("actors/" + _resourceName + ".bin"); @@ -134,34 +160,34 @@ void Portrait::init() { // raw lip-sync ID table follows uint32 lipSyncIDTableSize; - + lipSyncIDTableSize = READ_LE_UINT32(data); data += 4; assert( lipSyncIDTableSize == (_lipSyncIDCount * 4) ); _lipSyncIDTable = data; data += lipSyncIDTableSize; - + // raw lip-sync frame table follows uint32 lipSyncDataTableSize; uint32 lipSyncDataTableLastOffset; byte lipSyncData; uint16 lipSyncDataNr; uint16 lipSyncCurOffset; - + lipSyncDataTableSize = READ_LE_UINT32(data); data += 4; assert( lipSyncDataTableSize == 0x220 ); // always this size, just a safety-check - + _lipSyncData = data; lipSyncDataTableLastOffset = lipSyncDataTableSize - 1; _lipSyncDataOffsetTable = new uint16[ _lipSyncIDCount ]; - + lipSyncDataNr = 0; lipSyncCurOffset = 0; while ( (lipSyncCurOffset < lipSyncDataTableSize) && (lipSyncDataNr < _lipSyncIDCount) ) { // We are currently at the start of ID-frame data _lipSyncDataOffsetTable[lipSyncDataNr] = lipSyncCurOffset; - + // Look for end of ID-frame data lipSyncData = *data++; lipSyncCurOffset++; while ( (lipSyncData != 0xFF) && (lipSyncCurOffset < lipSyncDataTableLastOffset) ) { @@ -195,15 +221,16 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint Resource *syncResource = _resMan->findResource(syncResourceId, true); uint syncOffset = 0; #endif - + #ifdef DEBUG_PORTRAIT // prints out the current lip sync ASCII data char debugPrint[4000]; if (raveResource->size < 4000) { memcpy(debugPrint, raveResource->data, raveResource->size); debugPrint[raveResource->size] = 0; // set terminating NUL + debug("kPortrait: using actor %s", _resourceName.c_str()); debug("kPortrait (noun %d, verb %d, cond %d, seq %d)", noun, verb, cond, seq); - debug("kPortrait: %s", debugPrint); + debug("kPortrait: rave data is '%s'", debugPrint); } #endif @@ -246,7 +273,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint warning("kPortrait: no rave resource %d %X", resourceId, audioNumber); return; } - + // Do animation depending on rave resource till audio is done playing int16 raveTicks; uint16 raveID; @@ -264,7 +291,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint raveTicks = raveGetTicks(raveResource, &raveOffset); if (raveTicks < 0) break; - + // get lipSyncID raveID = raveGetID(raveResource, &raveOffset); if (raveID) { @@ -272,7 +299,15 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint } else { raveLipSyncData = NULL; } - + +#ifdef DEBUG_PORTRAIT + if (raveID & 0x0ff) { + debug("kPortrait: rave '%c%c' after %d ticks", raveID >> 8, raveID & 0x0ff, raveTicks); + } else if (raveID) { + debug("kPortrait: rave '%c' after %d ticks", raveID >> 8, raveTicks); + } +#endif + timerPosition += raveTicks; // Wait till syncTime passed, then show specific animation bitmap @@ -282,12 +317,13 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint curEvent = _event->getSciEvent(SCI_EVENT_ANY); if (curEvent.type == SCI_EVENT_MOUSE_PRESS || (curEvent.type == SCI_EVENT_KEYBOARD && curEvent.data == SCI_KEY_ESC) || - g_sci->getEngineState()->abortScriptProcessing == kAbortQuitGame) + g_sci->getEngineState()->abortScriptProcessing == kAbortQuitGame || + g_sci->getEngineState()->_delayedRestoreGame) userAbort = true; curPosition = _audio->getAudioPosition(); } while ((curPosition != -1) && (curPosition < timerPosition) && (!userAbort)); } - + if (raveLipSyncData) { // lip sync data is // Tick:Byte, Bitmap-Nr:BYTE @@ -295,6 +331,8 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint timerPositionWithin = timerPosition; raveLipSyncTicks = *raveLipSyncData++; while ( (raveLipSyncData < _lipSyncDataOffsetTableEnd) && (raveLipSyncTicks != 0xFF) ) { + if (raveLipSyncTicks) + raveLipSyncTicks--; // 1 -> wait 0 ticks, 2 -> wait 1 tick, etc. timerPositionWithin += raveLipSyncTicks; do { @@ -308,7 +346,14 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint } while ((curPosition != -1) && (curPosition < timerPositionWithin) && (!userAbort)); raveLipSyncBitmapNr = *raveLipSyncData++; - +#ifdef DEBUG_PORTRAIT + if (!raveLipSyncTicks) { + debug("kPortrait: showing frame %d", raveLipSyncBitmapNr); + } else { + debug("kPortrait: showing frame %d after %d ticks", raveLipSyncBitmapNr, raveLipSyncTicks); + } +#endif + // bitmap nr within sync data is base 1, we need base 0 raveLipSyncBitmapNr--; @@ -319,7 +364,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint } else { warning("kPortrait: rave lip sync data tried to draw non-existent bitmap %d", raveLipSyncBitmapNr); } - + raveLipSyncTicks = *raveLipSyncData++; } } @@ -372,7 +417,7 @@ void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint } } #endif - + // Reset the portrait bitmap to "closed mouth" state (rave.dll seems to do the same) drawBitmap(0); bitsShow(); @@ -393,10 +438,10 @@ int16 Portrait::raveGetTicks(Resource *resource, uint *offset) { byte *curData = resource->data + curOffset; byte curByte; uint16 curValue = 0; - + if (curOffset >= resource->size) return -1; - + while (curOffset < resource->size) { curByte = *curData++; curOffset++; if ( curByte == ' ' ) @@ -418,7 +463,7 @@ uint16 Portrait::raveGetID(Resource *resource, uint *offset) { byte *curData = resource->data + curOffset; byte curByte = 0; uint16 curValue = 0; - + while (curOffset < resource->size) { curByte = *curData++; curOffset++; if ( curByte == ' ' ) @@ -429,7 +474,7 @@ uint16 Portrait::raveGetID(Resource *resource, uint *offset) { curValue |= curByte; } } - + *offset = curOffset; return curValue; } @@ -440,17 +485,17 @@ byte *Portrait::raveGetLipSyncData(uint16 raveID) { byte *lipSyncIDPtr = _lipSyncIDTable; byte lipSyncIDByte1, lipSyncIDByte2; uint16 lipSyncID; - + lipSyncIDPtr++; // skip over first byte while (lipSyncIDNr < _lipSyncIDCount) { lipSyncIDByte1 = *lipSyncIDPtr++; lipSyncIDByte2 = *lipSyncIDPtr++; lipSyncID = ( lipSyncIDByte1 << 8 ) | lipSyncIDByte2; - + if ( lipSyncID == raveID ) { return _lipSyncData + _lipSyncDataOffsetTable[lipSyncIDNr]; } - + lipSyncIDNr++; lipSyncIDPtr += 2; // ID is every 4 bytes } diff --git a/engines/sci/graphics/portrait.h b/engines/sci/graphics/portrait.h index 877b253bcf..e0888daa86 100644 --- a/engines/sci/graphics/portrait.h +++ b/engines/sci/graphics/portrait.h @@ -72,7 +72,7 @@ private: Common::String _resourceName; byte *_fileData; - + uint32 _lipSyncIDCount; byte *_lipSyncIDTable; diff --git a/engines/sci/graphics/ports.cpp b/engines/sci/graphics/ports.cpp index 56c63a7b12..bcc991081e 100644 --- a/engines/sci/graphics/ports.cpp +++ b/engines/sci/graphics/ports.cpp @@ -63,10 +63,10 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te openPort(_menuPort); setPort(_menuPort); _text16->SetFont(0); - _menuPort->rect = Common::Rect(0, 0, _screen->getWidth(), _screen->getHeight()); - _menuBarRect = Common::Rect(0, 0, _screen->getWidth(), 9); - _menuRect = Common::Rect(0, 0, _screen->getWidth(), 10); - _menuLine = Common::Rect(0, 9, _screen->getWidth(), 10); + _menuPort->rect = Common::Rect(0, 0, _screen->getScriptWidth(), _screen->getScriptHeight()); + _menuBarRect = Common::Rect(0, 0, _screen->getScriptWidth(), 9); + _menuRect = Common::Rect(0, 0, _screen->getScriptWidth(), 10); + _menuLine = Common::Rect(0, 9, _screen->getScriptWidth(), 10); _wmgrPort = new Port(1); _windowsById.resize(2); @@ -122,13 +122,13 @@ void GfxPorts::init(bool usesOldGfxFunctions, GfxPaint16 *paint16, GfxText16 *te } else { _wmgrPort->rect.bottom = _screen->getHeight(); } - _wmgrPort->rect.right = _screen->getWidth(); + _wmgrPort->rect.right = _screen->getScriptWidth(); _wmgrPort->rect.moveTo(0, 0); _wmgrPort->curTop = 0; _wmgrPort->curLeft = 0; _windowList.push_front(_wmgrPort); - _picWind = addWindow(Common::Rect(0, offTop, _screen->getWidth(), _screen->getHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true); + _picWind = addWindow(Common::Rect(0, offTop, _screen->getScriptWidth(), _screen->getScriptHeight()), 0, 0, SCI_WINDOWMGR_STYLE_TRANSPARENT | SCI_WINDOWMGR_STYLE_NOFRAME, 0, true); // For SCI0 games till kq4 (.502 - not including) we set _picWind top to offTop instead // Because of the menu/status bar if (_usesOldGfxFunctions) @@ -321,13 +321,13 @@ Window *GfxPorts::addWindow(const Common::Rect &dims, const Common::Rect *restor // their interpreter even in the newer VGA games. r.left = r.left & 0xFFFE; - if (r.width() > _screen->getWidth()) { + if (r.width() > _screen->getScriptWidth()) { // We get invalid dimensions at least at the end of sq3 (script bug!). // Same happens very often in lsl5, sierra sci didnt fix it but it looked awful. // Also happens frequently in the demo of GK1. warning("Fixing too large window, left: %d, right: %d", dims.left, dims.right); r.left = 0; - r.right = _screen->getWidth() - 1; + r.right = _screen->getScriptWidth() - 1; if ((style != _styleUser) && !(style & SCI_WINDOWMGR_STYLE_NOFRAME)) r.right--; } diff --git a/engines/sci/graphics/screen.cpp b/engines/sci/graphics/screen.cpp index c5c94d7991..ca5b5b3b8c 100644 --- a/engines/sci/graphics/screen.cpp +++ b/engines/sci/graphics/screen.cpp @@ -37,7 +37,15 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { // Scale the screen, if needed _upscaledHires = GFX_SCREEN_UPSCALED_DISABLED; - + + // we default to scripts running at 320x200 + _scriptWidth = 320; + _scriptHeight = 200; + _width = 0; + _height = 0; + _displayWidth = 0; + _displayHeight = 0; + // King's Quest 6 and Gabriel Knight 1 have hires content, gk1/cd was able // to provide that under DOS as well, but as gk1/floppy does support // upscaled hires scriptswise, but doesn't actually have the hires content @@ -50,10 +58,34 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { _upscaledHires = GFX_SCREEN_UPSCALED_640x480; #endif } + + // Japanese versions of games use hi-res font on upscaled version of the game. + if ((g_sci->getLanguage() == Common::JA_JPN) && (getSciVersion() <= SCI_VERSION_1_1)) + _upscaledHires = GFX_SCREEN_UPSCALED_640x400; + // Macintosh SCI0 games used 480x300, while the scripts were running at 320x200 if (g_sci->getPlatform() == Common::kPlatformMacintosh) { - if (getSciVersion() <= SCI_VERSION_01) + if (getSciVersion() <= SCI_VERSION_01) { _upscaledHires = GFX_SCREEN_UPSCALED_480x300; + _width = 480; + _height = 300; // regular visual, priority and control map are 480x300 (this is different than other upscaled SCI games) + } + + // Some Mac SCI1/1.1 games only take up 190 rows and do not + // have the menu bar. + // TODO: Verify that LSL1 and LSL5 use height 190 + switch (g_sci->getGameId()) { + case GID_FREDDYPHARKAS: + case GID_KQ5: + case GID_KQ6: + case GID_LSL1: + case GID_LSL5: + case GID_SQ1: + _scriptHeight = 190; + break; + default: + break; + } } #ifdef ENABLE_SCI32 @@ -65,76 +97,77 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { #endif if (_resMan->detectHires()) { - _width = 640; - _pitch = 640; - _height = 480; - } else { - _width = 320; - _pitch = 320; - _height = getLowResScreenHeight(); + _scriptWidth = 640; + _scriptHeight = 480; } #ifdef ENABLE_SCI32 - // Phantasmagoria 1 sets a window area of 630x450 + // Phantasmagoria 1 effectively outputs 630x450 + // Coordinate translation has to use this resolution as well if (g_sci->getGameId() == GID_PHANTASMAGORIA) { _width = 630; _height = 450; } #endif - // Japanese versions of games use hi-res font on upscaled version of the game. - if ((g_sci->getLanguage() == Common::JA_JPN) && (getSciVersion() <= SCI_VERSION_1_1)) - _upscaledHires = GFX_SCREEN_UPSCALED_640x400; + // if not yet set, set those to script-width/height + if (!_width) + _width = _scriptWidth; + if (!_height) + _height = _scriptHeight; - _pixels = _pitch * _height; + _pixels = _width * _height; switch (_upscaledHires) { case GFX_SCREEN_UPSCALED_480x300: // Space Quest 3, Hoyle 1+2 on MAC use this one - // TODO: Sierra's upscaling worked differently. We need to figure out the exact algo _displayWidth = 480; _displayHeight = 300; - for (int i = 0; i <= _height; i++) + for (int i = 0; i <= _scriptHeight; i++) _upscaledHeightMapping[i] = (i * 3) >> 1; - for (int i = 0; i <= _width; i++) + for (int i = 0; i <= _scriptWidth; i++) _upscaledWidthMapping[i] = (i * 3) >> 1; break; case GFX_SCREEN_UPSCALED_640x400: // Police Quest 2 and Quest For Glory on PC9801 (Japanese) _displayWidth = 640; _displayHeight = 400; - for (int i = 0; i <= _height; i++) + for (int i = 0; i <= _scriptHeight; i++) _upscaledHeightMapping[i] = i * 2; - for (int i = 0; i <= _width; i++) + for (int i = 0; i <= _scriptWidth; i++) _upscaledWidthMapping[i] = i * 2; break; case GFX_SCREEN_UPSCALED_640x440: // used by King's Quest 6 on Windows _displayWidth = 640; _displayHeight = 440; - for (int i = 0; i <= _height; i++) + for (int i = 0; i <= _scriptHeight; i++) _upscaledHeightMapping[i] = (i * 11) / 5; - for (int i = 0; i <= _width; i++) + for (int i = 0; i <= _scriptWidth; i++) _upscaledWidthMapping[i] = i * 2; break; case GFX_SCREEN_UPSCALED_640x480: // Gabriel Knight 1 (VESA, Mac) _displayWidth = 640; _displayHeight = 480; - for (int i = 0; i <= _height; i++) + for (int i = 0; i <= _scriptHeight; i++) _upscaledHeightMapping[i] = (i * 12) / 5; - for (int i = 0; i <= _width; i++) + for (int i = 0; i <= _scriptWidth; i++) _upscaledWidthMapping[i] = i * 2; break; default: - _displayWidth = _pitch; - _displayHeight = _height; + if (!_displayWidth) + _displayWidth = _width; + if (!_displayHeight) + _displayHeight = _height; memset(&_upscaledHeightMapping, 0, sizeof(_upscaledHeightMapping) ); memset(&_upscaledWidthMapping, 0, sizeof(_upscaledWidthMapping) ); break; } _displayPixels = _displayWidth * _displayHeight; + + // Allocate visual, priority, control and display screen _visualScreen = (byte *)calloc(_pixels, 1); _priorityScreen = (byte *)calloc(_pixels, 1); _controlScreen = (byte *)calloc(_pixels, 1); @@ -179,6 +212,36 @@ GfxScreen::GfxScreen(ResourceManager *resMan) : _resMan(resMan) { error("Unknown SCI1.1 Mac game"); } else initGraphics(_displayWidth, _displayHeight, _displayWidth > 320); + + // Initialize code pointers + _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinateNOP; + _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinatesNOP; + _vectorIsFillMatchPtr = &GfxScreen::vectorIsFillMatchNormal; + _vectorPutPixelPtr = &GfxScreen::putPixelNormal; + _vectorPutLinePixelPtr = &GfxScreen::putPixel; + _vectorGetPixelPtr = &GfxScreen::getPixelNormal; + _putPixelPtr = &GfxScreen::putPixelNormal; + _getPixelPtr = &GfxScreen::getPixelNormal; + + switch (_upscaledHires) { + case GFX_SCREEN_UPSCALED_480x300: + _vectorAdjustCoordinatePtr = &GfxScreen::vectorAdjustCoordinate480x300Mac; + _vectorAdjustLineCoordinatesPtr = &GfxScreen::vectorAdjustLineCoordinates480x300Mac; + // vectorPutPixel -> we already adjust coordinates for vector code, that's why we can set pixels directly + // vectorGetPixel -> see vectorPutPixel + _vectorPutLinePixelPtr = &GfxScreen::vectorPutLinePixel480x300Mac; + _putPixelPtr = &GfxScreen::putPixelAllUpscaled; + _getPixelPtr = &GfxScreen::getPixelUpscaled; + break; + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: + _vectorPutPixelPtr = &GfxScreen::putPixelDisplayUpscaled; + _putPixelPtr = &GfxScreen::putPixelDisplayUpscaled; + break; + case GFX_SCREEN_UPSCALED_DISABLED: + break; + } } GfxScreen::~GfxScreen() { @@ -188,6 +251,18 @@ GfxScreen::~GfxScreen() { free(_displayScreen); } +// should not be used regularly; only meant for restore game +void GfxScreen::clearForRestoreGame() { + // reset all screen data + memset(_visualScreen, 0, _pixels); + memset(_priorityScreen, 0, _pixels); + memset(_controlScreen, 0, _pixels); + memset(_displayScreen, 0, _displayPixels); + memset(&_ditheredPicColors, 0, sizeof(_ditheredPicColors)); + _fontIsUpscaled = false; + copyToScreen(); +} + void GfxScreen::copyToScreen() { g_system->copyRectToScreen(_activeScreen, _displayWidth, 0, 0, _displayWidth, _displayHeight); } @@ -232,7 +307,7 @@ void GfxScreen::copyRectToScreen(const Common::Rect &rect, int16 x, int16 y) { } else { int rectHeight = _upscaledHeightMapping[rect.bottom] - _upscaledHeightMapping[rect.top]; int rectWidth = _upscaledWidthMapping[rect.right] - _upscaledWidthMapping[rect.left]; - + g_system->copyRectToScreen(_activeScreen + _upscaledHeightMapping[rect.top] * _displayWidth + _upscaledWidthMapping[rect.left], _displayWidth, _upscaledWidthMapping[x], _upscaledHeightMapping[y], rectWidth, rectHeight); } } @@ -248,43 +323,162 @@ byte GfxScreen::getDrawingMask(byte color, byte prio, byte control) { return flag; } -void GfxScreen::putPixel(int x, int y, byte drawMask, byte color, byte priority, byte control) { - int offset = y * _pitch + x; +void GfxScreen::vectorAdjustCoordinateNOP(int16 *x, int16 *y) { +} - if (drawMask & GFX_SCREEN_MASK_VISUAL) { - _visualScreen[offset] = color; - if (!_upscaledHires) { - _displayScreen[offset] = color; +void GfxScreen::vectorAdjustCoordinate480x300Mac(int16 *x, int16 *y) { + *x = _upscaledWidthMapping[*x]; + *y = _upscaledHeightMapping[*y]; +} + +void GfxScreen::vectorAdjustLineCoordinatesNOP(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { +} + +void GfxScreen::vectorAdjustLineCoordinates480x300Mac(int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { + int16 displayLeft = _upscaledWidthMapping[*left]; + int16 displayRight = _upscaledWidthMapping[*right]; + int16 displayTop = _upscaledHeightMapping[*top]; + int16 displayBottom = _upscaledHeightMapping[*bottom]; + + if (displayLeft < displayRight) { + // one more pixel to the left, one more pixel to the right + if (displayLeft > 0) + vectorPutLinePixel(displayLeft - 1, displayTop, drawMask, color, priority, control); + vectorPutLinePixel(displayRight + 1, displayBottom, drawMask, color, priority, control); + } else if (displayLeft > displayRight) { + if (displayRight > 0) + vectorPutLinePixel(displayRight - 1, displayBottom, drawMask, color, priority, control); + vectorPutLinePixel(displayLeft + 1, displayTop, drawMask, color, priority, control); + } + *left = displayLeft; + *top = displayTop; + *right = displayRight; + *bottom = displayBottom; +} + +byte GfxScreen::vectorIsFillMatchNormal(int16 x, int16 y, byte screenMask, byte checkForColor, byte checkForPriority, byte checkForControl, bool isEGA) { + int offset = y * _width + x; + byte match = 0; + + if (screenMask & GFX_SCREEN_MASK_VISUAL) { + if (!isEGA) { + if (*(_visualScreen + offset) == checkForColor) + match |= GFX_SCREEN_MASK_VISUAL; } else { - putScaledPixelOnDisplay(x, y, color); + // In EGA games a pixel in the framebuffer is only 4 bits. We store + // a full byte per pixel to allow undithering, but when comparing + // pixels for flood-fill purposes, we should only compare the + // visible color of a pixel. + + byte EGAcolor = *(_visualScreen + offset); + if ((x ^ y) & 1) + EGAcolor = (EGAcolor ^ (EGAcolor >> 4)) & 0x0F; + else + EGAcolor = EGAcolor & 0x0F; + if (EGAcolor == checkForColor) + match |= GFX_SCREEN_MASK_VISUAL; } } + if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == checkForPriority) + match |= GFX_SCREEN_MASK_PRIORITY; + if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == checkForControl) + match |= GFX_SCREEN_MASK_CONTROL; + return match; +} + +// Special 480x300 Mac putPixel for vector line drawing, also draws an additional pixel below the actual one +void GfxScreen::vectorPutLinePixel480x300Mac(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + _visualScreen[offset + _width] = color; + _displayScreen[offset] = color; + // also set pixel below actual pixel + _displayScreen[offset + _displayWidth] = color; + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) { + _priorityScreen[offset] = priority; + _priorityScreen[offset + _width] = priority; + } + if (drawMask & GFX_SCREEN_MASK_CONTROL) { + _controlScreen[offset] = control; + _controlScreen[offset + _width] = control; + } +} + +// Directly sets a pixel on various screens, display is not upscaled +void GfxScreen::putPixelNormal(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + _displayScreen[offset] = color; + } if (drawMask & GFX_SCREEN_MASK_PRIORITY) _priorityScreen[offset] = priority; if (drawMask & GFX_SCREEN_MASK_CONTROL) _controlScreen[offset] = control; } +// Directly sets a pixel on various screens, display IS upscaled +void GfxScreen::putPixelDisplayUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + int offset = y * _width + x; + + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + _visualScreen[offset] = color; + putScaledPixelOnScreen(_displayScreen, x, y, color); + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) + _priorityScreen[offset] = priority; + if (drawMask & GFX_SCREEN_MASK_CONTROL) + _controlScreen[offset] = control; +} + +// Directly sets a pixel on various screens, ALL screens ARE upscaled +void GfxScreen::putPixelAllUpscaled(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + if (drawMask & GFX_SCREEN_MASK_VISUAL) { + putScaledPixelOnScreen(_visualScreen, x, y, color); + putScaledPixelOnScreen(_displayScreen, x, y, color); + } + if (drawMask & GFX_SCREEN_MASK_PRIORITY) + putScaledPixelOnScreen(_priorityScreen, x, y, priority); + if (drawMask & GFX_SCREEN_MASK_CONTROL) + putScaledPixelOnScreen(_controlScreen, x, y, control); +} + /** * This is used to put font pixels onto the screen - we adjust differently, so that we won't * do triple pixel lines in any case on upscaled hires. That way the font will not get distorted * Sierra SCI didn't do this */ -void GfxScreen::putFontPixel(int startingY, int x, int y, byte color) { - int actualY = startingY + y; +void GfxScreen::putFontPixel(int16 startingY, int16 x, int16 y, byte color) { + int16 actualY = startingY + y; if (_fontIsUpscaled) { // Do not scale ourselves, but put it on the display directly putPixelOnDisplay(x, actualY, color); } else { - int offset = actualY * _pitch + x; + int offset = actualY * _width + x; _visualScreen[offset] = color; switch (_upscaledHires) { case GFX_SCREEN_UPSCALED_DISABLED: _displayScreen[offset] = color; break; + case GFX_SCREEN_UPSCALED_640x400: + case GFX_SCREEN_UPSCALED_640x440: + case GFX_SCREEN_UPSCALED_640x480: { + // to 1-> 4 pixels upscaling for all of those, so that fonts won't look weird + int displayOffset = (_upscaledHeightMapping[startingY] + y * 2) * _displayWidth + x * 2; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + displayOffset += _displayWidth; + _displayScreen[displayOffset] = color; + _displayScreen[displayOffset + 1] = color; + break; + } default: - putScaledPixelOnDisplay(x, actualY, color); + putScaledPixelOnScreen(_displayScreen, x, actualY, color); break; } } @@ -295,12 +489,15 @@ void GfxScreen::putFontPixel(int startingY, int x, int y, byte color) { * only used on upscaled-Hires games where hires content needs to get drawn ONTO * the upscaled display screen (like japanese fonts, hires portraits, etc.). */ -void GfxScreen::putPixelOnDisplay(int x, int y, byte color) { +void GfxScreen::putPixelOnDisplay(int16 x, int16 y, byte color) { int offset = y * _displayWidth + x; _displayScreen[offset] = color; } -void GfxScreen::putScaledPixelOnDisplay(int x, int y, byte color) { +//void GfxScreen::putScaledPixelOnDisplay(int16 x, int16 y, byte color) { +//} + +void GfxScreen::putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte data) { int displayOffset = _upscaledHeightMapping[y] * _displayWidth + _upscaledWidthMapping[x]; int heightOffsetBreak = (_upscaledHeightMapping[y + 1] - _upscaledHeightMapping[y]) * _displayWidth; int heightOffset = 0; @@ -308,7 +505,7 @@ void GfxScreen::putScaledPixelOnDisplay(int x, int y, byte color) { do { int widthOffset = 0; do { - _displayScreen[displayOffset + heightOffset + widthOffset] = color; + screen[displayOffset + heightOffset + widthOffset] = data; widthOffset++; } while (widthOffset != widthOffsetBreak); heightOffset += _displayWidth; @@ -329,16 +526,18 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte int16 top = CLIP<int16>(startPoint.y, 0, maxHeight); int16 right = CLIP<int16>(endPoint.x, 0, maxWidth); int16 bottom = CLIP<int16>(endPoint.y, 0, maxHeight); - + //set_drawing_flag byte drawMask = getDrawingMask(color, priority, control); + vectorAdjustLineCoordinates(&left, &top, &right, &bottom, drawMask, color, priority, control); + // horizontal line if (top == bottom) { if (right < left) SWAP(right, left); for (int i = left; i <= right; i++) - putPixel(i, top, drawMask, color, priority, control); + vectorPutLinePixel(i, top, drawMask, color, priority, control); return; } // vertical line @@ -346,20 +545,20 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte if (top > bottom) SWAP(top, bottom); for (int i = top; i <= bottom; i++) - putPixel(left, i, drawMask, color, priority, control); + vectorPutLinePixel(left, i, drawMask, color, priority, control); return; } // sloped line - draw with Bresenham algorithm - int dy = bottom - top; - int dx = right - left; - int stepy = dy < 0 ? -1 : 1; - int stepx = dx < 0 ? -1 : 1; + int16 dy = bottom - top; + int16 dx = right - left; + int16 stepy = dy < 0 ? -1 : 1; + int16 stepx = dx < 0 ? -1 : 1; dy = ABS(dy) << 1; dx = ABS(dx) << 1; // setting the 1st and last pixel - putPixel(left, top, drawMask, color, priority, control); - putPixel(right, bottom, drawMask, color, priority, control); + vectorPutLinePixel(left, top, drawMask, color, priority, control); + vectorPutLinePixel(right, bottom, drawMask, color, priority, control); // drawing the line if (dx > dy) { // going horizontal int fraction = dy - (dx >> 1); @@ -370,7 +569,7 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte } left += stepx; fraction += dy; - putPixel(left, top, drawMask, color, priority, control); + vectorPutLinePixel(left, top, drawMask, color, priority, control); } } else { // going vertical int fraction = dx - (dy >> 1); @@ -381,7 +580,7 @@ void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte } top += stepy; fraction += dx; - putPixel(left, top, drawMask, color, priority, control); + vectorPutLinePixel(left, top, drawMask, color, priority, control); } } } @@ -394,46 +593,14 @@ void GfxScreen::putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, u commonFont->drawChar(displayPtr, chr, _displayWidth, 1, color, 0, -1, -1); } -byte GfxScreen::getVisual(int x, int y) { - return _visualScreen[y * _pitch + x]; +byte GfxScreen::getPixelNormal(byte *screen, int16 x, int16 y) { + return screen[y * _width + x]; } -byte GfxScreen::getPriority(int x, int y) { - return _priorityScreen[y * _pitch + x]; -} - -byte GfxScreen::getControl(int x, int y) { - return _controlScreen[y * _pitch + x]; -} - -byte GfxScreen::isFillMatch(int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) { - int offset = y * _pitch + x; - byte match = 0; - - if (screenMask & GFX_SCREEN_MASK_VISUAL) { - if (!isEGA) { - if (*(_visualScreen + offset) == t_color) - match |= GFX_SCREEN_MASK_VISUAL; - } else { - // In EGA games a pixel in the framebuffer is only 4 bits. We store - // a full byte per pixel to allow undithering, but when comparing - // pixels for flood-fill purposes, we should only compare the - // visible color of a pixel. - - byte c = *(_visualScreen + offset); - if ((x ^ y) & 1) - c = (c ^ (c >> 4)) & 0x0F; - else - c = c & 0x0F; - if (c == t_color) - match |= GFX_SCREEN_MASK_VISUAL; - } - } - if ((screenMask & GFX_SCREEN_MASK_PRIORITY) && *(_priorityScreen + offset) == t_pri) - match |= GFX_SCREEN_MASK_PRIORITY; - if ((screenMask & GFX_SCREEN_MASK_CONTROL) && *(_controlScreen + offset) == t_con) - match |= GFX_SCREEN_MASK_CONTROL; - return match; +byte GfxScreen::getPixelUpscaled(byte *screen, int16 x, int16 y) { + int16 mappedX = _upscaledWidthMapping[x]; + int16 mappedY = _upscaledHeightMapping[y]; + return screen[mappedY * _width + mappedX]; } int GfxScreen::bitsGetDataSize(Common::Rect rect, byte mask) { @@ -469,14 +636,14 @@ void GfxScreen::bitsSave(Common::Rect rect, byte mask, byte *memoryPtr) { memcpy(memoryPtr, (void *)&mask, sizeof(mask)); memoryPtr += sizeof(mask); if (mask & GFX_SCREEN_MASK_VISUAL) { - bitsSaveScreen(rect, _visualScreen, _pitch, memoryPtr); + bitsSaveScreen(rect, _visualScreen, _width, memoryPtr); bitsSaveDisplayScreen(rect, memoryPtr); } if (mask & GFX_SCREEN_MASK_PRIORITY) { - bitsSaveScreen(rect, _priorityScreen, _pitch, memoryPtr); + bitsSaveScreen(rect, _priorityScreen, _width, memoryPtr); } if (mask & GFX_SCREEN_MASK_CONTROL) { - bitsSaveScreen(rect, _controlScreen, _pitch, memoryPtr); + bitsSaveScreen(rect, _controlScreen, _width, memoryPtr); } if (mask & GFX_SCREEN_MASK_DISPLAY) { if (!_upscaledHires) @@ -530,14 +697,14 @@ void GfxScreen::bitsRestore(byte *memoryPtr) { memcpy((void *)&mask, memoryPtr, sizeof(mask)); memoryPtr += sizeof(mask); if (mask & GFX_SCREEN_MASK_VISUAL) { - bitsRestoreScreen(rect, memoryPtr, _visualScreen, _pitch); + bitsRestoreScreen(rect, memoryPtr, _visualScreen, _width); bitsRestoreDisplayScreen(rect, memoryPtr); } if (mask & GFX_SCREEN_MASK_PRIORITY) { - bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _pitch); + bitsRestoreScreen(rect, memoryPtr, _priorityScreen, _width); } if (mask & GFX_SCREEN_MASK_CONTROL) { - bitsRestoreScreen(rect, memoryPtr, _controlScreen, _pitch); + bitsRestoreScreen(rect, memoryPtr, _controlScreen, _width); } if (mask & GFX_SCREEN_MASK_DISPLAY) { if (!_upscaledHires) @@ -612,21 +779,22 @@ void GfxScreen::dither(bool addToFlag) { byte color, ditheredColor; byte *visualPtr = _visualScreen; byte *displayPtr = _displayScreen; - + if (!_unditheringEnabled) { // Do dithering on visual and display-screen for (y = 0; y < _height; y++) { - for (x = 0; x < _pitch; x++) { + for (x = 0; x < _width; x++) { color = *visualPtr; if (color & 0xF0) { color ^= color << 4; color = ((x^y) & 1) ? color >> 4 : color & 0x0F; switch (_upscaledHires) { case GFX_SCREEN_UPSCALED_DISABLED: + case GFX_SCREEN_UPSCALED_480x300: *displayPtr = color; break; default: - putScaledPixelOnDisplay(x, y, color); + putScaledPixelOnScreen(_displayScreen, x, y, color); break; } *visualPtr = color; @@ -639,7 +807,7 @@ void GfxScreen::dither(bool addToFlag) { memset(&_ditheredPicColors, 0, sizeof(_ditheredPicColors)); // Do dithering on visual screen and put decoded but undithered byte onto display-screen for (y = 0; y < _height; y++) { - for (x = 0; x < _pitch; x++) { + for (x = 0; x < _width; x++) { color = *visualPtr; if (color & 0xF0) { color ^= color << 4; @@ -654,10 +822,11 @@ void GfxScreen::dither(bool addToFlag) { } switch (_upscaledHires) { case GFX_SCREEN_UPSCALED_DISABLED: + case GFX_SCREEN_UPSCALED_480x300: *displayPtr = ditheredColor; break; default: - putScaledPixelOnDisplay(x, y, ditheredColor); + putScaledPixelOnScreen(_displayScreen, x, y, ditheredColor); break; } color = ((x^y) & 1) ? color >> 4 : color & 0x0F; @@ -685,8 +854,8 @@ int16 *GfxScreen::unditherGetDitheredBgColors() { } void GfxScreen::debugShowMap(int mapNo) { - // We cannot really support changing maps when in upscaledHires mode - if (_upscaledHires) + // We cannot really support changing maps when display screen has a different resolution than visual screen + if ((_width != _displayWidth) || (_height != _displayHeight)) return; switch (mapNo) { @@ -779,8 +948,8 @@ void GfxScreen::adjustBackUpscaledCoordinates(int16 &y, int16 &x, Sci32ViewNativ switch (_upscaledHires) { case GFX_SCREEN_UPSCALED_480x300: - x = (x << 1) / 3; - y = (y << 1) / 3; + x = (x * 4) / 6; + y = (y * 4) / 6; break; case GFX_SCREEN_UPSCALED_640x400: x /= 2; @@ -816,26 +985,4 @@ int16 GfxScreen::kernelPicNotValid(int16 newPicNotValid) { return oldPicNotValid; } -uint16 GfxScreen::getLowResScreenHeight() { - // Some Mac SCI1/1.1 games only take up 190 rows and do not - // have the menu bar. - // TODO: Verify that LSL1 and LSL5 use height 190 - if (g_sci->getPlatform() == Common::kPlatformMacintosh) { - switch (g_sci->getGameId()) { - case GID_FREDDYPHARKAS: - case GID_KQ5: - case GID_KQ6: - case GID_LSL1: - case GID_LSL5: - case GID_SQ1: - return 190; - default: - break; - } - } - - // Everything else is 200 - return 200; -} - } // End of namespace Sci diff --git a/engines/sci/graphics/screen.h b/engines/sci/graphics/screen.h index e266a4ed16..1c946ef02f 100644 --- a/engines/sci/graphics/screen.h +++ b/engines/sci/graphics/screen.h @@ -69,11 +69,14 @@ public: uint16 getWidth() { return _width; } uint16 getHeight() { return _height; } + uint16 getScriptWidth() { return _scriptWidth; } + uint16 getScriptHeight() { return _scriptHeight; } uint16 getDisplayWidth() { return _displayWidth; } uint16 getDisplayHeight() { return _displayHeight; } byte getColorWhite() { return _colorWhite; } byte getColorDefaultVectorData() { return _colorDefaultVectorData; } + void clearForRestoreGame(); void copyToScreen(); void copyFromScreen(byte *buffer); void kernelSyncWithFramebuffer(); @@ -81,11 +84,51 @@ public: void copyDisplayRectToScreen(const Common::Rect &rect); void copyRectToScreen(const Common::Rect &rect, int16 x, int16 y); + // calls to code pointers + void inline vectorAdjustCoordinate (int16 *x, int16 *y) { + (this->*_vectorAdjustCoordinatePtr)(x, y); + } + void inline vectorAdjustLineCoordinates (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control) { + (this->*_vectorAdjustLineCoordinatesPtr)(left, top, right, bottom, drawMask, color, priority, control); + } + byte inline vectorIsFillMatch (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA) { + return (this->*_vectorIsFillMatchPtr)(x, y, screenMask, t_color, t_pri, t_con, isEGA); + } + void inline vectorPutPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + (this->*_vectorPutPixelPtr)(x, y, drawMask, color, priority, control); + } + void inline vectorPutLinePixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + (this->*_vectorPutLinePixelPtr)(x, y, drawMask, color, priority, control); + } + byte inline vectorGetVisual(int16 x, int16 y) { + return (this->*_vectorGetPixelPtr)(_visualScreen, x, y); + } + byte inline vectorGetPriority(int16 x, int16 y) { + return (this->*_vectorGetPixelPtr)(_priorityScreen, x, y); + } + byte inline vectorGetControl(int16 x, int16 y) { + return (this->*_vectorGetPixelPtr)(_controlScreen, x, y); + } + + + void inline putPixel(int16 x, int16 y, byte drawMask, byte color, byte priority, byte control) { + (this->*_putPixelPtr)(x, y, drawMask, color, priority, control); + } + + byte inline getVisual(int16 x, int16 y) { + return (this->*_getPixelPtr)(_visualScreen, x, y); + } + byte inline getPriority(int16 x, int16 y) { + return (this->*_getPixelPtr)(_priorityScreen, x, y); + } + byte inline getControl(int16 x, int16 y) { + return (this->*_getPixelPtr)(_controlScreen, x, y); + } + byte getDrawingMask(byte color, byte prio, byte control); - void putPixel(int x, int y, byte drawMask, byte color, byte prio, byte control); - void putFontPixel(int startingY, int x, int y, byte color); - void putPixelOnDisplay(int x, int y, byte color); - void putScaledPixelOnDisplay(int x, int y, byte color); + //void putPixel(int16 x, int16 y, byte drawMask, byte color, byte prio, byte control); + void putFontPixel(int16 startingY, int16 x, int16 y, byte color); + void putPixelOnDisplay(int16 x, int16 y, byte color); void drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte prio, byte control); void drawLine(int16 left, int16 top, int16 right, int16 bottom, byte color, byte prio, byte control) { drawLine(Common::Point(left, top), Common::Point(right, bottom), color, prio, control); @@ -101,10 +144,6 @@ public: void enableUndithering(bool flag); void putKanjiChar(Graphics::FontSJIS *commonFont, int16 x, int16 y, uint16 chr, byte color); - byte getVisual(int x, int y); - byte getPriority(int x, int y); - byte getControl(int x, int y); - byte isFillMatch(int16 x, int16 y, byte drawMask, byte t_color, byte t_pri, byte t_con, bool isEGA); int bitsGetDataSize(Common::Rect rect, byte mask); void bitsSave(Common::Rect rect, byte mask, byte *memoryPtr); @@ -135,9 +174,10 @@ public: private: uint16 _width; - uint16 _pitch; uint16 _height; uint _pixels; + uint16 _scriptWidth; + uint16 _scriptHeight; uint16 _displayWidth; uint16 _displayHeight; uint _displayPixels; @@ -190,8 +230,8 @@ private: * This here holds a translation for vertical+horizontal coordinates between native * (visual) and actual (display) screen. */ - int _upscaledHeightMapping[SCI_SCREEN_UPSCALEDMAXHEIGHT + 1]; - int _upscaledWidthMapping[SCI_SCREEN_UPSCALEDMAXWIDTH + 1]; + int16 _upscaledHeightMapping[SCI_SCREEN_UPSCALEDMAXHEIGHT + 1]; + int16 _upscaledWidthMapping[SCI_SCREEN_UPSCALEDMAXWIDTH + 1]; /** * This defines whether or not the font we're drawing is already scaled @@ -199,7 +239,38 @@ private: */ bool _fontIsUpscaled; - uint16 getLowResScreenHeight(); + // dynamic code + void (GfxScreen::*_vectorAdjustCoordinatePtr) (int16 *x, int16 *y); + void vectorAdjustCoordinateNOP (int16 *x, int16 *y); + void vectorAdjustCoordinate480x300Mac (int16 *x, int16 *y); + + void (GfxScreen::*_vectorAdjustLineCoordinatesPtr) (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); + void vectorAdjustLineCoordinatesNOP (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); + void vectorAdjustLineCoordinates480x300Mac (int16 *left, int16 *top, int16 *right, int16 *bottom, byte drawMask, byte color, byte priority, byte control); + + byte (GfxScreen::*_vectorIsFillMatchPtr) (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); + byte vectorIsFillMatchNormal (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); + byte vectorIsFillMatch480x300Mac (int16 x, int16 y, byte screenMask, byte t_color, byte t_pri, byte t_con, bool isEGA); + + void (GfxScreen::*_vectorPutPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void vectorPutPixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + + void (GfxScreen::*_vectorPutLinePixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void vectorPutLinePixel480x300Mac (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + + byte (GfxScreen::*_vectorGetPixelPtr) (byte *screen, int16 x, int16 y); + + void (GfxScreen::*_putPixelPtr) (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void putPixelNormal (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void putPixelDisplayUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + void putPixelAllUpscaled (int16 x, int16 y, byte drawMask, byte color, byte priority, byte control); + + byte (GfxScreen::*_getPixelPtr) (byte *screen, int16 x, int16 y); + byte getPixelNormal (byte *screen, int16 x, int16 y); + byte getPixelUpscaled (byte *screen, int16 x, int16 y); + + // pixel helper + void putScaledPixelOnScreen(byte *screen, int16 x, int16 y, byte color); }; } // End of namespace Sci diff --git a/engines/sci/graphics/text16.cpp b/engines/sci/graphics/text16.cpp index 245d6996cb..f463dff4b1 100644 --- a/engines/sci/graphics/text16.cpp +++ b/engines/sci/graphics/text16.cpp @@ -143,18 +143,30 @@ int16 GfxText16::CodeProcessing(const char *&text, GuiResourceId orgFontId, int1 return textCodeSize; } -static const uint16 text16_punctuationSjis[] = { - 0x9F82, 0xA182, 0xA382, 0xA582, 0xA782, 0xC182, 0xA782, 0xC182, 0xE182, 0xE382, 0xE582, 0xEC82, - 0x4083, 0x4283, 0x4483, 0x4683, 0x4883, 0x6283, 0x8383, 0x8583, 0x8783, 0x8E83, 0x9583, 0x9683, - 0x5B81, 0x4181, 0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0 +// Has actually punctuation and characters in it, that may not be the first in a line +static const uint16 text16_shiftJIS_punctuation[] = { + 0x9F82, 0xA182, 0xA382, 0xA582, 0xA782, 0xC182, 0xE182, 0xE382, 0xE582, 0xEC82, 0x4083, 0x4283, + 0x4483, 0x4683, 0x4883, 0x6283, 0x8383, 0x8583, 0x8783, 0x8E83, 0x9583, 0x9683, 0x5B81, 0x4181, + 0x4281, 0x7681, 0x7881, 0x4981, 0x4881, 0 }; // return max # of chars to fit maxwidth with full words, does not include // breaking space -int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId) { +// Also adjusts text pointer to the new position for the caller +// +// Special cases in games: +// Laura Bow 2 - Credits in the game menu - all the text lines start with spaces (bug #5159) +// Act 6 Coroner questionaire - the text of all control buttons has trailing spaces +// "Detective Ryan Hanrahan O'Riley" contains even more spaces (bug #5334) +// Conquests of Camelot - talking with Cobb - one text box of the dialogue contains a longer word, +// that will be broken into 2 lines (bug #5159) +int16 GfxText16::GetLongest(const char *&textPtr, int16 maxWidth, GuiResourceId orgFontId) { uint16 curChar = 0; - int16 maxChars = 0, curCharCount = 0; - uint16 width = 0; + const char *textStartPtr = textPtr; + const char *lastSpacePtr = NULL; + int16 lastSpaceCharCount = 0; + int16 curCharCount = 0, resultCharCount = 0; + uint16 curWidth = 0, tempWidth = 0; GuiResourceId previousFontId = GetFontId(); int16 previousPenColor = _ports->_curPort->penClr; @@ -162,35 +174,38 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF if (!_font) return 0; - while (width <= maxWidth) { - curChar = (*(const byte *)text++); + while (1) { + curChar = (*(const byte *)textPtr); if (_font->isDoubleByte(curChar)) { - curChar |= (*(const byte *)text++) << 8; - curCharCount++; + curChar |= (*(const byte *)(textPtr + 1)) << 8; } switch (curChar) { case 0x7C: if (getSciVersion() >= SCI_VERSION_1_1) { - curCharCount++; - curCharCount += CodeProcessing(text, orgFontId, previousPenColor, false); + curCharCount++; textPtr++; + curCharCount += CodeProcessing(textPtr, orgFontId, previousPenColor, false); continue; } break; // 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) + // which means, we split text like for example + // - 'Mature, experienced software analyst available.' 0xD 0xA + // 'Bug installation a proven speciality. "No version too clean."' (normal game text, this is from lsl2) + // - 0xA '-------' 0xA (which is the official sierra subtitle separator) (found in multilingual versions) // 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++; + if ((*(const byte *)(textPtr + 1)) == 0xA) { + curCharCount++; textPtr++; + } // it's meant to pass through here case 0xA: case 0x9781: // this one is used by SQ4/japanese as line break as well - curCharCount++; + curCharCount++; textPtr++; + if (curChar > 0xFF) { + curCharCount++; textPtr++; + } // and it's also meant to pass through here case 0: SetFont(previousFontId); @@ -198,55 +213,86 @@ int16 GfxText16::GetLongest(const char *text, int16 maxWidth, GuiResourceId orgF return curCharCount; case ' ': - maxChars = curCharCount; // return count up to (but not including) breaking space + lastSpaceCharCount = curCharCount; // return count up to (but not including) breaking space + lastSpacePtr = textPtr + 1; // remember position right after the current space break; } - // Sometimes this can go off the screen, like for example bug #3040161. - // However, we only perform this for non-Japanese games, as these require - // special handling, done after this loop. - if (width + _font->getCharWidth(curChar) > maxWidth && g_sci->getLanguage() != Common::JA_JPN) + tempWidth += _font->getCharWidth(curChar); + + // Width is too large? -> break out + if (tempWidth > maxWidth) break; - width += _font->getCharWidth(curChar); - curCharCount++; + + // still fits, remember width + curWidth = tempWidth; + + // go to next character + curCharCount++; textPtr++; + if (curChar > 0xFF) { + // Double-Byte + curCharCount++; textPtr++; + } } - // Text without spaces, probably Kanji/Japanese - if (maxChars == 0) { - maxChars = curCharCount; + if (lastSpaceCharCount) { + // Break and at least one space was found before that + resultCharCount = lastSpaceCharCount; - uint16 nextChar; + // additionally skip over all spaces, that are following that space, but don't count them for displaying purposes + textPtr = lastSpacePtr; + while (*textPtr == ' ') + textPtr++; - // We remove the last char only, if maxWidth was actually equal width - // before adding the last char. Otherwise we won't get the same cutting - // as in sierra pc98 sci. - if (maxWidth == (width - _font->getCharWidth(curChar))) { - maxChars--; - if (curChar > 0xFF) - maxChars--; - nextChar = curChar; - } else { - nextChar = (*(const byte *)text++); - if (_font->isDoubleByte(nextChar)) - nextChar |= (*(const byte *)text++) << 8; - } - // sierra checked the following character against a punctuation kanji table - if (nextChar > 0xFF) { - // if the character is punctuation, we go back one character - uint nonBreakingNr = 0; - while (text16_punctuationSjis[nonBreakingNr]) { - if (text16_punctuationSjis[nonBreakingNr] == nextChar) { - maxChars--; - if (curChar > 0xFF) - maxChars--; // go back 2 chars, when last char was double byte + } else { + // Break without spaces found, we split the very first word - may also be Kanji/Japanese + if (curChar > 0xFF) { + // current charracter is Japanese + + // PC-9801 SCI actually added the last character, which shouldn't fit anymore, still onto the + // screen in case maxWidth wasn't fully reached with the last character + if (( maxWidth - 1 ) > curWidth) { + curCharCount += 2; textPtr += 2; + + curChar = (*(const byte *)textPtr); + if (_font->isDoubleByte(curChar)) { + curChar |= (*(const byte *)(textPtr + 1)) << 8; + } + } + + // But it also checked, if the current character is not inside a punctuation table and it even + // went backwards in case it found multiple ones inside that table. + uint nonBreakingPos = 0; + + while (1) { + // Look up if character shouldn't be the first on a new line + nonBreakingPos = 0; + while (text16_shiftJIS_punctuation[nonBreakingPos]) { + if (text16_shiftJIS_punctuation[nonBreakingPos] == curChar) + break; + nonBreakingPos++; + } + if (!text16_shiftJIS_punctuation[nonBreakingPos]) { + // character is fine break; } - nonBreakingNr++; + // Character is not acceptable, seek backward in the text + curCharCount -= 2; textPtr -= 2; + if (textPtr < textStartPtr) + error("Seeking back went too far, data corruption?"); + + curChar = (*(const byte *)textPtr); + if (!_font->isDoubleByte(curChar)) + error("Non double byte while seeking back"); + curChar |= (*(const byte *)(textPtr + 1)) << 8; } } + + // We split the word in that case + resultCharCount = curCharCount; } SetFont(previousFontId); _ports->penColor(previousPenColor); - return maxChars; + return resultCharCount; } void GfxText16::Width(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 &textWidth, int16 &textHeight, bool restoreFont) { @@ -303,7 +349,7 @@ void GfxText16::DrawString(const char *str, GuiResourceId orgFontId, int16 orgPe Draw(str, 0, (int16)strlen(str), orgFontId, orgPenColor); } -int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth) { +int16 GfxText16::Size(Common::Rect &rect, const char *text, uint16 languageSplitter, GuiResourceId fontId, int16 maxWidth) { GuiResourceId previousFontId = GetFontId(); int16 previousPenColor = _ports->_curPort->penClr; int16 charCount; @@ -315,12 +361,12 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId else fontId = previousFontId; - if (g_sci->getLanguage() == Common::JA_JPN) - SwitchToFont900OnSjis(text); - rect.top = rect.left = 0; if (maxWidth < 0) { // force output as single line + if (g_sci->getLanguage() == Common::JA_JPN) + SwitchToFont900OnSjis(text, languageSplitter); + StringWidth(text, fontId, textWidth, textHeight); rect.bottom = textHeight; rect.right = textWidth; @@ -328,17 +374,20 @@ int16 GfxText16::Size(Common::Rect &rect, const char *text, GuiResourceId fontId // 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, fontId); + const char *curTextPos = text; // in work position for GetLongest() + const char *curTextLine = text; // starting point of current line + while (*curTextPos) { + // We need to check for Shift-JIS every line + if (g_sci->getLanguage() == Common::JA_JPN) + SwitchToFont900OnSjis(curTextPos, languageSplitter); + + charCount = GetLongest(curTextPos, rect.right, fontId); if (charCount == 0) break; - Width(curPos, 0, charCount, fontId, textWidth, textHeight, false); + Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, false); maxTextWidth = MAX(textWidth, maxTextWidth); totalHeight += textHeight; - curPos += charCount; - while (*curPos == ' ') - curPos++; // skip over breaking spaces + curTextLine = curTextPos; } rect.bottom = totalHeight; rect.right = maxWidth ? maxWidth : MIN(rect.right, maxTextWidth); @@ -405,34 +454,38 @@ void GfxText16::Show(const char *text, int16 from, int16 len, GuiResourceId orgF } // Draws a text in rect. -void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) { +void GfxText16::Box(const char *text, uint16 languageSplitter, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) { int16 textWidth, maxTextWidth, textHeight, charCount; int16 offset = 0; int16 hline = 0; GuiResourceId previousFontId = GetFontId(); int16 previousPenColor = _ports->_curPort->penClr; bool doubleByteMode = false; + const char *curTextPos = text; + const char *curTextLine = text; if (fontId != -1) SetFont(fontId); else fontId = previousFontId; - if (g_sci->getLanguage() == Common::JA_JPN) { - if (SwitchToFont900OnSjis(text)) - doubleByteMode = true; - } - // Reset reference code rects _codeRefRects.clear(); _codeRefTempRect.left = _codeRefTempRect.top = -1; maxTextWidth = 0; - while (*text) { - charCount = GetLongest(text, rect.width(), fontId); + while (*curTextPos) { + // We need to check for Shift-JIS every line + // Police Quest 2 PC-9801 often draws English + Japanese text during the same call + if (g_sci->getLanguage() == Common::JA_JPN) { + if (SwitchToFont900OnSjis(curTextPos, languageSplitter)) + doubleByteMode = true; + } + + charCount = GetLongest(curTextPos, rect.width(), fontId); if (charCount == 0) break; - Width(text, 0, charCount, fontId, textWidth, textHeight, true); + Width(curTextLine, 0, charCount, fontId, textWidth, textHeight, true); maxTextWidth = MAX<int16>(maxTextWidth, textWidth); switch (alignment) { case SCI_TEXT16_ALIGNMENT_RIGHT: @@ -451,15 +504,13 @@ void GfxText16::Box(const char *text, bool show, const Common::Rect &rect, TextA _ports->moveTo(rect.left + offset, rect.top + hline); if (show) { - Show(text, 0, charCount, fontId, previousPenColor); + Show(curTextLine, 0, charCount, fontId, previousPenColor); } else { - Draw(text, 0, charCount, fontId, previousPenColor); + Draw(curTextLine, 0, charCount, fontId, previousPenColor); } hline += textHeight; - text += charCount; - while (*text == ' ') - text++; // skip over breaking spaces + curTextLine = curTextPos; } SetFont(previousFontId); _ports->penColor(previousPenColor); @@ -521,11 +572,13 @@ void GfxText16::DrawStatus(const char *text) { // Sierra did this in their PC98 interpreter only, they identify a text as being // sjis and then switch to font 900 -bool GfxText16::SwitchToFont900OnSjis(const char *text) { +bool GfxText16::SwitchToFont900OnSjis(const char *text, uint16 languageSplitter) { byte firstChar = (*(const byte *)text++); - if (((firstChar >= 0x81) && (firstChar <= 0x9F)) || ((firstChar >= 0xE0) && (firstChar <= 0xEF))) { - SetFont(900); - return true; + if (languageSplitter != 0x6a23) { // #j prefix as language splitter + if (((firstChar >= 0x81) && (firstChar <= 0x9F)) || ((firstChar >= 0xE0) && (firstChar <= 0xEF))) { + SetFont(900); + return true; + } } return false; } @@ -554,9 +607,9 @@ reg_t GfxText16::allocAndFillReferenceRectArray() { return NULL_REG; } -void GfxText16::kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) { +void GfxText16::kernelTextSize(const char *text, uint16 languageSplitter, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight) { Common::Rect rect(0, 0, 0, 0); - Size(rect, text, font, maxWidth); + Size(rect, text, languageSplitter, font, maxWidth); *textWidth = rect.width(); *textHeight = rect.height(); } diff --git a/engines/sci/graphics/text16.h b/engines/sci/graphics/text16.h index ab0cb13a64..2724d97347 100644 --- a/engines/sci/graphics/text16.h +++ b/engines/sci/graphics/text16.h @@ -51,15 +51,20 @@ public: void ClearChar(int16 chr); - int16 GetLongest(const char *text, int16 maxWidth, GuiResourceId orgFontId); + int16 GetLongest(const char *&text, int16 maxWidth, GuiResourceId orgFontId); 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 ShowString(const char *str, GuiResourceId orgFontId, int16 orgPenColor); void DrawString(const char *str, GuiResourceId orgFontId, int16 orgPenColor); - int16 Size(Common::Rect &rect, const char *text, GuiResourceId fontId, int16 maxWidth); + int16 Size(Common::Rect &rect, const char *text, uint16 textLanguage, GuiResourceId fontId, int16 maxWidth); void Draw(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); void Show(const char *text, int16 from, int16 len, GuiResourceId orgFontId, int16 orgPenColor); - void Box(const char *text, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId); + void Box(const char *text, uint16 languageSplitter, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId); + + void Box(const char *text, bool show, const Common::Rect &rect, TextAlignment alignment, GuiResourceId fontId) { + Box(text, 0, show, rect, alignment, fontId); + } + void DrawString(const char *text); void DrawStatus(const char *text); @@ -67,13 +72,13 @@ public: reg_t allocAndFillReferenceRectArray(); - void kernelTextSize(const char *text, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); + void kernelTextSize(const char *text, uint16 textLanguage, int16 font, int16 maxWidth, int16 *textWidth, int16 *textHeight); void kernelTextFonts(int argc, reg_t *argv); void kernelTextColors(int argc, reg_t *argv); private: void init(); - bool SwitchToFont900OnSjis(const char *text); + bool SwitchToFont900OnSjis(const char *text, uint16 languageSplitter); GfxCache *_cache; GfxPorts *_ports; diff --git a/engines/sci/graphics/transitions.cpp b/engines/sci/graphics/transitions.cpp index 5e7dbc6c15..ccc7a4389a 100644 --- a/engines/sci/graphics/transitions.cpp +++ b/engines/sci/graphics/transitions.cpp @@ -339,10 +339,10 @@ void GfxTransitions::pixelation(bool blackoutFlag) { do { mask = (mask & 1) ? (mask >> 1) ^ 0xB400 : mask >> 1; - if (mask >= _screen->getWidth() * _screen->getHeight()) + if (mask >= _screen->getScriptWidth() * _screen->getScriptHeight()) continue; - pixelRect.left = mask % _screen->getWidth(); pixelRect.right = pixelRect.left + 1; - pixelRect.top = mask / _screen->getWidth(); pixelRect.bottom = pixelRect.top + 1; + pixelRect.left = mask % _screen->getScriptWidth(); pixelRect.right = pixelRect.left + 1; + pixelRect.top = mask / _screen->getScriptWidth(); pixelRect.bottom = pixelRect.top + 1; pixelRect.clip(_picRect); if (!pixelRect.isEmpty()) copyRectToScreen(pixelRect, blackoutFlag); diff --git a/engines/sci/graphics/view.cpp b/engines/sci/graphics/view.cpp index f3f352e5b8..da61ecf4c3 100644 --- a/engines/sci/graphics/view.cpp +++ b/engines/sci/graphics/view.cpp @@ -283,6 +283,7 @@ void GfxView::initData(GuiResourceId resourceId) { _isScaleable = false; break; case 0x40: + case 0x4F: // LSL6 Polish, seems to be garbage - bug #6718 case 0: break; // don't do anything, we already have _isScaleable set default: @@ -366,7 +367,7 @@ void GfxView::initData(GuiResourceId resourceId) { default: error("ViewType was not detected, can't continue"); } - + // Inject our own views // Currently only used for Dual mode (speech + text) for games, that do not have a "dual" icon already // Which is Laura Bow 2 + King's Quest 6 |