void GfxPaint16::kernelGraphUpdateBox(const Common::Rect &rect, bool hiresMode) { // some calls are hiresMode even under kq6 DOS, that's why we check for // upscaled hires here if ((!hiresMode) || (!_screen->getUpscaledHires())) bitsShow(rect); else bitsShowHires(rect); }
// This one is the only one that updates screen! void GfxPaint16::drawCelAndShow(GuiResourceId viewId, int16 loopNo, int16 celNo, uint16 leftPos, uint16 topPos, byte priority, uint16 paletteNo, uint16 scaleX, uint16 scaleY) { GfxView *view = _cache->getView(viewId); Common::Rect celRect; if (view) { celRect.left = leftPos; celRect.top = topPos; celRect.right = celRect.left + view->getWidth(loopNo, celNo); celRect.bottom = celRect.top + view->getHeight(loopNo, celNo); drawCel(view, loopNo, celNo, celRect, priority, paletteNo, scaleX, scaleY); if (getSciVersion() >= SCI_VERSION_1_1) { if (!_screen->_picNotValidSci11) { bitsShow(celRect); } } else { if (!_screen->_picNotValid) bitsShow(celRect); } } }
reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { reg_t displayArg; TextAlignment alignment = SCI_TEXT16_ALIGNMENT_LEFT; int16 colorPen = -1, colorBack = -1, width = -1, bRedraw = 1; bool doSaveUnder = false; Common::Rect rect; reg_t result = NULL_REG; // Make a "backup" of the port settings (required for some SCI0LATE and // SCI01+ only) Port oldPort = *_ports->getPort(); // setting defaults _ports->penMode(0); _ports->penColor(0); _ports->textGreyedOutput(false); // processing codes in argv while (argc > 0) { displayArg = argv[0]; if (displayArg.segment) displayArg.offset = 0xFFFF; argc--; argv++; switch (displayArg.offset) { case SCI_DISPLAY_MOVEPEN: _ports->moveTo(argv[0].toUint16(), argv[1].toUint16()); argc -= 2; argv += 2; break; case SCI_DISPLAY_SETALIGNMENT: alignment = argv[0].toSint16(); argc--; argv++; break; case SCI_DISPLAY_SETPENCOLOR: colorPen = argv[0].toUint16(); _ports->penColor(colorPen); argc--; argv++; break; case SCI_DISPLAY_SETBACKGROUNDCOLOR: colorBack = argv[0].toUint16(); argc--; argv++; break; case SCI_DISPLAY_SETGREYEDOUTPUT: _ports->textGreyedOutput(argv[0].isNull() ? false : true); argc--; argv++; break; case SCI_DISPLAY_SETFONT: _text16->SetFont(argv[0].toUint16()); argc--; argv++; break; case SCI_DISPLAY_WIDTH: width = argv[0].toUint16(); argc--; argv++; break; case SCI_DISPLAY_SAVEUNDER: doSaveUnder = true; break; case SCI_DISPLAY_RESTOREUNDER: bitsGetRect(argv[0], &rect); rect.translate(-_ports->getPort()->left, -_ports->getPort()->top); if (g_sci->getGameId() == GID_PQ3 && g_sci->getEngineState()->currentRoomNumber() == 29) { // WORKAROUND: PQ3 calls this without calling the associated // kDisplay(SCI_DISPLAY_SAVEUNDER) call before. Theoretically, // this would result in no rect getting restored. However, we // still maintain a pointer from the previous room, resulting // in invalidated content being restored on screen, and causing // graphics glitches. Thus, we simply don't restore a rect in // that room. The correct fix for this would be to erase hunk // pointers when changing rooms, but this will suffice for now, // as restoring from a totally invalid pointer is very rare. // Fixes bug #3037945. } else { bitsRestore(argv[0]); } kernelGraphRedrawBox(rect); // finishing loop argc = 0; break; case SCI_DISPLAY_DONTSHOWBITS: bRedraw = 0; break; // 2 Dummy functions, longbow-demo is using those several times but sierra sci doesn't support them at all // The Quest for Glory 1 EGA demo also calls kDisplay(114) case SCI_DISPLAY_DUMMY1: case SCI_DISPLAY_DUMMY2: if (!g_sci->isDemo() || (g_sci->getGameId() != GID_LONGBOW && g_sci->getGameId() != GID_QFG1)) error("Unknown kDisplay argument %d", displayArg.offset); if (displayArg.offset == SCI_DISPLAY_DUMMY2) { if (argc) { argc--; argv++; } else { error("No parameter left for kDisplay(115)"); } } break; default: SciTrackOriginReply originReply; SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, kDisplay_workarounds, &originReply); if (solution.type == WORKAROUND_NONE) error("Unknown kDisplay argument (%04x:%04x) from method %s::%s (script %d, localCall %x)", PRINT_REG(displayArg), originReply.objectName.c_str(), originReply.methodName.c_str(), originReply.scriptNr, originReply.localCallOffset); assert(solution.type == WORKAROUND_IGNORE); break; } } // now drawing the text _text16->Size(rect, text, -1, width); rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop); if (getSciVersion() >= SCI_VERSION_1_LATE) { int16 leftPos = rect.right <= _screen->getWidth() ? 0 : _screen->getWidth() - rect.right; int16 topPos = rect.bottom <= _screen->getHeight() ? 0 : _screen->getHeight() - rect.bottom; _ports->move(leftPos, topPos); rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop); } if (doSaveUnder) 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); if (_screen->_picNotValid == 0 && bRedraw) bitsShow(rect); // restoring port and cursor pos Port *currport = _ports->getPort(); uint16 tTop = currport->curTop; uint16 tLeft = currport->curLeft; if (!g_sci->_features->usesOldGfxFunctions()) { // Restore port settings for some SCI0LATE and SCI01+ only. // // The change actually happened inbetween .530 (hoyle1) and .566 (heros // quest). We don't have any detection for that currently, so we are // using oldGfxFunctions (.502). The only games that could get // regressions because of this are hoyle1, kq4 and funseeker. If there // are regressions, we should use interpreter version (which would // require exe version detection). // // If we restore the port for whole SCI0LATE, at least sq3old will get // an issue - font 0 will get used when scanning for planets instead of // font 600 - a setfont parameter is missing in one of the kDisplay // calls in script 19. I assume this is a script bug, because it was // added in sq3new. *currport = oldPort; } currport->curTop = tTop; currport->curLeft = tLeft; return result; }
void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq) { _position = position; // Now init audio and sync resource uint32 audioNumber = ((noun & 0xff) << 24) | ((verb & 0xff) << 16) | ((cond & 0xff) << 8) | (seq & 0xff); #ifndef DEBUG_PORTRAIT_USE_SYNC_RESOURCES ResourceId raveResourceId = ResourceId(kResourceTypeRave, resourceId, noun, verb, cond, seq); Resource *raveResource = _resMan->findResource(raveResourceId, true); uint raveOffset = 0; #else ResourceId syncResourceId = ResourceId(kResourceTypeSync36, resourceId, noun, verb, cond, seq); 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: rave data is '%s'", debugPrint); } #endif // TODO: maybe try to create the missing sync resources for low-res KQ6 out of the rave resources #ifdef DEBUG_PORTRAIT_USE_SYNC_RESOURCES // Dump the sync resources to disk Common::DumpFile *outFile = new Common::DumpFile(); Common::String outName = syncResourceId.toPatchNameBase36() + ".sync36"; outFile->open(outName); syncResource->writeToStream(outFile); outFile->finalize(); outFile->close(); ResourceId raveResourceId = ResourceId(kResourceTypeRave, resourceId, noun, verb, cond, seq); Resource *raveResource = _resMan->findResource(raveResourceId, true); outName = raveResourceId.toPatchNameBase36() + ".rave"; outFile->open(outName); raveResource->writeToStream(outFile); outFile->finalize(); outFile->close(); _resMan->unlockResource(raveResource); delete outFile; #endif // Set the portrait palette _palette->set(&_portraitPalette, false, true); // Draw base bitmap drawBitmap(0); bitsShow(); // Start playing audio... _audio->stopAudio(); _audio->startAudio(resourceId, audioNumber); #ifndef DEBUG_PORTRAIT_USE_SYNC_RESOURCES if (!raveResource) { 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; byte *raveLipSyncData; byte raveLipSyncTicks; byte raveLipSyncBitmapNr; int timerPosition = 0; int timerPositionWithin = 0; int curPosition; SciEvent curEvent; bool userAbort = false; while ((raveOffset < raveResource->size) && (!userAbort)) { // rave string starts with tick count, followed by lipSyncID, tick count and so on raveTicks = raveGetTicks(raveResource, &raveOffset); if (raveTicks < 0) break; // get lipSyncID raveID = raveGetID(raveResource, &raveOffset); if (raveID) { raveLipSyncData = raveGetLipSyncData(raveID); } 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) {
reg_t GfxPaint16::kernelDisplay(const char *text, int argc, reg_t *argv) { reg_t displayArg; TextAlignment alignment = SCI_TEXT16_ALIGNMENT_LEFT; int16 colorPen = -1, colorBack = -1, width = -1, bRedraw = 1; bool doSaveUnder = false; Common::Rect rect; reg_t result = NULL_REG; // Make a "backup" of the port settings (required for some SCI0LATE and // SCI01+ only) Port oldPort = *_ports->getPort(); // setting defaults _ports->penMode(0); _ports->penColor(0); _ports->textGreyedOutput(false); // processing codes in argv while (argc > 0) { displayArg = argv[0]; if (displayArg.getSegment()) displayArg.setOffset(0xFFFF); argc--; argv++; switch (displayArg.getOffset()) { case SCI_DISPLAY_MOVEPEN: _ports->moveTo(argv[0].toUint16(), argv[1].toUint16()); argc -= 2; argv += 2; break; case SCI_DISPLAY_SETALIGNMENT: alignment = argv[0].toSint16(); argc--; argv++; break; case SCI_DISPLAY_SETPENCOLOR: colorPen = argv[0].toUint16(); _ports->penColor(colorPen); argc--; argv++; break; case SCI_DISPLAY_SETBACKGROUNDCOLOR: colorBack = argv[0].toUint16(); argc--; argv++; break; case SCI_DISPLAY_SETGREYEDOUTPUT: _ports->textGreyedOutput(!argv[0].isNull()); argc--; argv++; break; case SCI_DISPLAY_SETFONT: _text16->SetFont(argv[0].toUint16()); argc--; argv++; break; case SCI_DISPLAY_WIDTH: width = argv[0].toUint16(); argc--; argv++; break; case SCI_DISPLAY_SAVEUNDER: doSaveUnder = true; break; case SCI_DISPLAY_RESTOREUNDER: bitsGetRect(argv[0], &rect); rect.translate(-_ports->getPort()->left, -_ports->getPort()->top); bitsRestore(argv[0]); kernelGraphRedrawBox(rect); // finishing loop argc = 0; break; case SCI_DISPLAY_DONTSHOWBITS: 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); if (solution.type == WORKAROUND_NONE) error("Unknown kDisplay argument (%04x:%04x) from method %s::%s (script %d, localCall %x)", PRINT_REG(displayArg), originReply.objectName.c_str(), originReply.methodName.c_str(), originReply.scriptNr, originReply.localCallOffset); assert(solution.type == WORKAROUND_IGNORE); break; } } //20140521 Text Exchange std::map<std::string, std::string>::iterator iter; if(g_sci->_ScriptData) { _ShouterInfo* pInfo = g_sci->_ScriptData->GetShouterInfo(); iter = pInfo->SentenceList.find(text); if(iter == pInfo->SentenceList.end()) _text16->Size(rect, text, -1, width); else _text16->Size(rect, iter->second.c_str(), -1, width); } else { // now drawing the text _text16->Size(rect, text, -1, width); } //End 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 // this code. if (getSciVersion() >= SCI_VERSION_1_MIDDLE) { int16 leftPos = rect.right <= _screen->getWidth() ? 0 : _screen->getWidth() - rect.right; int16 topPos = rect.bottom <= _screen->getHeight() ? 0 : _screen->getHeight() - rect.bottom; _ports->move(leftPos, topPos); rect.moveTo(_ports->getPort()->curLeft, _ports->getPort()->curTop); } if (doSaveUnder) result = bitsSave(rect, GFX_SCREEN_MASK_VISUAL); if (colorBack != -1) fillRect(rect, GFX_SCREEN_MASK_VISUAL, colorBack, 0, 0); //20140521 if(g_sci->_ScriptData) { if(iter == g_sci->_ScriptData->GetShouterInfo()->SentenceList.end()) _text16->Box(text, false, rect, alignment, -1, false); else _text16->Box(iter->second.c_str(), false, rect, alignment, -1); } else { _text16->Box(text, false, rect, alignment, -1); } //End if (_screen->_picNotValid == 0 && bRedraw) bitsShow(rect); // restoring port and cursor pos Port *currport = _ports->getPort(); uint16 tTop = currport->curTop; uint16 tLeft = currport->curLeft; if (!g_sci->_features->usesOldGfxFunctions()) { // Restore port settings for some SCI0LATE and SCI01+ only. // // The change actually happened inbetween .530 (hoyle1) and .566 (heros // quest). We don't have any detection for that currently, so we are // using oldGfxFunctions (.502). The only games that could get // regressions because of this are hoyle1, kq4 and funseeker. If there // are regressions, we should use interpreter version (which would // require exe version detection). // // If we restore the port for whole SCI0LATE, at least sq3old will get // an issue - font 0 will get used when scanning for planets instead of // font 600 - a setfont parameter is missing in one of the kDisplay // calls in script 19. I assume this is a script bug, because it was // added in sq3new. *currport = oldPort; } currport->curTop = tTop; currport->curLeft = tLeft; return result; }
void Portrait::doit(Common::Point position, uint16 resourceId, uint16 noun, uint16 verb, uint16 cond, uint16 seq) { _position = position; // Now init audio and sync resource uint32 audioNumber = ((noun & 0xff) << 24) | ((verb & 0xff) << 16) | ((cond & 0xff) << 8) | (seq & 0xff); ResourceId syncResourceId = ResourceId(kResourceTypeSync36, resourceId, noun, verb, cond, seq); Resource *syncResource = _resMan->findResource(syncResourceId, true); uint syncOffset = 0; // Set the portrait palette _palette->set(&_portraitPalette, false, true); // Draw base bitmap drawBitmap(0); bitsShow(); // Start playing audio... _audio->stopAudio(); _audio->startAudio(resourceId, audioNumber); if (!syncResource) { // Getting the book in the book shop calls kPortrait where no sync exists // TODO: find out what to do then warning("kPortrait: no sync resource %d %X", resourceId, audioNumber); return; } // Do animation depending on sync resource till audio is done playing uint16 syncCue; int timerPosition, curPosition; SciEvent curEvent; bool userAbort = false; while ((syncOffset < syncResource->size - 2) && (!userAbort)) { timerPosition = (int16)READ_LE_UINT16(syncResource->data + syncOffset); syncOffset += 2; if (syncOffset < syncResource->size - 2) { syncCue = READ_LE_UINT16(syncResource->data + syncOffset); syncOffset += 2; } else { syncCue = 0xFFFF; } // Wait till syncTime passed, then show specific animation bitmap do { g_sci->getEngineState()->wait(1); 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) userAbort = true; curPosition = _audio->getAudioPosition(); } while ((curPosition != -1) && (curPosition < timerPosition) && (!userAbort)); if (syncCue != 0xFFFF) { // Display animation bitmap if (syncCue < _bitmapCount) { if (syncCue) drawBitmap(0); // Draw base bitmap first to get valid animation frame drawBitmap(syncCue); bitsShow(); } else { warning("kPortrait: sync information tried to draw non-existant %d", syncCue); } } } if (userAbort) { // Reset the portrait bitmap to "closed mouth" state, when skipping dialogs drawBitmap(0); bitsShow(); _audio->stopAudio(); } _resMan->unlockResource(syncResource); }