SCI32: Implement kPlayVMD
This commit is contained in:
parent
28d4f5b0e4
commit
4d91b458e5
15 changed files with 822 additions and 122 deletions
|
@ -441,6 +441,17 @@ reg_t kDoAudioFade(EngineState *s, int argc, reg_t *argv);
|
||||||
reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv);
|
reg_t kDoAudioHasSignal(EngineState *s, int argc, reg_t *argv);
|
||||||
reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv);
|
reg_t kDoAudioSetLoop(EngineState *s, int argc, reg_t *argv);
|
||||||
|
|
||||||
|
reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDBlack(EngineState *s, int argc, reg_t *argv);
|
||||||
|
reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv);
|
||||||
|
|
||||||
reg_t kIsHiRes(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 kArray(EngineState *s, int argc, reg_t *argv);
|
||||||
reg_t kListAt(EngineState *s, int argc, reg_t *argv);
|
reg_t kListAt(EngineState *s, int argc, reg_t *argv);
|
||||||
|
|
|
@ -412,6 +412,22 @@ static const SciKernelMapSubEntry kList_subops[] = {
|
||||||
SCI_SUBOPENTRY_TERMINATOR
|
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
|
||||||
|
static const SciKernelMapSubEntry kPlayVMD_subops[] = {
|
||||||
|
{ SIG_SINCE_SCI21, 0, MAP_CALL(PlayVMDOpen), "r(i)(i)", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 1, MAP_CALL(PlayVMDInit), "ii(i)(i)(ii)", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 6, MAP_CALL(PlayVMDClose), "", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 14, MAP_CALL(PlayVMDPlayUntilEvent), "i(i)(i)", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 16, MAP_CALL(PlayVMDShowCursor), "i", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 17, MAP_DUMMY(PlayVMDStartBlob), "", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 18, MAP_DUMMY(PlayVMDStopBlobs), "", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 21, MAP_CALL(PlayVMDBlack), "iiii", NULL },
|
||||||
|
{ SIG_SINCE_SCI21, 23, MAP_CALL(PlayVMDRestrictPalette), "ii", NULL },
|
||||||
|
SCI_SUBOPENTRY_TERMINATOR
|
||||||
|
};
|
||||||
|
|
||||||
// version, subId, function-mapping, signature, workarounds
|
// version, subId, function-mapping, signature, workarounds
|
||||||
static const SciKernelMapSubEntry kRemapColors_subops[] = {
|
static const SciKernelMapSubEntry kRemapColors_subops[] = {
|
||||||
{ SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL },
|
{ SIG_SCI32, 0, MAP_CALL(RemapColorsOff), "(i)", NULL },
|
||||||
|
@ -792,7 +808,7 @@ static SciKernelMapEntry s_kernelMap[] = {
|
||||||
{ MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
|
{ MAP_CALL(IsOnMe), SIG_EVERYWHERE, "iioi", NULL, NULL },
|
||||||
{ MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
|
{ MAP_CALL(List), SIG_SINCE_SCI21, SIGFOR_ALL, "(.*)", kList_subops, NULL },
|
||||||
{ MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
|
{ MAP_CALL(MulDiv), SIG_EVERYWHERE, "iii", NULL, NULL },
|
||||||
{ MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
{ MAP_CALL(PlayVMD), SIG_EVERYWHERE, "(.*)", kPlayVMD_subops, NULL },
|
||||||
{ MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
{ MAP_CALL(Robot), SIG_EVERYWHERE, "(.*)", NULL, NULL },
|
||||||
{ MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL },
|
{ MAP_CALL(Save), SIG_EVERYWHERE, "i(.*)", kSave_subops, NULL },
|
||||||
{ MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL },
|
{ MAP_CALL(Text), SIG_SINCE_SCI21MID, SIGFOR_ALL, "i(.*)", kText_subops, NULL },
|
||||||
|
|
|
@ -40,7 +40,8 @@
|
||||||
#include "video/qt_decoder.h"
|
#include "video/qt_decoder.h"
|
||||||
#include "sci/video/seq_decoder.h"
|
#include "sci/video/seq_decoder.h"
|
||||||
#ifdef ENABLE_SCI32
|
#ifdef ENABLE_SCI32
|
||||||
#include "video/coktel_decoder.h"
|
#include "sci/graphics/frameout.h"
|
||||||
|
#include "sci/graphics/video32.h"
|
||||||
#include "sci/video/robot_decoder.h"
|
#include "sci/video/robot_decoder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -289,113 +290,83 @@ reg_t kRobot(EngineState *s, int argc, reg_t *argv) {
|
||||||
}
|
}
|
||||||
|
|
||||||
reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
|
reg_t kPlayVMD(EngineState *s, int argc, reg_t *argv) {
|
||||||
uint16 operation = argv[0].toUint16();
|
if (!s)
|
||||||
Video::VideoDecoder *videoDecoder = 0;
|
return make_reg(0, getSciVersion());
|
||||||
bool reshowCursor = g_sci->_gfxCursor->isVisible();
|
error("not supposed to call this");
|
||||||
Common::String warningMsg;
|
}
|
||||||
|
|
||||||
switch (operation) {
|
reg_t kPlayVMDOpen(EngineState *s, int argc, reg_t *argv) {
|
||||||
case 0: // init
|
const Common::String fileName = s->_segMan->getString(argv[0]);
|
||||||
s->_videoState.reset();
|
// argv[1] is an optional cache size argument which we do not use
|
||||||
s->_videoState.fileName = s->_segMan->derefString(argv[1]);
|
// const uint16 cacheSize = argc > 1 ? CLIP<int16>(argv[1].toSint16(), 16, 1024) : 0;
|
||||||
|
const VMDPlayer::OpenFlags flags = argc > 2 ? (VMDPlayer::OpenFlags)argv[2].toUint16() : VMDPlayer::kOpenFlagNone;
|
||||||
|
|
||||||
if (argc > 2 && argv[2] != NULL_REG)
|
return make_reg(0, g_sci->_video32->getVMDPlayer().open(fileName, flags));
|
||||||
warning("kPlayVMD: third parameter isn't 0 (it's %04x:%04x - %s)", PRINT_REG(argv[2]), s->_segMan->getObjectName(argv[2]));
|
}
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
{
|
|
||||||
// Set VMD parameters. Called with a maximum of 6 parameters:
|
|
||||||
//
|
|
||||||
// x, y, flags, gammaBoost, gammaFirst, gammaLast
|
|
||||||
//
|
|
||||||
// gammaBoost boosts palette colors in the range gammaFirst to
|
|
||||||
// gammaLast, but only if bit 4 in flags is set. Percent value such that
|
|
||||||
// 0% = no amplification These three parameters are optional if bit 4 is
|
|
||||||
// clear. Also note that the x, y parameters play subtle games if used
|
|
||||||
// with subfx 21. The subtleness has to do with creation of temporary
|
|
||||||
// planes and positioning relative to such planes.
|
|
||||||
|
|
||||||
uint16 flags = argv[3].getOffset();
|
reg_t kPlayVMDInit(EngineState *s, int argc, reg_t *argv) {
|
||||||
Common::String flagspec;
|
const int16 x = argv[0].toSint16();
|
||||||
|
const int16 y = argv[1].toSint16();
|
||||||
if (argc > 3) {
|
const VMDPlayer::PlayFlags flags = argc > 2 ? (VMDPlayer::PlayFlags)argv[2].toUint16() : VMDPlayer::kPlayFlagNone;
|
||||||
if (flags & kDoubled)
|
int16 boostPercent;
|
||||||
flagspec += "doubled ";
|
int16 boostStartColor;
|
||||||
if (flags & kDropFrames)
|
int16 boostEndColor;
|
||||||
flagspec += "dropframes ";
|
if (argc > 5 && (flags & VMDPlayer::kPlayFlagBoost)) {
|
||||||
if (flags & kBlackLines)
|
boostPercent = argv[3].toSint16();
|
||||||
flagspec += "blacklines ";
|
boostStartColor = argv[4].toSint16();
|
||||||
if (flags & kUnkBit3)
|
boostEndColor = argv[5].toSint16();
|
||||||
flagspec += "bit3 ";
|
} else {
|
||||||
if (flags & kGammaBoost)
|
boostPercent = 0;
|
||||||
flagspec += "gammaboost ";
|
boostStartColor = -1;
|
||||||
if (flags & kHoldBlackFrame)
|
boostEndColor = -1;
|
||||||
flagspec += "holdblack ";
|
|
||||||
if (flags & kHoldLastFrame)
|
|
||||||
flagspec += "holdlast ";
|
|
||||||
if (flags & kUnkBit7)
|
|
||||||
flagspec += "bit7 ";
|
|
||||||
if (flags & kStretch)
|
|
||||||
flagspec += "stretch";
|
|
||||||
|
|
||||||
warning("VMDFlags: %s", flagspec.c_str());
|
|
||||||
|
|
||||||
s->_videoState.flags = flags;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
warning("x, y: %d, %d", argv[1].getOffset(), argv[2].getOffset());
|
g_sci->_video32->getVMDPlayer().init(x, y, flags, boostPercent, boostStartColor, boostEndColor);
|
||||||
s->_videoState.x = argv[1].getOffset();
|
|
||||||
s->_videoState.y = argv[2].getOffset();
|
|
||||||
|
|
||||||
if (argc > 4 && flags & 16)
|
return make_reg(0, 0);
|
||||||
warning("gammaBoost: %d%% between palette entries %d and %d", argv[4].getOffset(), argv[5].getOffset(), argv[6].getOffset());
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 6: // Play
|
|
||||||
videoDecoder = new Video::AdvancedVMDDecoder();
|
|
||||||
|
|
||||||
if (s->_videoState.fileName.empty()) {
|
reg_t kPlayVMDClose(EngineState *s, int argc, reg_t *argv) {
|
||||||
// Happens in Lighthouse
|
return make_reg(0, g_sci->_video32->getVMDPlayer().close());
|
||||||
warning("kPlayVMD: Empty filename passed");
|
}
|
||||||
|
|
||||||
|
reg_t kPlayVMDPlayUntilEvent(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
const VMDPlayer::EventFlags flags = (VMDPlayer::EventFlags)argv[0].toUint16();
|
||||||
|
const int16 lastFrameNo = argc > 1 ? argv[1].toSint16() : -1;
|
||||||
|
const int16 yieldInterval = argc > 2 ? argv[2].toSint16() : -1;
|
||||||
|
return make_reg(0, g_sci->_video32->getVMDPlayer().kernelPlayUntilEvent(flags, lastFrameNo, yieldInterval));
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_t kPlayVMDShowCursor(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
g_sci->_video32->getVMDPlayer().setShowCursor((bool)argv[0].toUint16());
|
||||||
return s->r_acc;
|
return s->r_acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!videoDecoder->loadFile(s->_videoState.fileName)) {
|
reg_t kPlayVMDStartBlob(EngineState *s, int argc, reg_t *argv) {
|
||||||
warning("Could not open VMD %s", s->_videoState.fileName.c_str());
|
debug("kPlayVMDStartBlob");
|
||||||
break;
|
return s->r_acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (reshowCursor)
|
reg_t kPlayVMDStopBlobs(EngineState *s, int argc, reg_t *argv) {
|
||||||
g_sci->_gfxCursor->kernelHide();
|
debug("kPlayVMDStopBlobs");
|
||||||
|
return s->r_acc;
|
||||||
|
}
|
||||||
|
|
||||||
playVideo(videoDecoder, s->_videoState);
|
reg_t kPlayVMDBlack(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
const int16 scriptWidth = g_sci->_gfxFrameout->getCurrentBuffer().scriptWidth;
|
||||||
|
const int16 scriptHeight = g_sci->_gfxFrameout->getCurrentBuffer().scriptHeight;
|
||||||
|
|
||||||
if (reshowCursor)
|
Common::Rect blackoutArea;
|
||||||
g_sci->_gfxCursor->kernelShow();
|
blackoutArea.left = MAX((int16)0, argv[0].toSint16());
|
||||||
break;
|
blackoutArea.top = MAX((int16)0, argv[1].toSint16());
|
||||||
case 23: // set video palette range
|
blackoutArea.right = MIN(scriptWidth, (int16)(argv[2].toSint16() + 1));
|
||||||
s->_vmdPalStart = argv[1].toUint16();
|
blackoutArea.bottom = MIN(scriptHeight, (int16)(argv[3].toSint16() + 1));
|
||||||
s->_vmdPalEnd = argv[2].toUint16();
|
g_sci->_video32->getVMDPlayer().setBlackoutArea(blackoutArea);
|
||||||
break;
|
return s->r_acc;
|
||||||
case 14:
|
}
|
||||||
// Takes an additional integer parameter (e.g. 3)
|
|
||||||
case 16:
|
|
||||||
// Takes an additional parameter, usually 0
|
|
||||||
case 21:
|
|
||||||
// Looks to be setting the video size and position. Called with 4 extra integer
|
|
||||||
// parameters (e.g. 86, 41, 235, 106)
|
|
||||||
default:
|
|
||||||
warningMsg = Common::String::format("PlayVMD - unsupported subop %d. Params: %d (", operation, argc);
|
|
||||||
|
|
||||||
for (int i = 0; i < argc; i++) {
|
|
||||||
warningMsg += Common::String::format("%04x:%04x", PRINT_REG(argv[i]));
|
|
||||||
warningMsg += (i == argc - 1 ? ")" : ", ");
|
|
||||||
}
|
|
||||||
|
|
||||||
warning("%s", warningMsg.c_str());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
reg_t kPlayVMDRestrictPalette(EngineState *s, int argc, reg_t *argv) {
|
||||||
|
g_sci->_video32->getVMDPlayer().restrictPalette(argv[0].toUint16(), argv[1].toUint16());
|
||||||
return s->r_acc;
|
return s->r_acc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -201,6 +201,7 @@ public:
|
||||||
uint16 _memorySegmentSize;
|
uint16 _memorySegmentSize;
|
||||||
byte _memorySegment[kMemorySegmentMax];
|
byte _memorySegment[kMemorySegmentMax];
|
||||||
|
|
||||||
|
// TODO: Excise video code from the state manager
|
||||||
VideoState _videoState;
|
VideoState _videoState;
|
||||||
uint16 _vmdPalStart, _vmdPalEnd;
|
uint16 _vmdPalStart, _vmdPalEnd;
|
||||||
bool _syncedAudioOptions;
|
bool _syncedAudioOptions;
|
||||||
|
|
|
@ -459,7 +459,7 @@ void ScrollWindow::hide() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
g_sci->_gfxFrameout->deleteScreenItem(_screenItem, _plane);
|
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem, _plane);
|
||||||
_screenItem = nullptr;
|
_screenItem = nullptr;
|
||||||
g_sci->_gfxFrameout->frameOut(true);
|
g_sci->_gfxFrameout->frameOut(true);
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
|
|
||||||
#include "common/array.h"
|
#include "common/array.h"
|
||||||
#include "common/hashmap.h"
|
#include "common/hashmap.h"
|
||||||
|
#include "sci/sci.h"
|
||||||
|
#include "sci/graphics/helpers.h"
|
||||||
|
|
||||||
namespace Sci {
|
namespace Sci {
|
||||||
|
|
||||||
|
|
|
@ -278,20 +278,52 @@ bool GfxFrameout::checkForFred(const reg_t object) {
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
#pragma mark Screen items
|
#pragma mark Screen items
|
||||||
|
|
||||||
void GfxFrameout::deleteScreenItem(ScreenItem *screenItem, Plane *plane) {
|
void GfxFrameout::addScreenItem(ScreenItem &screenItem) const {
|
||||||
if (screenItem->_created == 0) {
|
Plane *plane = _planes.findByObject(screenItem._plane);
|
||||||
screenItem->_created = 0;
|
if (plane == nullptr) {
|
||||||
screenItem->_updated = 0;
|
error("GfxFrameout::addScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
|
||||||
screenItem->_deleted = getScreenCount();
|
}
|
||||||
|
plane->_screenItemList.add(&screenItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxFrameout::updateScreenItem(ScreenItem &screenItem) const {
|
||||||
|
// TODO: In SCI3+ this will need to go through Plane
|
||||||
|
// Plane *plane = _planes.findByObject(screenItem._plane);
|
||||||
|
// if (plane == nullptr) {
|
||||||
|
// error("GfxFrameout::updateScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
|
||||||
|
// }
|
||||||
|
|
||||||
|
screenItem.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxFrameout::deleteScreenItem(ScreenItem &screenItem) {
|
||||||
|
Plane *plane = _planes.findByObject(screenItem._plane);
|
||||||
|
if (plane == nullptr) {
|
||||||
|
error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(screenItem._plane), PRINT_REG(screenItem._object));
|
||||||
|
}
|
||||||
|
if (plane->_screenItemList.findByObject(screenItem._object) == nullptr) {
|
||||||
|
error("GfxFrameout::deleteScreenItem: Screen item %04x:%04x not found in plane %04x:%04x", PRINT_REG(screenItem._object), PRINT_REG(screenItem._plane));
|
||||||
|
}
|
||||||
|
deleteScreenItem(screenItem, *plane);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, Plane &plane) {
|
||||||
|
if (screenItem._created == 0) {
|
||||||
|
screenItem._created = 0;
|
||||||
|
screenItem._updated = 0;
|
||||||
|
screenItem._deleted = getScreenCount();
|
||||||
} else {
|
} else {
|
||||||
plane->_screenItemList.erase(screenItem);
|
plane._screenItemList.erase(&screenItem);
|
||||||
plane->_screenItemList.pack();
|
plane._screenItemList.pack();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxFrameout::deleteScreenItem(ScreenItem *screenItem, const reg_t planeObject) {
|
void GfxFrameout::deleteScreenItem(ScreenItem &screenItem, const reg_t planeObject) {
|
||||||
Plane *plane = _planes.findByObject(planeObject);
|
Plane *plane = _planes.findByObject(planeObject);
|
||||||
deleteScreenItem(screenItem, plane);
|
if (plane == nullptr) {
|
||||||
|
error("GfxFrameout::deleteScreenItem: Could not find plane %04x:%04x for screen item %04x:%04x", PRINT_REG(planeObject), PRINT_REG(screenItem._object));
|
||||||
|
}
|
||||||
|
deleteScreenItem(screenItem, *plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxFrameout::kernelAddScreenItem(const reg_t object) {
|
void GfxFrameout::kernelAddScreenItem(const reg_t object) {
|
||||||
|
@ -364,7 +396,7 @@ void GfxFrameout::kernelDeleteScreenItem(const reg_t object) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteScreenItem(screenItem, plane);
|
deleteScreenItem(*screenItem, *plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
|
@ -202,14 +202,29 @@ private:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Deletes a screen item from the given plane.
|
* Adds a screen item.
|
||||||
*/
|
*/
|
||||||
void deleteScreenItem(ScreenItem *screenItem, Plane *plane);
|
void addScreenItem(ScreenItem &screenItem) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates a screen item.
|
||||||
|
*/
|
||||||
|
void updateScreenItem(ScreenItem &screenItem) const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a screen item.
|
||||||
|
*/
|
||||||
|
void deleteScreenItem(ScreenItem &screenItem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes a screen item from the given plane.
|
* Deletes a screen item from the given plane.
|
||||||
*/
|
*/
|
||||||
void deleteScreenItem(ScreenItem *screenItem, const reg_t plane);
|
void deleteScreenItem(ScreenItem &screenItem, Plane &plane);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a screen item from the given plane.
|
||||||
|
*/
|
||||||
|
void deleteScreenItem(ScreenItem &screenItem, const reg_t plane);
|
||||||
|
|
||||||
void kernelAddScreenItem(const reg_t object);
|
void kernelAddScreenItem(const reg_t object);
|
||||||
void kernelUpdateScreenItem(const reg_t object);
|
void kernelUpdateScreenItem(const reg_t object);
|
||||||
|
|
|
@ -81,7 +81,7 @@ void GfxPaint32::kernelDeleteLine(const reg_t screenItemObject, const reg_t plan
|
||||||
}
|
}
|
||||||
|
|
||||||
_segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
|
_segMan->freeHunkEntry(screenItem->_celInfo.bitmap);
|
||||||
g_sci->_gfxFrameout->deleteScreenItem(screenItem, plane);
|
g_sci->_gfxFrameout->deleteScreenItem(*screenItem, *plane);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GfxPaint32::plotter(int x, int y, int color, void *data) {
|
void GfxPaint32::plotter(int x, int y, int color, void *data) {
|
||||||
|
|
|
@ -64,12 +64,12 @@ private:
|
||||||
*/
|
*/
|
||||||
static uint16 _nextObjectId;
|
static uint16 _nextObjectId;
|
||||||
|
|
||||||
|
public:
|
||||||
/**
|
/**
|
||||||
* The parent plane of this screen item.
|
* The parent plane of this screen item.
|
||||||
*/
|
*/
|
||||||
reg_t _plane;
|
reg_t _plane;
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
/**
|
||||||
* Scaling data used to calculate the final screen
|
* Scaling data used to calculate the final screen
|
||||||
* dimensions of the screen item as well as the scaling
|
* dimensions of the screen item as well as the scaling
|
||||||
|
|
365
engines/sci/graphics/video32.cpp
Normal file
365
engines/sci/graphics/video32.cpp
Normal file
|
@ -0,0 +1,365 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "audio/mixer.h"
|
||||||
|
#include "sci/console.h"
|
||||||
|
#include "sci/event.h"
|
||||||
|
#include "sci/graphics/cursor.h"
|
||||||
|
#include "sci/graphics/frameout.h"
|
||||||
|
#include "sci/graphics/palette32.h"
|
||||||
|
#include "sci/graphics/text32.h"
|
||||||
|
#include "sci/graphics/video32.h"
|
||||||
|
#include "sci/sci.h"
|
||||||
|
#include "video/coktel_decoder.h"
|
||||||
|
|
||||||
|
namespace Sci {
|
||||||
|
VMDPlayer::VMDPlayer(SegManager *segMan, EventManager *eventMan) :
|
||||||
|
_segMan(segMan),
|
||||||
|
_eventMan(eventMan),
|
||||||
|
_decoder(new Video::AdvancedVMDDecoder(Audio::Mixer::kSFXSoundType)),
|
||||||
|
_isOpen(false),
|
||||||
|
_isInitialized(false),
|
||||||
|
_startColor(0),
|
||||||
|
_planeSet(false),
|
||||||
|
_endColor(255),
|
||||||
|
_blackLines(false),
|
||||||
|
_doublePixels(false),
|
||||||
|
_lastYieldedFrameNo(0),
|
||||||
|
_blackoutRect(),
|
||||||
|
_blackPalette(false),
|
||||||
|
_boostPercent(100),
|
||||||
|
_boostStartColor(0),
|
||||||
|
_boostEndColor(255),
|
||||||
|
_leaveLastFrame(false),
|
||||||
|
_leaveScreenBlack(false),
|
||||||
|
_plane(nullptr),
|
||||||
|
_screenItem(nullptr),
|
||||||
|
_stretchVertical(false),
|
||||||
|
_priority(0),
|
||||||
|
_blackoutPlane(nullptr),
|
||||||
|
_yieldInterval(0) {}
|
||||||
|
|
||||||
|
VMDPlayer::~VMDPlayer() {
|
||||||
|
close();
|
||||||
|
delete _decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
VMDPlayer::IOStatus VMDPlayer::open(const Common::String &fileName, const OpenFlags flags) {
|
||||||
|
if (_isOpen) {
|
||||||
|
error("Attempted to play %s, but another VMD was loaded", fileName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_decoder->loadFile(fileName)) {
|
||||||
|
if (flags & kOpenFlagMute) {
|
||||||
|
_decoder->setVolume(0);
|
||||||
|
}
|
||||||
|
_isOpen = true;
|
||||||
|
return kIOSuccess;
|
||||||
|
} else {
|
||||||
|
return kIOError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMDPlayer::init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor) {
|
||||||
|
_x = getSciVersion() >= SCI_VERSION_3 ? x : (x & ~1);
|
||||||
|
_y = y;
|
||||||
|
_leaveScreenBlack = flags & kPlayFlagLeaveScreenBlack;
|
||||||
|
_leaveLastFrame = flags & kPlayFlagLeaveLastFrame;
|
||||||
|
_doublePixels = flags & kPlayFlagDoublePixels;
|
||||||
|
_blackLines = flags & kPlayFlagBlackLines;
|
||||||
|
_boostPercent = 100 + (flags & kPlayFlagBoost ? boostPercent : 0);
|
||||||
|
_blackPalette = flags & kPlayFlagBlackPalette;
|
||||||
|
_stretchVertical = flags & kPlayFlagStretchVertical;
|
||||||
|
_boostStartColor = CLIP<int16>(boostStartColor, 0, 255);
|
||||||
|
_boostEndColor = CLIP<int16>(boostEndColor, 0, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMDPlayer::restrictPalette(const uint8 startColor, const uint8 endColor) {
|
||||||
|
_startColor = startColor;
|
||||||
|
_endColor = endColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
VMDPlayer::EventFlags VMDPlayer::kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval) {
|
||||||
|
assert(lastFrameNo >= -1);
|
||||||
|
|
||||||
|
const int32 maxFrameNo = (int32)(_decoder->getFrameCount() - 1);
|
||||||
|
|
||||||
|
if ((flags & kEventFlagToFrame) && lastFrameNo > 0) {
|
||||||
|
_decoder->setEndFrame(MIN((int32)lastFrameNo, maxFrameNo));
|
||||||
|
} else {
|
||||||
|
_decoder->setEndFrame(maxFrameNo);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & kEventFlagYieldToVM) {
|
||||||
|
_yieldInterval = 3;
|
||||||
|
if (yieldInterval == -1 && !(flags & kEventFlagToFrame)) {
|
||||||
|
_yieldInterval = lastFrameNo;
|
||||||
|
} else if (yieldInterval != -1) {
|
||||||
|
_yieldInterval = MIN((int32)yieldInterval, maxFrameNo);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
_yieldInterval = maxFrameNo;
|
||||||
|
}
|
||||||
|
|
||||||
|
return playUntilEvent(flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
VMDPlayer::EventFlags VMDPlayer::playUntilEvent(const EventFlags flags) {
|
||||||
|
// Flushing all the keyboard and mouse events out of the event manager to
|
||||||
|
// avoid letting any events queued from before the video started from
|
||||||
|
// accidentally activating an event callback
|
||||||
|
for (;;) {
|
||||||
|
const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_MOUSE_PRESS | SCI_EVENT_MOUSE_RELEASE | SCI_EVENT_QUIT);
|
||||||
|
if (event.type == SCI_EVENT_NONE) {
|
||||||
|
break;
|
||||||
|
} else if (event.type == SCI_EVENT_QUIT) {
|
||||||
|
return kEventFlagEnd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_decoder->pauseVideo(false);
|
||||||
|
|
||||||
|
if (flags & kEventFlagReverse) {
|
||||||
|
// NOTE: This flag may not work properly since SSCI does not care
|
||||||
|
// if a video has audio, but the VMD decoder does.
|
||||||
|
const bool success = _decoder->setReverse(true);
|
||||||
|
assert(success);
|
||||||
|
_decoder->setVolume(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_isInitialized) {
|
||||||
|
_isInitialized = true;
|
||||||
|
|
||||||
|
if (!_showCursor) {
|
||||||
|
g_sci->_gfxCursor->kernelHide();
|
||||||
|
}
|
||||||
|
|
||||||
|
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 vmdRect(
|
||||||
|
_x,
|
||||||
|
_y,
|
||||||
|
_x + _decoder->getWidth(),
|
||||||
|
_y + _decoder->getHeight()
|
||||||
|
);
|
||||||
|
ScaleInfo vmdScaleInfo;
|
||||||
|
|
||||||
|
if (!_blackoutRect.isEmpty() && !_planeSet) {
|
||||||
|
_blackoutPlane = new Plane(_blackoutRect);
|
||||||
|
g_sci->_gfxFrameout->addPlane(*_blackoutPlane);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_doublePixels) {
|
||||||
|
vmdScaleInfo.x = 256;
|
||||||
|
vmdScaleInfo.y = 256;
|
||||||
|
vmdScaleInfo.signal = kScaleSignalDoScaling32;
|
||||||
|
vmdRect.right += vmdRect.width();
|
||||||
|
vmdRect.bottom += vmdRect.height();
|
||||||
|
} else if (_stretchVertical) {
|
||||||
|
vmdScaleInfo.y = 256;
|
||||||
|
vmdScaleInfo.signal = kScaleSignalDoScaling32;
|
||||||
|
vmdRect.bottom += vmdRect.height();
|
||||||
|
}
|
||||||
|
|
||||||
|
BitmapResource vmdBitmap(_segMan, vmdRect.width(), vmdRect.height(), 255, 0, 0, screenWidth, screenHeight, 0, false);
|
||||||
|
|
||||||
|
if (screenWidth != scriptWidth || screenHeight != scriptHeight) {
|
||||||
|
mulru(vmdRect, Ratio(scriptWidth, screenWidth), Ratio(scriptHeight, screenHeight), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
CelInfo32 vmdCelInfo;
|
||||||
|
vmdCelInfo.bitmap = vmdBitmap.getObject();
|
||||||
|
_decoder->setSurfaceMemory(vmdBitmap.getPixels(), vmdBitmap.getWidth(), vmdBitmap.getHeight(), 1);
|
||||||
|
|
||||||
|
if (!_planeSet) {
|
||||||
|
_x = 0;
|
||||||
|
_y = 0;
|
||||||
|
_plane = new Plane(vmdRect, kPlanePicColored);
|
||||||
|
if (_priority) {
|
||||||
|
_plane->_priority = _priority;
|
||||||
|
}
|
||||||
|
g_sci->_gfxFrameout->addPlane(*_plane);
|
||||||
|
_screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(), vmdScaleInfo);
|
||||||
|
} else {
|
||||||
|
_screenItem = new ScreenItem(_plane->_object, vmdCelInfo, Common::Point(_x, _y), vmdScaleInfo);
|
||||||
|
if (_priority) {
|
||||||
|
_screenItem->_priority = _priority;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: There was code for positioning the screen item using insetRect
|
||||||
|
// here, but none of the game scripts seem to use this functionality.
|
||||||
|
|
||||||
|
g_sci->_gfxFrameout->addScreenItem(*_screenItem);
|
||||||
|
|
||||||
|
_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();
|
||||||
|
}
|
||||||
|
|
||||||
|
const int currentFrameNo = _decoder->getCurFrame();
|
||||||
|
|
||||||
|
if (
|
||||||
|
_yieldInterval > 0 &&
|
||||||
|
currentFrameNo != _lastYieldedFrameNo &&
|
||||||
|
(currentFrameNo % _yieldInterval) == 0
|
||||||
|
) {
|
||||||
|
_lastYieldedFrameNo = currentFrameNo;
|
||||||
|
stopFlag = kEventFlagYieldToVM;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & kEventFlagMouseDown && _eventMan->getSciEvent(SCI_EVENT_MOUSE_PRESS | SCI_EVENT_PEEK).type != SCI_EVENT_NONE) {
|
||||||
|
stopFlag = kEventFlagMouseDown;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & kEventFlagEscapeKey) {
|
||||||
|
const SciEvent event = _eventMan->getSciEvent(SCI_EVENT_KEYBOARD | SCI_EVENT_PEEK);
|
||||||
|
if (event.type != SCI_EVENT_NONE && event.character == SCI_KEY_ESC) {
|
||||||
|
stopFlag = kEventFlagEscapeKey;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (flags & kEventFlagHotRectangle) {
|
||||||
|
// TODO: Hot rectangles
|
||||||
|
warning("Hot rectangles not implemented in VMD player");
|
||||||
|
stopFlag = kEventFlagHotRectangle;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_decoder->pauseVideo(true);
|
||||||
|
return stopFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VMDPlayer::renderFrame() {
|
||||||
|
// TODO: This is kind of different from the original implementation
|
||||||
|
// which has access to dirty rects from the decoder; we probably do
|
||||||
|
// not need to care to limit output this way
|
||||||
|
|
||||||
|
_decoder->decodeNextFrame();
|
||||||
|
|
||||||
|
// NOTE: Normally this would write a hunk palette at the end of the
|
||||||
|
// video bitmap that CelObjMem would read out and submit, but instead
|
||||||
|
// 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) {
|
||||||
|
Palette palette;
|
||||||
|
if (_blackPalette) {
|
||||||
|
for (uint16 i = _startColor; i <= _endColor; ++i) {
|
||||||
|
palette.colors[i].r = palette.colors[i].g = palette.colors[i].b = 0;
|
||||||
|
palette.colors[i].used = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
|
||||||
|
for (uint16 i = _startColor; i <= _endColor; ++i) {
|
||||||
|
palette.colors[i].r = *vmdPalette++;
|
||||||
|
palette.colors[i].g = *vmdPalette++;
|
||||||
|
palette.colors[i].b = *vmdPalette++;
|
||||||
|
palette.colors[i].used = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
g_sci->_gfxPalette32->submit(palette);
|
||||||
|
g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
|
||||||
|
g_sci->_gfxFrameout->frameOut(true);
|
||||||
|
|
||||||
|
if (_blackPalette) {
|
||||||
|
const byte *vmdPalette = _decoder->getPalette() + _startColor * 3;
|
||||||
|
for (uint16 i = _startColor; i <= _endColor; ++i) {
|
||||||
|
palette.colors[i].r = *vmdPalette++;
|
||||||
|
palette.colors[i].g = *vmdPalette++;
|
||||||
|
palette.colors[i].b = *vmdPalette++;
|
||||||
|
palette.colors[i].used = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
g_sci->_gfxPalette32->submit(palette);
|
||||||
|
g_sci->_gfxPalette32->updateForFrame();
|
||||||
|
g_sci->_gfxPalette32->updateHardware();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
g_sci->_gfxFrameout->updateScreenItem(*_screenItem);
|
||||||
|
g_sci->getSciDebugger()->onFrame();
|
||||||
|
g_sci->_gfxFrameout->frameOut(true);
|
||||||
|
g_sci->_gfxFrameout->throttle();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VMDPlayer::IOStatus VMDPlayer::close() {
|
||||||
|
if (!_isOpen) {
|
||||||
|
return kIOSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
_decoder->close();
|
||||||
|
_isOpen = false;
|
||||||
|
_isInitialized = false;
|
||||||
|
|
||||||
|
if (_planeSet && _screenItem != nullptr) {
|
||||||
|
g_sci->_gfxFrameout->deleteScreenItem(*_screenItem);
|
||||||
|
_screenItem = nullptr;
|
||||||
|
} else if (_plane != nullptr) {
|
||||||
|
g_sci->_gfxFrameout->deletePlane(*_plane);
|
||||||
|
_plane = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_leaveLastFrame && _leaveScreenBlack) {
|
||||||
|
// This call *actually* deletes the plane/screen item
|
||||||
|
g_sci->_gfxFrameout->frameOut(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_blackoutPlane != nullptr) {
|
||||||
|
g_sci->_gfxFrameout->deletePlane(*_blackoutPlane);
|
||||||
|
_blackoutPlane = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_leaveLastFrame && !_leaveScreenBlack) {
|
||||||
|
// This call *actually* deletes the blackout plane
|
||||||
|
g_sci->_gfxFrameout->frameOut(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_showCursor) {
|
||||||
|
g_sci->_gfxCursor->kernelShow();
|
||||||
|
}
|
||||||
|
|
||||||
|
_planeSet = false;
|
||||||
|
_priority = 0;
|
||||||
|
return kIOSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Sci
|
275
engines/sci/graphics/video32.h
Normal file
275
engines/sci/graphics/video32.h
Normal file
|
@ -0,0 +1,275 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SCI_GRAPHICS_VIDEO32_H
|
||||||
|
#define SCI_GRAPHICS_VIDEO32_H
|
||||||
|
|
||||||
|
namespace Video { class AdvancedVMDDecoder; }
|
||||||
|
namespace Sci {
|
||||||
|
class Plane;
|
||||||
|
class ScreenItem;
|
||||||
|
class SegManager;
|
||||||
|
|
||||||
|
class VMDPlayer {
|
||||||
|
public:
|
||||||
|
enum OpenFlags {
|
||||||
|
kOpenFlagNone = 0,
|
||||||
|
kOpenFlagMute = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
enum IOStatus {
|
||||||
|
kIOSuccess = 0,
|
||||||
|
kIOError = 0xFFFF
|
||||||
|
};
|
||||||
|
|
||||||
|
enum PlayFlags {
|
||||||
|
kPlayFlagNone = 0,
|
||||||
|
kPlayFlagDoublePixels = 1,
|
||||||
|
kPlayFlagNoFrameskip = 2, // NOTE: the current VMD decoder does not allow this
|
||||||
|
kPlayFlagBlackLines = 4,
|
||||||
|
kPlayFlagBoost = 0x10,
|
||||||
|
kPlayFlagLeaveScreenBlack = 0x20,
|
||||||
|
kPlayFlagLeaveLastFrame = 0x40,
|
||||||
|
kPlayFlagBlackPalette = 0x80,
|
||||||
|
kPlayFlagStretchVertical = 0x100
|
||||||
|
};
|
||||||
|
|
||||||
|
enum EventFlags {
|
||||||
|
kEventFlagNone = 0,
|
||||||
|
kEventFlagEnd = 1,
|
||||||
|
kEventFlagEscapeKey = 2,
|
||||||
|
kEventFlagMouseDown = 4,
|
||||||
|
kEventFlagHotRectangle = 8,
|
||||||
|
kEventFlagToFrame = 0x10,
|
||||||
|
kEventFlagYieldToVM = 0x20,
|
||||||
|
kEventFlagReverse = 0x80
|
||||||
|
};
|
||||||
|
|
||||||
|
VMDPlayer(SegManager *segMan, EventManager *eventMan);
|
||||||
|
~VMDPlayer();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opens a stream to a VMD resource.
|
||||||
|
*/
|
||||||
|
IOStatus open(const Common::String &fileName, const OpenFlags flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initializes the VMD rendering parameters for the
|
||||||
|
* current VMD. This must be called after `open`.
|
||||||
|
*/
|
||||||
|
void init(const int16 x, const int16 y, const PlayFlags flags, const int16 boostPercent, const int16 boostStartColor, const int16 boostEndColor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stops playback and closes the currently open VMD stream.
|
||||||
|
*/
|
||||||
|
IOStatus close();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restricts use of the system palette by VMD playback to
|
||||||
|
* the given range of palette indexes.
|
||||||
|
*/
|
||||||
|
void restrictPalette(const uint8 startColor, const uint8 endColor);
|
||||||
|
|
||||||
|
// NOTE: Was WaitForEvent in SSCI
|
||||||
|
EventFlags kernelPlayUntilEvent(const EventFlags flags, const int16 lastFrameNo, const int16 yieldInterval);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the area of the screen that should be blacked out
|
||||||
|
* during VMD playback.
|
||||||
|
*/
|
||||||
|
void setBlackoutArea(const Common::Rect &rect) { _blackoutRect = rect; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets whether or not the mouse cursor should be drawn.
|
||||||
|
* This does not have any effect during playback, but can
|
||||||
|
* be used to prevent the mouse cursor from being shown
|
||||||
|
* after the video has finished.
|
||||||
|
*/
|
||||||
|
void setShowCursor(const bool shouldShow) { _showCursor = shouldShow; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
SegManager *_segMan;
|
||||||
|
EventManager *_eventMan;
|
||||||
|
Video::AdvancedVMDDecoder *_decoder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plays the VMD until an event occurs (e.g. user
|
||||||
|
* presses escape, clicks, etc.).
|
||||||
|
*/
|
||||||
|
EventFlags playUntilEvent(const EventFlags flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renders a frame of video to the output bitmap.
|
||||||
|
*/
|
||||||
|
void renderFrame();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not a VMD stream has been opened with
|
||||||
|
* `open`.
|
||||||
|
*/
|
||||||
|
bool _isOpen;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not a VMD player has been initialised
|
||||||
|
* with `init`.
|
||||||
|
*/
|
||||||
|
bool _isInitialized;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the playback area of the VMD
|
||||||
|
* should be left black at the end of playback.
|
||||||
|
*/
|
||||||
|
bool _leaveScreenBlack;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the area of the VMD should be left
|
||||||
|
* displaying the final frame of the video.
|
||||||
|
*/
|
||||||
|
bool _leaveLastFrame;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the video should be pixel doubled.
|
||||||
|
*/
|
||||||
|
bool _doublePixels;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the video should be pixel doubled
|
||||||
|
* vertically only.
|
||||||
|
*/
|
||||||
|
bool _stretchVertical;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not black lines should be rendered
|
||||||
|
* across the video.
|
||||||
|
*/
|
||||||
|
bool _blackLines;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The amount of brightness boost for the video.
|
||||||
|
* Values above 100 increase brightness; values below
|
||||||
|
* 100 reduce it.
|
||||||
|
*/
|
||||||
|
int16 _boostPercent;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first color in the palette that should be
|
||||||
|
* brightness boosted.
|
||||||
|
*/
|
||||||
|
uint8 _boostStartColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last color in the palette that should be
|
||||||
|
* brightness boosted.
|
||||||
|
*/
|
||||||
|
uint8 _boostEndColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The first color in the system palette that the VMD
|
||||||
|
* can write to.
|
||||||
|
*/
|
||||||
|
uint8 _startColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The last color in the system palette that the VMD
|
||||||
|
* can write to.
|
||||||
|
*/
|
||||||
|
uint8 _endColor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If true, video frames are rendered after a blank
|
||||||
|
* palette is submitted to the palette manager,
|
||||||
|
* which is then restored after the video pixels
|
||||||
|
* have already been rendered.
|
||||||
|
*/
|
||||||
|
bool _blackPalette;
|
||||||
|
|
||||||
|
// TODO: planeSet and priority are used in SCI3+ only
|
||||||
|
bool _planeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The screen priority of the video.
|
||||||
|
* @see ScreenItem::_priority
|
||||||
|
*/
|
||||||
|
int _priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plane where the VMD will be drawn.
|
||||||
|
*/
|
||||||
|
Plane *_plane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The screen item representing the VMD surface.
|
||||||
|
*/
|
||||||
|
ScreenItem *_screenItem;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An optional plane that will be used to black out
|
||||||
|
* areas of the screen outside the area of the VMD
|
||||||
|
* surface.
|
||||||
|
*/
|
||||||
|
Plane *_blackoutPlane;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The dimensions of the blackout plane.
|
||||||
|
*/
|
||||||
|
Common::Rect _blackoutRect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not the mouse cursor should be shown
|
||||||
|
* during playback.
|
||||||
|
*/
|
||||||
|
bool _showCursor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The location of the VMD plane, in game script
|
||||||
|
* coordinates.
|
||||||
|
*/
|
||||||
|
int16 _x, _y;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For VMDs played with the `kEventFlagYieldToVM` flag,
|
||||||
|
* the number of frames that should be drawn until
|
||||||
|
* yielding back to the SCI VM.
|
||||||
|
*/
|
||||||
|
int32 _yieldInterval;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For VMDs played with the `kEventFlagYieldToVM` flag,
|
||||||
|
* the last frame when control of the main thread was
|
||||||
|
* yielded back to the SCI VM.
|
||||||
|
*/
|
||||||
|
int _lastYieldedFrameNo;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Video32 {
|
||||||
|
public:
|
||||||
|
Video32(SegManager *segMan, EventManager *eventMan) :
|
||||||
|
_VMDPlayer(segMan, eventMan) {}
|
||||||
|
|
||||||
|
VMDPlayer &getVMDPlayer() { return _VMDPlayer; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
VMDPlayer _VMDPlayer;
|
||||||
|
};
|
||||||
|
} // End of namespace Sci
|
||||||
|
|
||||||
|
#endif
|
|
@ -91,6 +91,7 @@ MODULE_OBJS += \
|
||||||
graphics/remap32.o \
|
graphics/remap32.o \
|
||||||
graphics/screen_item32.o \
|
graphics/screen_item32.o \
|
||||||
graphics/text32.o \
|
graphics/text32.o \
|
||||||
|
graphics/video32.o \
|
||||||
sound/audio32.o \
|
sound/audio32.o \
|
||||||
sound/decoders/sol.o \
|
sound/decoders/sol.o \
|
||||||
video/robot_decoder.o
|
video/robot_decoder.o
|
||||||
|
|
|
@ -69,7 +69,9 @@
|
||||||
#include "sci/graphics/palette32.h"
|
#include "sci/graphics/palette32.h"
|
||||||
#include "sci/graphics/remap32.h"
|
#include "sci/graphics/remap32.h"
|
||||||
#include "sci/graphics/text32.h"
|
#include "sci/graphics/text32.h"
|
||||||
|
#include "sci/graphics/video32.h"
|
||||||
#include "sci/sound/audio32.h"
|
#include "sci/sound/audio32.h"
|
||||||
|
// TODO: Move this to video32
|
||||||
#include "sci/video/robot_decoder.h"
|
#include "sci/video/robot_decoder.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -92,6 +94,7 @@ SciEngine::SciEngine(OSystem *syst, const ADGameDescription *desc, SciGameId gam
|
||||||
_sync = nullptr;
|
_sync = nullptr;
|
||||||
#ifdef ENABLE_SCI32
|
#ifdef ENABLE_SCI32
|
||||||
_audio32 = nullptr;
|
_audio32 = nullptr;
|
||||||
|
_video32 = nullptr;
|
||||||
#endif
|
#endif
|
||||||
_features = 0;
|
_features = 0;
|
||||||
_resMan = 0;
|
_resMan = 0;
|
||||||
|
@ -277,15 +280,20 @@ Common::Error SciEngine::run() {
|
||||||
if (getGameId() == GID_CHRISTMAS1990)
|
if (getGameId() == GID_CHRISTMAS1990)
|
||||||
_vocabulary = new Vocabulary(_resMan, false);
|
_vocabulary = new Vocabulary(_resMan, false);
|
||||||
|
|
||||||
|
_gamestate = new EngineState(segMan);
|
||||||
|
_eventMan = new EventManager(_resMan->detectFontExtended());
|
||||||
#ifdef ENABLE_SCI32
|
#ifdef ENABLE_SCI32
|
||||||
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
|
if (getSciVersion() >= SCI_VERSION_2_1_EARLY) {
|
||||||
_audio32 = new Audio32(_resMan);
|
_audio32 = new Audio32(_resMan);
|
||||||
} else
|
} else
|
||||||
#endif
|
#endif
|
||||||
_audio = new AudioPlayer(_resMan);
|
_audio = new AudioPlayer(_resMan);
|
||||||
|
#ifdef ENABLE_SCI32
|
||||||
|
if (getSciVersion() >= SCI_VERSION_2) {
|
||||||
|
_video32 = new Video32(segMan, _eventMan);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
_sync = new Sync(_resMan, segMan);
|
_sync = new Sync(_resMan, segMan);
|
||||||
_gamestate = new EngineState(segMan);
|
|
||||||
_eventMan = new EventManager(_resMan->detectFontExtended());
|
|
||||||
|
|
||||||
// Create debugger console. It requires GFX and _gamestate to be initialized
|
// Create debugger console. It requires GFX and _gamestate to be initialized
|
||||||
_console = new Console(this);
|
_console = new Console(this);
|
||||||
|
|
|
@ -80,9 +80,11 @@ class GfxText32;
|
||||||
class GfxTransitions;
|
class GfxTransitions;
|
||||||
|
|
||||||
#ifdef ENABLE_SCI32
|
#ifdef ENABLE_SCI32
|
||||||
|
// TODO: Move RobotDecoder to Video32
|
||||||
class RobotDecoder;
|
class RobotDecoder;
|
||||||
class GfxFrameout;
|
class GfxFrameout;
|
||||||
class Audio32;
|
class Audio32;
|
||||||
|
class Video32;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// our engine debug levels
|
// our engine debug levels
|
||||||
|
@ -371,6 +373,7 @@ public:
|
||||||
|
|
||||||
#ifdef ENABLE_SCI32
|
#ifdef ENABLE_SCI32
|
||||||
Audio32 *_audio32;
|
Audio32 *_audio32;
|
||||||
|
Video32 *_video32;
|
||||||
RobotDecoder *_robotDecoder;
|
RobotDecoder *_robotDecoder;
|
||||||
GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
|
GfxFrameout *_gfxFrameout; // kFrameout and the like for 32-bit gfx
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue