aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/graphics/video32.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/graphics/video32.cpp')
-rw-r--r--engines/sci/graphics/video32.cpp161
1 files changed, 82 insertions, 79 deletions
diff --git a/engines/sci/graphics/video32.cpp b/engines/sci/graphics/video32.cpp
index 1db66644c8..bf0c990015 100644
--- a/engines/sci/graphics/video32.cpp
+++ b/engines/sci/graphics/video32.cpp
@@ -28,6 +28,7 @@
#include "engine.h" // for Engine, g_engine
#include "engines/util.h" // for initGraphics
#include "sci/console.h" // for Console
+#include "sci/engine/features.h" // for GameFeatures
#include "sci/engine/state.h" // for EngineState
#include "sci/engine/vm_types.h" // for reg_t
#include "sci/event.h" // for SciEvent, EventManager, SCI_...
@@ -39,10 +40,12 @@
#include "sci/graphics/plane32.h" // for Plane, PlanePictureCodes::kP...
#include "sci/graphics/screen_item32.h" // for ScaleInfo, ScreenItem, Scale...
#include "sci/sci.h" // for SciEngine, g_sci, getSciVersion
-#include "sci/graphics/video32.h"
+#include "sci/sound/audio32.h" // for Audio32
#include "sci/video/seq_decoder.h" // for SEQDecoder
#include "video/avi_decoder.h" // for AVIDecoder
#include "video/coktel_decoder.h" // for AdvancedVMDDecoder
+#include "sci/graphics/video32.h"
+
namespace Graphics { struct Surface; }
namespace Sci {
@@ -68,7 +71,8 @@ void SEQPlayer::play(const Common::String &fileName, const int16 numTicks, const
// 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);
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, kLowResX, kLowResY, 0, false, false);
+ bitmap.getBuffer().fillRect(Common::Rect(_decoder->getWidth(), _decoder->getHeight()), 0);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
@@ -163,49 +167,37 @@ AVIPlayer::IOStatus AVIPlayer::init1x(const int16 x, const int16 y, int16 width,
_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
+ 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;
+ const Ratio screenToScriptX(scriptWidth, screenWidth);
+ const Ratio screenToScriptY(scriptHeight, screenHeight);
+ width = (_decoder->getWidth() * screenToScriptX).toInt();
+ height = (_decoder->getHeight() * screenToScriptY).toInt();
+ }
+
+ // QFG4CD gives non-multiple-of-2 values for width and height of the intro
+ // video, which would normally be OK except the source video is a pixel
+ // bigger in each dimension so it just causes part of the video to get cut
+ // off
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;
- }
+ // GK1 CREDITS.AVI is not rendered correctly in SSCI because it is a 640x480
+ // video and the game script gives the wrong dimensions.
+ // Since this is the only high-resolution AVI ever used by any SCI game,
+ // just set the draw rectangle to draw across the entire screen
+ if (g_sci->getGameId() == GID_GK1 && _decoder->getWidth() > 320) {
+ _drawRect.left = 0;
+ _drawRect.top = 0;
+ _drawRect.right = 320;
+ _drawRect.bottom = 200;
+ } else {
+ _drawRect.left = x;
+ _drawRect.top = y;
+ _drawRect.right = x + width;
+ _drawRect.bottom = y + height;
}
init();
@@ -222,8 +214,8 @@ AVIPlayer::IOStatus AVIPlayer::init2x(const int16 x, const int16 y) {
_drawRect.top = y;
_drawRect.right = x + _decoder->getWidth() * 2;
_drawRect.bottom = y + _decoder->getHeight() * 2;
-
_pixelDouble = true;
+
init();
return kIOSuccess;
@@ -233,42 +225,38 @@ 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) {
+ // GK1 CREDITS.AVI or KQ7 1.51 half-size videos
+ if ((g_sci->_gfxFrameout->_isHiRes && _decoder->getWidth() > 320) ||
+ (g_sci->getGameId() == GID_KQ7 && getSciVersion() == SCI_VERSION_2_1_EARLY && _drawRect.width() <= 160)) {
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;
+
+ const Ratio videoRatio(_decoder->getWidth(), _decoder->getHeight());
+ const Ratio screenRatio(4, 3);
+
+ // Videos that already have a 4:3 aspect ratio should not receive any
+ // aspect ratio correction
+ if (videoRatio == screenRatio) {
+ yRes = 240;
+ } else {
+ 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);
+ SciBitmap &bitmap = *_segMan->allocateBitmap(&_bitmap, _decoder->getWidth(), _decoder->getHeight(), kDefaultSkipColor, 0, 0, xRes, yRes, 0, false, false);
+ bitmap.getBuffer().fillRect(Common::Rect(_decoder->getWidth(), _decoder->getHeight()), 0);
CelInfo32 celInfo;
celInfo.type = kCelTypeMem;
celInfo.bitmap = _bitmap;
- _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(_drawRect.left, _drawRect.top), ScaleInfo());
+ _screenItem = new ScreenItem(_plane->_object, celInfo, Common::Point(), ScaleInfo());
g_sci->_gfxFrameout->addScreenItem(*_screenItem);
g_sci->_gfxFrameout->frameOut(true);
} else {
@@ -384,7 +372,7 @@ void AVIPlayer::renderFrame() const {
const uint8 *end = (const uint8 *)surface->getPixels() + surface->w * surface->h;
while (source != end) {
- uint8 value = *source++;
+ const uint8 value = *source++;
*target++ = value == 0 ? 255 : value;
}
} else {
@@ -414,12 +402,19 @@ void AVIPlayer::renderFrame() const {
} else {
assert(surface->format.bytesPerPixel == 4);
+ 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;
+
Common::Rect drawRect(_drawRect);
+ mulru(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight), 1);
if (_pixelDouble) {
const uint32 *source = (const uint32 *)surface->getPixels();
uint32 *target = (uint32 *)_scaleBuffer;
- // target pitch here is in uint32s, not bytes
+ // target pitch here is in uint32s, not bytes, because the surface
+ // bpp is 4
const uint16 pitch = surface->pitch / 2;
for (int y = 0; y < surface->h; ++y) {
for (int x = 0; x < surface->w; ++x) {
@@ -434,17 +429,12 @@ void AVIPlayer::renderFrame() const {
target += pitch;
}
- g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, _drawRect.left, _drawRect.top, _drawRect.width(), _drawRect.height());
+ g_system->copyRectToScreen(_scaleBuffer, surface->pitch * 2, drawRect.left, drawRect.top, _drawRect.width(), _drawRect.height());
} else {
- 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;
-
- mulinc(drawRect, Ratio(screenWidth, scriptWidth), Ratio(screenHeight, scriptHeight));
-
g_system->copyRectToScreen(surface->getPixels(), surface->pitch, drawRect.left, drawRect.top, surface->w, surface->h);
}
+
+ g_system->updateScreen();
}
}
@@ -500,6 +490,7 @@ VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
_isOpen(false),
_isInitialized(false),
+ _yieldFrame(0),
_yieldInterval(0),
_lastYieldedFrameNo(0),
@@ -512,6 +503,7 @@ VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
_blackLines(false),
_leaveScreenBlack(false),
_leaveLastFrame(false),
+ _ignorePalettes(false),
_blackoutPlane(nullptr),
@@ -538,6 +530,10 @@ VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFl
error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
}
+ if (g_sci->_features->VMDOpenStopsAudio()) {
+ g_sci->_audio32->stop(kAllChannels);
+ }
+
if (_decoder->loadFile(fileName)) {
if (flags & kOpenFlagMute) {
_decoder->setVolume(0);
@@ -571,6 +567,7 @@ VMDPlayer::IOStatus VMDPlayer::close() {
_decoder->close();
_isOpen = false;
_isInitialized = false;
+ _ignorePalettes = false;
if (!_planeIsOwned && _screenItem != nullptr) {
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
@@ -625,12 +622,12 @@ VMDPlayer::VMDStatus VMDPlayer::getStatus() const {
VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
assert(lastFrameNo >= -1);
- const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
+ const int32 maxFrameNo = _decoder->getFrameCount() - 1;
- if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
- _decoder->setEndFrame(MIN<int32>(lastFrameNo, maxFrameNo));
+ if (flags & kEventFlagToFrame) {
+ _yieldFrame = MIN<int32>(lastFrameNo, maxFrameNo);
} else {
- _decoder->setEndFrame(maxFrameNo);
+ _yieldFrame = maxFrameNo;
}
if (flags & kEventFlagYieldToVM) {
@@ -705,6 +702,7 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
reg_t bitmapId;
SciBitmap &vmdBitmap = *_segMan->allocateBitmap(&bitmapId, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false, false);
+ vmdBitmap.getBuffer().fillRect(Common::Rect(vmdRect.width(), vmdRect.height()), 0);
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
@@ -767,6 +765,11 @@ VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
const int currentFrameNo = _decoder->getCurFrame();
+ if (currentFrameNo == _yieldFrame) {
+ stopFlag = kEventFlagEnd;
+ break;
+ }
+
if (_yieldInterval > 0 &&
currentFrameNo != _lastYieldedFrameNo &&
(currentFrameNo % _yieldInterval) == 0
@@ -826,7 +829,7 @@ void VMDPlayer::renderFrame() const {
// we are just submitting it directly here because the decoder exposes
// this information a little bit differently than the one in SSCI
const bool dirtyPalette = _decoder->hasDirtyPalette();
- if (dirtyPalette) {
+ if (dirtyPalette && !_ignorePalettes) {
Palette palette;
palette.timestamp = g_sci->getTickCount();
for (uint16 i = 0; i < _startColor; ++i) {