diff options
Diffstat (limited to 'engines/titanic/support')
25 files changed, 579 insertions, 307 deletions
diff --git a/engines/titanic/support/avi_surface.cpp b/engines/titanic/support/avi_surface.cpp index 2cc32971ae..9e465c705f 100644 --- a/engines/titanic/support/avi_surface.cpp +++ b/engines/titanic/support/avi_surface.cpp @@ -30,73 +30,46 @@ 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) { _videoSurface = nullptr; _streamCount = 0; _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() { if (_videoSurface) - _videoSurface->_transBlitFlag = false; + _videoSurface->_flipVertically = false; + 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) { @@ -121,26 +94,23 @@ bool AVISurface::play(int startFrame, int endFrame, int initialFrame, uint flags me->_endFrame = endFrame; me->_initialFrame = 0; me->_gameObject = obj; - + info->addEvent(me); } _movieRangeInfo.push_back(info); - + if (_movieRangeInfo.size() == 1) { // First play call, so start the movie playing setReversed(info->_isReversed); return startAtFrame(initialFrame); } else { return true; - } + } } void AVISurface::stop() { - _decoders[0]->stop(); - if (_decoders[1]) - _decoders[1]->stop(); - + _decoder->stop(); _movieRangeInfo.destroyContents(); } @@ -158,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; } @@ -178,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; } @@ -219,7 +181,7 @@ bool AVISurface::handleEvents(CMovieEventList &events) { setReversed(info->_isReversed); seekToFrame(newFrame); } - + // Get any events for the given position info->getMovieFrame(events, newFrame); return renderFrame(); @@ -232,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; @@ -250,27 +212,56 @@ 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(), - g_system->getScreenFormat()); + _movieFrameSurface[idx] = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(), + _decoder->getVideoTrack(idx).getPixelFormat()); + + bool flag = false; + if (idx == 0 && _videoSurface && + _videoSurface->getPitch() == _movieFrameSurface[idx]->pitch) { + const uint bitCount = _decoder->getVideoTrack(0).getBitCount(); + const int vDepth = _videoSurface->getPixelDepth(); + + switch (bitCount) { + case 15: + flag = vDepth == 1; + break; + + case 16: + flag = vDepth == 1 || vDepth == 2; + break; + + case 24: + flag = vDepth == 3; + break; + + default: + break; + } + } - // TODO: See whether this simplified form of original works - if (idx == 1) - _videoSurface->_transBlitFlag = true; + if (!flag) { + _framePixels = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(), + _decoder->getVideoTrack(0).getPixelFormat()); + } else if (idx == 0) { + // The original developers used a vertical flipped playback to indicate + // an incompatibility between source video and dest surface bit-depths, + // which would result in poor playback performance + _videoSurface->_flipVertically = true; + } } } 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) { @@ -279,42 +270,49 @@ 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; - // Decode each decoder's video stream into the appropriate surface + // Make a copy of each decoder's video frame for (int idx = 0; idx < _streamCount; ++idx) { - const Graphics::Surface *frame = _decoders[idx]->decodeNextFrame(); - - if (_movieFrameSurface[idx]->format == frame->format) { - _movieFrameSurface[idx]->blitFrom(*frame); - } else { - // Format mis-match, so we need to convert the frame - Graphics::Surface *s = frame->convertTo(_movieFrameSurface[idx]->format, - _decoders[idx]->getPalette()); - _movieFrameSurface[idx]->blitFrom(*s); - s->free(); - delete s; - } + const Graphics::Surface *frame = (idx == 0) ? + _decoder->decodeNextFrame() : _decoder->decodeNextTransparency(); + + assert(_movieFrameSurface[idx]->format == frame->format); + _movieFrameSurface[idx]->blitFrom(*frame); } - // Blit the primary video frame onto the main overall surface - _videoSurface->lock(); - _videoSurface->getRawSurface()->blitFrom(*_movieFrameSurface[0]); - _videoSurface->unlock(); + if (!_framePixels) { + if (_videoSurface->lock()) { + // 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(), _decoder->getPalette()); + _videoSurface->lock(); + _videoSurface->getRawSurface()->blitFrom(*s); + _videoSurface->unlock(); + s->free(); + delete s; + } return false; } @@ -340,9 +338,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() { @@ -368,7 +364,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 0acf7ab23b..b6231a646f 100644 --- a/engines/titanic/support/avi_surface.h +++ b/engines/titanic/support/avi_surface.h @@ -40,21 +40,30 @@ 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) {} - - Video::AVIDecoder::AVIVideoTrack &getVideoTrack(); + 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) {} + + /** + * 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; Graphics::ManagedSurface *_movieFrameSurface[2]; + Graphics::ManagedSurface *_framePixels; bool _isReversed; int _currentFrame; private: @@ -113,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/credit_text.cpp b/engines/titanic/support/credit_text.cpp index 009c3f4944..da6de6278e 100644 --- a/engines/titanic/support/credit_text.cpp +++ b/engines/titanic/support/credit_text.cpp @@ -67,7 +67,7 @@ void CCreditText::setup() { // Create a new group and line within it CCreditLineGroup *group = new CCreditLineGroup(); - CCreditLine *line = new CCreditLine(srcLine, + CCreditLine *line = new CCreditLine(srcLine, _screenManagerP->stringWidth(srcLine)); group->_lines.push_back(line); @@ -125,7 +125,7 @@ void CCreditText::handleDots(CCreditLineGroup *group) { // Figure out the maximum width of secondary lines for (CCreditLines::iterator i = second; i != group->_lines.end(); ++i) maxWidth = MAX(maxWidth, (*i)->_lineWidth); - + int charWidth = _screenManagerP->stringWidth("."); // Process the secondary lines diff --git a/engines/titanic/support/direct_draw.h b/engines/titanic/support/direct_draw.h index a7e9cc8d93..08ead6d798 100644 --- a/engines/titanic/support/direct_draw.h +++ b/engines/titanic/support/direct_draw.h @@ -70,7 +70,7 @@ public: * @param width Screen width * @param height Screen height * @param bpp Bits per pixel - * @param numBackSurfaces Number of back surfaces + * @param numBackSurfaces Number of back surfaces */ void initVideo(int width, int height, int bpp, int numBackSurfaces); diff --git a/engines/titanic/support/files_manager.cpp b/engines/titanic/support/files_manager.cpp index 22bff275d2..2882b8da85 100644 --- a/engines/titanic/support/files_manager.cpp +++ b/engines/titanic/support/files_manager.cpp @@ -75,7 +75,7 @@ bool CFilesManager::scanForFile(const CString &name) { CString filename = name; filename.toLowercase(); - + if (filename[0] == 'y' || filename[0] == 'z') return true; else if (filename[0] < 'a' || filename[0] > 'c') diff --git a/engines/titanic/support/files_manager.h b/engines/titanic/support/files_manager.h index a980ef1b25..45b067e86e 100644 --- a/engines/titanic/support/files_manager.h +++ b/engines/titanic/support/files_manager.h @@ -39,7 +39,7 @@ class CFilesManager { struct ResourceEntry { uint _offset; uint _size; - + ResourceEntry() : _offset(0), _size(0) {} ResourceEntry(uint offset, uint size) : _offset(offset), _size(size) {} }; diff --git a/engines/titanic/support/font.cpp b/engines/titanic/support/font.cpp index e519237c3b..625d03720b 100644 --- a/engines/titanic/support/font.cpp +++ b/engines/titanic/support/font.cpp @@ -80,7 +80,7 @@ int STFont::getTextBounds(const CString &str, int maxWidth, Point *sizeOut) cons if (_fontHeight == 0 || !_dataPtr) // No font, so return immediately return 0; - + // Loop through the characters of the string if (!str.empty()) { for (const char *strP = str.c_str(); *strP; ++strP) { @@ -296,8 +296,9 @@ void STFont::copyRect(CVideoSurface *surface, const Point &pt, Rect &rect) { for (int yp = rect.top; yp < rect.bottom; ++yp, lineP += surface->getWidth()) { uint16 *destP = lineP; for (int xp = rect.left; xp < rect.right; ++xp, ++destP) { - const byte *srcP = _dataPtr + yp * _dataWidth + xp; - surface->changePixel(destP, &color, *srcP >> 3, true); + const byte *transP = _dataPtr + yp * _dataWidth + xp; + surface->copyPixel(destP, &color, *transP >> 3, + surface->getRawSurface()->format, true); } } @@ -330,7 +331,7 @@ void STFont::checkLineWrap(Point &textSize, int maxWidth, const char *&str) cons flag = true; } } - + if ((textSize.x + totalWidth) >= maxWidth && totalWidth < maxWidth) { // Word wrap textSize.x = 0; diff --git a/engines/titanic/support/font.h b/engines/titanic/support/font.h index 6c4fe8e9c3..685ab8ad73 100644 --- a/engines/titanic/support/font.h +++ b/engines/titanic/support/font.h @@ -50,13 +50,13 @@ private: * Copys a rectangle representing a character in the font data to * a given destination position in the surface */ - void copyRect(CVideoSurface *surface, const Common::Point &destPos, + void copyRect(CVideoSurface *surface, const Common::Point &destPos, Rect &srcRect); /** * Write a character */ - WriteCharacterResult writeChar(CVideoSurface *surface, unsigned char c, + WriteCharacterResult writeChar(CVideoSurface *surface, unsigned char c, const Common::Point &pt, const Rect &destRect, const Rect *srcRect); /** diff --git a/engines/titanic/support/image_decoders.cpp b/engines/titanic/support/image_decoders.cpp index 495d1d0982..2dba66fbb3 100644 --- a/engines/titanic/support/image_decoders.cpp +++ b/engines/titanic/support/image_decoders.cpp @@ -32,9 +32,9 @@ void CJPEGDecode::decode(OSVideoSurface &surface, const CString &name) { // Use the ScucmmVM deoder to decode it loadStream(*file.readStream()); const Graphics::Surface *srcSurf = getSurface(); - + // Resize the surface if necessary - if (!surface.hasSurface() || surface.getWidth() != srcSurf->w + if (!surface.hasSurface() || surface.getWidth() != srcSurf->w || surface.getHeight() != srcSurf->h) surface.recreate(srcSurf->w, srcSurf->h); diff --git a/engines/titanic/support/mouse_cursor.cpp b/engines/titanic/support/mouse_cursor.cpp index 0cefc368fa..4dd1ab4366 100644 --- a/engines/titanic/support/mouse_cursor.cpp +++ b/engines/titanic/support/mouse_cursor.cpp @@ -20,18 +20,16 @@ * */ -#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/transparency_surface.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,10 +50,10 @@ static const int CURSOR_DATA[NUM_CURSORS][4] = { CMouseCursor::CursorEntry::~CursorEntry() { delete _videoSurface; - delete _frameSurface; + delete _transSurface; } -CMouseCursor::CMouseCursor(CScreenManager *screenManager) : +CMouseCursor::CMouseCursor(CScreenManager *screenManager) : _screenManager(screenManager), _cursorId(CURSOR_HOURGLASS), _setCursorCount(0), _fieldE4(0), _fieldE8(0) { loadCursorImages(); @@ -75,16 +73,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 +98,35 @@ 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(); + CTransparencySurface transSurface(&ce._transSurface->rawSurface(), TRANS_DEFAULT); + uint16 *destP = (uint16 *)surface.getPixels(); - CursorMan.replaceCursor(surface.getPixels(), surface.getWidth(), surface.getHeight(), - ce._centroid.x, ce._centroid.y, 0, false, &g_vm->_screen->format); - surface.unlock(); + for (int y = 0; y < CURSOR_SIZE; ++y) { + transSurface.setRow(y); + transSurface.setCol(0); + for (int x = 0; x < CURSOR_SIZE; ++x, ++srcP, ++destP) { + *destP = transSurface.isPixelTransparent() ? srcSurface.getTransparencyColor() : *srcP; + transSurface.moveX(); + } + } + + 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); } } @@ -129,7 +147,7 @@ void CMouseCursor::unlockE4() { void CMouseCursor::setPosition(const Point &pt, double rate) { assert(rate >= 0.0 && rate <= 1.0); - + // TODO: Figure out use of the rate parameter g_system->warpMouse(pt.x, pt.y); } diff --git a/engines/titanic/support/mouse_cursor.h b/engines/titanic/support/mouse_cursor.h index 74fb1f6113..08de28e29d 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: @@ -86,12 +86,12 @@ public: * Hide the mouse cursor */ void hide(); - + /** * Set the cursor */ void setCursor(CursorId cursorId); - + /** * Updates the mouse cursor */ diff --git a/engines/titanic/support/movie.cpp b/engines/titanic/support/movie.cpp index a605cc3465..aea51e1a1e 100644 --- a/engines/titanic/support/movie.cpp +++ b/engines/titanic/support/movie.cpp @@ -125,7 +125,7 @@ void OSMovie::play(uint startFrame, uint endFrame, uint initialFrame, uint flags void OSMovie::playCutscene(const Rect &drawRect, uint startFrame, uint endFrame) { if (!_movieSurface) _movieSurface = CScreenManager::_screenManagerPtr->createSurface(600, 340); - + bool widthLess = _videoSurface->getWidth() < 600; bool heightLess = _videoSurface->getHeight() < 340; Rect r(drawRect.left, drawRect.top, @@ -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..acc647065f 100644 --- a/engines/titanic/support/movie.h +++ b/engines/titanic/support/movie.h @@ -72,7 +72,7 @@ public: * Starts playing the movie */ virtual void play(uint flags, CGameObject *obj) = 0; - + /** * Starts playing the movie */ @@ -82,13 +82,13 @@ public: * Starts playing the movie */ virtual void play(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) = 0; - + /** * Plays a sub-section of a movie, and doesn't return until either * the playback ends or a key has been pressed */ virtual void playCutscene(const Rect &drawRect, uint startFrame, uint endFrame) = 0; - + /** * Stops the movie */ @@ -103,12 +103,12 @@ public: * Set the current frame number */ virtual void setFrame(uint frameNumber) = 0; - + /** * Handle any pending movie events */ virtual bool handleEvents(CMovieEventList &events) = 0; - + /** * Return any movie range info associated with the movie */ @@ -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 @@ -171,17 +171,17 @@ public: * Starts playing the movie */ virtual void play(uint flags, CGameObject *obj); - + /** * Starts playing the movie */ virtual void play(uint startFrame, uint endFrame, uint flags, CGameObject *obj); - + /** * Starts playing the movie */ virtual void play(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj); - + /** * Plays a sub-section of a movie, and doesn't return until either * the playback ends or a key has been pressed @@ -192,7 +192,7 @@ public: * Stops the movie */ virtual void stop(); - + /** * Add a playback event */ @@ -202,7 +202,7 @@ public: * Set the current frame number */ virtual void setFrame(uint frameNumber); - + /** * Handle any pending movie events */ @@ -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/movie_clip.h b/engines/titanic/support/movie_clip.h index 513ed4a339..17c91b190c 100644 --- a/engines/titanic/support/movie_clip.h +++ b/engines/titanic/support/movie_clip.h @@ -27,7 +27,7 @@ namespace Titanic { -enum ClipFlag { +enum ClipFlag { CLIPFLAG_HAS_END_FRAME = 1, CLIPFLAG_4 = 4, CLIPFLAG_HAS_START_FRAME = 8, diff --git a/engines/titanic/support/movie_range_info.cpp b/engines/titanic/support/movie_range_info.cpp index d4d9fc0e2a..018ffd63b5 100644 --- a/engines/titanic/support/movie_range_info.cpp +++ b/engines/titanic/support/movie_range_info.cpp @@ -91,7 +91,7 @@ void CMovieRangeInfo::process(CGameObject *owner) { flags |= MOVIE_REPEAT; if (_startFrame) flags |= MOVIE_REVERSE; - + for (CMovieEventList::iterator i = _events.begin(); i != _events.end(); ++i) { CMovieEvent *movieEvent = *i; if (movieEvent->_type == MET_MOVIE_END) { diff --git a/engines/titanic/support/screen_manager.cpp b/engines/titanic/support/screen_manager.cpp index bcf43fc8cb..2e9bbcb6de 100644 --- a/engines/titanic/support/screen_manager.cpp +++ b/engines/titanic/support/screen_manager.cpp @@ -178,7 +178,7 @@ void OSScreenManager::blitFrom(SurfaceNum surfaceNum, CVideoSurface *src, destSurface = _backSurfaces[surfaceNum]._surface; if (!destSurface->hasSurface()) return; - + Point destPoint = destPos ? *destPos : Point(0, 0); Rect srcBounds = srcRect ? *srcRect : Rect(0, 0, src->getWidth(), src->getHeight()); Rect *bounds = &srcBounds; @@ -220,7 +220,7 @@ void OSScreenManager::blitFrom(SurfaceNum surfaceNum, const Rect *rect, CVideoSu destSurface->blitFrom(Point(rect->left, rect->top), src, rect); } -int OSScreenManager::writeString(int surfaceNum, const Rect &destRect, +int OSScreenManager::writeString(int surfaceNum, const Rect &destRect, int yOffset, const CString &str, CTextCursor *textCursor) { CVideoSurface *surface; Rect bounds; diff --git a/engines/titanic/support/screen_manager.h b/engines/titanic/support/screen_manager.h index cad6901b02..f88928af8b 100644 --- a/engines/titanic/support/screen_manager.h +++ b/engines/titanic/support/screen_manager.h @@ -78,7 +78,7 @@ public: virtual void setWindowHandle(int v); virtual bool resetWindowHandle(int v); - + /** * Sets the video mode */ @@ -88,17 +88,17 @@ public: * Handles drawing the cursors */ virtual void drawCursors() = 0; - + /** * Locks a specified surface number for access and returns a pointer to it */ virtual CVideoSurface *lockSurface(SurfaceNum surfaceNum) = 0; - + /** * Unlocks a previously locked surface */ virtual void unlockSurface(CVideoSurface *surface) = 0; - + /** * Gets a specified surface number */ @@ -108,7 +108,7 @@ public: * Return the front render surface */ virtual CVideoSurface *getFrontRenderSurface() const = 0; - + /** * Fill an area with a specific color */ @@ -191,7 +191,7 @@ public: * Creates a surface of a given size */ virtual CVideoSurface *createSurface(int w, int h) = 0; - + /** * Creates a surface from a specified resource */ @@ -213,7 +213,7 @@ public: * Show the mouse cursor */ virtual void showCursor() = 0; - + /** * Hide the mouse cursor */ @@ -272,12 +272,12 @@ public: * Locks a specified surface number for access and returns a pointer to it */ virtual CVideoSurface *lockSurface(SurfaceNum surfaceNum); - + /** * Unlocks a previously locked surface */ virtual void unlockSurface(CVideoSurface *surface); - + /** * Gets a specified surface number */ @@ -373,7 +373,7 @@ public: * Creates a surface of a given size */ virtual CVideoSurface *createSurface(int w, int h); - + /** * Creates a surface from a specified resource */ @@ -383,7 +383,7 @@ public: * Show the mouse cursor */ virtual void showCursor(); - + /** * Hide the mouse cursor */ diff --git a/engines/titanic/support/simple_file.cpp b/engines/titanic/support/simple_file.cpp index 35b2e28e4a..7e3cea35be 100644 --- a/engines/titanic/support/simple_file.cpp +++ b/engines/titanic/support/simple_file.cpp @@ -52,7 +52,7 @@ SimpleFile::~SimpleFile() { } void SimpleFile::open(Common::SeekableReadStream *stream) { - close(); + close(); _inStream = stream; } @@ -290,7 +290,7 @@ void SimpleFile::writeString(const CString &str) const { const char *msgP = str.c_str(); char c; - + while ((c = *msgP++) != '\0') { switch (c) { case '\r': @@ -422,8 +422,8 @@ bool SimpleFile::scanf(const char *format, ...) { while (!formatStr.empty()) { if (formatStr.hasPrefix(" ")) { formatStr.deleteChar(0); - - safeRead(&c, 1); + + safeRead(&c, 1); if (!Common::isSpace(c)) return false; @@ -434,7 +434,7 @@ bool SimpleFile::scanf(const char *format, ...) { formatStr = CString(formatStr.c_str() + 2); int *param = (int *)va_arg(va, int *); *param = readNumber(); - + if (!eos()) _inStream->seek(-1, SEEK_CUR); } else if (formatStr.hasPrefix("%s")) { @@ -488,7 +488,7 @@ bool StdCWadFile::open(const Common::String &filename) { CString resStr = name.mid(idx + 1, extPos - idx - 1); int resIndex = resStr.readInt(); - // Open up the index for access + // Open up the index for access f.open(fname); int indexSize = f.readUint32LE() / 4; assert(resIndex < indexSize); diff --git a/engines/titanic/support/string.cpp b/engines/titanic/support/string.cpp index 9961cfce59..cf1b29b6ec 100644 --- a/engines/titanic/support/string.cpp +++ b/engines/titanic/support/string.cpp @@ -41,7 +41,7 @@ CString CString::left(uint count) const { CString CString::right(uint count) const { uint strSize = size(); - return (count > strSize) ? CString() : + return (count > strSize) ? CString() : CString(c_str() + strSize - count, c_str() + strSize); } @@ -85,7 +85,7 @@ FileType CString::fileTypeSuffix() const { return FILETYPE_WAV; else if (ext == "2" || ext == "3") return FILETYPE_MOVIE; - + ext = right(3); if (ext == "tga" || ext == "jpg") return FILETYPE_IMAGE; diff --git a/engines/titanic/support/text_cursor.cpp b/engines/titanic/support/text_cursor.cpp index ad3fe4ed26..5c7593ba68 100644 --- a/engines/titanic/support/text_cursor.cpp +++ b/engines/titanic/support/text_cursor.cpp @@ -27,7 +27,7 @@ namespace Titanic { -CTextCursor::CTextCursor(CScreenManager *screenManager) : +CTextCursor::CTextCursor(CScreenManager *screenManager) : _screenManager(screenManager), _active(false), _blinkVisible(false), _backRenderSurface(nullptr), _frontRenderSurface(nullptr), _blinkDelay(300), _size(2, 10), _priorBlinkTime(0), @@ -70,7 +70,7 @@ void CTextCursor::draw() { if (_blinkVisible) { Rect cursorRect = getCursorBounds(); _surface->blitFrom(Common::Point(0, 0), _backRenderSurface, &cursorRect); - + if (!_screenBounds.isEmpty()) // Limit the cursor rect to only within designated screen area cursorRect.constrain(_screenBounds); @@ -80,7 +80,7 @@ void CTextCursor::draw() { _backRenderSurface->_ddSurface->fillRect(&cursorRect, _cursorR, _cursorG, _cursorB); } - + //_screenManager->blitFrom(SURFACE_BACKBUFFER, _surface, &_pos); } } diff --git a/engines/titanic/support/time_event_info.cpp b/engines/titanic/support/time_event_info.cpp index 0226223f1a..e088a8e0c2 100644 --- a/engines/titanic/support/time_event_info.cpp +++ b/engines/titanic/support/time_event_info.cpp @@ -90,7 +90,7 @@ void CTimeEventInfoList::setPersisent(uint id, bool flag) { uint CTimeEventInfo::_nextId; -CTimeEventInfo::CTimeEventInfo() : ListItem(), _lockCounter(0), +CTimeEventInfo::CTimeEventInfo() : ListItem(), _lockCounter(0), _repeated(false), _firstDuration(0), _repeatDuration(0), _target(nullptr), _actionVal(0), _timerCtr(0), _done(false), _lastTimerTicks(0), _relativeTicks(0), _persisent(true) { @@ -147,7 +147,7 @@ void CTimeEventInfo::load(SimpleFile *file) { void CTimeEventInfo::postLoad(uint ticks, CProjectItem *project) { if (!_persisent || _targetName.empty()) _done = true; - + // Get the timer's target if (project) _target = project->findByName(_targetName); diff --git a/engines/titanic/support/transparency_surface.cpp b/engines/titanic/support/transparency_surface.cpp new file mode 100644 index 0000000000..5ffa8b99b1 --- /dev/null +++ b/engines/titanic/support/transparency_surface.cpp @@ -0,0 +1,73 @@ +/* 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 *pixelP; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/transparency_surface.h b/engines/titanic/support/transparency_surface.h new file mode 100644 index 0000000000..0391b6d5b7 --- /dev/null +++ b/engines/titanic/support/transparency_surface.h @@ -0,0 +1,84 @@ +/* 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 TITANIC_TRANSPARENCY_SURFACE_H +#define TITANIC_TRANSPARENCY_SURFACE_H + +#include "common/rect.h" +#include "graphics/surface.h" + +namespace Titanic { + +enum TransparencyMode { + TRANS_MASK0 = 0, TRANS_MASK255 = 1, TRANS_ALPHA0 = 2, + TRANS_ALPHA255 = 3, TRANS_DEFAULT = 4 +}; + +class CTransparencySurface { +private: + const Graphics::Surface *_surface; + Common::Point _pos; + int _pitch; + int _runLength; + bool _flag; + bool _flag1; + bool _flag2; +public: + /** + * Constructor + */ + CTransparencySurface(const Graphics::Surface *surface, TransparencyMode transMode); + + /** + * Sets the row to get transparencies from + */ + void setRow(int yp) { _pos.y = yp; } + + /** + * Sets the column to get transparencies from + */ + void setCol(int xp) { _pos.x = xp; } + + /** + * Moves reading position horizontally by a single pixel + */ + int moveX(); + + /** + * Returns a byte from the transparency surface + */ + uint getPixel() const; + + /** + * Returns the alpha value for the pixel (0-31) + */ + uint getAlpha() const { return 31 - (getPixel() >> 3); } + + /** + * Returns true if the pixel is completely transparent + */ + bool isPixelTransparent() const { return getAlpha() == 31; } +}; + +} // End of namespace Titanic + +#endif /* TITANIC_TRANSPARENCY_SURFACE_H */ diff --git a/engines/titanic/support/video_surface.cpp b/engines/titanic/support/video_surface.cpp index 63ad782722..45813bb740 100644 --- a/engines/titanic/support/video_surface.cpp +++ b/engines/titanic/support/video_surface.cpp @@ -23,16 +23,19 @@ #include "titanic/support/video_surface.h" #include "titanic/support/image_decoders.h" #include "titanic/support/screen_manager.h" +#include "titanic/support/transparency_surface.h" #include "titanic/titanic.h" namespace Titanic { int CVideoSurface::_videoSurfaceCounter = 0; +byte CVideoSurface::_palette1[32][32]; +byte CVideoSurface::_palette2[32][32]; CVideoSurface::CVideoSurface(CScreenManager *screenManager) : _screenManager(screenManager), _rawSurface(nullptr), _movie(nullptr), - _pendingLoad(false), _transBlitFlag(false), _fastBlitFlag(false), - _transparencySurface(nullptr), _transparencyMode(TRANS_DEFAULT), + _pendingLoad(false), _flipVertically(false), _fastBlitFlag(false), + _transparencySurface(nullptr), _transparencyMode(TRANS_DEFAULT), _freeTransparencySurface(DisposeAfterUse::NO), _hasFrame(true), _lockCount(0) { _videoSurfaceNum = _videoSurfaceCounter++; } @@ -46,6 +49,19 @@ CVideoSurface::~CVideoSurface() { delete _transparencySurface; } +void CVideoSurface::setupPalette(byte palette[32][32], byte val) { + for (uint idx1 = 0; idx1 < 32; ++idx1) { + for (uint idx2 = 0, base = 0; idx2 < 32; ++idx2, base += idx1) { + uint v = base / 31; + palette[idx1][idx2] = (byte)v; + + if (val != 0xff && v != idx2) { + assert(0); + } + } + } +} + void CVideoSurface::setSurface(CScreenManager *screenManager, DirectDrawSurface *surface) { _screenManager = screenManager; _ddSurface = surface; @@ -56,10 +72,10 @@ void CVideoSurface::blitFrom(const Point &destPos, CVideoSurface *src, const Rec Rect srcBounds, destBounds; clipBounds(srcBounds, destBounds, src, srcRect, &destPos); - if (src->_transBlitFlag) - blitRect2(srcBounds, destBounds, src); + if (src->_flipVertically) + flippedBlitRect(srcBounds, destBounds, src); else - blitRect1(srcBounds, destBounds, src); + blitRect(srcBounds, destBounds, src); } } @@ -132,44 +148,118 @@ void CVideoSurface::clipBounds(Rect &srcRect, Rect &destRect, error("Invalid rect"); } -void CVideoSurface::blitRect1(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { +void CVideoSurface::blitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { src->lock(); lock(); if (src->_fastBlitFlag) { _rawSurface->blitFrom(*src->_rawSurface, srcRect, Point(destRect.left, destRect.top)); - } else if (getTransparencySurface()) { - transBlitRect(srcRect, destRect, src); - } else { - _rawSurface->transBlitFrom(*src->_rawSurface, srcRect, destRect, src->getTransparencyColor()); - } + } else if (src->getTransparencySurface()) { + transBlitRect(srcRect, destRect, src, false); + } else if (lock()) { + if (src->lock()) { + const Graphics::ManagedSurface *srcSurface = src->_rawSurface; + Graphics::ManagedSurface *destSurface = _rawSurface; + Graphics::Surface destArea = destSurface->getSubArea(destRect); + const uint transColor = src->getTransparencyColor(); + + const uint16 *srcPtr = (const uint16 *)srcSurface->getBasePtr( + srcRect.left, srcRect.top); + uint16 *destPtr = (uint16 *)destArea.getBasePtr(0, 0); + + for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr, + srcPtr += src->getPitch() / 2, + destPtr += destArea.pitch / 2) { + // Prepare for copying the line + const uint16 *lineSrcP = srcPtr; + uint16 *lineDestP = destPtr; + + for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX, ++lineSrcP, ++lineDestP) { + if (*lineSrcP != transColor) + *lineDestP = *lineSrcP; + } + } - src->unlock(); - unlock(); + src->unlock(); + } + + unlock(); + } } -void CVideoSurface::blitRect2(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { - if (getTransparencySurface()) { - transBlitRect(srcRect, destRect, src); - } else { - src->lock(); - lock(); +void CVideoSurface::flippedBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { + if (src->getTransparencySurface()) { + transBlitRect(srcRect, destRect, src, true); + } else if (lock()) { + if (src->lock()) { + const Graphics::ManagedSurface *srcSurface = src->_rawSurface; + Graphics::ManagedSurface *destSurface = _rawSurface; + Graphics::Surface destArea = destSurface->getSubArea(destRect); + const uint transColor = src->getTransparencyColor(); + + const uint16 *srcPtr = (const uint16 *)srcSurface->getBasePtr( + srcRect.left, srcRect.top); + uint16 *destPtr = (uint16 *)destArea.getBasePtr(0, destArea.h - 1); + + for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr, + srcPtr += src->getPitch() / 2, + destPtr -= destArea.pitch / 2) { + // Prepare for copying the line + const uint16 *lineSrcP = srcPtr; + uint16 *lineDestP = destPtr; + + for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX, ++lineSrcP, ++lineDestP) { + if (*lineSrcP != transColor) + *lineDestP = *lineSrcP; + } + } - _rawSurface->blitFrom(*src->_rawSurface, srcRect, Point(destRect.left, destRect.top)); + src->unlock(); + } - src->unlock(); unlock(); } } -void CVideoSurface::transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { +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; - - // TODO: Handle the transparency mode correctly - destSurface->blitFrom(*srcSurface, srcRect, Point(srcRect.left, srcRect.top)); + Graphics::Surface destArea = destSurface->getSubArea(destRect); + + const uint16 *srcPtr = (const uint16 *)srcSurface->getBasePtr( + srcRect.left, flipFlag ? srcRect.top : srcRect.bottom - 1); + uint16 *destPtr = (uint16 *)destArea.getBasePtr(0, destArea.h - 1); + bool isAlpha = src->_transparencyMode == TRANS_ALPHA0 || + src->_transparencyMode == TRANS_ALPHA255; + + CTransparencySurface transSurface(src->getTransparencySurface(), src->_transparencyMode); + + for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) { + // Prepare for copying the line + const uint16 *lineSrcP = srcPtr; + uint16 *lineDestP = destPtr; + transSurface.setRow(flipFlag ? srcRect.top + yCtr : srcRect.bottom - yCtr - 1); + transSurface.setCol(srcRect.left); + + for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX) { + if (!transSurface.isPixelTransparent()) { + copyPixel(lineDestP, lineSrcP, transSurface.getAlpha(), srcSurface->format, isAlpha); + } + + ++lineSrcP; + ++lineDestP; + transSurface.moveX(); + } + + // Move to next line + srcPtr = flipFlag ? srcPtr + (src->getPitch() / 2) : + srcPtr - (src->getPitch() / 2); + destPtr -= destArea.pitch / 2; + } src->unlock(); } @@ -196,10 +286,40 @@ bool CVideoSurface::hasFrame() { } } -/*------------------------------------------------------------------------*/ +#define RGB_SHIFT 3 +void CVideoSurface::copyPixel(uint16 *destP, const uint16 *srcP, byte alpha, + const Graphics::PixelFormat &srcFormat, bool isAlpha) { + const Graphics::PixelFormat destFormat = _ddSurface->getFormat(); + alpha &= 0xff; + assert(alpha < 32); + + // Get the source color + byte r, g, b; + srcFormat.colorToRGB(*srcP, r, g, b); + r >>= RGB_SHIFT; + g >>= RGB_SHIFT; + b >>= RGB_SHIFT; + + if (isAlpha) { + r = _palette1[31 - alpha][r]; + g = _palette1[31 - alpha][g]; + b = _palette1[31 - alpha][b]; + } -byte OSVideoSurface::_palette1[32][32]; -byte OSVideoSurface::_palette2[32][32]; + byte r2, g2, b2; + destFormat.colorToRGB(*destP, r2, g2, b2); + r2 >>= RGB_SHIFT; + g2 >>= RGB_SHIFT; + b2 >>= RGB_SHIFT; + r2 = _palette1[alpha][r2]; + g2 = _palette1[alpha][g2]; + b2 = _palette1[alpha][b2]; + + *destP = destFormat.RGBToColor((r + r2) << RGB_SHIFT, + (g + g2) << RGB_SHIFT, (b + b2) << RGB_SHIFT); +} + +/*------------------------------------------------------------------------*/ OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, DirectDrawSurface *surface) : CVideoSurface(screenManager) { @@ -210,7 +330,7 @@ OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, const CResourceKey CVideoSurface(screenManager) { _ddSurface = nullptr; _pendingLoad = pendingLoad; - + if (_pendingLoad) { loadResource(key); } else { @@ -219,24 +339,6 @@ OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, const CResourceKey } } -void OSVideoSurface::setupPalette(byte palette[32][32], byte val) { - for (uint idx1 = 0; idx1 < 32; ++idx1) { - for (uint idx2 = 0, base = 0; idx2 < 32; ++idx2, base += idx1) { - int64 v = 0x84210843; - v *= base; - uint v2 = (v >> 36); - v = ((v2 >> 31) + v2) & 0xff; - palette[idx1][idx2] = v << 3; - - if (val != 0xff && v != idx2) { - v = 0x80808081 * v * val; - v2 = v >> 39; - palette[idx1][idx2] = ((v2 >> 31) + v2) << 3; - } - } - } -} - void OSVideoSurface::loadResource(const CResourceKey &key) { _resourceKey = key; _pendingLoad = true; @@ -351,7 +453,7 @@ void OSVideoSurface::recreate(int width, int height) { } void OSVideoSurface::resize(int width, int height) { - if (!_ddSurface || _ddSurface->getWidth() != width || + if (!_ddSurface || _ddSurface->getWidth() != width || _ddSurface->getHeight() != height) recreate(width, height); } @@ -365,7 +467,7 @@ int OSVideoSurface::getPixelDepth() { error("Could not load resource"); lock(); - + int result = _rawSurface->format.bytesPerPixel; if (result == 1) // Paletted 8-bit images don't store the color directly in the pixels @@ -408,8 +510,13 @@ uint16 OSVideoSurface::getPixel(const Common::Point &pt) { if (pt.x >= 0 && pt.y >= 0 && pt.x < getWidth() && pt.y < getHeight()) { if (_transparencySurface) { - const byte *pixelP = (const byte *)_transparencySurface->getBasePtr(pt.x, pt.y); - if (*pixelP != 0xF0) + // WORKAROUND: Original had the setRow _flipVertically check in reverse. + // Pretty sure putting it the way is below is the correct way + CTransparencySurface transSurface(&_transparencySurface->rawSurface(), _transparencyMode); + transSurface.setRow(_flipVertically ? getHeight() - pt.y - 1 : pt.y); + transSurface.setCol(pt.x); + + if (transSurface.isPixelTransparent()) return getTransparencyColor(); } @@ -429,29 +536,6 @@ void OSVideoSurface::setPixel(const Point &pt, uint pixel) { *pixelP = pixel; } -void OSVideoSurface::changePixel(uint16 *pixelP, uint16 *color, byte srcVal, bool remapFlag) { - assert(getPixelDepth() == 2); - const Graphics::PixelFormat &destFormat = _ddSurface->getFormat(); - const Graphics::PixelFormat srcFormat(2, 5, 5, 5, 0, 10, 5, 0, 0); - - // Get the color - byte r, g, b; - srcFormat.colorToRGB(*color, r, g, b); - if (remapFlag) { - r = _palette1[31 - srcVal][r >> 3]; - g = _palette1[31 - srcVal][g >> 3]; - b = _palette1[31 - srcVal][b >> 3]; - } - - byte r2, g2, b2; - destFormat.colorToRGB(*pixelP, r2, g2, b2); - r2 = _palette1[srcVal][r2 >> 3]; - g2 = _palette1[srcVal][g2 >> 3]; - b2 = _palette1[srcVal][b2 >> 3]; - - *pixelP = destFormat.RGBToColor(r + r2, g + g2, b + b2); -} - void OSVideoSurface::shiftColors() { if (!loadIfReady()) return; @@ -510,7 +594,7 @@ const CMovieRangeInfoList *OSVideoSurface::getMovieRangeInfo() const { } void OSVideoSurface::flipVertically(bool needsLock) { - if (!loadIfReady() || !_transBlitFlag) + if (!loadIfReady() || !_flipVertically) return; if (needsLock) @@ -529,7 +613,7 @@ void OSVideoSurface::flipVertically(bool needsLock) { Common::copy(lineBuffer, lineBuffer + pitch, line1P); } - _transBlitFlag = false; + _flipVertically = false; if (needsLock) unlock(); } @@ -576,8 +660,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 c21149333d..690669b79b 100644 --- a/engines/titanic/support/video_surface.h +++ b/engines/titanic/support/video_surface.h @@ -31,16 +31,12 @@ #include "titanic/support/movie.h" #include "titanic/support/movie_range_info.h" #include "titanic/support/rect.h" +#include "titanic/support/transparency_surface.h" #include "titanic/core/list.h" #include "titanic/core/resource_key.h" namespace Titanic { -enum TransparencyMode { - TRANS_MASK0 = 0, TRANS_MASK255 = 1, TRANS_ALPHA0 = 2, - TRANS_ALPHA255 = 3, TRANS_DEFAULT = 4 -}; - class CScreenManager; class CJPEGDecode; class CTargaDecode; @@ -49,15 +45,38 @@ class CVideoSurface : public ListItem { friend class CJPEGDecode; friend class CTargaDecode; private: + static byte _palette1[32][32]; + static byte _palette2[32][32]; + + /** + * Setup the shading palettes + */ + static void setupPalette(byte palette[32][32], byte val); +public: + /** + * Setup statics + */ + static void setup() { + setupPalette(_palette1, 0xff); + } +private: /** * Calculates blitting bounds */ void clipBounds(Rect &srcRect, Rect &destRect, CVideoSurface *srcSurface, const Rect *subRect = nullptr, const Point *destPos = nullptr); - void blitRect1(const Rect &srcRect, const Rect &destRect, CVideoSurface *src); - void blitRect2(const Rect &srcRect, const Rect &destRect, CVideoSurface *src); - void transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src); + /** + * Copies a rect from a given source surface + */ + void blitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src); + + /** + * Copies a rect from a given source surface and draws it vertically flipped + */ + void flippedBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src); + + void transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src, bool flipFlag); protected: static int _videoSurfaceCounter; protected: @@ -73,7 +92,7 @@ public: CMovie *_movie; DirectDrawSurface *_ddSurface; bool _fastBlitFlag; - bool _transBlitFlag; + bool _flipVertically; CResourceKey _resourceKey; TransparencyMode _transparencyMode; public: @@ -186,11 +205,6 @@ public: virtual void setPixel(const Point &pt, uint pixel) = 0; /** - * Change a pixel - */ - virtual void changePixel(uint16 *pixelP, uint16 *color, byte srcVal, bool remapFlag = true) = 0; - - /** * Shifts the colors of the surface.. maybe greys it out? */ virtual void shiftColors() = 0; @@ -270,9 +284,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 @@ -302,7 +316,9 @@ public: /** * Get the previously set transparency mask surface */ - Graphics::ManagedSurface *getTransparencySurface() const { return _transparencySurface; } + const Graphics::Surface *getTransparencySurface() const { + return _transparencySurface ? &_transparencySurface->rawSurface() : nullptr; + } /** * Get the pixels associated with the surface. Only valid when the @@ -320,26 +336,23 @@ public: * Returns the transparent color */ uint getTransparencyColor(); + + /** + * Copies a pixel, handling transparency + * @param destP Dest pointer to 16-bit pixel + * @param srcP Source pointer to 16-bit pixel + * @param alpha Alpha (0-31). At 0, it's completely opaque, + * and overwrites the dest pixel. Through to 31, which is completely + * transparent, and ignores the source pixel. + * @param srcFormat The source surface format + * @param isAlpha If true, has alpha channel + */ + void copyPixel(uint16 *destP, const uint16 *srcP, byte alpha, + const Graphics::PixelFormat &srcFormat, bool isAlpha); }; class OSVideoSurface : public CVideoSurface { friend class OSMovie; -private: - static byte _palette1[32][32]; - static byte _palette2[32][32]; - - /** - * Setup the shading palettes - */ - static void setupPalette(byte palette[32][32], byte val); -public: - /** - * Setup statics - */ - static void setup() { - setupPalette(_palette1, 0xff); - setupPalette(_palette2, 0xe0); - } public: OSVideoSurface(CScreenManager *screenManager, DirectDrawSurface *surface); OSVideoSurface(CScreenManager *screenManager, const CResourceKey &key, bool flag = false); @@ -437,11 +450,6 @@ public: virtual void setPixel(const Point &pt, uint pixel); /** - * Change a pixel - */ - virtual void changePixel(uint16 *pixelP, uint16 *color, byte srcVal, bool remapFlag = true); - - /** * Shifts the colors of the surface.. maybe greys it out? */ virtual void shiftColors(); @@ -516,10 +524,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 |