/* 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 3 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, see .
*
*/
#include "graphics/cursorman.h"
#include "bagel/spacebar/baglib/fmovie.h"
#include "bagel/boflib/string.h"
#include "bagel/boflib/palette.h"
#include "bagel/spacebar/boflib/app.h"
#include "bagel/spacebar/baglib/master_win.h"
#include "bagel/spacebar/baglib/pan_window.h"
#include "bagel/spacebar/boflib/std_keys.h"
namespace Bagel {
namespace SpaceBar {
CBagFMovie::CBagFMovie(CBofWindow *parent, const char *filename, CBofRect *bounds, bool useNewPalette, bool blackOutWindow) {
// Allow movie to not shift to new palette.
_useNewPaletteFl = useNewPalette;
// Black out first and last frame of flythroughs and examine movies
_blackOutWindowFl = blackOutWindow;
CBagFMovie::initialize(parent);
CBagFMovie::open(filename, bounds);
}
CBagFMovie::~CBagFMovie() {
CBagFMovie::closeMovie();
}
ErrorCode CBagFMovie::initialize(CBofWindow *pParent) {
// Movie Stuff
_movieStatus = MOVIE_STOPPED;
_escCanStopFl = true;
_smackerPal = nullptr;
_bmpBuf = nullptr;
_filterBmp = nullptr;
_bufferStart = nullptr;
_bufferLength = 0;
// Smacker Stuff
_smk = nullptr;
_loopFl = false;
// Call dialog box creates
if (create("MovieWin", 0, 0, 1, 1, pParent, 1) == ERR_NONE) {
setCapture();
}
return ERR_NONE;
}
bool CBagFMovie::open(const char *filename, CBofRect *bounds) {
// No filename, so put up an open file box
if (filename == nullptr) {
assert(filename);
return false;
}
if (bounds != nullptr) {
_cRect = *bounds;
}
if (openMovie(filename)) {
// We were given specific rect for movie
if (bounds)
reSize(bounds, true);
else
// Center the movie to the parent window
centerRect();
// Paint the image to the screen.
_filterBmp->paint(this, 0, 0);
return true;
}
return false;
}
bool CBagFMovie::openMovie(const char *sFilename) {
assert(sFilename[0] != '\0');
if (_smk) {
closeMovie();
}
_smk = new Video::SmackerDecoder();
_smk->setSoundType(Audio::Mixer::kSFXSoundType);
// Opened failed ?
if (!_smk->loadFile(sFilename)) {
error("Movie not found=%s", sFilename);
}
// Allocate the bitmaps.
_smackerPal = new CBofPalette();
_bmpBuf = new CBofBitmap(_smk->getWidth(), _smk->getHeight(), _smackerPal, false);
_filterBmp = new CBofBitmap(_smk->getWidth(), _smk->getHeight(), _smackerPal, false);
_filterBmp->lock();
selectPalette(_smackerPal);
if (_bmpBuf) {
_bmpBuf->lock();
_bmpBuf->fillRect(nullptr, _smackerPal->getNearestIndex(CTEXT_WHITE));
_bufferStart = (char *)_bmpBuf->getPixelAddress(0, _bmpBuf->isTopDown() ? 0 : (_bmpBuf->height() - 1));
_bufferLength = ABS(_bmpBuf->height() * _bmpBuf->width());
const Graphics::Surface *frame = _smk->decodeNextFrame();
_smackerPal->setData(_smk->getPalette());
if (frame) {
_bmpBuf->getSurface().blitFrom(*frame);
}
}
const bool repaintFl = true;
_bounds = CBofRect(0, 0, (uint16)_bmpBuf->width() - 1, (uint16)_bmpBuf->height() - 1);
reSize(&_bounds, repaintFl);
CBagMasterWin *curWin = CBagel::getBagApp()->getMasterWnd();
if (curWin != nullptr) {
CBagStorageDevWnd *curSDev = curWin->getCurrentStorageDev();
if ((curSDev != nullptr) && curSDev->isFiltered()) {
const uint16 filterId = curSDev->getFilterId();
const FilterFunction filterFunction = curSDev->getFilter();
_bmpBuf->paint(_filterBmp);
(*filterFunction)(filterId, _filterBmp, &_bounds);
}
}
return true;
}
void CBagFMovie::onKeyHit(uint32 keyCode, uint32 /* repCount */) {
if (_escCanStopFl && keyCode == BKEY_ESC) {
// Clean up and exit
_loopFl = false;
stop();
onMovieDone();
}
}
void CBagFMovie::onMainLoop() {
if (!_smk->needsUpdate() || (_movieStatus == MOVIE_STOPPED))
return;
// Smack the current frame into the buffer
const Graphics::Surface *frame = _smk->decodeNextFrame();
if (_smk->hasDirtyPalette()) {
_smackerPal->setData(_smk->getPalette());
}
if (frame) {
_bmpBuf->getSurface().blitFrom(*frame);
}
_bmpBuf->paint1To1(_filterBmp);
// Filter the bitmap.
CBagMasterWin *curWin = CBagel::getBagApp()->getMasterWnd();
if (curWin != nullptr) {
CBagStorageDevWnd *curSDev = curWin->getCurrentStorageDev();
if ((curSDev != nullptr) && curSDev->isFiltered()) {
const uint16 filterId = curSDev->getFilterId();
const FilterFunction filterFunction = curSDev->getFilter();
(*filterFunction)(filterId, _filterBmp, &_bounds);
}
}
// Paint the buffer to the screen.
_filterBmp->paint(this, 0, 0);
if (_movieStatus == MOVIE_FORWARD) {
if (_smk->getCurFrame() == (int)_smk->getFrameCount() - 1) {
if (_loopFl == false) {
onMovieDone();
} else {
seekToStart();
_smk->start();
}
}
} else if (_movieStatus == MOVIE_REVERSE) {
if (_smk->getCurFrame() == 0 || _smk->getCurFrame() == 1) {
if (_loopFl == false) {
onMovieDone();
} else {
seekToEnd();
}
} else {
setFrame(_smk->getCurFrame() - 2); // HACK: Reverse playback
}
}
}
void CBagFMovie::onPaint(CBofRect *) {
}
void CBagFMovie::closeMovie() {
delete _smk;
_smk = nullptr;
if (_filterBmp != nullptr) {
_filterBmp->unlock();
delete _filterBmp;
_filterBmp = nullptr;
}
if (_bmpBuf != nullptr) {
_bmpBuf->unlock();
delete _bmpBuf;
_bmpBuf = nullptr;
}
delete _smackerPal;
_smackerPal = nullptr;
_bufferStart = nullptr;
_bufferLength = 0;
}
void CBagFMovie::onClose() {
closeMovie();
CBofDialog::onClose();
}
void CBagFMovie::onMovieDone() {
if (!_loopFl) {
if (_bCaptured)
releaseCapture();
getParent()->enable();
_bEndDialog = true;
}
}
bool CBagFMovie::play(bool loop, bool escCanStop) {
_escCanStopFl = escCanStop;
_loopFl = loop;
const bool retVal = play();
getParent()->disable();
getParent()->flushAllMessages();
CursorMan.showMouse(false);
doModal();
CursorMan.showMouse(true);
return retVal;
}
bool CBagFMovie::play() {
if (!_smk)
return false;
_smk->pauseVideo(false);
// _smk->setReverse(false); // TODO: Not supported by SMK
_smk->start();
_movieStatus = MOVIE_FORWARD;
return true;
}
bool CBagFMovie::reverse(bool loop, bool escCanStop) {
_escCanStopFl = escCanStop;
_loopFl = loop;
const bool retVal = reverse();
getParent()->disable();
getParent()->flushAllMessages();
doModal();
return retVal;
}
bool CBagFMovie::reverse() {
if (!_smk)
return false;
_smk->pauseVideo(false);
// _smk->setReverse(true); // TODO: Not supported by SMK
_smk->start();
_movieStatus = MOVIE_REVERSE;
return true;
}
bool CBagFMovie::stop() {
if (!_smk)
return false;
_smk->stop();
_movieStatus = MOVIE_STOPPED;
return true;
}
bool CBagFMovie::pause() {
if (!_smk)
return false;
_smk->pauseVideo(true);
_movieStatus = MOVIE_PAUSED;
return true;
}
bool CBagFMovie::seekToStart() {
if (!_smk)
return false;
_smk->rewind();
return true;
}
bool CBagFMovie::seekToEnd() {
if (!_smk)
return false;
setFrame(_smk->getFrameCount() - 2); // HACK: Reverse rewind
return true;
}
uint32 CBagFMovie::getFrame() {
if (_smk) {
return _smk->getCurFrame();
}
return (uint32) -1;
}
bool CBagFMovie::setFrame(uint32 frameNum) {
if (!_smk)
return false;
frameNum = CLIP(frameNum, 0, _smk->getFrameCount() - 1);
_smk->forceSeekToFrame(frameNum);
return true;
}
bool CBagFMovie::centerRect() {
CBofRect clientRect = getParent()->getClientRect();
const RECT parentRect = clientRect.getWinRect();
const int clientWidth = parentRect.right - parentRect.left;
const int clientHeight = parentRect.bottom - parentRect.top;
// Get Movies width and height
const int movieWidth = _smk->getWidth();
const int movieHeight = _smk->getHeight();
RECT movieBounds;
movieBounds.left = (clientWidth - movieWidth) / 2;
movieBounds.top = (clientHeight - movieHeight) / 2;
movieBounds.right = movieBounds.left + movieWidth;
movieBounds.bottom = movieBounds.top + movieHeight;
// Reposition the playback window
clientRect = movieBounds;
reSize(&clientRect, true);
return true;
}
} // namespace SpaceBar
} // namespace Bagel