aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sandulenko2016-10-04 23:21:41 +0200
committerGitHub2016-10-04 23:21:41 +0200
commit42c518238def133be776b7b857572bb54bc235ed (patch)
tree65aae1e613558f89387ced9d4680cbc49aefc29f
parent43d5ed570ef7863b892979e903ccfd20f4282c15 (diff)
parent054bfb3c196ac5a02d149c758a2ee0a4711b55e4 (diff)
downloadscummvm-rg350-42c518238def133be776b7b857572bb54bc235ed.tar.gz
scummvm-rg350-42c518238def133be776b7b857572bb54bc235ed.tar.bz2
scummvm-rg350-42c518238def133be776b7b857572bb54bc235ed.zip
Merge pull request #839 from dreammaster/video
VIDEO: AVIDecoder changes for Titanic videos
-rw-r--r--engines/titanic/module.mk2
-rw-r--r--engines/titanic/support/avi_surface.cpp130
-rw-r--r--engines/titanic/support/avi_surface.h22
-rw-r--r--engines/titanic/support/mouse_cursor.cpp43
-rw-r--r--engines/titanic/support/mouse_cursor.h4
-rw-r--r--engines/titanic/support/movie.cpp2
-rw-r--r--engines/titanic/support/movie.h10
-rw-r--r--engines/titanic/support/raw_surface.cpp134
-rw-r--r--engines/titanic/support/transparency_surface.cpp83
-rw-r--r--engines/titanic/support/transparency_surface.h (renamed from engines/titanic/support/raw_surface.h)26
-rw-r--r--engines/titanic/support/video_surface.cpp77
-rw-r--r--engines/titanic/support/video_surface.h11
-rw-r--r--video/avi_decoder.cpp107
-rw-r--r--video/avi_decoder.h16
-rw-r--r--video/video_decoder.h2
15 files changed, 318 insertions, 351 deletions
diff --git a/engines/titanic/module.mk b/engines/titanic/module.mk
index f1a6c751df..e802456c5a 100644
--- a/engines/titanic/module.mk
+++ b/engines/titanic/module.mk
@@ -474,7 +474,7 @@ MODULE_OBJS := \
support/movie_range_info.o \
support/movie_manager.o \
support/credit_text.o \
- support/raw_surface.o \
+ support/transparency_surface.o \
support/rect.o \
support/screen_manager.o \
support/simple_file.o \
diff --git a/engines/titanic/support/avi_surface.cpp b/engines/titanic/support/avi_surface.cpp
index 7fbb05ed58..5b11c7799e 100644
--- a/engines/titanic/support/avi_surface.cpp
+++ b/engines/titanic/support/avi_surface.cpp
@@ -30,28 +30,10 @@
namespace Titanic {
-Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack() {
- for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++)
- if ((*it)->getTrackType() == Track::kTrackTypeVideo)
- return *dynamic_cast<AVIVideoTrack *>(*it);
-
- error("Could not find video track");
-}
-
-/**
- * Track filter for AVIDecoder that filters out any secondary
- * video track some videos have to hold transparency masks
- */
-static bool primaryTrackSelect(bool isVideo, int trackCounter) {
- return !isVideo || trackCounter == 0;
-}
-
-/**
- * Track filter for AVIDecoder that only accepts the secondary
- * transparency msak video track for a video, if present
- */
-static bool secondaryTrackSelect(bool isVideo, int trackCounter) {
- return isVideo && trackCounter > 0;
+Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack(uint idx) {
+ assert(idx < _videoTracks.size());
+ AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track);
+ return *track;
}
AVISurface::AVISurface(const CResourceKey &key) {
@@ -60,28 +42,18 @@ AVISurface::AVISurface(const CResourceKey &key) {
_movieFrameSurface[0] = _movieFrameSurface[1] = nullptr;
_framePixels = nullptr;
- // Reset current frame. We need to keep track of frames separately from the decoders,
+ // Reset current frame. We need to keep track of frames separately from the decoder,
// since it needs to be able to go beyond the frame count or to negative to allow
// correct detection of when range playbacks have finished
_currentFrame = -1;
_isReversed = false;
- // Create a decoder for the audio (if any) and primary video track
- _decoders[0] = new AVIDecoder(Audio::Mixer::kPlainSoundType, primaryTrackSelect);
- if (!_decoders[0]->loadFile(key.getString()))
+ // Create a decoder
+ _decoder = new AVIDecoder(Audio::Mixer::kPlainSoundType);
+ if (!_decoder->loadFile(key.getString()))
error("Could not open video - %s", key.getString().c_str());
- _streamCount = 1;
-
- // Create a decoder for any secondary video track
- AVIDecoder *decoder2 = new AVIDecoder(Audio::Mixer::kPlainSoundType, secondaryTrackSelect);
- if (decoder2->loadFile(key.getString())) {
- _decoders[1] = decoder2;
- ++_streamCount;
- } else {
- delete decoder2;
- _decoders[1] = nullptr;
- }
+ _streamCount = _decoder->videoTrackCount();
}
AVISurface::~AVISurface() {
@@ -90,15 +62,14 @@ AVISurface::~AVISurface() {
delete _framePixels;
delete _movieFrameSurface[0];
delete _movieFrameSurface[1];
- delete _decoders[0];
- delete _decoders[1];
+ delete _decoder;
}
bool AVISurface::play(uint flags, CGameObject *obj) {
if (flags & MOVIE_REVERSE)
- return play(_decoders[0]->getFrameCount() - 1, 0, flags, obj);
+ return play(_decoder->getFrameCount() - 1, 0, flags, obj);
else
- return play(0, _decoders[0]->getFrameCount() - 1, flags, obj);
+ return play(0, _decoder->getFrameCount() - 1, flags, obj);
}
bool AVISurface::play(int startFrame, int endFrame, uint flags, CGameObject *obj) {
@@ -139,10 +110,7 @@ bool AVISurface::play(int startFrame, int endFrame, int initialFrame, uint flags
}
void AVISurface::stop() {
- _decoders[0]->stop();
- if (_decoders[1])
- _decoders[1]->stop();
-
+ _decoder->stop();
_movieRangeInfo.destroyContents();
}
@@ -160,19 +128,14 @@ bool AVISurface::startAtFrame(int frameNumber) {
renderFrame();
// Start the playback
- _decoders[0]->start();
- if (_decoders[1])
- _decoders[1]->start();
-
+ _decoder->start();
+
return true;
}
void AVISurface::seekToFrame(uint frameNumber) {
if ((int)frameNumber != getFrame()) {
- _decoders[0]->seekToFrame(frameNumber);
- if (_decoders[1])
- _decoders[1]->seekToFrame(frameNumber);
-
+ _decoder->seekToFrame(frameNumber);
_currentFrame = (int)frameNumber;
}
@@ -180,10 +143,7 @@ void AVISurface::seekToFrame(uint frameNumber) {
}
void AVISurface::setReversed(bool isReversed) {
- _decoders[0]->setReverse(isReversed);
- if (_decoders[1])
- _decoders[1]->setReverse(isReversed);
-
+ _decoder->setReverse(isReversed);
_isReversed = isReversed;
}
@@ -234,8 +194,8 @@ void AVISurface::setVideoSurface(CVideoSurface *surface) {
_videoSurface = surface;
// Handling for secondary video stream
- if (_decoders[1]) {
- const Common::String &streamName = _decoders[1]->getVideoTrack().getName();
+ if (_streamCount == 2) {
+ const Common::String &streamName = _decoder->getVideoTrack(1).getName();
if (streamName == "mask0") {
_videoSurface->_transparencyMode = TRANS_MASK0;
@@ -252,18 +212,18 @@ void AVISurface::setVideoSurface(CVideoSurface *surface) {
}
void AVISurface::setupDecompressor() {
- for (int idx = 0; idx < 2; ++idx) {
- if (!_decoders[idx])
- continue;
- AVIDecoder &decoder = *_decoders[idx];
+ if (!_decoder)
+ return;
+ for (int idx = 0; idx < _streamCount; ++idx) {
// Setup frame surface
- _movieFrameSurface[idx] = new Graphics::ManagedSurface(decoder.getWidth(), decoder.getHeight(),
- decoder.getVideoTrack().getPixelFormat());
+ _movieFrameSurface[idx] = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(),
+ _decoder->getVideoTrack(idx).getPixelFormat());
bool flag = false;
- if (idx == 0 && _videoSurface) {
- const Graphics::PixelFormat &ff = decoder.getVideoTrack().getPixelFormat();
+ if (idx == 0 && _videoSurface &&
+ _videoSurface->getPitch() == _movieFrameSurface[idx]->pitch) {
+ const Graphics::PixelFormat &ff = _decoder->getVideoTrack(0).getPixelFormat();
const int vDepth = _videoSurface->getPixelDepth();
switch (ff.bpp()) {
@@ -285,8 +245,8 @@ void AVISurface::setupDecompressor() {
}
if (!flag) {
- _framePixels = new Graphics::ManagedSurface(decoder.getWidth(), decoder.getHeight(),
- decoder.getVideoTrack().getPixelFormat());
+ _framePixels = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(),
+ _decoder->getVideoTrack(0).getPixelFormat());
} else if (idx == 0) {
_videoSurface->_transBlitFlag = true;
}
@@ -294,11 +254,11 @@ void AVISurface::setupDecompressor() {
}
uint AVISurface::getWidth() const {
- return _decoders[0]->getWidth();
+ return _decoder->getWidth();
}
uint AVISurface::getHeight() const {
- return _decoders[0]->getHeight();
+ return _decoder->getHeight();
}
void AVISurface::setFrame(int frameNumber) {
@@ -307,25 +267,26 @@ void AVISurface::setFrame(int frameNumber) {
stop();
// Ensure the frame number is valid
- if (frameNumber >= (int)_decoders[0]->getFrameCount())
- frameNumber = _decoders[0]->getFrameCount() - 1;
+ if (frameNumber >= (int)_decoder->getFrameCount())
+ frameNumber = _decoder->getFrameCount() - 1;
seekToFrame(frameNumber);
renderFrame();
}
bool AVISurface::isNextFrame() const {
- return _decoders[0]->getTimeToNextFrame() == 0;
+ return _decoder->getTimeToNextFrame() == 0;
}
bool AVISurface::renderFrame() {
// Check there's a frame ready for display
- if (!_decoders[0]->needsUpdate())
+ if (!_decoder->needsUpdate())
return false;
// Make a copy of each decoder's video frame
for (int idx = 0; idx < _streamCount; ++idx) {
- const Graphics::Surface *frame = _decoders[idx]->decodeNextFrame();
+ const Graphics::Surface *frame = (idx == 0) ?
+ _decoder->decodeNextFrame() : _decoder->decodeNextTransparency();
assert(_movieFrameSurface[idx]->format == frame->format);
_movieFrameSurface[idx]->blitFrom(*frame);
@@ -333,17 +294,16 @@ bool AVISurface::renderFrame() {
if (!_framePixels) {
if (_videoSurface->lock()) {
- if (_streamCount == 1) {
- // Original seems to call a stubbed empty method here.
- // Likely this form of blitting to surface wasn't needed
- }
-
+ // Blit the frame directly to the video surface
+ assert(_streamCount == 1);
+ _videoSurface->blitFrom(Point(0, 0), &_movieFrameSurface[0]->rawSurface());
+
_videoSurface->unlock();
}
} else {
// Blit the primary video track's frame to the video surface
Graphics::Surface *s = _movieFrameSurface[0]->rawSurface().convertTo(
- g_system->getScreenFormat(), _decoders[0]->getPalette());
+ g_system->getScreenFormat(), _decoder->getPalette());
_videoSurface->lock();
_videoSurface->getRawSurface()->blitFrom(*s);
_videoSurface->unlock();
@@ -375,9 +335,7 @@ bool AVISurface::addEvent(int frameNumber, CGameObject *obj) {
}
void AVISurface::setFrameRate(double rate) {
- _decoders[0]->setRate(Common::Rational((int)rate));
- if (_decoders[1])
- _decoders[1]->setRate(Common::Rational((int)rate));
+ _decoder->setRate(Common::Rational((int)rate));
}
Graphics::ManagedSurface *AVISurface::getSecondarySurface() {
@@ -403,7 +361,7 @@ void AVISurface::playCutscene(const Rect &r, uint startFrame, uint endFrame) {
while (_currentFrame < (int)endFrame && !g_vm->shouldQuit()) {
if (isNextFrame()) {
renderFrame();
- _currentFrame = _decoders[0]->getCurFrame();
+ _currentFrame = _decoder->getCurFrame();
if (isDifferent) {
// Clear the destination area, and use the transBlitFrom method,
diff --git a/engines/titanic/support/avi_surface.h b/engines/titanic/support/avi_surface.h
index c0cf0af60c..0bb14ceb27 100644
--- a/engines/titanic/support/avi_surface.h
+++ b/engines/titanic/support/avi_surface.h
@@ -40,17 +40,25 @@ enum MovieFlag {
class AVIDecoder : public Video::AVIDecoder {
public:
- AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType, SelectTrackFn trackFn = nullptr) :
- Video::AVIDecoder(soundType, trackFn) {}
- AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType,
- SelectTrackFn trackFn = nullptr) : Video::AVIDecoder(frameRateOverride, soundType, trackFn) {}
+ AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType) :
+ Video::AVIDecoder(soundType) {}
+ AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType) :
+ Video::AVIDecoder(frameRateOverride, soundType) {}
- Video::AVIDecoder::AVIVideoTrack &getVideoTrack();
+ /**
+ * Returns the number of video tracks the decoder has
+ */
+ uint videoTrackCount() const { return _videoTracks.size(); }
+
+ /**
+ * Returns the specified video track
+ */
+ Video::AVIDecoder::AVIVideoTrack &getVideoTrack(uint idx);
};
class AVISurface {
private:
- AVIDecoder *_decoders[2];
+ AVIDecoder *_decoder;
CVideoSurface *_videoSurface;
CMovieRangeInfoList _movieRangeInfo;
int _streamCount;
@@ -114,7 +122,7 @@ public:
/**
* Return true if a video is currently playing
*/
- virtual bool isPlaying() const { return _decoders[0]->isPlaying(); }
+ virtual bool isPlaying() const { return _decoder->isPlaying(); }
/**
* Handle any movie events relevent for the frame
diff --git a/engines/titanic/support/mouse_cursor.cpp b/engines/titanic/support/mouse_cursor.cpp
index 0cefc368fa..3983e9fe60 100644
--- a/engines/titanic/support/mouse_cursor.cpp
+++ b/engines/titanic/support/mouse_cursor.cpp
@@ -20,18 +20,15 @@
*
*/
-#include "common/memstream.h"
-#include "common/textconsole.h"
#include "graphics/cursorman.h"
#include "titanic/support/mouse_cursor.h"
-#include "titanic/support/movie.h"
-#include "titanic/support/screen_manager.h"
#include "titanic/support/video_surface.h"
-#include "titanic/core/resource_key.h"
#include "titanic/titanic.h"
namespace Titanic {
+#define CURSOR_SIZE 64
+
static const int CURSOR_DATA[NUM_CURSORS][4] = {
{ 1, 136, 19, 18 },
{ 2, 139, 1, 1 },
@@ -52,7 +49,7 @@ static const int CURSOR_DATA[NUM_CURSORS][4] = {
CMouseCursor::CursorEntry::~CursorEntry() {
delete _videoSurface;
- delete _frameSurface;
+ delete _transSurface;
}
CMouseCursor::CMouseCursor(CScreenManager *screenManager) :
@@ -75,16 +72,16 @@ void CMouseCursor::loadCursorImages() {
CURSOR_DATA[idx][3]);
// Create the surface
- CVideoSurface *surface = _screenManager->createSurface(64, 64);
+ CVideoSurface *surface = _screenManager->createSurface(CURSOR_SIZE, CURSOR_SIZE);
_cursors[idx]._videoSurface = surface;
// Open the cursors video and move to the given frame
OSMovie movie(key, surface);
movie.setFrame(idx);
- Graphics::ManagedSurface *frameSurface = movie.duplicateFrame();
- _cursors[idx]._frameSurface = frameSurface;
- surface->setTransparencySurface(frameSurface);
+ Graphics::ManagedSurface *transSurface = movie.duplicateTransparency();
+ _cursors[idx]._transSurface = transSurface;
+ surface->setTransparencySurface(transSurface);
}
}
@@ -100,15 +97,31 @@ void CMouseCursor::setCursor(CursorId cursorId) {
++_setCursorCount;
if (cursorId != _cursorId) {
+ // The original cursors supported partial alpha when rendering the cursor.
+ // Since we're using the ScummVM CursorMan, we can't do that, so we need
+ // to build up a surface of the cursor with even partially transparent
+ // pixels as wholy transparent
CursorEntry &ce = _cursors[cursorId - 1];
- CVideoSurface &surface = *ce._videoSurface;
- surface.lock();
+ CVideoSurface &srcSurface = *ce._videoSurface;
+ srcSurface.lock();
+
+ Graphics::ManagedSurface surface(CURSOR_SIZE, CURSOR_SIZE, g_system->getScreenFormat());
+ const uint16 *srcP = srcSurface.getPixels();
+ const byte *maskP = (const byte *)ce._transSurface->getPixels();
+ uint16 *destP = (uint16 *)surface.getPixels();
+
+ for (int y = 0; y < CURSOR_SIZE; ++y) {
+ for (int x = 0; x < CURSOR_SIZE; ++x, ++srcP, ++maskP, ++destP) {
+ *destP = ((*maskP >> 4) == 0) ? srcSurface.getTransparencyColor() : *srcP;
+ }
+ }
- CursorMan.replaceCursor(surface.getPixels(), surface.getWidth(), surface.getHeight(),
- ce._centroid.x, ce._centroid.y, 0, false, &g_vm->_screen->format);
- surface.unlock();
+ srcSurface.unlock();
+ // Set the cursor
_cursorId = cursorId;
+ CursorMan.replaceCursor(surface.getPixels(), CURSOR_SIZE, CURSOR_SIZE,
+ ce._centroid.x, ce._centroid.y, srcSurface.getTransparencyColor(), false, &g_vm->_screen->format);
}
}
diff --git a/engines/titanic/support/mouse_cursor.h b/engines/titanic/support/mouse_cursor.h
index 74fb1f6113..5bf6895a67 100644
--- a/engines/titanic/support/mouse_cursor.h
+++ b/engines/titanic/support/mouse_cursor.h
@@ -55,10 +55,10 @@ class CVideoSurface;
class CMouseCursor {
struct CursorEntry {
CVideoSurface *_videoSurface;
- Graphics::ManagedSurface *_frameSurface;
+ Graphics::ManagedSurface *_transSurface;
Common::Point _centroid;
- CursorEntry() : _videoSurface(nullptr), _frameSurface(nullptr) {}
+ CursorEntry() : _videoSurface(nullptr), _transSurface(nullptr) {}
~CursorEntry();
};
private:
diff --git a/engines/titanic/support/movie.cpp b/engines/titanic/support/movie.cpp
index a605cc3465..eff0e0c754 100644
--- a/engines/titanic/support/movie.cpp
+++ b/engines/titanic/support/movie.cpp
@@ -203,7 +203,7 @@ void OSMovie::setFrameRate(double rate) {
_aviSurface.setFrameRate(rate);
}
-Graphics::ManagedSurface *OSMovie::duplicateFrame() const {
+Graphics::ManagedSurface *OSMovie::duplicateTransparency() const {
return _aviSurface.duplicateTransparency();
}
diff --git a/engines/titanic/support/movie.h b/engines/titanic/support/movie.h
index 8c89f9e6dd..be34244d96 100644
--- a/engines/titanic/support/movie.h
+++ b/engines/titanic/support/movie.h
@@ -130,9 +130,9 @@ public:
virtual void setFrameRate(double rate) = 0;
/**
- * Creates a duplicate of the movie's frame
- */
- virtual Graphics::ManagedSurface *duplicateFrame() const = 0;
+ * Creates a duplicate of the transparency surface
+ */
+ virtual Graphics::ManagedSurface *duplicateTransparency() const = 0;
/**
* Removes the movie from the list of currently playing movies
@@ -229,9 +229,9 @@ public:
virtual void setFrameRate(double rate);
/**
- * Creates a duplicate of the frame info
+ * Creates a duplicate of the transparency surface
*/
- virtual Graphics::ManagedSurface *duplicateFrame() const;
+ virtual Graphics::ManagedSurface *duplicateTransparency() const;
};
} // End of namespace Titanic
diff --git a/engines/titanic/support/raw_surface.cpp b/engines/titanic/support/raw_surface.cpp
deleted file mode 100644
index 4123b86e68..0000000000
--- a/engines/titanic/support/raw_surface.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-/* 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 "titanic/support/raw_surface.h"
-#include "common/algorithm.h"
-
-namespace Titanic {
-
-CRawSurface::CRawSurface(const Graphics::Surface *surface, TransparencyMode transMode) {
- _width = surface->w;
- _pixelsBaseP = (byte *)surface->getPixels();
- _pixelsP = nullptr;
- _pitch = 0;
- _runLength = 0;
- _flag = false;
- _flag1 = false;
- _flag2 = true;
-
- switch (transMode) {
- case TRANS_MASK0:
- case TRANS_ALPHA0:
- _flag2 = false;
- _flag1 = true;
- break;
- case TRANS_MASK255:
- case TRANS_ALPHA255:
- _flag2 = true;
- _flag1 = false;
- break;
- case TRANS_DEFAULT:
- if ((_pixelsBaseP[0] == 0 && _pixelsBaseP[2] < 0x80) ||
- (_pixelsBaseP[0] != 0 && _pixelsBaseP[1] < 0x80)) {
- _flag1 = true;
- _flag2 = false;
- }
- break;
- default:
- break;
- }
-}
-
-void CRawSurface::setRow(int yp) {
- for (int y = 0; y < yp; ++yp) {
- resetPitch();
- skipPitch();
- }
-}
-
-void CRawSurface::setCol(int xp) {
- while (xp > 0)
- xp -= moveX(xp);
-}
-
-void CRawSurface::skipPitch() {
- setCol(_pitch);
-}
-
-int CRawSurface::moveX(int xp) {
- if (_runLength) {
- if (!_flag) {
- --_runLength;
- --_pitch;
- ++_pixelsP;
- return 1;
- }
- } else {
- while (!*_pixelsBaseP) {
- _runLength = *++_pixelsBaseP;
- ++_pixelsBaseP;
-
- if (_runLength) {
- _pixelsP = _pixelsBaseP;
- _pixelsBaseP += _runLength;
- if (_runLength & 1)
- ++_pixelsBaseP;
-
- _flag = false;
- --_pitch;
- --_runLength;
- return 1;
- }
- }
-
- _runLength = *_pixelsBaseP;
- _pixelsP = _pixelsBaseP + 1;
- _pixelsBaseP += 2;
- _flag = true;
- }
-
- if (xp < 0 || xp > _pitch)
- xp = _pitch;
-
- int len = MIN(_runLength, xp);
- _pitch -= len;
- _runLength -= len;
- return len;
-}
-
-uint CRawSurface::getPixel() const {
- return _flag1 ? 0xFF - *_pixelsP : *_pixelsP;
-}
-
-bool CRawSurface::isPixelTransparent1() const {
- return _flag1 ? *_pixelsP == 0xF0 : *_pixelsP == 0x10;
-}
-
-bool CRawSurface::isPixelTransparent2() const {
- return _flag2 ? *_pixelsP == 0xF0 : *_pixelsP == 0x10;
-}
-
-void CRawSurface::resetPitch() {
- _pitch = _width;
-}
-
-} // End of namespace Titanic
diff --git a/engines/titanic/support/transparency_surface.cpp b/engines/titanic/support/transparency_surface.cpp
new file mode 100644
index 0000000000..f917dfb48b
--- /dev/null
+++ b/engines/titanic/support/transparency_surface.cpp
@@ -0,0 +1,83 @@
+/* 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 "titanic/support/transparency_surface.h"
+#include "common/algorithm.h"
+#include "common/textconsole.h"
+
+namespace Titanic {
+
+CTransparencySurface::CTransparencySurface(const Graphics::Surface *surface,
+ TransparencyMode transMode) : _surface(surface) {
+ _pitch = 0;
+ _runLength = 0;
+ _flag = false;
+ _flag1 = false;
+ _flag2 = true;
+
+ switch (transMode) {
+ case TRANS_MASK0:
+ case TRANS_ALPHA0:
+ _flag2 = false;
+ _flag1 = true;
+ break;
+ case TRANS_MASK255:
+ case TRANS_ALPHA255:
+ _flag2 = true;
+ _flag1 = false;
+ break;
+ case TRANS_DEFAULT:
+ if (*(byte *)surface->getPixels() < 0x80) {
+ _flag1 = true;
+ _flag2 = false;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+int CTransparencySurface::moveX() {
+ if (++_pos.x >= _surface->w) {
+ _pos.x = 0;
+ ++_pos.y;
+ }
+
+ return 1;
+}
+
+uint CTransparencySurface::getPixel() const {
+ const byte *pixelP = (const byte *)_surface->getBasePtr(_pos.x, _pos.y);
+ return _flag1 ? 0xFF - *pixelP : *pixelP;
+}
+
+bool CTransparencySurface::isPixelTransparent1() const {
+ const byte *pixelP = (const byte *)_surface->getBasePtr(_pos.x, _pos.y);
+ return _flag1 ? *pixelP == 0xF0 : *pixelP == 0x10;
+}
+
+bool CTransparencySurface::isPixelTransparent2() const {
+ const byte *pixelP = (const byte *)_surface->getBasePtr(_pos.x, _pos.y);
+ return _flag2 ? *pixelP == 0xF0 : *pixelP == 0x10;
+}
+
+} // End of namespace Titanic
diff --git a/engines/titanic/support/raw_surface.h b/engines/titanic/support/transparency_surface.h
index 69efc1e3db..5593dfa66d 100644
--- a/engines/titanic/support/raw_surface.h
+++ b/engines/titanic/support/transparency_surface.h
@@ -20,9 +20,10 @@
*
*/
-#ifndef TITANIC_RAW_SURFACE_H
-#define TITANIC_RAW_SURFACE_H
+#ifndef TITANIC_TRANSPARENCY_SURFACE_H
+#define TITANIC_TRANSPARENCY_SURFACE_H
+#include "common/rect.h"
#include "graphics/surface.h"
namespace Titanic {
@@ -32,24 +33,21 @@ enum TransparencyMode {
TRANS_ALPHA255 = 3, TRANS_DEFAULT = 4
};
-class CRawSurface {
+class CTransparencySurface {
private:
- const byte *_pixelsBaseP;
- const byte *_pixelsP;
+ const Graphics::Surface *_surface;
+ Common::Point _pos;
int _pitch;
int _runLength;
bool _flag;
- int _width;
bool _flag1;
bool _flag2;
public:
- CRawSurface(const Graphics::Surface *surface, TransparencyMode transMode);
+ CTransparencySurface(const Graphics::Surface *surface, TransparencyMode transMode);
- void setRow(int yp);
+ void setRow(int yp) { _pos.y = yp; }
- void setCol(int xp);
-
- void skipPitch();
+ void setCol(int xp) { _pos.x = xp; }
uint getPixel() const;
@@ -57,11 +55,9 @@ public:
bool isPixelTransparent2() const;
- void resetPitch();
-
- int moveX(int xp);
+ int moveX();
};
} // End of namespace Titanic
-#endif /* TITANIC_RAW_SURFACE_H */
+#endif /* TITANIC_TRANSPARENCY_SURFACE_H */
diff --git a/engines/titanic/support/video_surface.cpp b/engines/titanic/support/video_surface.cpp
index fa87e6df0c..bcaaad4492 100644
--- a/engines/titanic/support/video_surface.cpp
+++ b/engines/titanic/support/video_surface.cpp
@@ -22,8 +22,8 @@
#include "titanic/support/video_surface.h"
#include "titanic/support/image_decoders.h"
-#include "titanic/support/raw_surface.h"
#include "titanic/support/screen_manager.h"
+#include "titanic/support/transparency_surface.h"
#include "titanic/titanic.h"
namespace Titanic {
@@ -184,65 +184,46 @@ void CVideoSurface::blitRect2(const Rect &srcRect, const Rect &destRect, CVideoS
}
void CVideoSurface::transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src, bool flipFlag) {
+ assert(srcRect.width() == destRect.width() && srcRect.height() == destRect.height());
+
if (lock()) {
if (src->lock()) {
Graphics::ManagedSurface *srcSurface = src->_rawSurface;
Graphics::ManagedSurface *destSurface = _rawSurface;
Graphics::Surface destArea = destSurface->getSubArea(destRect);
- const uint16 *srcPtr = flipFlag ?
- (const uint16 *)srcSurface->getBasePtr(srcRect.left, srcRect.top) :
- (const uint16 *)srcSurface->getBasePtr(srcRect.left, srcRect.bottom);
- uint16 *destPtr = (uint16 *)destSurface->getBasePtr(destArea.w, destArea.h - 1);
+ const uint16 *srcPtr = (const uint16 *)srcSurface->getBasePtr(
+ srcRect.left, flipFlag ? srcRect.top : srcRect.bottom - 1);
+ uint16 *destPtr = (uint16 *)destSurface->getBasePtr(0, destArea.h - 1);
bool is16Bit = src->getPixelDepth() == 2;
bool isAlpha = src->_transparencyMode == TRANS_ALPHA0 ||
src->_transparencyMode == TRANS_ALPHA255;
- CRawSurface rawSurface(src->getTransparencySurface(), src->_transparencyMode);
- if (flipFlag)
- rawSurface.setRow(srcRect.top);
- else
- rawSurface.setRow(src->getHeight() - srcRect.bottom);
+ CTransparencySurface transSurface(src->getTransparencySurface(), src->_transparencyMode);
- for (int srcY = srcRect.top; srcY < srcRect.bottom; ++srcY) {
+ for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
// Prepare for copying the line
const uint16 *lineSrcP = srcPtr;
uint16 *lineDestP = destPtr;
- rawSurface.resetPitch();
- rawSurface.setCol(srcRect.left);
-
- int srcWidth = srcRect.width();
- while (srcWidth > 0) {
- int move = rawSurface.moveX(0);
-
- if (move <= 1) {
- if (!rawSurface.isPixelTransparent2()) {
- copyPixel(lineDestP, lineSrcP, rawSurface.getPixel() >> 3,
- is16Bit, isAlpha);
- }
- } else {
- if (move > srcWidth)
- move = srcWidth;
-
- if (rawSurface.isPixelTransparent1()) {
- Common::copy(lineSrcP, lineSrcP + move, lineDestP);
- } else if (!rawSurface.isPixelTransparent2()) {
- byte transVal = rawSurface.getPixel() >> 3;
- for (int idx = 0; idx < move; ++idx) {
- copyPixel(lineDestP + idx, lineSrcP + idx, transVal, is16Bit, isAlpha);
- }
- }
+ transSurface.setRow(flipFlag ? srcRect.top + yCtr : srcRect.bottom - yCtr - 1);
+ transSurface.setCol(srcRect.left);
+
+ for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX) {
+ transSurface.moveX();
+
+ if (!transSurface.isPixelTransparent2()) {
+ copyPixel(lineDestP, lineSrcP, transSurface.getPixel() >> 3,
+ is16Bit, isAlpha);
}
- lineSrcP += move;
- lineDestP += move;
- srcWidth -= move;
+ ++lineSrcP;
+ ++lineDestP;
}
// Move to next line
- rawSurface.skipPitch();
- srcPtr = flipFlag ? srcPtr + getWidth() : srcPtr - getWidth();
- destPtr -= destArea.w;
+ srcPtr = flipFlag ? srcPtr + (src->getPitch() / 2) :
+ srcPtr - (src->getPitch() / 2);
+ destPtr -= destArea.pitch / 2;
}
src->unlock();
@@ -487,13 +468,11 @@ uint16 OSVideoSurface::getPixel(const Common::Point &pt) {
if (pt.x >= 0 && pt.y >= 0 && pt.x < getWidth() && pt.y < getHeight()) {
if (_transparencySurface) {
- CRawSurface rawSurface(&_transparencySurface->rawSurface(), _transparencyMode);
- rawSurface.setRow(_transBlitFlag ? pt.y : getHeight() - pt.y - 1);
- rawSurface.resetPitch();
- rawSurface.setCol(pt.x);
- rawSurface.moveX(0);
+ CTransparencySurface transSurface(&_transparencySurface->rawSurface(), _transparencyMode);
+ transSurface.setRow(_transBlitFlag ? pt.y : getHeight() - pt.y - 1);
+ transSurface.setCol(pt.x);
- if (rawSurface.isPixelTransparent2())
+ if (transSurface.isPixelTransparent2())
return getTransparencyColor();
}
@@ -637,8 +616,8 @@ void OSVideoSurface::transPixelate() {
unlock();
}
-Graphics::ManagedSurface *OSVideoSurface::dupMovieFrame() const {
- return _movie ? _movie->duplicateFrame() : nullptr;
+Graphics::ManagedSurface *OSVideoSurface::dupMovieTransparency() const {
+ return _movie ? _movie->duplicateTransparency() : nullptr;
}
int OSVideoSurface::freeSurface() {
diff --git a/engines/titanic/support/video_surface.h b/engines/titanic/support/video_surface.h
index 37ff7917dc..3625a3555c 100644
--- a/engines/titanic/support/video_surface.h
+++ b/engines/titanic/support/video_surface.h
@@ -30,8 +30,8 @@
#include "titanic/support/direct_draw.h"
#include "titanic/support/movie.h"
#include "titanic/support/movie_range_info.h"
-#include "titanic/support/raw_surface.h"
#include "titanic/support/rect.h"
+#include "titanic/support/transparency_surface.h"
#include "titanic/core/list.h"
#include "titanic/core/resource_key.h"
@@ -277,9 +277,9 @@ public:
virtual bool hasFrame();
/**
- * Duplicates movie frame surface
+ * Duplicates movie transparency surface
*/
- virtual Graphics::ManagedSurface *dupMovieFrame() const = 0;
+ virtual Graphics::ManagedSurface *dupMovieTransparency() const = 0;
/**
* Frees the underlying surface
@@ -509,10 +509,9 @@ public:
virtual void transPixelate();
/**
- * Duplicates movie frame surface
+ * Duplicates movie transparency surface
*/
- virtual Graphics::ManagedSurface *dupMovieFrame() const;
-
+ virtual Graphics::ManagedSurface *dupMovieTransparency() const;
/**
* Frees the underlying surface
diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp
index 980ce3a3ea..c4b091d240 100644
--- a/video/avi_decoder.cpp
+++ b/video/avi_decoder.cpp
@@ -76,13 +76,13 @@ enum {
};
-AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType, SelectTrackFn trackFn) :
- _frameRateOverride(0), _soundType(soundType), _selectTrackFn(trackFn) {
+AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) :
+ _frameRateOverride(0), _soundType(soundType) {
initCommon();
}
-AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType,
- SelectTrackFn trackFn) : _frameRateOverride(frameRateOverride), _soundType(soundType), _selectTrackFn(trackFn) {
+AVIDecoder::AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType) :
+ _frameRateOverride(frameRateOverride), _soundType(soundType) {
initCommon();
}
@@ -94,6 +94,23 @@ AVIDecoder::AVIAudioTrack *AVIDecoder::createAudioTrack(AVIStreamHeader sHeader,
return new AVIAudioTrack(sHeader, wvInfo, _soundType);
}
+bool AVIDecoder::seekToFrame(uint frame) {
+ if (!isSeekable())
+ return false;
+
+ // If we didn't find a video track, we can't seek by frame (of course)
+ if (_videoTracks.empty())
+ return false;
+
+ AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks.front().track);
+ Audio::Timestamp time = track->getFrameTime(frame);
+
+ if (time < 0)
+ return false;
+
+ return seek(time);
+}
+
void AVIDecoder::initCommon() {
_decodedHeader = false;
_foundMovieList = false;
@@ -111,6 +128,14 @@ bool AVIDecoder::isSeekable() const {
return isVideoLoaded() && !_indexEntries.empty();
}
+const Graphics::Surface *AVIDecoder::decodeNextTransparency() {
+ if (_videoTracks.size() != 2)
+ return nullptr;
+
+ AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[1].track);
+ return track->decodeNextFrame();
+}
+
bool AVIDecoder::parseNextChunk() {
uint32 tag = _fileStream->readUint32BE();
uint32 size = _fileStream->readUint32LE();
@@ -293,14 +318,8 @@ void AVIDecoder::handleStreamHeader(uint32 size) {
}
void AVIDecoder::addTrack(Track *track, bool isExternal) {
- if (!_selectTrackFn ||
- (dynamic_cast<AVIVideoTrack *>(track) && _selectTrackFn(true, _videoTrackCounter++)) ||
- (dynamic_cast<AVIAudioTrack *>(track) && _selectTrackFn(false, _audioTrackCounter++))) {
- VideoDecoder::addTrack(track, isExternal);
- _lastAddedTrack = track;
- } else {
- _lastAddedTrack = nullptr;
- }
+ VideoDecoder::addTrack(track, isExternal);
+ _lastAddedTrack = track;
}
void AVIDecoder::readStreamName(uint32 size) {
@@ -366,17 +385,30 @@ bool AVIDecoder::loadStream(Common::SeekableReadStream *stream) {
TrackStatus status;
status.track = *it;
status.index = index;
- status.chunkSearchOffset = _movieListStart;
+ status.chunkSearchOffset = 0;
- if ((*it)->getTrackType() == Track::kTrackTypeVideo)
- _videoTracks.push_back(status);
- else
+ if ((*it)->getTrackType() == Track::kTrackTypeAudio) {
_audioTracks.push_back(status);
- }
+ } else if (_videoTracks.empty()) {
+ _videoTracks.push_back(status);
+ } else {
+ // Secondary video track. Figure out the starting chunk offset,
+ // by iteratiing through the index
+ assert(_videoTracks.size() == 1);
+
+ // Find the index entry for the frame and move to it
+ for (uint idx = 0; idx < _indexEntries.size(); ++idx) {
+ if (_indexEntries[idx].id != ID_REC &&
+ getStreamIndex(_indexEntries[idx].id) == index) {
+ status.chunkSearchOffset = _indexEntries[idx].offset;
+ break;
+ }
+ }
+ assert(status.chunkSearchOffset != 0);
- if (_videoTracks.size() != 1) {
- close();
- return false;
+ // Add the video track to the list
+ _videoTracks.push_back(status);
+ }
}
// Check if this is a special Duck Truemotion video
@@ -407,12 +439,13 @@ void AVIDecoder::readNextPacket() {
if (_videoTracks.empty())
return;
- // Get the video frame first
- handleNextPacket(_videoTracks[0]);
+ // Handle the video first
+ for (uint idx = 0; idx < _videoTracks.size(); ++idx)
+ handleNextPacket(_videoTracks[idx]);
// Handle audio tracks next
- for (uint32 i = 0; i < _audioTracks.size(); i++)
- handleNextPacket(_audioTracks[i]);
+ for (uint idx = 0; idx < _audioTracks.size(); ++idx)
+ handleNextPacket(_audioTracks[idx]);
}
void AVIDecoder::handleNextPacket(TrackStatus &status) {
@@ -666,6 +699,32 @@ bool AVIDecoder::seekIntern(const Audio::Timestamp &time) {
videoTrack->decodeFrame(chunk);
}
+ // Update any secondary video track for transparencies
+ if (_videoTracks.size() == 2) {
+ AVIVideoTrack *videoTrack2 = static_cast<AVIVideoTrack *>(_videoTracks.back().track);
+
+ // Set it's frame number
+ videoTrack2->setCurFrame((int)frame - 1);
+
+ // Find the index entry for the frame and move to it
+ for (uint i = 0, frameNum = 0; i < _indexEntries.size(); ++i) {
+ if (_indexEntries[i].id != ID_REC &&
+ getStreamIndex(_indexEntries[i].id) == _videoTracks.back().index) {
+ if (frameNum++ == frame) {
+ Common::SeekableReadStream *chunk = nullptr;
+ _fileStream->seek(_indexEntries[i].offset + 8);
+ _videoTracks.back().chunkSearchOffset = _indexEntries[i].offset;
+
+ if (_indexEntries[i].size != 0)
+ chunk = _fileStream->readStream(_indexEntries[i].size);
+
+ videoTrack2->decodeFrame(chunk);
+ break;
+ }
+ }
+ }
+ }
+
// Set the video track's frame
videoTrack->setCurFrame((int)frame - 1);
diff --git a/video/avi_decoder.h b/video/avi_decoder.h
index a3733b579c..3581b65409 100644
--- a/video/avi_decoder.h
+++ b/video/avi_decoder.h
@@ -62,10 +62,8 @@ namespace Video {
*/
class AVIDecoder : public VideoDecoder {
public:
- typedef bool(*SelectTrackFn)(bool isVideo, int trackNumber);
- AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType, SelectTrackFn trackFn = nullptr);
- AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType,
- SelectTrackFn trackFn = nullptr);
+ AVIDecoder(Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
+ AVIDecoder(const Common::Rational &frameRateOverride, Audio::Mixer::SoundType soundType = Audio::Mixer::kPlainSoundType);
virtual ~AVIDecoder();
bool loadStream(Common::SeekableReadStream *stream);
@@ -77,6 +75,7 @@ public:
bool isRewindable() const { return true; }
bool isSeekable() const;
+ const Graphics::Surface *decodeNextTransparency();
protected:
// VideoDecoder API
void readNextPacket();
@@ -287,7 +286,6 @@ protected:
int _videoTrackCounter, _audioTrackCounter;
Track *_lastAddedTrack;
- SelectTrackFn _selectTrackFn;
void initCommon();
@@ -306,6 +304,14 @@ protected:
public:
virtual AVIAudioTrack *createAudioTrack(AVIStreamHeader sHeader, PCMWaveFormat wvInfo);
+
+ /**
+ * Seek to a given frame.
+ *
+ * This only works when the video track(s) supports getFrameTime().
+ * This calls seek() internally.
+ */
+ virtual bool seekToFrame(uint frame);
};
} // End of namespace Video
diff --git a/video/video_decoder.h b/video/video_decoder.h
index eca15e7265..a415a70724 100644
--- a/video/video_decoder.h
+++ b/video/video_decoder.h
@@ -184,7 +184,7 @@ public:
* This only works when one video track is present, and that track
* supports getFrameTime(). This calls seek() internally.
*/
- bool seekToFrame(uint frame);
+ virtual bool seekToFrame(uint frame);
/**
* Pause or resume the video. This should stop/resume any audio playback