diff options
author | Colin Snover | 2016-08-11 21:41:49 -0500 |
---|---|---|
committer | Colin Snover | 2016-08-11 21:43:57 -0500 |
commit | 31f344079ff6b66f933becd6602e446d94717a4d (patch) | |
tree | d3ae9e3eefb176176841975cf5fd5ab20a562e01 | |
parent | c8affb54cca259f37522216bad739be085bf9caa (diff) | |
download | scummvm-rg350-31f344079ff6b66f933becd6602e446d94717a4d.tar.gz scummvm-rg350-31f344079ff6b66f933becd6602e446d94717a4d.tar.bz2 scummvm-rg350-31f344079ff6b66f933becd6602e446d94717a4d.zip |
SCI32: Temporarily revert kShowMovie due to buildbot failures
Revert "SCI32: Fix KQ7 1.51 video background"
This reverts commit c8affb54cca259f37522216bad739be085bf9caa.
Revert "SCI32: Fix crash when kShowMovie is called but the video cannot be found"
This reverts commit 93b06f4a9e08de281ee7eb9c780ceac147c3fb23.
Revert "SCI32: Fix KQ7 1.51 basic video playback"
This reverts commit cdab24aa07c18ad4a25a1659f7fca15cca5e358e.
Revert "SCI32: Additional Video32 documentation"
This reverts commit 4ff0924e57a9bc9101ee0799a967fe3373dd2574.
Revert "SCI32: Implement kShowMovie"
This reverts commit 13297c19298c5ad73c9e996c5c31ca91de124911.
-rw-r--r-- | engines/sci/engine/kernel.h | 11 | ||||
-rw-r--r-- | engines/sci/engine/kernel_tables.h | 29 | ||||
-rw-r--r-- | engines/sci/engine/kmisc.cpp | 16 | ||||
-rw-r--r-- | engines/sci/engine/kvideo.cpp | 166 | ||||
-rw-r--r-- | engines/sci/engine/vm.cpp | 15 | ||||
-rw-r--r-- | engines/sci/graphics/video32.cpp | 450 | ||||
-rw-r--r-- | engines/sci/graphics/video32.h | 210 |
7 files changed, 87 insertions, 810 deletions
diff --git a/engines/sci/engine/kernel.h b/engines/sci/engine/kernel.h index b02a7e545a..5ff4f932be 100644 --- a/engines/sci/engine/kernel.h +++ b/engines/sci/engine/kernel.h @@ -450,17 +450,6 @@ reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv); reg_t kPlayVMDSetBlackoutArea(EngineState *s, int argc, reg_t *argv); reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovie32(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWin(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinOpen(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinInit(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinPlay(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinClose(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinCue(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv); -reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv); - reg_t kIsHiRes(EngineState *s, int argc, reg_t *argv); reg_t kArray(EngineState *s, int argc, reg_t *argv); reg_t kListAt(EngineState *s, int argc, reg_t *argv); diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index 76c24b09e3..e0e4dcc233 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -423,27 +423,6 @@ static const SciKernelMapSubEntry kList_subops[] = { SCI_SUBOPENTRY_TERMINATOR }; -// version, subId, function-mapping, signature, workarounds -static const SciKernelMapSubEntry kShowMovieWin_subops[] = { - { SIG_SCI2, 0, MAP_CALL(ShowMovieWinOpen), "r", NULL }, - { SIG_SCI2, 1, MAP_CALL(ShowMovieWinInit), "ii(ii)", NULL }, - { SIG_SCI2, 2, MAP_CALL(ShowMovieWinPlay), "i", NULL }, - { SIG_SCI2, 6, MAP_CALL(ShowMovieWinClose), "", NULL }, - { SIG_SINCE_SCI21, 0, MAP_CALL(ShowMovieWinOpen), "ir", NULL }, - { SIG_SINCE_SCI21, 1, MAP_CALL(ShowMovieWinInit), "iii(ii)", NULL }, - { SIG_SINCE_SCI21, 2, MAP_CALL(ShowMovieWinPlay), "i(ii)(i)(i)", NULL }, - { SIG_SINCE_SCI21, 6, MAP_CALL(ShowMovieWinClose), "i", NULL }, - // Since movies are rendered within the graphics engine in ScummVM, - // it is not necessary to copy the palette from SCI to MCI, so this - // can be a no-op - { SIG_SINCE_SCI21, 7, MAP_EMPTY(ShowMovieWinSetPalette), "i", NULL }, - { SIG_SINCE_SCI21, 8, MAP_CALL(ShowMovieWinGetDuration), "i", NULL }, - { SIG_SINCE_SCI21, 11, MAP_CALL(ShowMovieWinCue), "ii", NULL }, - { SIG_SINCE_SCI21, 14, MAP_CALL(ShowMovieWinPlayUntilEvent), "i(i)", NULL }, - { SIG_SINCE_SCI21, 15, MAP_CALL(ShowMovieWinInitDouble), "iii", NULL }, - SCI_SUBOPENTRY_TERMINATOR -}; - // There are a lot of subops to PlayVMD, but only a few of them are ever // actually used by games // version, subId, function-mapping, signature, workarounds @@ -709,11 +688,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(SetSynonyms), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(SetVideoMode), SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(ShakeScreen), SIG_EVERYWHERE, "(i)(i)", NULL, NULL }, - { MAP_CALL(ShowMovie), SIG_SCI16, SIGFOR_ALL, "(.*)", NULL, NULL }, -#ifdef ENABLE_SCI32 - { "ShowMovie", kShowMovie32, SIG_SCI32, SIGFOR_DOS, "ri(i)(i)", NULL, NULL }, - { "ShowMovie", kShowMovieWin, SIG_SCI32, SIGFOR_WIN, "(.*)", kShowMovieWin_subops, NULL }, -#endif + { MAP_CALL(ShowMovie), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Show), SIG_EVERYWHERE, "i", NULL, NULL }, { MAP_CALL(SinDiv), SIG_EVERYWHERE, "ii", NULL, NULL }, { MAP_CALL(Sort), SIG_EVERYWHERE, "ooo", NULL, NULL }, @@ -845,7 +820,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL }, { MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL }, { MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", kPlayVMD_subops, NULL }, - { MAP_EMPTY(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, + { MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL }, { MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL }, { MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL }, { MAP_CALL(AddPicAt), SIG_EVERYWHERE, "oiii(i)(i)", NULL, NULL }, diff --git a/engines/sci/engine/kmisc.cpp b/engines/sci/engine/kmisc.cpp index c99540967c..1924848717 100644 --- a/engines/sci/engine/kmisc.cpp +++ b/engines/sci/engine/kmisc.cpp @@ -20,7 +20,6 @@ * */ -#include "common/config-manager.h" #include "common/system.h" #include "sci/sci.h" @@ -543,7 +542,7 @@ enum kSciPlatforms { enum kPlatformOps { kPlatformUnk0 = 0, kPlatformCDSpeed = 1, - kPlatformColorDepth = 2, + kPlatformUnk2 = 2, kPlatformCDCheck = 3, kPlatformGetPlatform = 4, kPlatformUnk5 = 5, @@ -564,6 +563,11 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { return NULL_REG; } + if (g_sci->forceHiresGraphics()) { + // force Windows platform, so that hires-graphics are enabled + isWindows = true; + } + uint16 operation = (argc == 0) ? 0 : argv[0].toUint16(); switch (operation) { @@ -571,9 +575,9 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { // TODO: Returns CD Speed? warning("STUB: kPlatform(CDSpeed)"); break; - case kPlatformColorDepth: + case kPlatformUnk2: // Always returns 2 - return make_reg(0, /* 256-color */ 2); + return make_reg(0, 2); case kPlatformCDCheck: // TODO: Some sort of CD check? warning("STUB: kPlatform(CDCheck)"); @@ -587,9 +591,9 @@ reg_t kPlatform(EngineState *s, int argc, reg_t *argv) { return make_reg(0, (isWindows) ? kSciPlatformWindows : kSciPlatformDOS); case kPlatformUnk5: // This case needs to return the opposite of case 6 to get hires graphics - return make_reg(0, !ConfMan.getBool("enable_high_resolution_graphics")); + return make_reg(0, !isWindows); case kPlatformIsHiRes: - return make_reg(0, ConfMan.getBool("enable_high_resolution_graphics")); + return make_reg(0, isWindows); case kPlatformIsItWindows: return make_reg(0, isWindows); default: diff --git a/engines/sci/engine/kvideo.cpp b/engines/sci/engine/kvideo.cpp index 86d8a4b817..de4d4a282c 100644 --- a/engines/sci/engine/kvideo.cpp +++ b/engines/sci/engine/kvideo.cpp @@ -61,15 +61,33 @@ void playVideo(Video::VideoDecoder *videoDecoder, VideoState videoState) { uint16 screenWidth = g_sci->_gfxScreen->getDisplayWidth(); uint16 screenHeight = g_sci->_gfxScreen->getDisplayHeight(); - if (screenWidth == 640 && width <= 320 && height <= 240) { + videoState.fileName.toLowercase(); + bool isVMD = videoState.fileName.hasSuffix(".vmd"); + + if (screenWidth == 640 && width <= 320 && height <= 240 && ((videoState.flags & kDoubled) || !isVMD)) { width *= 2; height *= 2; pitch *= 2; scaleBuffer = new byte[width * height * bytesPerPixel]; } - uint16 x = (screenWidth - width) / 2; - uint16 y = (screenHeight - height) / 2; + uint16 x, y; + + // Sanity check... + if (videoState.x > 0 && videoState.y > 0 && isVMD) { + x = videoState.x; + y = videoState.y; + + if (x + width > screenWidth || y + height > screenHeight) { + // Happens in the Lighthouse demo + warning("VMD video won't fit on screen, centering it instead"); + x = (screenWidth - width) / 2; + y = (screenHeight - height) / 2; + } + } else { + x = (screenWidth - width) / 2; + y = (screenHeight - height) / 2; + } bool skipVideo = false; EngineState *s = g_sci->getEngineState(); @@ -163,6 +181,16 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { // TODO: This appears to be some sort of subop. case 0 contains the string // for the video, so we'll just play it from there for now. +#ifdef ENABLE_SCI32 + if (getSciVersion() >= SCI_VERSION_2_1_EARLY) { + // SCI2.1 always has argv[0] as 1, the rest of the arguments seem to + // follow SCI1.1/2. + if (argv[0].toUint16() != 1) + error("SCI2.1 kShowMovie argv[0] not 1"); + argv++; + argc--; + } +#endif switch (argv[0].toUint16()) { case 0: { Common::String filename = s->_segMan->getString(argv[1]); @@ -215,100 +243,50 @@ reg_t kShowMovie(EngineState *s, int argc, reg_t *argv) { } #ifdef ENABLE_SCI32 -reg_t kShowMovie32(EngineState *s, int argc, reg_t *argv) { - Common::String fileName = s->_segMan->getString(argv[0]); - const int16 numTicks = argv[1].toSint16(); - const int16 x = argc > 3 ? argv[2].toSint16() : 0; - const int16 y = argc > 3 ? argv[3].toSint16() : 0; - - g_sci->_video32->getSEQPlayer().play(fileName, numTicks, x, y); - - return s->r_acc; -} - -reg_t kShowMovieWin(EngineState *s, int argc, reg_t *argv) { - if (!s) - return make_reg(0, getSciVersion()); - error("not supposed to call this"); -} - -reg_t kShowMovieWinOpen(EngineState *s, int argc, reg_t *argv) { - // SCI2.1 adds a movie ID to the call, but the movie ID is broken, - // so just ignore it - if (getSciVersion() > SCI_VERSION_2) { - ++argv; - --argc; - } - - const Common::String fileName = s->_segMan->getString(argv[0]); - return make_reg(0, g_sci->_video32->getAVIPlayer().open(fileName)); -} - -reg_t kShowMovieWinInit(EngineState *s, int argc, reg_t *argv) { - // SCI2.1 adds a movie ID to the call, but the movie ID is broken, - // so just ignore it - if (getSciVersion() > SCI_VERSION_2) { - ++argv; - --argc; - } - - const int16 x = argv[0].toSint16(); - const int16 y = argv[1].toSint16(); - const int16 width = argc > 3 ? argv[2].toSint16() : 0; - const int16 height = argc > 3 ? argv[3].toSint16() : 0; - return make_reg(0, g_sci->_video32->getAVIPlayer().init1x(x, y, width, height)); -} - -reg_t kShowMovieWinPlay(EngineState *s, int argc, reg_t *argv) { - if (getSciVersion() == SCI_VERSION_2) { - AVIPlayer::EventFlags flags = (AVIPlayer::EventFlags)argv[0].toUint16(); - return make_reg(0, g_sci->_video32->getAVIPlayer().playUntilEvent(flags)); - } else { - // argv[0] is a broken movie ID - const int16 from = argc > 2 ? argv[1].toSint16() : 0; - const int16 to = argc > 2 ? argv[2].toSint16() : 0; - const int16 showStyle = argc > 3 ? argv[3].toSint16() : 0; - const bool cue = argc > 4 ? (bool)argv[4].toSint16() : false; - return make_reg(0, g_sci->_video32->getAVIPlayer().play(from, to, showStyle, cue)); - } -} - -reg_t kShowMovieWinClose(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, g_sci->_video32->getAVIPlayer().close()); -} - -reg_t kShowMovieWinGetDuration(EngineState *s, int argc, reg_t *argv) { - return make_reg(0, g_sci->_video32->getAVIPlayer().getDuration()); -} -reg_t kShowMovieWinCue(EngineState *s, int argc, reg_t *argv) { - // SCI2.1 adds a movie ID to the call, but the movie ID is broken, - // so just ignore it - if (getSciVersion() > SCI_VERSION_2) { - ++argv; - --argc; +reg_t kRobot(EngineState *s, int argc, reg_t *argv) { + int16 subop = argv[0].toUint16(); + + switch (subop) { + case 0: { // init + int id = argv[1].toUint16(); + reg_t obj = argv[2]; + int16 flag = argv[3].toSint16(); + int16 x = argv[4].toUint16(); + int16 y = argv[5].toUint16(); + warning("kRobot(init), id %d, obj %04x:%04x, flag %d, x=%d, y=%d", id, PRINT_REG(obj), flag, x, y); + g_sci->_robotDecoder->load(id); + g_sci->_robotDecoder->start(); + g_sci->_robotDecoder->setPos(x, y); + } + break; + case 1: // LSL6 hires (startup) + // TODO + return NULL_REG; // an integer is expected + case 4: { // start - we don't really have a use for this one + //int id = argv[1].toUint16(); + //warning("kRobot(start), id %d", id); + } + break; + case 7: // unknown, called e.g. by Phantasmagoria + warning("kRobot(%d)", subop); + break; + case 8: // sync + //if (true) { // debug: automatically skip all robot videos + if (g_sci->_robotDecoder->endOfVideo()) { + g_sci->_robotDecoder->close(); + // Signal the engine scripts that the video is done + writeSelector(s->_segMan, argv[1], SELECTOR(signal), SIGNAL_REG); + } else { + writeSelector(s->_segMan, argv[1], SELECTOR(signal), NULL_REG); + } + break; + default: + warning("kRobot(%d)", subop); + break; } - const uint16 frameNo = argv[0].toUint16(); - return make_reg(0, g_sci->_video32->getAVIPlayer().cue(frameNo)); -} - -reg_t kShowMovieWinPlayUntilEvent(EngineState *s, int argc, reg_t *argv) { - const int defaultFlags = - AVIPlayer::kEventFlagEnd | - AVIPlayer::kEventFlagEscapeKey; - - // argv[0] is the movie number, which is not used by this method - const AVIPlayer::EventFlags flags = (AVIPlayer::EventFlags)(argc > 1 ? argv[1].toUint16() : defaultFlags); - - return make_reg(0, g_sci->_video32->getAVIPlayer().playUntilEvent(flags)); -} - -reg_t kShowMovieWinInitDouble(EngineState *s, int argc, reg_t *argv) { - // argv[0] is a broken movie ID - const int16 x = argv[1].toSint16(); - const int16 y = argv[2].toSint16(); - return make_reg(0, g_sci->_video32->getAVIPlayer().init2x(x, y)); + return s->r_acc; } reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) { diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index 548fd477bf..3e12084ed6 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -405,21 +405,6 @@ static void callKernelFunc(EngineState *s, int kernelCallNr, int argc) { error("[VM] k%s[%x]: no subfunction ID parameter given", kernelCall.name, kernelCallNr); if (argv[0].isPointer()) error("[VM] k%s[%x]: given subfunction ID is actually a pointer", kernelCall.name, kernelCallNr); - -#ifdef ENABLE_SCI32 - // The Windows version of kShowMovie has subops, but the subop number - // is put in the second parameter in SCI2.1+, even though every other - // kcall with subops puts the subop in the first parameter. To allow use - // of the normal subops system, we swap the arguments so the subop - // number is in the usual place. - if (getSciVersion() > SCI_VERSION_2 && - g_sci->getPlatform() == Common::kPlatformWindows && - strcmp(kernelCall.name, "ShowMovie") == 0) { - assert(argc > 1); - SWAP(argv[0], argv[1]); - } -#endif - const uint16 subId = argv[0].toUint16(); // Skip over subfunction-id argc--; diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp index 380ab804d7..dc2641c92a 100644 --- a/engines/sci/graphics/video32.cpp +++ b/engines/sci/graphics/video32.cpp @@ -29,457 +29,11 @@ #include "sci/graphics/palette32.h" #include "sci/graphics/text32.h" #include "sci/graphics/video32.h" -#include "audio/mixer.h" // for Audio::Mixer::kSFXSoundType -#include "common/config-manager.h" // for ConfMan -#include "common/textconsole.h" // for error, warning -#include "common/system.h" -#include "engine.h" // for Engine, g_engine -#include "engines/util.h" -#include "graphics/scaler/scalebit.h" -#include "sci/console.h" // for Console -#include "sci/engine/state.h" // for EngineState -#include "sci/engine/vm_types.h" // for reg_t -#include "sci/event.h" // for SciEvent, EventManager, SCI_... -#include "sci/graphics/celobj32.h" // for CelInfo32 -#include "sci/graphics/cursor.h" // for GfxCursor -#include "sci/graphics/helpers.h" // for Color, Palette -#include "sci/graphics/palette32.h" // for GfxPalette32 -#include "sci/graphics/plane32.h" // for Plane, PlanePictureCodes::kP... -#include "sci/graphics/screen_item32.h" // for ScaleInfo, ScreenItem, Scale... -#include "sci/graphics/text32.h" // for BitmapResource -#include "sci/video/seq_decoder.h" -#include "sci/sci.h" // for SciEngine, g_sci, getSciVersion -#include "video/avi_decoder.h" +#include "sci/sci.h" #include "video/coktel_decoder.h" namespace Sci { -#pragma mark SEQPlayer - -SEQPlayer::SEQPlayer(SegManager *segMan) : - _segMan(segMan), - _decoder(nullptr), - _plane(nullptr), - _screenItem(nullptr) {} - -void SEQPlayer::play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y) { - delete _decoder; - _decoder = new SEQDecoder(numTicks); - _decoder->loadFile(fileName); - - // NOTE: In the original engine, video was output directly to the hardware, - // bypassing the game's rendering engine. Instead of doing this, we use a - // mechanism that is very similar to that used by the VMD player, which - // allows the SEQ to be drawn into a bitmap ScreenItem and displayed using - // the normal graphics system. - _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false); - - CelInfo32 celInfo; - celInfo.type = kCelTypeMem; - celInfo.bitmap = _bitmap; - - _plane = new Plane(Common::Rect(kLowResX, kLowResY), kPlanePicColored); - g_sci->_gfxFrameout->addPlane(*_plane); - - // Normally we would use the x, y coordinates passed into the play function - // to position the screen item, but because the video frame bitmap is - // drawn in low-resolution coordinates, it gets automatically scaled up by - // the engine (pixel doubling with aspect ratio correction). As a result, - // the animation does not need the extra offsets from the game in order to - // be correctly positioned in the middle of the window, so we ignore them. - _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(0, 0), ScaleInfo()); - g_sci->_gfxFrameout->addScreenItem(*_screenItem); - g_sci->_gfxFrameout->frameOut(true); - _decoder->start(); - - while (!g_engine->shouldQuit() && !_decoder->endOfVideo()) { - renderFrame(); - g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame()); - g_sci->getEngineState()->_throttleTrigger = true; - } - - _segMan->freeBitmap(_screenItem->_celInfo.bitmap); - g_sci->_gfxFrameout->deletePlane(*_plane); - g_sci->_gfxFrameout->frameOut(true); - _screenItem = nullptr; - _plane = nullptr; -} - -void SEQPlayer::renderFrame() const { - const Graphics::Surface *surface = _decoder->decodeNextFrame(); - - SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap); - bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h)); - - const bool dirtyPalette = _decoder->hasDirtyPalette(); - if (dirtyPalette) { - Palette palette; - const byte *rawPalette = _decoder->getPalette(); - for (int i = 0; i < ARRAYSIZE(palette.colors); ++i) { - palette.colors[i].r = *rawPalette++; - palette.colors[i].g = *rawPalette++; - palette.colors[i].b = *rawPalette++; - palette.colors[i].used = true; - } - - g_sci->_gfxPalette32->submit(palette); - } - - g_sci->_gfxFrameout->updateScreenItem(*_screenItem); - g_sci->getSciDebugger()->onFrame(); - g_sci->_gfxFrameout->frameOut(true); -} - -#pragma mark - -#pragma mark AVIPlayer - -AVIPlayer::AVIPlayer(SegManager *segMan, EventManager *eventMan) : - _segMan(segMan), - _eventMan(eventMan), - _decoder(new Video::AVIDecoder(Audio::Mixer::kSFXSoundType)), - _scaleBuffer(nullptr), - _plane(nullptr), - _screenItem(nullptr), - _status(kAVINotOpen) {} - -AVIPlayer::~AVIPlayer() { - close(); - delete _decoder; -} - -AVIPlayer::IOStatus AVIPlayer::open(const Common::String &fileName) { - if (_status != kAVINotOpen) { - close(); - } - - if (!_decoder->loadFile(fileName)) { - return kIOFileNotFound; - } - - _status = kAVIOpen; - return kIOSuccess; -} - -AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width, int16 height) { - if (_status == kAVINotOpen) { - return kIOFileNotFound; - } - - _pixelDouble = false; - - if (!width || !height) { - width = _decoder->getWidth(); - height = _decoder->getHeight(); - } else if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) { - // KQ7 1.51 provides an explicit width and height when it wants scaling, - // though the width and height it provides are not scaled - _pixelDouble = true; - width *= 2; - height *= 2; - } - - // QFG4CD gives non-multiple-of-2 values for width and height, - // which would normally be OK except the source video is a pixel bigger - // in each dimension - width = (width + 1) & ~1; - height = (height + 1) & ~1; - - _drawRect.left = x; - _drawRect.top = y; - _drawRect.right = x + width; - _drawRect.bottom = y + height; - - // SCI2.1mid uses init2x to draw a pixel-doubled AVI, but SCI2 has only the - // one play routine which automatically pixel-doubles in hi-res mode - if (getSciVersion() == SCI_VERSION_2) { - // This is somewhat of a hack; credits.avi from GK1 is not - // rendered correctly in SSCI because it is a 640x480 video, but the - // game script gives the wrong dimensions. Since this is the only - // high-resolution AVI ever used, just set the draw rectangle to draw - // the entire screen - if (_decoder->getWidth() > 320) { - _drawRect.left = 0; - _drawRect.top = 0; - _drawRect.right = 320; - _drawRect.bottom = 200; - } - - // In hi-res mode, video will be pixel doubled, so the origin (which - // corresponds to the correct position without pixel doubling) needs to - // be corrected - if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() <= 320) { - _drawRect.left /= 2; - _drawRect.top /= 2; - } - } - - init(); - - return kIOSuccess; -} - -AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) { - if (_status == kAVINotOpen) { - return kIOFileNotFound; - } - - _drawRect.left = x; - _drawRect.top = y; - _drawRect.right = x + _decoder->getWidth() * 2; - _drawRect.bottom = y + _decoder->getHeight() * 2; - - _pixelDouble = true; - init(); - - return kIOSuccess; -} - -void AVIPlayer::init() { - int16 xRes; - int16 yRes; - - bool useScreenDimensions = false; - if (g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) { - useScreenDimensions = true; - } - - // KQ7 1.51 gives video position in screen coordinates, not game - // coordinates, because in SSCI they are passed to Video for Windows, which - // renders as an overlay on the game video. Because we put the video into a - // ScreenItem instead of rendering directly to the hardware surface, the - // coordinates need to be converted to game script coordinates - if (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY) { - useScreenDimensions = !_pixelDouble; - // This y-translation is arbitrary, based on what roughly centers the - // videos in the game window - _drawRect.translate(-_drawRect.left / 2, -_drawRect.top * 2 / 3); - } - - if (useScreenDimensions) { - xRes = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; - yRes = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; - } else { - xRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; - yRes = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; - } - - _plane = new Plane(_drawRect); - g_sci->_gfxFrameout->addPlane(*_plane); - - if (_decoder->getPixelFormat().bytesPerPixel == 1) { - _segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false); - - CelInfo32 celInfo; - celInfo.type = kCelTypeMem; - celInfo.bitmap = _bitmap; - - _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(_drawRect.left, _drawRect.top), ScaleInfo()); - g_sci->_gfxFrameout->addScreenItem(*_screenItem); - g_sci->_gfxFrameout->frameOut(true); - } else { - const Buffer ¤tBuffer = g_sci->_gfxFrameout->getCurrentBuffer(); - const Graphics::PixelFormat format = _decoder->getPixelFormat(); - initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, g_sci->_gfxFrameout->_isHiRes, &format); - - if (_pixelDouble) { - const int16 width = _drawRect.width(); - const int16 height = _drawRect.height(); - _scaleBuffer = calloc(1, width * height * format.bytesPerPixel); - } - } -} - -AVIPlayer::IOStatus AVIPlayer::play(const int16 from, const int16 to, const int16, const bool async) { - if (_status == kAVINotOpen) { - return kIOFileNotFound; - } - - if (from >= 0 && to > 0 && from <= to) { - _decoder->seekToFrame(from); - _decoder->setEndFrame(to); - } - - if (!async) { - renderVideo(); - } else if (getSciVersion() == SCI_VERSION_2_1_EARLY) { - playUntilEvent((EventFlags)(kEventFlagEnd | kEventFlagEscapeKey)); - } else { - _status = kAVIPlaying; - } - - return kIOSuccess; -} - -void AVIPlayer::renderVideo() const { - _decoder->start(); - while (!g_engine->shouldQuit() && !_decoder->endOfVideo()) { - g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame()); - g_sci->getEngineState()->_throttleTrigger = true; - if (_decoder->needsUpdate()) { - renderFrame(); - } - } -} - -AVIPlayer::IOStatus AVIPlayer::close() { - if (_status == kAVINotOpen) { - return kIOSuccess; - } - - free(_scaleBuffer); - _scaleBuffer = nullptr; - - if (_decoder->getPixelFormat().bytesPerPixel != 1) { - const bool isHiRes = g_sci->_gfxFrameout->_isHiRes; - const Buffer ¤tBuffer = g_sci->_gfxFrameout->getCurrentBuffer(); - const Graphics::PixelFormat format = Graphics::PixelFormat::createFormatCLUT8(); - initGraphics(currentBuffer.screenWidth, currentBuffer.screenHeight, isHiRes, &format); - } - - _decoder->close(); - _status = kAVINotOpen; - g_sci->_gfxFrameout->deletePlane(*_plane); - _plane = nullptr; - _screenItem = nullptr; - return kIOSuccess; -} - -AVIPlayer::IOStatus AVIPlayer::cue(const uint16 frameNo) { - if (!_decoder->seekToFrame(frameNo)) { - return kIOSeekFailed; - } - - _status = kAVIPaused; - return kIOSuccess; -} - -uint16 AVIPlayer::getDuration() const { - if (_status == kAVINotOpen) { - return 0; - } - - return _decoder->getFrameCount(); -} - -void AVIPlayer::renderFrame() const { - const Graphics::Surface *surface = _decoder->decodeNextFrame(); - - if (surface->format.bytesPerPixel == 1) { - SciBitmap &bitmap = *_segMan->lookupBitmap(_bitmap); - if (surface->w > bitmap.getWidth() || surface->h > bitmap.getHeight()) { - warning("Attempted to draw a video frame larger than the destination bitmap"); - return; - } - - // KQ7 1.51 encodes videos with palette entry 0 as white, which makes - // the area around the video turn white too, since it is coded to use - // palette entry 0. This happens to work in the original game because - // the video is rendered by VfW, not in the engine itself. To fix this, - // we just modify the incoming pixel data from the video so if a pixel - // is using entry 0, we change it to use entry 255, which is guaranteed - // to always be white - if (getSciVersion() == SCI_VERSION_2_1_EARLY && g_sci->getGameId() == GID_KQ7) { - uint8 *target = bitmap.getPixels(); - uint8 *source = (uint8 *)surface->getPixels(); - uint8 *end = (uint8 *)surface->getPixels() + surface->w * surface->h; - - while (source != end) { - uint8 value = *source++; - *target++ = value == 0 ? 255 : value; - } - } else { - bitmap.getBuffer().copyRectToSurface(*surface, 0, 0, Common::Rect(surface->w, surface->h)); - } - - const bool dirtyPalette = _decoder->hasDirtyPalette(); - if (dirtyPalette) { - Palette palette; - const byte *rawPalette = _decoder->getPalette(); - for (int i = 0; i < ARRAYSIZE(palette.colors); ++i) { - palette.colors[i].r = *rawPalette++; - palette.colors[i].g = *rawPalette++; - palette.colors[i].b = *rawPalette++; - palette.colors[i].used = true; - } - - // Prevent KQ7 1.51 from setting entry 0 to white - palette.colors[0].used = false; - - g_sci->_gfxPalette32->submit(palette); - } - - g_sci->_gfxFrameout->updateScreenItem(*_screenItem); - g_sci->getSciDebugger()->onFrame(); - g_sci->_gfxFrameout->frameOut(true); - } else { - Common::Rect drawRect(_drawRect); - const int16 screenWidth = g_sci->_gfxFrameout->getCurrentBuffer().screenWidth; - const int16 screenHeight = g_sci->_gfxFrameout->getCurrentBuffer().screenHeight; - const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth; - const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight; - - if (_pixelDouble) { - scale(2, _scaleBuffer, surface->pitch * 2, surface->getPixels(), surface->pitch, surface->format.bytesPerPixel, surface->w, surface->h); - g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height()); - } else { - mulinc(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight)); - - g_system->copyRectToScreen(surface->getPixels(), surface->pitch, drawRect.left, drawRect.top, surface->w, surface->h); - } - } -} - -AVIPlayer::EventFlags AVIPlayer::playUntilEvent(EventFlags flags) { - _decoder->start(); - - EventFlags stopFlag = kEventFlagNone; - while (!g_engine->shouldQuit()) { - if (_decoder->endOfVideo()) { - stopFlag = kEventFlagEnd; - break; - } - - g_sci->getEngineState()->speedThrottler(_decoder->getTimeToNextFrame()); - g_sci->getEngineState()->_throttleTrigger = true; - if (_decoder->needsUpdate()) { - renderFrame(); - } - - SciEvent event = _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK); - if ((flags & kEventFlagMouseDown) && event.type == SCI_EVENT_MOUSE_PRESS) { - stopFlag = kEventFlagMouseDown; - break; - } - - event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK); - if ((flags & kEventFlagEscapeKey) && event.type == SCI_EVENT_KEYBOARD) { - bool stop = false; - while ((event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD)), - event.type != SCI_EVENT_NONE) { - if (event.character == SCI_KEY_ESC) { - stop = true; - break; - } - } - - if (stop) { - stopFlag = kEventFlagEscapeKey; - break; - } - } - - // TODO: Hot rectangles - if ((flags & kEventFlagHotRectangle) /* && event.type == SCI_EVENT_HOT_RECTANGLE */) { - warning("Hot rectangles not implemented in VMD player"); - stopFlag = kEventFlagHotRectangle; - break; - } - } - - return stopFlag; -} - -#pragma mark - #pragma mark VMDPlayer VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) : @@ -563,7 +117,7 @@ VMDPlayer::IOStatus VMDPlayer::close() { if (!_planeIsOwned && _screenItem != nullptr) { g_sci->_gfxFrameout->deleteScreenItem(*_screenItem); - _segMan->freeBitmap(_screenItem->_celInfo.bitmap); + g_sci->getEngineState()->_segMan->freeBitmap(_screenItem->_celInfo.bitmap); _screenItem = nullptr; } else if (_plane != nullptr) { g_sci->_gfxFrameout->deletePlane(*_plane); diff --git a/engines/sci/graphics/video32.h b/engines/sci/graphics/video32.h index 7320ede5dc..7033f7c647 100644 --- a/engines/sci/graphics/video32.h +++ b/engines/sci/graphics/video32.h @@ -23,214 +23,16 @@ #ifndef SCI_GRAPHICS_VIDEO32_H #define SCI_GRAPHICS_VIDEO32_H -#include "common/rect.h" // for Rect -#include "common/scummsys.h" // for int16, uint8, int32 -#include "common/str.h" // for String -#include "sci/video/robot_decoder.h" // for RobotDecoder - -namespace Video { -class AdvancedVMDDecoder; -class AVIDecoder; -} +namespace Video { class AdvancedVMDDecoder; } namespace Sci { class Plane; class ScreenItem; class SegManager; -class SEQDecoder; -struct Palette; -#pragma mark SEQPlayer - -/** - * SEQPlayer is used to play SEQ animations. - * Used by DOS versions of GK1 and QFG4CD. - */ -class SEQPlayer { -public: - SEQPlayer(SegManager *segMan); - - /** - * Plays a SEQ animation with the given - * file name, with each frame being displayed - * for `numTicks` ticks. - */ - void play(const Common::String &fileName, const int16 numTicks, const int16 x, const int16 y); - -private: - SegManager *_segMan; - SEQDecoder *_decoder; - - /** - * The plane where the SEQ will be drawn. - */ - Plane *_plane; - - /** - * The screen item representing the SEQ surface. - */ - ScreenItem *_screenItem; - - /** - * The bitmap used to render video output. - */ - reg_t _bitmap; - - /** - * Renders a single frame of video. - */ - void renderFrame() const; -}; - -#pragma mark - -#pragma mark AVIPlayer - -/** - * AVIPlayer is used to play AVI videos. Used by - * Windows versions of GK1CD, KQ7, and QFG4CD. - */ -class AVIPlayer { -public: - enum IOStatus { - kIOSuccess = 0, - kIOFileNotFound = 2, - kIOSeekFailed = 12 - }; - - enum AVIStatus { - kAVINotOpen = 0, - kAVIOpen = 1, - kAVIPlaying = 2, - kAVIPaused = 3 - }; - - enum EventFlags { - kEventFlagNone = 0, - kEventFlagEnd = 1, - kEventFlagEscapeKey = 2, - kEventFlagMouseDown = 4, - kEventFlagHotRectangle = 8 - }; - - AVIPlayer(SegManager *segMan, EventManager *eventMan); - ~AVIPlayer(); - - /** - * Opens a stream to an AVI resource. - */ - IOStatus open(const Common::String &fileName); - - /** - * Initializes the AVI rendering parameters for the - * current AVI. This must be called after `open`. - */ - IOStatus init1x(const int16 x, const int16 y, const int16 width, const int16 height); - - /** - * Initializes the AVI rendering parameters for the - * current AVI, in pixel-doubling mode. This must - * be called after `open`. - */ - IOStatus init2x(const int16 x, const int16 y); - - /** - * Begins playback of the current AVI. - */ - IOStatus play(const int16 from, const int16 to, const int16 showStyle, const bool cue); - - /** - * Stops playback and closes the currently open AVI stream. - */ - IOStatus close(); - - /** - * Seeks the currently open AVI stream to the given frame. - */ - IOStatus cue(const uint16 frameNo); - - /** - * Returns the duration of the current video. - */ - uint16 getDuration() const; - - /** - * Plays the AVI until an event occurs (e.g. user - * presses escape, clicks, etc.). - */ - EventFlags playUntilEvent(const EventFlags flags); - -private: - typedef Common::HashMap<uint16, AVIStatus> StatusMap; - - SegManager *_segMan; - EventManager *_eventMan; - Video::AVIDecoder *_decoder; - - /** - * Playback status of the player. - */ - AVIStatus _status; - - /** - * The plane where the AVI will be drawn. - */ - Plane *_plane; - - /** - * The screen item representing the AVI surface, - * in 8bpp mode. In 24bpp mode, video is drawn - * directly to the screen. - */ - ScreenItem *_screenItem; - - /** - * The bitmap used to render video output in - * 8bpp mode. - */ - reg_t _bitmap; - - /** - * The rectangle where the video will be drawn, - * in game script coordinates. - */ - Common::Rect _drawRect; - - /** - * The scale buffer for pixel-doubled videos - * drawn in 24bpp mode. - */ - void *_scaleBuffer; - - /** - * In SCI2.1, whether or not the video should - * be pixel doubled for playback. - */ - bool _pixelDouble; - - /** - * Performs common initialisation for both - * scaled and unscaled videos. - */ - void init(); - - /** - * Renders video without event input until the - * video is complete. - */ - void renderVideo() const; - - /** - * Renders a single frame of video. - */ - void renderFrame() const; -}; - -#pragma mark - #pragma mark VMDPlayer /** * VMDPlayer is used to play VMD videos. - * Used by Phant1, GK2, PQ:SWAT, Shivers, SQ6, - * Torin, and Lighthouse. */ class VMDPlayer { public: @@ -495,24 +297,14 @@ private: bool _showCursor; }; -/** - * Video32 provides facilities for playing back - * video in SCI engine. - */ class Video32 { public: Video32(SegManager *segMan, EventManager *eventMan) : - _SEQPlayer(segMan), - _AVIPlayer(segMan, eventMan), _VMDPlayer(segMan, eventMan) {} - SEQPlayer &getSEQPlayer() { return _SEQPlayer; } - AVIPlayer &getAVIPlayer() { return _AVIPlayer; } VMDPlayer &getVMDPlayer() { return _VMDPlayer; } private: - SEQPlayer _SEQPlayer; - AVIPlayer _AVIPlayer; VMDPlayer _VMDPlayer; }; } // End of namespace Sci |