diff options
author | Eugene Sandulenko | 2016-08-01 00:27:28 +0300 |
---|---|---|
committer | GitHub | 2016-08-01 00:27:28 +0300 |
commit | 9d3a2c1c7f9365f65908f583e62047830f60693d (patch) | |
tree | d7ba49593a1e3d79f17b350e700b1fbcf71f5b22 /engines/titanic/support | |
parent | 567054d8298a013f93dd9e0e332e2a08402b10a6 (diff) | |
parent | 19f8a0965be832a71a101054748cf000adf16add (diff) | |
download | scummvm-rg350-9d3a2c1c7f9365f65908f583e62047830f60693d.tar.gz scummvm-rg350-9d3a2c1c7f9365f65908f583e62047830f60693d.tar.bz2 scummvm-rg350-9d3a2c1c7f9365f65908f583e62047830f60693d.zip |
Merge pull request #786 from dreammaster/titanic
TITANIC: Starship Titanic engine
Diffstat (limited to 'engines/titanic/support')
46 files changed, 7202 insertions, 0 deletions
diff --git a/engines/titanic/support/avi_surface.cpp b/engines/titanic/support/avi_surface.cpp new file mode 100644 index 0000000000..6507c8bbd4 --- /dev/null +++ b/engines/titanic/support/avi_surface.cpp @@ -0,0 +1,361 @@ +/* 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/avi_surface.h" +#include "titanic/support/screen_manager.h" +#include "titanic/support/video_surface.h" +#include "common/system.h" +#include "graphics/pixelformat.h" +#include "video/avi_decoder.h" + +namespace Titanic { + +Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack() { + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++) + if ((*it)->getTrackType() == Track::kTrackTypeVideo) + return *static_cast<AVIVideoTrack *>(*it); + + error("Could not find video track"); +} + +/** + * Track filter for AVIDecoder that filters out any secondary video track + */ +static bool primaryTrackSelect(bool isVideo, int trackCounter) { + return !isVideo || trackCounter == 0; +} + +/** + * Track filter for AVIDecoder that only accepts the secondary video track + * for a video, if present + */ +static bool secondaryTrackSelect(bool isVideo, int trackCounter) { + return isVideo && trackCounter > 0; +} + +AVISurface::AVISurface(const CResourceKey &key) { + _videoSurface = nullptr; + _streamCount = 0; + _movieFrameSurface[0] = _movieFrameSurface[1] = nullptr; + + // Reset current frame. We need to keep track of frames separately from the decoders, + // 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())) + 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; + } +} + +AVISurface::~AVISurface() { + if (_videoSurface) + _videoSurface->_transBlitFlag = false; + delete _movieFrameSurface[0]; + delete _movieFrameSurface[1]; + delete _decoders[0]; + delete _decoders[1]; +} + +bool AVISurface::play(uint flags, CGameObject *obj) { + if (flags & MOVIE_REVERSE) + return play(_decoders[0]->getFrameCount() - 1, 0, flags, obj); + else + return play(0, _decoders[0]->getFrameCount() - 1, flags, obj); +} + +bool AVISurface::play(int startFrame, int endFrame, uint flags, CGameObject *obj) { + if (flags & MOVIE_STOP_PREVIOUS) + stop(); + + return play(startFrame, endFrame, -1, flags, obj); +} + +bool AVISurface::play(int startFrame, int endFrame, int initialFrame, uint flags, CGameObject *obj) { + CMovieRangeInfo *info = new CMovieRangeInfo(); + info->_startFrame = startFrame; + info->_endFrame = endFrame; + info->_isReversed = endFrame < startFrame; + info->_initialFrame = 0; + info->_isRepeat = flags & MOVIE_REPEAT; + + if (obj) { + CMovieEvent *me = new CMovieEvent(); + me->_type = MET_MOVIE_END; + me->_startFrame = startFrame; + 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(); + + _movieRangeInfo.destroyContents(); +} + +bool AVISurface::startAtFrame(int frameNumber) { + if (isPlaying()) + // If it's already playing, then don't allow it + return false; + + if (frameNumber == -1) + // Default to starting frame of first movie range + frameNumber = _movieRangeInfo.front()->_startFrame; + + // Get the initial frame + seekToFrame(frameNumber); + renderFrame(); + + // Start the playback + _decoders[0]->start(); + if (_decoders[1]) + _decoders[1]->start(); + + return true; +} + +void AVISurface::seekToFrame(uint frameNumber) { + if ((int)frameNumber != getFrame()) { + _decoders[0]->seekToFrame(frameNumber); + if (_decoders[1]) + _decoders[1]->seekToFrame(frameNumber); + + _currentFrame = (int)frameNumber; + } + + renderFrame(); +} + +void AVISurface::setReversed(bool isReversed) { + _decoders[0]->setReverse(isReversed); + if (_decoders[1]) + _decoders[1]->setReverse(isReversed); + + _isReversed = isReversed; +} + +bool AVISurface::handleEvents(CMovieEventList &events) { + if (!isPlaying()) + return true; + + CMovieRangeInfo *info = _movieRangeInfo.front(); + _currentFrame += _isReversed ? -1 : 1; + + int newFrame = _currentFrame; + if ((info->_isReversed && newFrame <= info->_endFrame) || + (!info->_isReversed && newFrame >= info->_endFrame)) { + if (info->_isRepeat) { + newFrame = info->_startFrame; + } else { + info->getMovieEnd(events); + _movieRangeInfo.remove(info); + delete info; + + if (_movieRangeInfo.empty()) { + // NO more ranges, so stop playback + stop(); + } else { + // Not empty, so move onto new first one + info = _movieRangeInfo.front(); + newFrame = info->_startFrame; + } + } + } + + if (isPlaying()) { + if (newFrame != getFrame()) { + // The frame has been changed, so move to new position + setReversed(info->_isReversed); + seekToFrame(newFrame); + } + + // Get any events for the given position + info->getMovieFrame(events, newFrame); + return renderFrame(); + } else { + return false; + } +} + +void AVISurface::setVideoSurface(CVideoSurface *surface) { + _videoSurface = surface; + + // Handling for secondary video stream + if (_decoders[1]) { + const Common::String &streamName = _decoders[1]->getVideoTrack().getName(); + + if (streamName == "mask0") { + _videoSurface->_transparencyMode = TRANS_MASK0; + } else if (streamName == "mask255") { + _videoSurface->_transparencyMode = TRANS_MASK255; + } else if (streamName == "alpha0") { + _videoSurface->_transparencyMode = TRANS_ALPHA0; + } else if (streamName == "alpha255") { + _videoSurface->_transparencyMode = TRANS_ALPHA255; + } + } + + setupDecompressor(); +} + +void AVISurface::setupDecompressor() { + for (int idx = 0; idx < 2; ++idx) { + if (!_decoders[idx]) + continue; + AVIDecoder &decoder = *_decoders[idx]; + + // Setup frame surface + _movieFrameSurface[idx] = new Graphics::ManagedSurface(decoder.getWidth(), decoder.getHeight(), + g_system->getScreenFormat()); + + // TODO: See whether this simplified form of original works + if (idx == 2) + _videoSurface->_transBlitFlag = true; + } +} + +uint AVISurface::getWidth() const { + return _decoders[0]->getWidth(); +} + +uint AVISurface::getHeight() const { + return _decoders[0]->getHeight(); +} + +void AVISurface::setFrame(int frameNumber) { + // If playback was in process, stop it + if (isPlaying()) + stop(); + + // Ensure the frame number is valid + if (frameNumber >= (int)_decoders[0]->getFrameCount()) + frameNumber = _decoders[0]->getFrameCount() - 1; + + seekToFrame(frameNumber); + renderFrame(); +} + +bool AVISurface::isNextFrame() const { + return _decoders[0]->getTimeToNextFrame() == 0; +} + +bool AVISurface::renderFrame() { + // Check there's a frame ready for display + if (!_decoders[0]->needsUpdate()) + return false; + + // Decode each decoder's video stream into the appropriate surface + 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; + } + } + + // Blit the primary video frame onto the main overall surface + _videoSurface->lock(); + _videoSurface->getRawSurface()->blitFrom(*_movieFrameSurface[0]); + _videoSurface->unlock(); + + return false; +} + +bool AVISurface::addEvent(int frameNumber, CGameObject *obj) { + if (!_movieRangeInfo.empty()) { + CMovieRangeInfo *tail = _movieRangeInfo.back(); + if (frameNumber == -1) + frameNumber = tail->_startFrame; + + CMovieEvent *me = new CMovieEvent(); + me->_type = MET_FRAME; + me->_startFrame = 0; + me->_endFrame = 0; + me->_initialFrame = frameNumber; + me->_gameObject = obj; + tail->addEvent(me); + + return _movieRangeInfo.size() == 1 && frameNumber == getFrame(); + } + + return false; +} + +void AVISurface::setFrameRate(double rate) { + _decoders[0]->setRate(Common::Rational(rate)); + if (_decoders[1]) + _decoders[1]->setRate(Common::Rational(rate)); +} + +Graphics::ManagedSurface *AVISurface::getSecondarySurface() { + return _streamCount <= 1 ? nullptr : _movieFrameSurface[1]; +} + +Graphics::ManagedSurface *AVISurface::duplicateSecondaryFrame() const { + if (_streamCount <= 1) { + return nullptr; + } else { + Graphics::ManagedSurface *dest = new Graphics::ManagedSurface(_movieFrameSurface[1]->w, + _movieFrameSurface[1]->h, _movieFrameSurface[1]->format); + dest->blitFrom(*_movieFrameSurface[1]); + return dest; + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/avi_surface.h b/engines/titanic/support/avi_surface.h new file mode 100644 index 0000000000..d21182bca9 --- /dev/null +++ b/engines/titanic/support/avi_surface.h @@ -0,0 +1,183 @@ +/* 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_AVI_SURFACE_H +#define TITANIC_AVI_SURFACE_H + +#include "video/avi_decoder.h" +#include "graphics/managed_surface.h" +#include "titanic/core/resource_key.h" +#include "titanic/support/movie_range_info.h" + +namespace Titanic { + +class CSoundManager; +class CVideoSurface; + +enum MovieFlag { + MOVIE_REPEAT = 1, MOVIE_STOP_PREVIOUS = 2, MOVIE_NOTIFY_OBJECT = 4, + MOVIE_REVERSE = 8, MOVIE_GAMESTATE = 0x10 +}; + +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(); +}; + +class AVISurface { +private: + AVIDecoder *_decoders[2]; + CVideoSurface *_videoSurface; + CMovieRangeInfoList _movieRangeInfo; + int _streamCount; + Graphics::ManagedSurface *_movieFrameSurface[2]; + bool _isReversed; + int _currentFrame; +private: + /** + * Render a frame to the video surface + */ + bool renderFrame(); + + /** + * Sets up for video decompression + */ + void setupDecompressor(); +protected: + /** + * Start playback at the specified frame + */ + bool startAtFrame(int frameNumber); + + /** + * Sets whether the movie is playing in reverse + */ + void setReversed(bool isReversed); + + /** + * Seeks to a given frame number in the video + */ + virtual void seekToFrame(uint frameNumber); +public: + CSoundManager *_soundManager; + bool _hasAudio; + double _frameRate; +public: + AVISurface(const CResourceKey &key); + virtual ~AVISurface(); + + /** + * Start playing the loaded AVI video + */ + virtual bool play(uint flags, CGameObject *obj); + + /** + * Start playing the loaded AVI video + */ + virtual bool play(int startFrame, int endFrame, uint flags, CGameObject *obj); + + /** + * Start playing the loaded AVI video + */ + virtual bool play(int startFrame, int endFrame, int initialFrame, uint flags, CGameObject *obj); + + /** + * Stop the currently playing video + */ + virtual void stop(); + + /** + * Return true if a video is currently playing + */ + virtual bool isPlaying() const { return _decoders[0]->isPlaying(); } + + /** + * Handle any movie events relevent for the frame + */ + virtual bool handleEvents(CMovieEventList &events); + + /** + * Set the video surface the AVI Surface will render on + */ + void setVideoSurface(CVideoSurface *surface); + + /** + * Get the width of the video + */ + uint getWidth() const; + + /** + * Get the height of the video + */ + uint getHeight() const; + + /** + * Set the current frame + */ + void setFrame(int frameNumber); + + /** + * Gets the current frame + */ + int getFrame() const { return _currentFrame; } + + /** + * Add a movie event + */ + bool addEvent(int frameNumber, CGameObject *obj); + + /** + * Set the frame rate + */ + void setFrameRate(double rate); + + /** + * Returns the surface for the secondary video track frame, if present + */ + Graphics::ManagedSurface *getSecondarySurface(); + + /** + * Get a reference to the movie range info list + */ + const CMovieRangeInfoList *getMovieRangeInfo() const { + return &_movieRangeInfo; + } + + /** + * Duplicates the secondary frame, if the movie has a second video track + */ + Graphics::ManagedSurface *duplicateSecondaryFrame() const; + + /** + * Returns true if it's time for the next + */ + bool isNextFrame() const; +}; + +} // End of namespace Titanic + +#endif /* TITANIC_AVI_SURFACE_H */ diff --git a/engines/titanic/support/credit_text.cpp b/engines/titanic/support/credit_text.cpp new file mode 100644 index 0000000000..0e9715aaa6 --- /dev/null +++ b/engines/titanic/support/credit_text.cpp @@ -0,0 +1,153 @@ +/* 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/credit_text.h" +#include "titanic/titanic.h" + +namespace Titanic { + +CCreditText::CCreditText() : _screenManagerP(nullptr), _field14(0), + _ticks(0), _fontHeight(1), _objectP(nullptr), _totalHeight(0), + _field40(0), _field44(0), _field48(0), _field4C(0), _field50(0), + _field54(0), _field58(0), _field5C(0) { +} + +void CCreditText::clear() { + _groups.destroyContents(); + _objectP = nullptr; +} + +void CCreditText::load(CGameObject *obj, CScreenManager *screenManager, + const Rect &rect, int v) { + _objectP = obj; + _screenManagerP = screenManager; + _field14 = v; + + setup(); + + _ticks = g_vm->_events->getTicksCount(); + _field40 = 0; + _field44 = 0xFF; + _field48 = 0xFF; + _field4C = 0xFF; + _field50 = 0; + _field54 = 0; + _field58 = 0; + _field5C = 0; +} + +void CCreditText::setup() { + Common::SeekableReadStream *stream = g_vm->_filesManager->getResource( + CString::format("TEXT/155")); + int oldFontNumber = _screenManagerP->setFontNumber(3); + _fontHeight = _screenManagerP->getFontHeight(); + + while (stream->pos() < stream->size()) { + // Read in the line + CString srcLine = readLine(stream); + + // Create a new group and line within it + CCreditLineGroup *group = new CCreditLineGroup(); + CCreditLine *line = new CCreditLine(srcLine, + _screenManagerP->stringWidth(srcLine)); + group->_lines.push_back(line); + + // Loop to add more lines to the group + bool hasDots = false; + while (stream->pos() < stream->size()) { + srcLine = readLine(stream); + if (srcLine.empty()) + break; + + line = new CCreditLine(srcLine, + _screenManagerP->stringWidth(srcLine)); + group->_lines.push_back(line); + + if (srcLine.contains("....")) + hasDots = true; + } + + _groups.push_back(group); + } + + _groupIt = _groups.begin(); + _lineIt = (*_groupIt)->_lines.begin(); + _totalHeight = _objectP->getBounds().height() + _fontHeight * 2; +} + +CString CCreditText::readLine(Common::SeekableReadStream *stream) { + CString line; + char c = stream->readByte(); + + while (c != '\r' && c != '\n' && c != '\0') { + line += c; + + if (stream->pos() == stream->size()) + break; + c = stream->readByte(); + } + + if (c == '\r') { + // Read following '\n' + stream->readByte(); + } + + return line; +} + +void CCreditText::handleDots(CCreditLineGroup *group) { + uint maxWidth = 0; + CCreditLines::iterator second = group->_lines.begin(); + ++second; + + // 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 + for (CCreditLines::iterator i = second; i != group->_lines.end(); ++i) { + CCreditLine *line = *i; + if (line->_lineWidth >= maxWidth) + continue; + + int dotsCount = (maxWidth + charWidth / 2 - line->_lineWidth) / charWidth; + int dotIndex = line->_line.indexOf("...."); + + if (dotIndex > 0) { + CString leftStr = line->_line.left(dotIndex); + CString dotsStr('.', dotsCount); + CString rightStr = line->_line.right(dotIndex); + + line->_line = CString::format("%s%s%s", leftStr.c_str(), + dotsStr.c_str(), rightStr.c_str()); + line->_lineWidth = maxWidth; + } + } +} + +bool CCreditText::draw() { + return false; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/credit_text.h b/engines/titanic/support/credit_text.h new file mode 100644 index 0000000000..ec8fc22cda --- /dev/null +++ b/engines/titanic/support/credit_text.h @@ -0,0 +1,106 @@ +/* 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_CREDIT_TEXT_H +#define TITANIC_CREDIT_TEXT_H + +#include "titanic/core/list.h" + +namespace Titanic { + +class CGameObject; +class CScreenManager; + +class CCreditLine : public ListItem { +public: + CString _line; + uint _lineWidth; +public: + CCreditLine() : _lineWidth(0) {} + CCreditLine(const CString &line, uint lineWidth) : _line(line), _lineWidth(lineWidth) {} +}; +typedef List<CCreditLine> CCreditLines; + +class CCreditLineGroup : public ListItem { +public: + CCreditLines _lines; +}; +typedef List<CCreditLineGroup> CCreditLineGroups; + +class CCreditText { +private: + /** + * Sets up needed data + */ + void setup(); + + /** + * Read in a text line from the passed stream + */ + CString readLine(Common::SeekableReadStream *stream); + + /** + * Handles a group where the .... sequence was encountered + */ + void handleDots(CCreditLineGroup *group); +public: + CScreenManager *_screenManagerP; + Rect _rect; + int _field14; + CCreditLineGroups _groups; + uint _ticks; + uint _fontHeight; + CGameObject *_objectP; + CCreditLineGroups::iterator _groupIt; + CCreditLines::iterator _lineIt; + uint _totalHeight; + int _field40; + int _field44; + int _field48; + int _field4C; + int _field50; + int _field54; + int _field58; + int _field5C; +public: + CCreditText(); + + /** + * Clears the object + */ + void clear(); + + /** + * Sets the game object this override is associated with + */ + void load(CGameObject *obj, CScreenManager *screenManager, + const Rect &rect, int v = 0); + + /** + * Draw the item + */ + bool draw(); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_CREDIT_TEXT_H */ diff --git a/engines/titanic/support/direct_draw.cpp b/engines/titanic/support/direct_draw.cpp new file mode 100644 index 0000000000..5ddb25bec9 --- /dev/null +++ b/engines/titanic/support/direct_draw.cpp @@ -0,0 +1,109 @@ +/* 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 "common/debug.h" +#include "engines/util.h" +#include "graphics/pixelformat.h" +#include "titanic/titanic.h" +#include "titanic/support/direct_draw.h" + +namespace Titanic { + +DirectDraw::DirectDraw(TitanicEngine *vm) : _vm(vm), + _windowed(false), _fieldC(0), _width(0), _height(0), + _bpp(0), _numBackSurfaces(0), _field24(0) { +} + +void DirectDraw::setDisplayMode(int width, int height, int bpp, int refreshRate) { + debugC(ERROR_BASIC, kDebugGraphics, "DirectDraw::SetDisplayMode (%d x %d), %d bpp", + width, height, bpp); + assert(bpp == 16); + + Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + initGraphics(width, height, true, &pixelFormat); +} + +void DirectDraw::diagnostics() { + debugC(ERROR_BASIC, kDebugGraphics, "Running DirectDraw Diagnostic..."); +} + +DirectDrawSurface *DirectDraw::createSurfaceFromDesc(const DDSurfaceDesc &desc) { + DirectDrawSurface *surface = new DirectDrawSurface(); + surface->create(desc._w, desc._h); + + return surface; +} + +/*------------------------------------------------------------------------*/ + +DirectDrawManager::DirectDrawManager(TitanicEngine *vm, bool windowed) : _directDraw(vm) { + _mainSurface = nullptr; + _backSurfaces[0] = _backSurfaces[1] = nullptr; + _directDraw._windowed = windowed; +} + +void DirectDrawManager::initVideo(int width, int height, int bpp, int numBackSurfaces) { + debugC(ERROR_BASIC, kDebugGraphics, "Initialising video surfaces"); + _directDraw._width = width; + _directDraw._numBackSurfaces = numBackSurfaces; + _directDraw._height = height; + _directDraw._bpp = bpp; + + if (_directDraw._windowed) { + initWindowed(); + } else { + initFullScreen(); + } +} + +void DirectDrawManager::setResolution() { + // TODO +} + +void DirectDrawManager::proc2() { + +} + +void DirectDrawManager::proc3() { + +} + +void DirectDrawManager::initFullScreen() { + debugC(ERROR_BASIC, kDebugGraphics, "Creating surfaces"); + _directDraw.setDisplayMode(_directDraw._width, _directDraw._height, + _directDraw._bpp, 0); + + _mainSurface = new DirectDrawSurface(); + _mainSurface->create(g_vm->_screen); + _backSurfaces[0] = new DirectDrawSurface(); + _backSurfaces[0]->create(_directDraw._width, _directDraw._height); +} + +DirectDrawSurface *DirectDrawManager::createSurface(int w, int h, int surfaceNum) { + if (surfaceNum) + return nullptr; + + assert(_mainSurface); + return _directDraw.createSurfaceFromDesc(DDSurfaceDesc(w, h)); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/direct_draw.h b/engines/titanic/support/direct_draw.h new file mode 100644 index 0000000000..85c344c600 --- /dev/null +++ b/engines/titanic/support/direct_draw.h @@ -0,0 +1,105 @@ +/* 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_DIRECT_DRAW_H +#define TITANIC_DIRECT_DRAW_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "titanic/support/direct_draw_surface.h" + +namespace Titanic { + +class TitanicEngine; + +class DirectDraw { +private: + TitanicEngine *_vm; +public: + bool _windowed; + int _fieldC; + int _width; + int _height; + int _bpp; + int _numBackSurfaces; + int _field24; +public: + DirectDraw(TitanicEngine *vm); + + /** + * Sets a new display mode + */ + void setDisplayMode(int width, int height, int bpp, int refreshRate); + + /** + * Logs diagnostic information + */ + void diagnostics(); + + /** + * Create a surface from a passed description record + */ + DirectDrawSurface *createSurfaceFromDesc(const DDSurfaceDesc &desc); +}; + +class DirectDrawManager { +public: + DirectDraw _directDraw; + DirectDrawSurface *_mainSurface; + DirectDrawSurface *_backSurfaces[2]; +public: + DirectDrawManager(TitanicEngine *vm, bool windowed); + + /** + * Initializes video surfaces + * @param width Screen width + * @param height Screen height + * @param bpp Bits per pixel + * @param numBackSurfaces Number of back surfaces + */ + void initVideo(int width, int height, int bpp, int numBackSurfaces); + + void setResolution(); + + void proc2(); + + void proc3(); + + /** + * Initializes the surfaces in windowed mode + */ + void initWindowed() { initFullScreen(); } + + /** + * Initializes the surfaces for the screen + */ + void initFullScreen(); + + /** + * Create a surface + */ + DirectDrawSurface *createSurface(int w, int h, int surfaceNum); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_DIRECT_DRAW_H */ diff --git a/engines/titanic/support/direct_draw_surface.cpp b/engines/titanic/support/direct_draw_surface.cpp new file mode 100644 index 0000000000..9ebda15b0e --- /dev/null +++ b/engines/titanic/support/direct_draw_surface.cpp @@ -0,0 +1,100 @@ +/* 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/direct_draw_surface.h" + +namespace Titanic { + +DirectDrawSurface::DirectDrawSurface() : _surface(nullptr), + _disposeAfterUse(DisposeAfterUse::YES) { +} + +DirectDrawSurface::~DirectDrawSurface() { + free(); +} + +void DirectDrawSurface::create(Graphics::ManagedSurface *surface) { + free(); + _surface = surface; + _disposeAfterUse = DisposeAfterUse::NO; +} + +void DirectDrawSurface::create(int w, int h) { + Graphics::PixelFormat pixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + _surface = new Graphics::ManagedSurface(w, h, pixelFormat); + _disposeAfterUse = DisposeAfterUse::YES; +} + +void DirectDrawSurface::free() { + if (_disposeAfterUse == DisposeAfterUse::YES) + delete _surface; + _surface = nullptr; + _disposeAfterUse = DisposeAfterUse::NO; +} + +Graphics::ManagedSurface *DirectDrawSurface::lock(const Rect *bounds, int flags) { + assert(!_surface->empty()); + return _surface; +} + +void DirectDrawSurface::unlock() { + assert(_surface->w != 0 && _surface->h != 0); +} + +void DirectDrawSurface::fill(const Rect *bounds, uint32 color) { + Rect tempBounds; + + assert(_surface); + if (bounds) { + // Bounds are provided, clip them to the bounds of this surface + tempBounds = *bounds; + tempBounds.clip(Rect(0, 0, _surface->w, _surface->h)); + } else { + // No bounds provided, so use the entire surface + tempBounds = Rect(0, 0, _surface->w, _surface->h); + } + + // Fill the area + _surface->fillRect(tempBounds, color); +} + +void DirectDrawSurface::fillRect(Rect *rect, byte r, byte g, byte b) { + uint color = _surface->format.RGBToColor(r, g, b); + Rect tempRect = rect ? *rect : Rect(0, 0, getWidth(), getHeight()); + + _surface->fillRect(tempRect, color); +} + +void DirectDrawSurface::blit(const Rect &destRect, DirectDrawSurface *srcSurface, Rect &srcRect) { + assert(srcSurface); + if (!destRect.isEmpty()) + _surface->transBlitFrom(*srcSurface->_surface, srcRect, destRect, (uint)-1); +} + +void DirectDrawSurface::blit(const Point &destPos, DirectDrawSurface *srcSurface, Rect *bounds) { + if (bounds) + _surface->blitFrom(*srcSurface->_surface, *bounds, destPos); + else + _surface->blitFrom(*srcSurface->_surface, destPos); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/direct_draw_surface.h b/engines/titanic/support/direct_draw_surface.h new file mode 100644 index 0000000000..af19e369d2 --- /dev/null +++ b/engines/titanic/support/direct_draw_surface.h @@ -0,0 +1,126 @@ +/* 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_DIRECT_DRAW_SURFACE_H +#define TITANIC_DIRECT_DRAW_SURFACE_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "graphics/managed_surface.h" +#include "titanic/support/rect.h" + +namespace Titanic { + +class TitanicEngine; + +struct DDSurfaceDesc { + int _w; + int _h; + int _flags; + int _caps; + + DDSurfaceDesc(int w, int h) : _w(w), _h(h), _flags(0x1006), _caps(64) {} +}; + +class DirectDrawSurface { +private: + Graphics::ManagedSurface *_surface; + DisposeAfterUse::Flag _disposeAfterUse; +public: + DirectDrawSurface(); + ~DirectDrawSurface(); + + /** + * Create a surface + */ + void create(int w, int h); + + /** + * Create a surface based on a passed surface + */ + void create(Graphics::ManagedSurface *surface); + + /** + * Frees the surface + */ + void free(); + + /** + * Return the size of the surface in ytes + */ + int getSize() const { return _surface->pitch * _surface->h; } + + /** + * Return the surface width + */ + int getWidth() const { return _surface->w; } + + /** + * Return the surface width + */ + int getHeight() const { return _surface->h; } + + /** + * Return the surface pitch + */ + int getPitch() const { return _surface->pitch; } + + /** + * Return the surface's format + */ + const Graphics::PixelFormat &getFormat() { return _surface->format; } + + /** + * Lock the surface for access + */ + Graphics::ManagedSurface *lock(const Rect *bounds, int flags); + + /** + * Unlocks the surface at the end of direct accesses + */ + void unlock(); + + /** + * Fills an area of the surfae with the specified color. If no bounds are passed, + * then the entire surface is filled + */ + void fill(const Rect *bounds, uint32 color); + + /** + * Fill an area with a specific color + */ + void fillRect(Rect *rect, byte r, byte g, byte b); + + /** + * Copy data from a source surfcae into this one + */ + void blit(const Rect &destRect, DirectDrawSurface *srcSurface, Rect &srcRect); + + /** + * Copy data from a source surfcae into this one + */ + void blit(const Point &destPos, DirectDrawSurface *srcSurface, Rect *bounds); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_DIRECT_DRAW_SURFACE_H */ diff --git a/engines/titanic/support/exe_resources.cpp b/engines/titanic/support/exe_resources.cpp new file mode 100644 index 0000000000..522e92f718 --- /dev/null +++ b/engines/titanic/support/exe_resources.cpp @@ -0,0 +1,37 @@ +/* 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/exe_resources.h" +#include "titanic/titanic.h" + +namespace Titanic { + +CExeResources::CExeResources() : _owner(nullptr), _field4(0), _field8(0), + _fieldC(0), _field10(0), _field14(0), _field18(0) { +} + +void CExeResources::reset(CScriptHandler *owner, int val1, int val2) { + _owner = owner; + _field18 = val2; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/exe_resources.h b/engines/titanic/support/exe_resources.h new file mode 100644 index 0000000000..49e05aa56f --- /dev/null +++ b/engines/titanic/support/exe_resources.h @@ -0,0 +1,51 @@ +/* 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_EXE_RESOURCES_H +#define TITANIC_EXE_RESOURCES_H + +namespace Titanic { + +class CScriptHandler; + +enum FileHandle { HANDLE_STDIN = 0, HANDLE_STDOUT = 1, HANDLE_STDERR = 2 }; + +class CExeResources { +public: + CScriptHandler *_owner; + int _field4; + int _field8; + int _fieldC; + int _field10; + int _field14; + int _field18; +public: + CExeResources(); + + void reset(CScriptHandler *owner, int val1, int val2); + + bool is18Equals(int val) const { return _field18 == val; } +}; + +} // End of namespace Titanic + +#endif /* TITANIC_EXE_RESOURCES_H */ diff --git a/engines/titanic/support/files_manager.cpp b/engines/titanic/support/files_manager.cpp new file mode 100644 index 0000000000..04928b96d6 --- /dev/null +++ b/engines/titanic/support/files_manager.cpp @@ -0,0 +1,132 @@ +/* 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 "common/file.h" +#include "titanic/support/files_manager.h" +#include "titanic/game_manager.h" + +namespace Titanic { + +CFilesManager::CFilesManager() : _gameManager(nullptr), _assetsPath("Assets"), + _field0(0), _drive(-1), _field18(0), _field1C(0), _field3C(0) { + loadResourceIndex(); +} + +CFilesManager::~CFilesManager() { + _datFile.close(); +} + +void CFilesManager::loadResourceIndex() { + if (!_datFile.open("titanic.dat")) + error("Could not find titanic.dat data file"); + + uint headerId = _datFile.readUint32BE(); + uint version = _datFile.readUint16LE(); + if (headerId != MKTAG('S', 'V', 'T', 'N') || version < 1) + error("Invalid data file"); + + // Read in entries + uint offset, size; + char c; + Common::String resourceName; + for (;;) { + offset = _datFile.readUint32LE(); + size = _datFile.readUint32LE(); + if (size == 0) + break; + + Common::String resName; + while ((c = _datFile.readByte()) != '\0') + resName += c; + + _resources[resName] = ResourceEntry(offset, size); + } +} + +bool CFilesManager::fileExists(const CString &name) { + Common::File f; + return f.exists(name); +} + +bool CFilesManager::scanForFile(const CString &name) { + if (name.empty()) + return false; + + CString filename = name; + filename.toLowercase(); + + if (filename[0] == 'y' || filename[0] == 'z') + return true; + else if (filename[0] < 'a' || filename[0] > 'c') + return false; + + CString fname = filename; + int idx = fname.indexOf('#'); + if (idx >= 0) { + fname = fname.left(idx); + fname += ".st"; + } + + // Return true if the file exists + if (fileExists(fname)) + return true; + + // Couldn't find file. Start by calling the game manager's viewChange + // method, which handles all active scene objects freeing their resources + if (_gameManager) + _gameManager->viewChange(); + + return false; +} + +void CFilesManager::loadDrive() { + assert(_drive == -1); + resetView(); +} + +void CFilesManager::debug(CScreenManager *screenManager) { + warning("TODO: CFilesManager::debug"); +} + +void CFilesManager::resetView() { + if (_gameManager) { + _gameManager->_gameState.setMode(GSMODE_INTERACTIVE); + _gameManager->initBounds(); + } +} + +void CFilesManager::fn4(const CString &name) { + warning("TODO: CFilesManager::fn4"); +} + +void CFilesManager::preload(const CString &name) { + // We don't currently do any preloading of resources +} + +Common::SeekableReadStream *CFilesManager::getResource(const CString &str) { + ResourceEntry resEntry = _resources[str]; + _datFile.seek(resEntry._offset); + + return _datFile.readStream(resEntry._size); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/files_manager.h b/engines/titanic/support/files_manager.h new file mode 100644 index 0000000000..ec0c7fc008 --- /dev/null +++ b/engines/titanic/support/files_manager.h @@ -0,0 +1,109 @@ +/* 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_FILES_MANAGER_H +#define TITANIC_FILES_MANAGER_H + +#include "common/hashmap.h" +#include "titanic/core/list.h" +#include "titanic/support/screen_manager.h" + +namespace Titanic { + +class CGameManager; + +class CFilesManagerList : public List<ListItem> { +}; + +class CFilesManager { + struct ResourceEntry { + uint _offset; + uint _size; + + ResourceEntry() : _offset(0), _size(0) {} + ResourceEntry(uint offset, uint size) : _offset(offset), _size(size) {} + }; + typedef Common::HashMap<Common::String, ResourceEntry> ResourceHash; +private: + CGameManager *_gameManager; + Common::File _datFile; + ResourceHash _resources; + CFilesManagerList _list; + CString _string1; + CString _string2; + int _field0; + int _drive; + int _field18; + int _field1C; + int _field3C; + const CString _assetsPath; +private: + void loadResourceIndex(); +public: + CFilesManager(); + ~CFilesManager(); + + /** + * Sets the game manager + */ + void setGameManager(CGameManager *gameManager) { + _gameManager = gameManager; + } + + /** + * Returns true if a file of the given name exists + */ + static bool fileExists(const CString &name); + + /** + * Scans for a file with a matching name + */ + bool scanForFile(const CString &name); + + /** + * Handles displaying a load drive view if necessary + */ + void loadDrive(); + + void debug(CScreenManager *screenManager); + + /** + * Resets the view being displayed + */ + void resetView(); + + void fn4(const CString &name); + + /** + * Preloads and caches a file for access shortly + */ + void preload(const CString &name); + + /** + * Get a resource from the executable + */ + Common::SeekableReadStream *getResource(const CString &str); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_FILES_MANAGER_H */ diff --git a/engines/titanic/support/font.cpp b/engines/titanic/support/font.cpp new file mode 100644 index 0000000000..07e4c28991 --- /dev/null +++ b/engines/titanic/support/font.cpp @@ -0,0 +1,279 @@ +/* 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 "common/textconsole.h" +#include "titanic/support/font.h" +#include "titanic/support/files_manager.h" +#include "titanic/titanic.h" + +namespace Titanic { + +STFont::STFont() { + _dataPtr = nullptr; + _dataSize = 0; + _fontHeight = 0; + _dataWidth = 0; + _fontR = _fontG = _fontB = 0; +} + +STFont::~STFont() { + delete[] _dataPtr; +} + +void STFont::load(int fontNumber) { + assert(!_dataPtr); + Common::SeekableReadStream *stream = g_vm->_filesManager->getResource( + CString::format("STFONT/%d", fontNumber)); + if (!stream) + error("Could not locate the specified font"); + + _fontHeight = stream->readUint32LE(); + _dataWidth = stream->readUint32LE(); + for (uint idx = 0; idx < 256; ++idx) + _chars[idx]._width = stream->readUint32LE(); + for (uint idx = 0; idx < 256; ++idx) + _chars[idx]._offset = stream->readUint32LE(); + + _dataSize = stream->readUint32LE(); + _dataPtr = new byte[_dataSize]; + stream->read(_dataPtr, _dataSize); + + delete stream; +} + +void STFont::setColor(byte r, byte g, byte b) { + _fontR = r; + _fontG = g; + _fontB = b; +} + +uint16 STFont::getColor() const { + return g_system->getScreenFormat().RGBToColor(_fontR, _fontG, _fontB); +} + +int STFont::getTextBounds(const CString &str, int maxWidth, Point *sizeOut) const { + Point textSize; + + // Reset output dimensions if provided + if (sizeOut) + *sizeOut = Point(0, 0); + + 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) { + if (*strP == TEXTCMD_NPC) { + strP += 3; + } else if (*strP == TEXTCMD_SET_COLOR) { + strP += 4; + } else { + if (*strP == ' ') { + // Check fo rline wrapping + checkLineWrap(textSize, maxWidth, strP); + } + + extendBounds(textSize, *strP, maxWidth); + } + } + } + + if (sizeOut) + *sizeOut = textSize; + + return textSize.y + _fontHeight; +} + +int STFont::stringWidth(const CString &text) const { + if (text.empty()) + return 0; + + const char *srcP = text.c_str(); + int total = 0; + char c; + while ((c = *srcP++)) { + if (c == 26) { + // Skip over command parameter bytes + srcP += 3; + } else if (c == TEXTCMD_SET_COLOR) { + // Skip over command parameter bytes + srcP += 4; + } else if (c != '\n') { + total += _chars[(byte)c]._width; + } + } + + return total; +} + +int STFont::writeString(CVideoSurface *surface, const Rect &rect1, const Rect &destRect, + int yOffset, const CString &str, CTextCursor *textCursor) { + if (!_fontHeight || !_dataPtr) + return -1; + + Point textSize(0, -yOffset); + Rect destBounds = destRect; + destBounds.constrain(rect1); + if (destBounds.isEmpty()) + return -1; + + const char *endP = nullptr; + const char *strEndP = str.c_str() + str.size() - 1; + for (const char *srcP = str.c_str(); *srcP; ++srcP) { + if (*srcP == TEXTCMD_NPC) { + srcP += 3; + } else if (*srcP == TEXTCMD_SET_COLOR) { + // Change the color used for characters + byte r = *++srcP; + byte g = *++srcP; + byte b = *++srcP; + ++srcP; + setColor(r, g, b); + } else { + if (*srcP == ' ') { + // Check fo rline wrapping + checkLineWrap(textSize, rect1.width(), srcP); + if (!*srcP) + return endP - str.c_str(); + } + + if (*srcP != '\n') { + WriteCharacterResult result = writeChar(surface, *srcP, textSize, rect1, &destBounds); + if (result == WC_OUTSIDE_BOTTOM) + return endP - str.c_str(); + else if (result == WC_IN_BOUNDS) + endP = srcP; + } + + if (srcP < strEndP) + extendBounds(textSize, *srcP, rect1.width()); + } + } + + if (textCursor && textCursor->getMode() == -2) { + Point cursorPos(rect1.left + textSize.x, rect1.top + textSize.y); + textCursor->setPos(cursorPos); + } + + return endP ? endP - str.c_str() : 0; +} + +WriteCharacterResult STFont::writeChar(CVideoSurface *surface, unsigned char c, const Point &pt, + const Rect &destRect, const Rect *srcRect) { + if (c == 233) + c = '$'; + + Rect tempRect; + tempRect.left = _chars[c]._offset; + tempRect.right = _chars[c]._offset + _chars[c]._width; + tempRect.top = 0; + tempRect.bottom = _fontHeight; + Point destPos(pt.x + destRect.left, pt.y + destRect.top); + + if (srcRect->isEmpty()) + srcRect = &destRect; + if (destPos.y > srcRect->bottom) + return WC_OUTSIDE_BOTTOM; + + if ((destPos.y + tempRect.height()) > srcRect->bottom) { + tempRect.bottom += tempRect.top - destPos.y; + } + + if (destPos.y < srcRect->top) { + if ((tempRect.height() + destPos.y) < srcRect->top) + return WC_OUTSIDE_TOP; + + tempRect.top += srcRect->top - destPos.y; + destPos.y = srcRect->top; + } + + if (destPos.x < srcRect->left) { + if ((tempRect.width() + destPos.x) < srcRect->left) + return WC_OUTSIDE_LEFT; + + tempRect.left += srcRect->left - destPos.x; + destPos.x = srcRect->left; + } else { + if ((tempRect.width() + destPos.x) > srcRect->right) { + if (destPos.x > srcRect->right) + return WC_OUTSIDE_RIGHT; + + tempRect.right += srcRect->left - destPos.x; + } + } + + copyRect(surface, destPos, tempRect); + return WC_IN_BOUNDS; +} + +void STFont::copyRect(CVideoSurface *surface, const Point &pt, Rect &rect) { + if (surface->lock()) { + uint16 *lineP = surface->getBasePtr(pt.x, pt.y); + uint16 color = getColor(); + + 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); + } + } + + surface->unlock(); + } +} + +void STFont::extendBounds(Point &textSize, byte c, int maxWidth) const { + textSize.x += _chars[c]._width; + + if (c == '\n' || textSize.x > maxWidth) { + textSize.x = 0; + textSize.y += _fontHeight; + } +} + +void STFont::checkLineWrap(Point &textSize, int maxWidth, const char *&str) const { + bool flag = false; + int totalWidth = 0; + for (const char *srcPtr = str; *srcPtr && *srcPtr != ' '; ++srcPtr) { + if (*srcPtr == ' ' && flag) + break; + + if (*srcPtr == TEXTCMD_NPC) + srcPtr += 3; + else if (*srcPtr == TEXTCMD_SET_COLOR) + srcPtr += 4; + else + totalWidth += _chars[(byte)*srcPtr]._width; + } + + if ((textSize.x + totalWidth) >= maxWidth && totalWidth < maxWidth) { + // Word wrap + textSize.x = 0; + textSize.y += _fontHeight; + ++str; + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/font.h b/engines/titanic/support/font.h new file mode 100644 index 0000000000..591fb4661c --- /dev/null +++ b/engines/titanic/support/font.h @@ -0,0 +1,123 @@ +/* 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_FONT_H +#define TITANIC_FONT_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "titanic/support/rect.h" +#include "titanic/support/string.h" +#include "titanic/support/text_cursor.h" + +namespace Titanic { + +enum TextCommand { TEXTCMD_NPC = 26, TEXTCMD_SET_COLOR = 27 }; + +enum WriteCharacterResult { + WC_IN_BOUNDS = 0, WC_OUTSIDE_TOP = -1, WC_OUTSIDE_BOTTOM = -2, + WC_OUTSIDE_LEFT = -3, WC_OUTSIDE_RIGHT = -4 +}; + +class CVideoSurface; + +class STFont { + struct CharEntry { + uint _width; + uint _offset; + }; +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, + Rect &srcRect); + + /** + * Write a character + */ + WriteCharacterResult writeChar(CVideoSurface *surface, unsigned char c, + const Common::Point &pt, const Rect &destRect, const Rect *srcRect); + + /** + * Extends a passed text area by the space required for + * the given character + */ + void extendBounds(Point &textSize, byte c, int maxWidth) const; + + /** + * Called at spacing between words, checks for line wrapping + */ + void checkLineWrap(Point &textSize, int maxWidth, const char *&str) const; +public: + byte *_dataPtr; + size_t _dataSize; + int _fontHeight; + uint _dataWidth; + CharEntry _chars[256]; + byte _fontR, _fontG, _fontB; +public: + STFont(); + ~STFont(); + + /** + * Load a specified font + */ + void load(int fontNumber); + + /** + * Return the width in pixels of the specified text + */ + int stringWidth(const CString &text) const; + + /** + * Write a string to the specified surface + * @returns The index of the last character that was visible + * with the drawing area + */ + int writeString(CVideoSurface *surface, const Rect &rect1, const Rect &destRect, + int yOffset, const CString &str, CTextCursor *textCursor); + + /** + * Get the text area a string will fit into + * @param str String + * @param maxWidth Maximum width in pixels + * @param sizeOut Optional pointer to output size (width, height) + * @returns Required height + */ + int getTextBounds(const CString &str, int maxWidth, Point *sizeOut) const; + + /** + * Sets the font color + */ + void setColor(byte r, byte g, byte b); + + /** + * Gets the font color + */ + uint16 getColor() const; +}; + +} // End of namespace Titanic + +#endif /* TITANIC_FONT_H */ diff --git a/engines/titanic/support/image.cpp b/engines/titanic/support/image.cpp new file mode 100644 index 0000000000..1e936b6940 --- /dev/null +++ b/engines/titanic/support/image.cpp @@ -0,0 +1,56 @@ +/* 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/image.h" +#include "titanic/titanic.h" +#include "image/bmp.h" + +namespace Titanic { + +void Image::load(const CString &resName) { + Common::SeekableReadStream *stream = g_vm->_filesManager->getResource(resName); + loadBitmap(*stream); + delete stream; +} + +void Image::loadBitmap(Common::SeekableReadStream &s) { + ::Image::BitmapDecoder decoder; + decoder.loadStream(s); + const Graphics::Surface *src = decoder.getSurface(); + Graphics::PixelFormat scrFormat = g_system->getScreenFormat(); + + if (src->format == scrFormat) { + create(src->w, src->h, scrFormat); + blitFrom(*src); + } else { + // Convert the loaded surface to the screen surface format + const byte *palette = decoder.getPalette(); + Graphics::Surface *surface = src->convertTo(scrFormat, palette); + create(surface->w, surface->h, scrFormat); + blitFrom(*surface); + + surface->free(); + delete surface; + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/image.h b/engines/titanic/support/image.h new file mode 100644 index 0000000000..9876f15c40 --- /dev/null +++ b/engines/titanic/support/image.h @@ -0,0 +1,43 @@ +/* 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_IMAGE_H +#define TITANIC_IMAGE_H + +#include "common/stream.h" +#include "graphics/managed_surface.h" +#include "titanic/support/string.h" + +namespace Titanic { + +class Image : public Graphics::ManagedSurface { +private: + void loadBitmap(Common::SeekableReadStream &s); +public: + virtual ~Image() {} + + void load(const CString &resName); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_IMAGE_H */ diff --git a/engines/titanic/support/image_decoders.cpp b/engines/titanic/support/image_decoders.cpp new file mode 100644 index 0000000000..495d1d0982 --- /dev/null +++ b/engines/titanic/support/image_decoders.cpp @@ -0,0 +1,81 @@ +/* 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/image_decoders.h" + +namespace Titanic { + +void CJPEGDecode::decode(OSVideoSurface &surface, const CString &name) { + // Open up the resource + StdCWadFile file; + file.open(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 + || surface.getHeight() != srcSurf->h) + surface.recreate(srcSurf->w, srcSurf->h); + + // Convert the decoded surface to the correct pixel format, and then copy it over + surface.lock(); + Graphics::Surface *convertedSurface = srcSurf->convertTo(surface._rawSurface->format); + + Common::copy((byte *)convertedSurface->getPixels(), (byte *)convertedSurface->getPixels() + + surface.getPitch() * surface.getHeight(), (byte *)surface._rawSurface->getPixels()); + + convertedSurface->free(); + delete convertedSurface; + surface.unlock(); +} + +/*------------------------------------------------------------------------*/ + +void CTargaDecode::decode(OSVideoSurface &surface, const CString &name) { + // Open up the resource + StdCWadFile file; + file.open(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 + || surface.getHeight() != srcSurf->h) + surface.recreate(srcSurf->w, srcSurf->h); + + // Convert the decoded surface to the correct pixel format, and then copy it over + surface.lock(); + Graphics::Surface *convertedSurface = srcSurf->convertTo(surface._rawSurface->format); + + Common::copy((byte *)convertedSurface->getPixels(), (byte *)convertedSurface->getPixels() + + surface.getPitch() * surface.getHeight(), (byte *)surface._rawSurface->getPixels()); + + convertedSurface->free(); + delete convertedSurface; + surface.unlock(); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/image_decoders.h b/engines/titanic/support/image_decoders.h new file mode 100644 index 0000000000..b824b786a7 --- /dev/null +++ b/engines/titanic/support/image_decoders.h @@ -0,0 +1,52 @@ +/* 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_IMAGE_DECODERS_H +#define TITANIC_IMAGE_DECODERS_H + +#include "image/jpeg.h" +#include "image/tga.h" +#include "titanic/support/string.h" +#include "titanic/support/simple_file.h" +#include "titanic/support/video_surface.h" + +namespace Titanic { + +class CJPEGDecode : public Image::JPEGDecoder { +public: + /** + * Decode the image file onto the passed surface + */ + void decode(OSVideoSurface &surface, const CString &name); +}; + +class CTargaDecode : public Image::TGADecoder { +public: + /** + * Decode the image file onto the passed surface + */ + void decode(OSVideoSurface &surface, const CString &name); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_IMAGE_DECODERS_H */ diff --git a/engines/titanic/support/mouse_cursor.cpp b/engines/titanic/support/mouse_cursor.cpp new file mode 100644 index 0000000000..d6a42823f5 --- /dev/null +++ b/engines/titanic/support/mouse_cursor.cpp @@ -0,0 +1,135 @@ +/* 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 "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/titanic.h" +#include "titanic/support/video_surface.h" +#include "titanic/core/resource_key.h" + +namespace Titanic { + +static const int CURSOR_DATA[NUM_CURSORS][4] = { + { 1, 136, 19, 18 }, + { 2, 139, 1, 1 }, + { 3, 140, 32, 1 }, + { 4, 137, 13, 0 }, + { 5, 145, 13, 0 }, + { 6, 144, 13, 22 }, + { 7, 137, 14, 0 }, + { 8, 148, 22, 40 }, + { 9, 136, 19, 18 }, + { 10, 143, 11, 11 }, + { 11, 146, 11, 11 }, + { 12, 136, 19, 18 }, + { 13, 136, 19, 25 }, + { 14, 136, 13, 22 }, + { 15, 138, 20, 28 } +}; + +CMouseCursor::CursorEntry::~CursorEntry() { + delete _videoSurface; + delete _frameSurface; +} + +CMouseCursor::CMouseCursor(CScreenManager *screenManager) : + _screenManager(screenManager), _cursorId(CURSOR_HOURGLASS), + _setCursorCount(0), _fieldE4(0), _fieldE8(0) { + loadCursorImages(); + setCursor(CURSOR_ARROW); +} + +CMouseCursor::~CMouseCursor() { +} + +void CMouseCursor::loadCursorImages() { + const CResourceKey key("ycursors.avi"); + g_vm->_filesManager->fn4(key.getString()); + + // Iterate through getting each cursor + for (int idx = 0; idx < NUM_CURSORS; ++idx) { + assert(CURSOR_DATA[idx][0] == (idx + 1)); + _cursors[idx]._centroid = Common::Point(CURSOR_DATA[idx][2], + CURSOR_DATA[idx][3]); + + // Create the surface + CVideoSurface *surface = _screenManager->createSurface(64, 64); + _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->setMovieFrameSurface(frameSurface); + } +} + +void CMouseCursor::show() { + CursorMan.showMouse(true); +} + +void CMouseCursor::hide() { + CursorMan.showMouse(false); +} + +void CMouseCursor::setCursor(CursorId cursorId) { + ++_setCursorCount; + + if (cursorId != _cursorId) { + CursorEntry &ce = _cursors[cursorId - 1]; + CVideoSurface &surface = *ce._videoSurface; + surface.lock(); + + CursorMan.replaceCursor(surface.getPixels(), surface.getWidth(), surface.getHeight(), + ce._centroid.x, ce._centroid.y, 0, false, &g_vm->_screen->format); + surface.unlock(); + + _cursorId = cursorId; + } +} + +void CMouseCursor::update() { + // No implementation needed +} + +void CMouseCursor::lockE4() { + _fieldE4 = 0; + CScreenManager::_screenManagerPtr->_inputHandler->incLockCount(); +} + +void CMouseCursor::unlockE4() { + _fieldE4 = 1; + _fieldE8 = 0; + CScreenManager::_screenManagerPtr->_inputHandler->decLockCount(); +} + +void CMouseCursor::saveState(int v1, int v2, int v3) { + // TODO +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/mouse_cursor.h b/engines/titanic/support/mouse_cursor.h new file mode 100644 index 0000000000..7a81ad43fa --- /dev/null +++ b/engines/titanic/support/mouse_cursor.h @@ -0,0 +1,114 @@ +/* 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_MOUSE_CURSOR_H +#define TITANIC_MOUSE_CURSOR_H + +#include "common/scummsys.h" +#include "common/rect.h" +#include "graphics/managed_surface.h" + +namespace Titanic { + +#define NUM_CURSORS 15 + +enum CursorId { + CURSOR_ARROW = 1, + CURSOR_MOVE_LEFT = 2, + CURSOR_MOVE_RIGHT = 3, + CURSOR_MOVE_FORWARD = 4, + CURSOR_MOVE_UP = 5, + CURSOR_MOVE_DOWN1 = 6, + CURSOR_MOVE_FORWARD2 = 7, + CURSOR_HAND = 8, + CURSOR_ACTIVATE = 9, + CURSOR_INVALID = 10, + CURSOR_MAGNIFIER = 11, + CURSOR_IGNORE = 12, + CURSOR_BACKWARDS = 13, + CURSOR_DOWN = 14, + CURSOR_HOURGLASS = 15 +}; + +class CScreenManager; +class CVideoSurface; + +class CMouseCursor { + struct CursorEntry { + CVideoSurface *_videoSurface; + Graphics::ManagedSurface *_frameSurface; + Common::Point _centroid; + + CursorEntry() : _videoSurface(nullptr), _frameSurface(nullptr) {} + ~CursorEntry(); + }; +private: + CScreenManager *_screenManager; + CursorId _cursorId; + CursorEntry _cursors[NUM_CURSORS]; + uint _setCursorCount; + int _fieldE4; + int _fieldE8; + + /** + * Load the images for each cursor + */ + void loadCursorImages(); +public: + CMouseCursor(CScreenManager *screenManager); + ~CMouseCursor(); + + /** + * Make the mouse cursor visible + */ + void show(); + + /** + * Hide the mouse cursor + */ + void hide(); + + /** + * Set the cursor + */ + void setCursor(CursorId cursorId); + + /** + * Updates the mouse cursor + */ + void update(); + + /** + * Returns the number of times the cursor has been set + */ + uint getChangeCount() const { return _setCursorCount; } + + void lockE4(); + void unlockE4(); + + void saveState(int v1, int v2, int v3); +}; + + +} // End of namespace Titanic + +#endif /* TITANIC_MOUSE_CURSOR_H */ diff --git a/engines/titanic/support/movie.cpp b/engines/titanic/support/movie.cpp new file mode 100644 index 0000000000..3c935e83a8 --- /dev/null +++ b/engines/titanic/support/movie.cpp @@ -0,0 +1,218 @@ +/* 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/movie.h" +#include "titanic/support/avi_surface.h" +#include "titanic/sound/sound_manager.h" +#include "titanic/messages/messages.h" +#include "titanic/titanic.h" + +namespace Titanic { + +#define CLIP_WIDTH 600 +#define CLIP_WIDTH_REDUCED (CLIP_WIDTH / 2) +#define CLIP_HEIGHT 340 +#define CLIP_HEIGHT_REDUCED (CLIP_HEIGHT / 2) + +CMovieList *CMovie::_playingMovies; +CVideoSurface *CMovie::_movieSurface; + +CMovie::CMovie() : ListItem(), _handled(false), _hasVideoFrame(false), + _field14(0) { +} + +CMovie::~CMovie() { + removeFromPlayingMovies(); +} + +void CMovie::init() { + _playingMovies = new CMovieList(); + _movieSurface = nullptr; +} + +void CMovie::deinit() { + // Delete each movie in turn + for (CMovieList::iterator i = _playingMovies->begin(); i != _playingMovies->end(); ) { + // We need to increment iterator before deleting movie, + // since the CMovie destructor calls removeFromPlayingMovies + CMovie *movie = *i; + ++i; + delete movie; + } + + delete _playingMovies; + delete _movieSurface; +} + +void CMovie::addToPlayingMovies() { + if (!isActive()) + _playingMovies->push_back(this); +} + +void CMovie::removeFromPlayingMovies() { + _playingMovies->remove(this); +} + +bool CMovie::isActive() const { + return _playingMovies->contains(this); +} + +bool CMovie::hasVideoFrame() { + if (_hasVideoFrame) { + _hasVideoFrame = 0; + return true; + } else { + return false; + } +} + +/*------------------------------------------------------------------------*/ + +OSMovie::OSMovie(const CResourceKey &name, CVideoSurface *surface) : + _aviSurface(name), _videoSurface(surface) { + _field18 = 0; + _field24 = 0; + _field28 = 0; + _field2C = 0; + + surface->resize(_aviSurface.getWidth(), _aviSurface.getHeight()); + _aviSurface.setVideoSurface(surface); +} + +OSMovie::~OSMovie() { +} + +void OSMovie::play(uint flags, CGameObject *obj) { + _aviSurface.play(flags, obj); + + if (_aviSurface.isPlaying()) + movieStarted(); +} + +void OSMovie::play(uint startFrame, uint endFrame, uint flags, CGameObject *obj) { + _aviSurface.play(startFrame, endFrame, flags, obj); + + if (_aviSurface.isPlaying()) + movieStarted(); +} + +void OSMovie::play(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) { + _aviSurface.play(startFrame, endFrame, initialFrame, flags, obj); + + if (_aviSurface.isPlaying()) + movieStarted(); +} + +void OSMovie::playClip(const Point &drawPos, uint startFrame, uint endFrame) { + if (!_movieSurface) + _movieSurface = CScreenManager::_screenManagerPtr->createSurface(600, 340); + + bool widthLess = _videoSurface->getWidth() < 600; + bool heightLess = _videoSurface->getHeight() < 340; + Rect r(drawPos.x, drawPos.y, + drawPos.x + widthLess ? CLIP_WIDTH_REDUCED : CLIP_WIDTH, + drawPos.y + heightLess ? CLIP_HEIGHT_REDUCED : CLIP_HEIGHT + ); + + uint timePerFrame = 1000 / _aviSurface._frameRate; + + for (; endFrame >= startFrame; ++startFrame) { + // Set the frame + _aviSurface.setFrame(startFrame); + + // TODO: See if we need to do anything further here. The original had a bunch + // of calls and using of the _movieSurface; perhaps to allow scaling down + // videos to half-size + if (widthLess || heightLess) + warning("Not properly reducing clip size: %d %d", r.width(), r.height()); + + // Wait for the next frame, unless the user interrupts the clip + if (g_vm->_events->waitForPress(timePerFrame)) + break; + } +} + +void OSMovie::stop() { + _aviSurface.stop(); + removeFromPlayingMovies(); +} + +void OSMovie::addEvent(int frameNumber, CGameObject *obj) { + if (_aviSurface.addEvent(frameNumber, obj)) { + CMovieFrameMsg frameMsg(frameNumber, 0); + frameMsg.execute(obj); + } +} + +void OSMovie::setFrame(uint frameNumber) { + _aviSurface.setFrame(frameNumber); + _videoSurface->setMovieFrameSurface(_aviSurface.getSecondarySurface()); +} + +bool OSMovie::handleEvents(CMovieEventList &events) { + if (!_aviSurface.isPlaying()) + return false; + if (!_aviSurface.isNextFrame()) + return _aviSurface.isPlaying(); + + // Handle updating the frame + while (_aviSurface.isPlaying() && _aviSurface.isNextFrame()) { + _aviSurface.handleEvents(events); + _videoSurface->setMovieFrameSurface(_aviSurface.getSecondarySurface()); + } + + // Flag there's a video frame + _hasVideoFrame = true; + + return _aviSurface.isPlaying(); +} + +const CMovieRangeInfoList *OSMovie::getMovieRangeInfo() const { + return _aviSurface.getMovieRangeInfo(); +} + +void OSMovie::setSoundManager(CSoundManager *soundManager) { + _aviSurface._soundManager = soundManager; +} + +int OSMovie::getFrame() const { + return _aviSurface.getFrame(); +} + +void OSMovie::movieStarted() { + if (_aviSurface._hasAudio) + _aviSurface._soundManager->movieStarted(); + + // Register the movie in the playing list + addToPlayingMovies(); + _hasVideoFrame = true; +} + +void OSMovie::setFrameRate(double rate) { + _aviSurface.setFrameRate(rate); +} + +Graphics::ManagedSurface *OSMovie::duplicateFrame() const { + return _aviSurface.duplicateSecondaryFrame(); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/movie.h b/engines/titanic/support/movie.h new file mode 100644 index 0000000000..2a7d589194 --- /dev/null +++ b/engines/titanic/support/movie.h @@ -0,0 +1,237 @@ +/* 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_MOVIE_H +#define TITANIC_MOVIE_H + +#include "common/list.h" +#include "video/video_decoder.h" +#include "titanic/core/list.h" +#include "titanic/core/resource_key.h" +#include "titanic/support/avi_surface.h" +#include "titanic/support/movie_range_info.h" + +namespace Titanic { + +class CGameObject; +class CMovie; +class CSoundManager; +class CVideoSurface; + +class CMovieList : public List<CMovie> { +public: +}; + +class CMovie : public ListItem { +protected: + /** + * Adds the movie to the list of currently playing movies + */ + void addToPlayingMovies(); +public: + bool _handled; + bool _hasVideoFrame; + int _field14; +public: + static CMovieList *_playingMovies; + static CVideoSurface *_movieSurface; + + /** + * Initializes statics + */ + static void init(); + + /** + * Deinitializes statics + */ + static void deinit(); +public: + CMovie(); + virtual ~CMovie(); + + /** + * Starts playing the movie + */ + virtual void play(uint flags, CGameObject *obj) = 0; + + /** + * Starts playing the movie + */ + virtual void play(uint startFrame, uint endFrame, uint flags, CGameObject *obj) = 0; + + /** + * 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 + */ + virtual void playClip(const Point &drawPos, uint startFrame, uint endFrame) = 0; + + /** + * Stops the movie + */ + virtual void stop() = 0; + + /** + * Add a playback event + */ + virtual void addEvent(int frameNumber, CGameObject *obj) = 0; + + /** + * 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 + */ + virtual const CMovieRangeInfoList *getMovieRangeInfo() const = 0; + + /** + * Set the sound manager reference + */ + virtual void setSoundManager(CSoundManager *soundManager) = 0; + + /** + * Get the current movie frame + */ + virtual int getFrame() const = 0; + + /** + * Set the frame rate for the movie + */ + virtual void setFrameRate(double rate) = 0; + + /** + * Creates a duplicate of the movie's frame + */ + virtual Graphics::ManagedSurface *duplicateFrame() const = 0; + + /** + * Removes the movie from the list of currently playing movies + */ + void removeFromPlayingMovies(); + + /** + * Returns true if the movie is currently active + */ + bool isActive() const; + + /** + * Returns true if there's a video frame + */ + bool hasVideoFrame(); +}; + +class OSMovie : public CMovie { +private: + AVISurface _aviSurface; + CVideoSurface *_videoSurface; + int _field18; + int _field24; + int _field28; + int _field2C; +private: + /** + * Called when a movie is started playing + */ + void movieStarted(); +public: + OSMovie(const CResourceKey &name, CVideoSurface *surface); + virtual ~OSMovie(); + + /** + * 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 + */ + virtual void playClip(const Point &drawPos, uint startFrame, uint endFrame); + + /** + * Stops the movie + */ + virtual void stop(); + + /** + * Add a playback event + */ + virtual void addEvent(int eventId, CGameObject *obj); + + /** + * Set the current frame number + */ + virtual void setFrame(uint frameNumber); + + /** + * Handle any pending movie events + */ + virtual bool handleEvents(CMovieEventList &events); + + /** + * Get the current frame number + */ + virtual int getFrame() const; + + /** + * Return any movie range info associated with the movie + */ + virtual const CMovieRangeInfoList *getMovieRangeInfo() const; + + /** + * Set the sound manager reference + */ + virtual void setSoundManager(CSoundManager *soundManager); + + /** + * Set the frame rate for the movie + */ + virtual void setFrameRate(double rate); + + /** + * Creates a duplicate of the frame info + */ + virtual Graphics::ManagedSurface *duplicateFrame() const; +}; + +} // End of namespace Titanic + +#endif /* TITANIC_MOVIE_H */ diff --git a/engines/titanic/support/movie_clip.cpp b/engines/titanic/support/movie_clip.cpp new file mode 100644 index 0000000000..1f2ef66428 --- /dev/null +++ b/engines/titanic/support/movie_clip.cpp @@ -0,0 +1,100 @@ +/* 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/movie_clip.h" +#include "titanic/core/game_object.h" + +namespace Titanic { + +CMovieClip::CMovieClip(): ListItem(), _startFrame(0), _endFrame(0) { +} + +CMovieClip::CMovieClip(const CString &name, int startFrame, int endFrame): + ListItem(), _name(name), _startFrame(startFrame), _endFrame(endFrame) { +} + +void CMovieClip::save(SimpleFile *file, int indent) { + file->writeNumberLine(2, indent); + file->writeQuotedLine("Clip", indent); + file->writeQuotedLine(_name, indent); + file->writeNumberLine(_startFrame, indent); + file->writeNumberLine(_endFrame, indent); + + ListItem::save(file, indent); +} + +void CMovieClip::load(SimpleFile *file) { + int val = file->readNumber(); + + switch (val) { + case 1: + // This should never be used + assert(0); + break; + + case 2: + file->readString(); + _name = file->readString(); + _startFrame = file->readNumber(); + _endFrame = file->readNumber(); + break; + + default: + break; + } + + ListItem::load(file); +} + +/*------------------------------------------------------------------------*/ + +CMovieClip *CMovieClipList::findByName(const Common::String &name) const { + for (const_iterator i = begin(); i != end(); ++i) { + CMovieClip *clip = *i; + if (clip->_name == name) + return clip; + } + + return nullptr; +} + +bool CMovieClipList::existsByStart(const CString &name, int startFrame) const { + for (const_iterator i = begin(); i != end(); ++i) { + CMovieClip *clip = *i; + if (clip->_startFrame == startFrame && clip->_name == name) + return true; + } + + return false; +} + +bool CMovieClipList::existsByEnd(const CString &name, int endFrame) const { + for (const_iterator i = begin(); i != end(); ++i) { + CMovieClip *clip = *i; + if (clip->_endFrame == endFrame && clip->_name == name) + return true; + } + + return false; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/movie_clip.h b/engines/titanic/support/movie_clip.h new file mode 100644 index 0000000000..513ed4a339 --- /dev/null +++ b/engines/titanic/support/movie_clip.h @@ -0,0 +1,92 @@ +/* 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_MOVIE_CLIP_H +#define TITANIC_MOVIE_CLIP_H + +#include "titanic/core/list.h" + +namespace Titanic { + +enum ClipFlag { + CLIPFLAG_HAS_END_FRAME = 1, + CLIPFLAG_4 = 4, + CLIPFLAG_HAS_START_FRAME = 8, + CLIPFLAG_PLAY = 0x10 +}; + +class CGameObject; + +/** + * Movie clip + */ +class CMovieClip : public ListItem { +private: + Common::List<void *> _items; + CString _string2; + CString _string3; +public: + CString _name; + int _startFrame; + int _endFrame; +public: + CLASSDEF; + CMovieClip(); + CMovieClip(const CString &name, int startFrame, int endFrame); + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); +}; + +/** + * Movie clip list + */ +class CMovieClipList: public List<CMovieClip> { +public: + /** + * Finds and returns a movie clip in the list by name + */ + CMovieClip *findByName(const Common::String &name) const; + + /** + * Returns true if a clip exists in the list with a given name + * and starting frame number + */ + bool existsByStart(const CString &name, int startFrame = 0) const; + + /** + * Returns true if a clip exists in the list with a given name + * and starting frame number + */ + bool existsByEnd(const CString &name, int endFrame = 0) const; +}; + +} // End of namespace Titanic + +#endif /* TITANIC_MOVIE_CLIP_H */ diff --git a/engines/titanic/support/movie_event.cpp b/engines/titanic/support/movie_event.cpp new file mode 100644 index 0000000000..5f8a6da019 --- /dev/null +++ b/engines/titanic/support/movie_event.cpp @@ -0,0 +1,64 @@ +/* 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/movie_event.h" +#include "titanic/core/game_object.h" + +namespace Titanic { + +CMovieEvent::CMovieEvent() : ListItem(), _type(MET_PLAY), _startFrame(0), + _endFrame(0), _initialFrame(0), _gameObject(nullptr) { +} + +CMovieEvent::CMovieEvent(const CMovieEvent *src) { + _type = src->_type; + _startFrame = src->_startFrame; + _endFrame = src->_endFrame; + _initialFrame = src->_initialFrame; + _gameObject = src->_gameObject; +} + +void CMovieEvent::save(SimpleFile *file, int indent) { + file->writeNumberLine(0, indent); + file->writeNumberLine(_startFrame, indent + 1); + file->writeNumberLine(_endFrame, indent + 1); + error("FIXME: Original save/loaded object pointer"); + // file->writeNumberLine(_gameObject, indent + 1); + file->writeNumberLine(_initialFrame, indent + 1); + + ListItem::save(file, indent); +} + +void CMovieEvent::load(SimpleFile *file) { + int val = file->readNumber(); + if (!val) { + _startFrame = file->readNumber(); + _endFrame = file->readNumber(); + file->readNumber(); + error("FIXME: Original save/loaded object pointer"); + _initialFrame = file->readNumber(); + } + + ListItem::load(file); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/movie_event.h b/engines/titanic/support/movie_event.h new file mode 100644 index 0000000000..af93c76a31 --- /dev/null +++ b/engines/titanic/support/movie_event.h @@ -0,0 +1,66 @@ +/* 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_MOVIE_EVENT_H +#define TITANIC_MOVIE_EVENT_H + +#include "titanic/core/list.h" + +namespace Titanic { + +enum MovieEventType { MET_PLAY = 0, MET_MOVIE_END = 1, MET_FRAME = 2 }; + +class CGameObject; + +class CMovieEvent : public ListItem { +public: + MovieEventType _type; + int _startFrame; + int _endFrame; + CGameObject *_gameObject; + int _initialFrame; +public: + CMovieEvent(); + CMovieEvent(const CMovieEvent *src); + virtual ~CMovieEvent() {} + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); +}; + +class CMovieEventList : public List<CMovieEvent> { +}; + +class CSharedMovieEventList : public Common::List<CMovieEvent> { +}; + + +} // End of namespace Titanic + +#endif /* TITANIC_MOVIE_EVENT_H */ diff --git a/engines/titanic/support/movie_manager.cpp b/engines/titanic/support/movie_manager.cpp new file mode 100644 index 0000000000..bfeb081b5c --- /dev/null +++ b/engines/titanic/support/movie_manager.cpp @@ -0,0 +1,35 @@ +/* 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/movie_manager.h" +#include "titanic/support/movie.h" +#include "titanic/support/video_surface.h" + +namespace Titanic { + +CMovie *CMovieManager::createMovie(const CResourceKey &key, CVideoSurface *surface) { + CMovie *movie = new OSMovie(key, surface); + movie->setSoundManager(_soundManager); + return movie; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/movie_manager.h b/engines/titanic/support/movie_manager.h new file mode 100644 index 0000000000..2920d909b7 --- /dev/null +++ b/engines/titanic/support/movie_manager.h @@ -0,0 +1,65 @@ +/* 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_MOVIE_MANAGER_H +#define TITANIC_MOVIE_MANAGER_H + +#include "titanic/core/list.h" +#include "titanic/core/resource_key.h" +#include "titanic/sound/sound_manager.h" + +namespace Titanic { + +class CMovie; +class CVideoSurface; + +class CMovieManagerBase { +public: + virtual ~CMovieManagerBase() {} + + /** + * Create a new movie and return it + */ + virtual CMovie *createMovie(const CResourceKey &key, CVideoSurface *surface) = 0; +}; + +class CMovieManager : public CMovieManagerBase { +private: + CSoundManager *_soundManager; +public: + CMovieManager() : CMovieManagerBase(), _soundManager(nullptr) {} + virtual ~CMovieManager() {} + + /** + * Create a new movie and return it + */ + virtual CMovie *createMovie(const CResourceKey &key, CVideoSurface *surface); + + /** + * Sets the sound manager that will be attached to all created movies + */ + void setSoundManager(CSoundManager *soundManager) { _soundManager = soundManager; } +}; + +} // End of namespace Titanic + +#endif /* TITANIC_MOVIE_MANAGER_H */ diff --git a/engines/titanic/support/movie_range_info.cpp b/engines/titanic/support/movie_range_info.cpp new file mode 100644 index 0000000000..634ab1cc62 --- /dev/null +++ b/engines/titanic/support/movie_range_info.cpp @@ -0,0 +1,112 @@ +/* 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/movie_range_info.h" +#include "titanic/support/movie_clip.h" +#include "titanic/core/game_object.h" + +namespace Titanic { + +CMovieRangeInfo::CMovieRangeInfo() : ListItem(), _startFrame(0), _endFrame(0) { +} + +CMovieRangeInfo::~CMovieRangeInfo() { + _events.destroyContents(); +} + +CMovieRangeInfo::CMovieRangeInfo(const CMovieRangeInfo *src) : ListItem() { + _startFrame = src->_startFrame; + _endFrame = src->_endFrame; + _initialFrame = src->_initialFrame; + _isReversed = src->_isReversed; + _isRepeat = src->_isRepeat; + + // Duplicate the events list + for (CMovieEventList::const_iterator i = _events.begin(); + i != _events.end(); ++i) { + _events.push_back(new CMovieEvent(*i)); + } +} + +void CMovieRangeInfo::save(SimpleFile *file, int indent) { + file->writeNumberLine(0, indent); + file->writeNumberLine(_startFrame, indent + 1); + file->writeNumberLine(_endFrame, indent + 1); + file->writeNumberLine(_initialFrame, indent + 1); + file->writeNumberLine(_isRepeat, indent + 1); + file->writeNumberLine(_isReversed, indent + 1); + _events.save(file, indent + 1); +} + +void CMovieRangeInfo::load(SimpleFile *file) { + int val = file->readNumber(); + if (!val) { + _startFrame = file->readNumber(); + _endFrame = file->readNumber(); + _initialFrame = file->readNumber(); + _isRepeat = file->readNumber(); + _isReversed = file->readNumber(); + _events.load(file); + } +} + +void CMovieRangeInfo::getMovieEnd(CMovieEventList &list) { + for (CMovieEventList::iterator i = _events.begin(); i != _events.end(); ++i) { + CMovieEvent *movieEvent = *i; + if (movieEvent->_type == MET_MOVIE_END) + list.push_back(new CMovieEvent(movieEvent)); + } +} + +void CMovieRangeInfo::getMovieFrame(CMovieEventList &list, int frameNumber) { + for (CMovieEventList::iterator i = _events.begin(); i != _events.end(); ++i) { + CMovieEvent *movieEvent = *i; + if (movieEvent->_type == MET_FRAME && movieEvent->_initialFrame == frameNumber) + list.push_back(new CMovieEvent(movieEvent)); + } +} + +void CMovieRangeInfo::process(CGameObject *owner) { + int flags = 0; + if (_endFrame) + 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_PLAY) { + flags |= CLIPFLAG_PLAY; + break; + } + } + + owner->playMovie(_startFrame, _endFrame, _initialFrame, flags); + + for (CMovieEventList::iterator i = _events.begin(); i != _events.end(); ++i) { + CMovieEvent *movieEvent = *i; + if (movieEvent->_type == MET_PLAY) + owner->movieEvent(movieEvent->_initialFrame); + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/movie_range_info.h b/engines/titanic/support/movie_range_info.h new file mode 100644 index 0000000000..6b13fbadb5 --- /dev/null +++ b/engines/titanic/support/movie_range_info.h @@ -0,0 +1,81 @@ +/* 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_MOVIE_RANGE_INFO_H +#define TITANIC_MOVIE_RANGE_INFO_H + +#include "video/video_decoder.h" +#include "titanic/core/list.h" +#include "titanic/core/resource_key.h" +#include "titanic/support/movie_event.h" + +namespace Titanic { + +class CGameObject; + +class CMovieRangeInfo : public ListItem { +public: + int _startFrame; + int _endFrame; + int _initialFrame; + bool _isReversed; + bool _isRepeat; + CMovieEventList _events; +public: + CMovieRangeInfo(); + CMovieRangeInfo(const CMovieRangeInfo *src); + virtual ~CMovieRangeInfo(); + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); + + /** + * Adds an event to the events list + */ + void addEvent(CMovieEvent *movieEvent) { _events.push_back(movieEvent); } + + /** + * Get any movie end events for the range + */ + void getMovieEnd(CMovieEventList &list); + + /** + * Get any movie frame events for a specified frame number + */ + void getMovieFrame(CMovieEventList &list, int frameNumber); + + void process(CGameObject *owner); +}; + +class CMovieRangeInfoList : public List<CMovieRangeInfo> { +}; + +} // End of namespace Titanic + +#endif /* TITANIC_MOVIE_RANGE_INFO_H */ diff --git a/engines/titanic/support/proximity.cpp b/engines/titanic/support/proximity.cpp new file mode 100644 index 0000000000..4a832b9217 --- /dev/null +++ b/engines/titanic/support/proximity.cpp @@ -0,0 +1,37 @@ +/* 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/proximity.h" +#include "titanic/true_talk/tt_talker.h" + +namespace Titanic { + +CProximity::CProximity() : _field4(0), _field8(100), _fieldC(0), + _speechHandle(-1), _field14(0), _field18(0), _field1C(0x3FF00000), + _field20(0), _field24(10), _field28(0), _field2C(0), + _field30(0x3F000000), _field34(0), _double1(0.0), _double2(0.0), + _double3(0.0), _field44(0), _field48(0), _field4C(0), + _field50(0), _field54(0), _field58(0), _field5C(0), + _field60(0), _method1(nullptr), _talker(nullptr), _field6C(0) { +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/proximity.h b/engines/titanic/support/proximity.h new file mode 100644 index 0000000000..935e2e6b1c --- /dev/null +++ b/engines/titanic/support/proximity.h @@ -0,0 +1,69 @@ +/* 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_PROXIMITY_H +#define TITANIC_PROXIMITY_H + +#include "common/scummsys.h" + +namespace Titanic { + +typedef bool (*CProximityFn)(int val); + +class TTtalker; + +class CProximity { +public: + int _field4; + int _field8; + int _fieldC; + int _speechHandle; + int _field14; + int _field18; + int _field1C; + int _field20; + int _field24; + int _field28; + uint32 _field2C; + int _field30; + int _field34; + double _double1; + double _double2; + double _double3; + int _field44; + int _field48; + int _field4C; + int _field50; + int _field54; + int _field58; + int _field5C; + int _field60; + CProximityFn _method1; + TTtalker *_talker; + int _field6C; +public: + CProximity(); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_PROXIMITY_H */ diff --git a/engines/titanic/support/rect.cpp b/engines/titanic/support/rect.cpp new file mode 100644 index 0000000000..5fce4402cb --- /dev/null +++ b/engines/titanic/support/rect.cpp @@ -0,0 +1,44 @@ +/* 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/rect.h" + +namespace Titanic { + +void Rect::combine(const Rect &r) { + if (isEmpty() || r.isEmpty()) + return; + + Common::Rect::extend(r); +} + +void Rect::constrain(const Rect &r) { + if (!isEmpty()) { + if (r.isEmpty()) { + clear(); + } else { + Common::Rect::clip(r); + } + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/rect.h b/engines/titanic/support/rect.h new file mode 100644 index 0000000000..1661711870 --- /dev/null +++ b/engines/titanic/support/rect.h @@ -0,0 +1,61 @@ +/* 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_RECT_H +#define TITANIC_RECT_H + +#include "common/rect.h" + +namespace Titanic { + +typedef Common::Point Point; + +class Rect : public Common::Rect { +public: + Rect() : Common::Rect() {} + Rect(int16 w, int16 h) : Common::Rect(w, h) {} + Rect(int16 x1, int16 y1, int16 x2, int16 y2) : Common::Rect(x1, y1, x2, y2) {} + + /** + * Returns the top/left corner of the rect as a point + */ + operator const Point() { return Point(left, top); } + + /** + * Clear the rect + */ + void clear() { left = top = right = bottom = 0; } + + /** + * Combine another rect into this one + */ + void combine(const Rect &r); + + /** + * Constrains/clips to the intersection area of the given rect + */ + void constrain(const Rect &r); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_RECT_H */ diff --git a/engines/titanic/support/screen_manager.cpp b/engines/titanic/support/screen_manager.cpp new file mode 100644 index 0000000000..d795f78764 --- /dev/null +++ b/engines/titanic/support/screen_manager.cpp @@ -0,0 +1,326 @@ +/* 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/screen_manager.h" +#include "titanic/titanic.h" +#include "titanic/support/video_surface.h" + +namespace Titanic { + +CScreenManager *CScreenManager::_screenManagerPtr; +CScreenManager *CScreenManager::_currentScreenManagerPtr; + +CScreenManager::CScreenManager(TitanicEngine *vm): _vm(vm) { + _screenManagerPtr = nullptr; + _currentScreenManagerPtr = nullptr; + + _frontRenderSurface = nullptr; + _mouseCursor = nullptr; + _textCursor = nullptr; + _inputHandler = nullptr; + _fontNumber = 0; + // TODO: Further initialization + + _screenManagerPtr = this; +} + +CScreenManager::~CScreenManager() { + _screenManagerPtr = nullptr; +} + +void CScreenManager::setWindowHandle(int v) { + // Not needed +} + +bool CScreenManager::resetWindowHandle(int v) { + hideCursor(); + return true; +} + +CScreenManager *CScreenManager::setCurrent() { + if (!_currentScreenManagerPtr) + _currentScreenManagerPtr = _screenManagerPtr; + + return _currentScreenManagerPtr; +} + +void CScreenManager::setSurfaceBounds(SurfaceNum surfaceNum, const Rect &r) { + if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) + _backSurfaces[surfaceNum]._bounds = r; +} + +int CScreenManager::setFontNumber(int fontNumber) { + int oldFontNumber = _fontNumber; + _fontNumber = fontNumber; + return oldFontNumber; +} + +/*------------------------------------------------------------------------*/ + +OSScreenManager::OSScreenManager(TitanicEngine *vm): CScreenManager(vm), + _directDrawManager(vm, false) { + _field48 = 0; + _field4C = 0; + _field50 = 0; + _field54 = 0; +} + +OSScreenManager::~OSScreenManager() { + destroyFrontAndBackBuffers(); + delete _mouseCursor; + delete _textCursor; +} + +void OSScreenManager::setMode(int width, int height, int bpp, uint numBackSurfaces, bool flag2) { + assert(bpp == 16); + destroyFrontAndBackBuffers(); + _directDrawManager.initVideo(width, height, bpp, numBackSurfaces); + + _vm->_screen->create(width, height, g_system->getScreenFormat()); + _frontRenderSurface = new OSVideoSurface(this, nullptr); + _frontRenderSurface->setSurface(this, _directDrawManager._mainSurface); + + _backSurfaces.resize(numBackSurfaces); + for (uint idx = 0; idx < numBackSurfaces; ++idx) { + _backSurfaces[idx]._surface = new OSVideoSurface(this, nullptr); + _backSurfaces[idx]._surface->setSurface(this, _directDrawManager._backSurfaces[idx]); + } + + // Load fonts + _fonts[0].load(149); + _fonts[1].load(151); + _fonts[2].load(152); + _fonts[3].load(153); + + // Load the cursors + loadCursors(); +} + +void OSScreenManager::drawCursors() { + // The original did both text and mouse cursor drawing here. + // For ScummVM, we only need to worry about the text cursor + _textCursor->draw(); +} + +DirectDrawSurface *OSScreenManager::getDDSurface(SurfaceNum surfaceNum) { + if (surfaceNum == SURFACE_PRIMARY) + return _directDrawManager._mainSurface; + else if (surfaceNum < (int)_backSurfaces.size()) + return _directDrawManager._backSurfaces[surfaceNum]; + else + return nullptr; +} + +CVideoSurface *OSScreenManager::lockSurface(SurfaceNum surfaceNum) { + CVideoSurface *surface = getSurface(surfaceNum); + surface->lock(); + return surface; +} + +void OSScreenManager::unlockSurface(CVideoSurface *surface) { + surface->unlock(); +} + +CVideoSurface *OSScreenManager::getSurface(SurfaceNum surfaceNum) const { + if (surfaceNum == SURFACE_PRIMARY) + return _frontRenderSurface; + else if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) + return _backSurfaces[surfaceNum]._surface; + else + return nullptr; +} + +void OSScreenManager::fillRect(SurfaceNum surfaceNum, Rect *rect, byte r, byte g, byte b) { + DirectDrawSurface *surface = getDDSurface(surfaceNum); + if (!surface) + return; + + // If bounds are provided, clip and use them. Otherwise, use entire surface area + Rect surfaceRect(0, 0, surface->getWidth(), surface->getHeight()); + Rect tempRect; + + if (rect) { + tempRect = *rect; + tempRect.clip(surfaceRect); + } else { + tempRect = surfaceRect; + } + + if (tempRect.isValidRect()) + surface->fillRect(&tempRect, r, g, b); +} + +void OSScreenManager::blitFrom(SurfaceNum surfaceNum, CVideoSurface *src, + const Point *destPos, const Rect *srcRect) { + // Get the dest surface + CVideoSurface *destSurface = _frontRenderSurface; + if (surfaceNum < -1) + return; + if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) + 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; + Rect rect2; + + if (surfaceNum >= 0 && !_backSurfaces[surfaceNum]._bounds.isEmpty()) { + // Perform clipping to the bounds of the back surface + rect2 = srcBounds; + rect2.translate(-srcBounds.left, -srcBounds.top); + rect2.translate(destPoint.x, destPoint.y); + rect2.constrain(_backSurfaces[surfaceNum]._bounds); + + rect2.translate(-destPoint.x, -destPoint.y); + rect2.translate(srcBounds.left, srcBounds.top); + + if (rect2.isEmpty()) + return; + + destPoint.x += rect2.left - srcBounds.left; + destPoint.y += rect2.top - srcBounds.top; + bounds = &rect2; + } + + if (!bounds->isEmpty()) + destSurface->blitFrom(destPoint, src, bounds); +} + +void OSScreenManager::blitFrom(SurfaceNum surfaceNum, const Rect *rect, CVideoSurface *src, int v) { + // Get the dest surface + CVideoSurface *destSurface = _frontRenderSurface; + if (surfaceNum < -1) + return; + if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) + destSurface = _backSurfaces[surfaceNum]._surface; + if (!destSurface->hasSurface()) + return; + + if (!rect->isEmpty()) + destSurface->blitFrom(Point(rect->left, rect->top), src, rect); +} + +int OSScreenManager::writeString(int surfaceNum, const Rect &destRect, + int yOffset, const CString &str, CTextCursor *textCursor) { + CVideoSurface *surface; + Rect bounds; + + if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) { + surface = _backSurfaces[surfaceNum]._surface; + bounds = _backSurfaces[surfaceNum]._bounds; + } else if (surfaceNum == -1) { + surface = _frontRenderSurface; + bounds = Rect(0, 0, surface->getWidth(), surface->getHeight()); + } else { + return -1; + } + + return _fonts[_fontNumber].writeString(surface, destRect, bounds, + yOffset, str, textCursor); +} + +int OSScreenManager::writeString(int surfaceNum, const Rect &srcRect, + const Rect &destRect, const CString &str, CTextCursor *textCursor) { + // TODO + return 0; +} + +void OSScreenManager::setFontColor(byte r, byte g, byte b) { + _fonts[_fontNumber].setColor(r, g, b); +} + +int OSScreenManager::getTextBounds(const CString &str, int maxWidth, Point *sizeOut) const { + return _fonts[_fontNumber].getTextBounds(str, maxWidth, sizeOut); +} + +int OSScreenManager::getFontHeight() const { + return _fonts[_fontNumber]._fontHeight; +} + +int OSScreenManager::stringWidth(const CString &str) { + return _fonts[_fontNumber].stringWidth(str); +} + +void OSScreenManager::frameRect(SurfaceNum surfaceNum, const Rect &rect, byte r, byte g, byte b) { + Rect top(rect.left, rect.top, rect.right, rect.top + 1); + fillRect(surfaceNum, &top, r, g, b); + Rect bottom(rect.left, rect.bottom - 1, rect.right, rect.bottom); + fillRect(surfaceNum, &bottom, r, g, b); + Rect left(rect.left, rect.top, rect.left + 1, rect.bottom); + fillRect(surfaceNum, &left, r, g, b); + Rect right(rect.right - 1, rect.top, rect.right, rect.bottom); +} + +void OSScreenManager::clearSurface(SurfaceNum surfaceNum, Rect *bounds) { + if (surfaceNum == SURFACE_PRIMARY) + _directDrawManager._mainSurface->fill(bounds, 0); + else if (surfaceNum >= 0 && surfaceNum < (int)_backSurfaces.size()) + _directDrawManager._backSurfaces[surfaceNum]->fill(bounds, 0); +} + +void OSScreenManager::resizeSurface(CVideoSurface *surface, int width, int height) { + DirectDrawSurface *ddSurface = _directDrawManager.createSurface(width, height, 0); + surface->setSurface(this, ddSurface); +} + +CVideoSurface *OSScreenManager::createSurface(int w, int h) { + DirectDrawSurface *ddSurface = _directDrawManager.createSurface(w, h, 0); + return new OSVideoSurface(this, ddSurface); +} + +CVideoSurface *OSScreenManager::createSurface(const CResourceKey &key) { + return new OSVideoSurface(this, key); +} + +void OSScreenManager::showCursor() { + CScreenManager::_screenManagerPtr->_mouseCursor->show(); +} + +void OSScreenManager::hideCursor() { + CScreenManager::_screenManagerPtr->_mouseCursor->hide(); +} + +void OSScreenManager::destroyFrontAndBackBuffers() { + delete _frontRenderSurface; + _frontRenderSurface = nullptr; + + for (uint idx = 0; idx < _backSurfaces.size(); ++idx) + delete _backSurfaces[idx]._surface; + _backSurfaces.clear(); +} + +void OSScreenManager::loadCursors() { + if (_mouseCursor) { + hideCursor(); + delete _mouseCursor; + } + _mouseCursor = new CMouseCursor(this); + showCursor(); + + if (!_textCursor) { + _textCursor = new CTextCursor(this); + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/screen_manager.h b/engines/titanic/support/screen_manager.h new file mode 100644 index 0000000000..0736f1393c --- /dev/null +++ b/engines/titanic/support/screen_manager.h @@ -0,0 +1,395 @@ +/* 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_SCREEN_MANAGER_H +#define TITANIC_SCREEN_MANAGER_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "titanic/support/direct_draw.h" +#include "titanic/support/font.h" +#include "titanic/input_handler.h" +#include "titanic/support/mouse_cursor.h" +#include "titanic/support/text_cursor.h" +#include "titanic/support/video_surface.h" +#include "titanic/core/resource_key.h" + +namespace Titanic { + +/** + * The original used page flipping with one primary and one back buffer. + * Since we don't need that in ScummVM, the back buffer number below is + * remapped to the primary surface + */ +enum SurfaceNum { + SURFACE_PRIMARY = -1, // Surface 0 + SURFACE_BACKBUFFER = -1 // Surface -1 +}; + +class TitanicEngine; + +class CScreenManager { + struct VideoSurfaceEntry { + CVideoSurface *_surface; + Rect _bounds; + }; +protected: + TitanicEngine *_vm; +public: + static CScreenManager *_screenManagerPtr; + static CScreenManager *_currentScreenManagerPtr; + + /** + * Set the current screen manager + */ + static CScreenManager *setCurrent(); +public: + Common::Array<VideoSurfaceEntry> _backSurfaces; + CVideoSurface *_frontRenderSurface; + CMouseCursor *_mouseCursor; + CTextCursor *_textCursor; + CInputHandler *_inputHandler; + int _fontNumber; +public: + CScreenManager(TitanicEngine *vm); + virtual ~CScreenManager(); + + void fn1() {} + void fn2() {} + + virtual void setWindowHandle(int v); + virtual bool resetWindowHandle(int v); + + /** + * Sets the video mode + */ + virtual void setMode(int width, int height, int bpp, uint numBackSurfaces, bool flag2) = 0; + + /** + * 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 + */ + virtual CVideoSurface *getSurface(SurfaceNum surfaceNum) const = 0; + + /** + * Return the front render surface + */ + virtual CVideoSurface *getFrontRenderSurface() const = 0; + + /** + * Fill an area with a specific color + */ + virtual void fillRect(SurfaceNum surfaceNum, Rect *rect, byte r, byte g, byte b) = 0; + + /** + * Blits a surface onto one of the screen surfaces + */ + virtual void blitFrom(SurfaceNum surfaceNum, CVideoSurface *src, const Point *destPos = nullptr, + const Rect *srcRect = nullptr) = 0; + + /** + * Blits a surface onto one of the screen surfaces + */ + virtual void blitFrom(SurfaceNum surfaceNum, const Rect *rect, CVideoSurface *src, int v = 0) = 0; + + /** + * Write a string + * @param surfaceNum Destination surface + * @param destRect Bounds within dest surface + * @param yOffset Y offset for drawing, to allow for parts of + * the text to be scrolled off-screen + * @param str Line or lines to write + * @param textCursor Optional text cursor pointer + */ + virtual int writeString(int surfaceNum, const Rect &destRect, + int yOffset, const CString &str, CTextCursor *textCursor) = 0; + + /** + * Write a string + * @param surfaceNum Destination surface + * @param srcRect Drawing area + * @param destRect Bounds of dest surface + * @param str Line or lines to write + * @param textCursor Optional text cursor pointer + */ + virtual int writeString(int surfaceNum, const Rect &srcRect, + const Rect &destRect, const CString &str, CTextCursor *textCursor) = 0; + + /** + * Set the font color + */ + virtual void setFontColor(byte r, byte g, byte b) = 0; + + /** + * Get the text area a string will fit into + * @param str String + * @param maxWidth Maximum width in pixels + * @param sizeOut Optional pointer to output size + * @returns Required height + */ + virtual int getTextBounds(const CString &str, int maxWidth, Point *sizeOut = nullptr) const = 0; + + /** + * Get the current font height + */ + virtual int getFontHeight() const = 0; + + /** + * Returns the width of a given string in pixels + */ + virtual int stringWidth(const CString &str) = 0; + + /** + * Draws a frame enclosing the specified area + */ + virtual void frameRect(SurfaceNum surfaceNum, const Rect &rect, byte r, byte g, byte b) = 0; + + /** + * Clear a portion of a specified surface + */ + virtual void clearSurface(SurfaceNum surfaceNum, Rect *_bounds) = 0; + + /** + * Resize the passed surface + */ + virtual void resizeSurface(CVideoSurface *surface, int width, int height) = 0; + + /** + * Creates a surface of a given size + */ + virtual CVideoSurface *createSurface(int w, int h) = 0; + + /** + * Creates a surface from a specified resource + */ + virtual CVideoSurface *createSurface(const CResourceKey &key) = 0; + + /** + * Get the top-left corner of the screen in global screen co-ordinates + * For ScummVM, this is always (0, 0), even in Windowed mode + */ + virtual Point getScreenTopLeft() { return Point(0, 0); } + + /** + * Waits for a vertical screen sync + * For ScummVM, this can be safely ignored + */ + virtual void waitForVSync() {} + + /** + * Show the mouse cursor + */ + virtual void showCursor() = 0; + + /** + * Hide the mouse cursor + */ + virtual void hideCursor() = 0; + + /** + * Set drawing bounds for a specified surface + */ + void setSurfaceBounds(SurfaceNum surfaceNum, const Rect &r); + + /** + * Set the current font number + */ + int setFontNumber(int fontNumber); +}; + +class OSScreenManager: CScreenManager { +private: + DirectDrawManager _directDrawManager; + + /** + * Frees any surface buffers + */ + void destroyFrontAndBackBuffers(); + + /** + * Load game cursors + */ + void loadCursors(); + + /** + * Gets an underlying surface + */ + DirectDrawSurface *getDDSurface(SurfaceNum surfaceNum); +public: + int _field48; + int _field4C; + int _field50; + int _field54; + STFont _fonts[4]; +public: + OSScreenManager(TitanicEngine *vm); + virtual ~OSScreenManager(); + + /** + * Sets the video mode + */ + virtual void setMode(int width, int height, int bpp, uint numBackSurfaces, bool flag2); + + /** + * Handles drawing the cursors + */ + virtual void drawCursors(); + + /** + * 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 + */ + virtual CVideoSurface *getSurface(SurfaceNum surfaceNum) const; + + /** + * Return the front render surface + */ + virtual CVideoSurface *getFrontRenderSurface() const { + return _frontRenderSurface; + } + + + /** + * Fill an area with a specific color + */ + virtual void fillRect(SurfaceNum surfaceNum, Rect *rect, byte r, byte g, byte b); + + /** + * Blits a surface onto one of the screen surfaces + */ + virtual void blitFrom(SurfaceNum surfaceNum, CVideoSurface *src, const Point *destPos, + const Rect *srcRect = nullptr); + + /** + * Blits a surface onto one of the screen surfaces + */ + virtual void blitFrom(SurfaceNum surfaceNum, const Rect *rect, CVideoSurface *src, int v = 0); + + /** + * Write a string + * @param surfaceNum Destination surface + * @param destRect Bounds within dest surface + * @param yOffset Y offset for drawing, to allow for parts of + * the text to be scrolled off-screen + * @param str Line or lines to write + * @param textCursor Optional text cursor pointer + */ + virtual int writeString(int surfaceNum, const Rect &destRect, + int yOffset, const CString &str, CTextCursor *textCursor); + + /** + * Write a string + * @param surfaceNum Destination surface + * @param srcRect Drawing area + * @param destRect Bounds of dest surface + * @param str Line or lines to write + * @param textCursor Optional text cursor pointer + */ + virtual int writeString(int surfaceNum, const Rect &srcRect, + const Rect &destRect, const CString &str, CTextCursor *textCursor); + + /** + * Set the font color + */ + virtual void setFontColor(byte r, byte g, byte b); + + /** + * Get the text area a string will fit into + * @param str String + * @param maxWidth Maximum width in pixels + * @param sizeOut Optional pointer to output size + * @returns Required height + */ + virtual int getTextBounds(const CString &str, int maxWidth, Point *sizeOut = nullptr) const; + + /** + * Get the current font height + */ + virtual int getFontHeight() const; + + /** + * Returns the width of a given string in pixels + */ + virtual int stringWidth(const CString &str); + + /** + * Draws a frame enclosing the specified area + */ + virtual void frameRect(SurfaceNum surfaceNum, const Rect &rect, byte r, byte g, byte b); + + /** + * Clear a portion of the screen surface + */ + virtual void clearSurface(SurfaceNum surfaceNum, Rect *bounds); + + /** + * Resize the passed surface + */ + virtual void resizeSurface(CVideoSurface *surface, int width, int height); + + /** + * Creates a surface of a given size + */ + virtual CVideoSurface *createSurface(int w, int h); + + /** + * Creates a surface from a specified resource + */ + virtual CVideoSurface *createSurface(const CResourceKey &key); + + /** + * Show the mouse cursor + */ + virtual void showCursor(); + + /** + * Hide the mouse cursor + */ + virtual void hideCursor(); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_SCREEN_MANAGER_H */ diff --git a/engines/titanic/support/simple_file.cpp b/engines/titanic/support/simple_file.cpp new file mode 100644 index 0000000000..35b2e28e4a --- /dev/null +++ b/engines/titanic/support/simple_file.cpp @@ -0,0 +1,512 @@ +/* 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 "common/util.h" +#include "titanic/support/simple_file.h" + +namespace Titanic { + +CString readStringFromStream(Common::SeekableReadStream *s) { + CString result; + char c; + while ((c = s->readByte()) != '\0') + result += c; + + return result; +} + +/*------------------------------------------------------------------------*/ + +bool File::open(const Common::String &filename) { + if (!Common::File::open(filename)) + error("Could not open file - %s", filename.c_str()); + return true; +} + +/*------------------------------------------------------------------------*/ + +SimpleFile::SimpleFile(): _inStream(nullptr), _outStream(nullptr), _lineCount(1) { +} + +SimpleFile::~SimpleFile() { + close(); +} + +void SimpleFile::open(Common::SeekableReadStream *stream) { + close(); + _inStream = stream; +} + +void SimpleFile::open(Common::OutSaveFile *stream) { + close(); + _outStream = stream; +} + +void SimpleFile::close() { + if (_outStream) { + _outStream->finalize(); + delete _outStream; + _outStream = nullptr; + } + + if (_inStream) { + delete _inStream; + _inStream = nullptr; + } +} + +void SimpleFile::safeRead(void *dst, size_t count) { + if (unsafeRead(dst, count) != count) + error("Could not read %d bytes", (int)count); +} + +size_t SimpleFile::unsafeRead(void *dst, size_t count) { + assert(_inStream); + return _inStream->read(dst, count); +} + +size_t SimpleFile::write(const void *src, size_t count) const { + assert(_outStream); + return _outStream->write(src, count); +} + +void SimpleFile::seek(int offset, int origin) { + assert(_inStream); + _inStream->seek(offset, origin); +} + +byte SimpleFile::readByte() { + byte b; + safeRead(&b, 1); + return b; +} + +uint SimpleFile::readUint16LE() { + uint val; + safeRead(&val, 2); + return READ_LE_UINT16(&val); +} + +uint SimpleFile::readUint32LE() { + uint val; + safeRead(&val, 4); + return READ_LE_UINT32(&val); +} + +CString SimpleFile::readString() { + char c; + CString result; + bool backslashFlag = false; + + // First skip any spaces + do { + safeRead(&c, 1); + } while (Common::isSpace(c)); + + // Ensure we've found a starting quote for the string + if (c != '"') + error("Could not find starting quote"); + + bool endFlag = false; + while (!endFlag) { + // Read the next character + safeRead(&c, 1); + + if (backslashFlag) { + backslashFlag = false; + switch (c) { + case 'n': + result += '\n'; + break; + case 'r': + result += '\r'; + break; + case '\t': + result += '\t'; + break; + default: + result += c; + break; + } + } else { + switch (c) { + case '"': + endFlag = true; + break; + case '\\': + backslashFlag = true; + break; + default: + result += c; + break; + } + } + } + + // Return the string + return result; +} + +int SimpleFile::readNumber() { + char c; + int result = 0; + bool minusFlag = false; + + // First skip any spaces + do { + safeRead(&c, 1); + } while (Common::isSpace(c)); + + // Check for prefix sign + if (c == '+' || c == '-') { + minusFlag = c == '-'; + safeRead(&c, 1); + } + + // Read in the number + if (!Common::isDigit(c)) + error("Invalid number"); + + while (Common::isDigit(c)) { + result = result * 10 + (c - '0'); + safeRead(&c, 1); + } + + // Finally, if it's a minus value, then negate it + if (minusFlag) + result = -result; + + return result; +} + +double SimpleFile::readFloat() { + char c; + Common::String result; + + // First skip any spaces + do { + safeRead(&c, 1); + } while (Common::isSpace(c)); + + // Check for prefix sign + if (c == '+' || c == '-') { + result += c; + safeRead(&c, 1); + } + + // Read in the number + if (!Common::isDigit(c)) + error("Invalid number"); + + while (Common::isDigit(c) || c == '.') { + result += c; + safeRead(&c, 1); + } + + // Convert to a float and return it + float floatValue; + sscanf(result.c_str(), "%f", &floatValue); + + return floatValue; +} + +Point SimpleFile::readPoint() { + Point pt; + pt.x = readNumber(); + pt.y = readNumber(); + + return pt; +} + +Rect SimpleFile::readRect() { + Rect r; + r.left = readNumber(); + r.top = readNumber(); + r.right = readNumber(); + r.bottom = readNumber(); + + return r; +} + +Rect SimpleFile::readBounds() { + Rect r; + r.left = readNumber(); + r.top = readNumber(); + r.setWidth(readNumber()); + r.setHeight(readNumber()); + + return r; +} + +void SimpleFile::readBuffer(char *buffer, size_t count) { + CString tempString = readString(); + if (buffer) { + strncpy(buffer, tempString.c_str(), count); + buffer[count - 1] = '\0'; + } +} + +void SimpleFile::writeUint16LE(uint val) { + byte lo = val & 0xff; + byte hi = (val >> 8) & 0xff; + write(&lo, 1); + write(&hi, 1); +} + +void SimpleFile::writeUint32LE(uint val) { + uint16 lo = val & 0xffff; + uint16 hi = (val >> 16) & 0xff; + writeUint16LE(lo); + writeUint16LE(hi); +} + +void SimpleFile::writeLine(const CString &str) const { + write(str.c_str(), str.size()); + write("\r\n", 2); +} + +void SimpleFile::writeString(const CString &str) const { + if (str.empty()) + return; + + const char *msgP = str.c_str(); + char c; + + while ((c = *msgP++) != '\0') { + switch (c) { + case '\r': + write("\\r", 2); + break; + case '\n': + write("\\n", 2); + break; + case '\t': + write("\\t", 2); + break; + case '\"': + write("\\\"", 2); + break; + case '\\': + write("\\\\", 2); + break; + case '{': + write("\\{", 2); + break; + case '}': + write("\\}", 2); + break; + default: + write(&c, 1); + break; + } + } +} + +void SimpleFile::writeQuotedString(const CString &str) const { + write("\"", 1); + writeString(str); + write("\" ", 2); +} + +void SimpleFile::writeQuotedLine(const CString &str, int indent) const { + writeIndent(indent); + writeQuotedString(str); + write("\n", 1); +} + +void SimpleFile::writeNumber(int val) const { + CString str = CString::format("%d ", val); + write(str.c_str(), str.size()); +} + +void SimpleFile::writeNumberLine(int val, int indent) const { + writeIndent(indent); + writeNumber(val); + write("\n", 1); +} + +void SimpleFile::writeFloat(double val) const { + Common::String valStr = Common::String::format("%f ", val); + write(valStr.c_str(), valStr.size()); +} + +void SimpleFile::writeFloatLine(double val, int indent) const { + writeIndent(indent); + writeFloat(val); + write("\n", 1); +} + +void SimpleFile::writePoint(const Point &pt, int indent) const { + writeIndent(indent); + writeNumber(pt.x); + writeNumber(pt.y); + write("\n", 1); +} + +void SimpleFile::writeRect(const Rect &r, int indent) const { + writePoint(Point(r.left, r.top), indent); + writePoint(Point(r.right, r.bottom), indent); +} + +void SimpleFile::writeBounds(const Rect &r, int indent) const { + writePoint(Point(r.left, r.top), indent); + writePoint(Point(r.width(), r.height()), indent); +} + +void SimpleFile::writeFormat(const char *format, ...) const { + // Convert the format specifier and params to a string + va_list va; + va_start(va, format); + CString line = CString::vformat(format, va); + va_end(va); + + // Write out the string + write(format, strlen(format)); +} + +void SimpleFile::writeIndent(uint indent) const { + for (uint idx = 0; idx < indent; ++idx) + write("\t", 1); +} + +bool SimpleFile::IsClassStart() { + char c; + + do { + safeRead(&c, 1); + } while (Common::isSpace(c)); + + assert(c == '{' || c == '}'); + return c == '{'; +} + +void SimpleFile::writeClassStart(const CString &classStr, int indent) { + write("\n", 1); + writeIndent(indent); + write("{\n", 2); + writeIndent(indent + 1); + writeQuotedString(classStr); + write("\n", 1); +} + +void SimpleFile::writeClassEnd(int indent) { + writeIndent(indent); + write("}\n", 2); +} + +bool SimpleFile::scanf(const char *format, ...) { + va_list va; + va_start(va, format); + char c; + + CString formatStr(format); + while (!formatStr.empty()) { + if (formatStr.hasPrefix(" ")) { + formatStr.deleteChar(0); + + safeRead(&c, 1); + if (!Common::isSpace(c)) + return false; + + // Skip over whitespaces + skipSpaces(); + } else if (formatStr.hasPrefix("%d")) { + // Read in a number + 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")) { + // Read in text until the next space + formatStr = CString(formatStr.c_str() + 2); + CString *str = (CString *)va_arg(va, CString *); + str->clear(); + while (!eos() && !Common::isSpace(c = readByte())) + *str += c; + + if (!eos()) + _inStream->seek(-1, SEEK_CUR); + } + } + + skipSpaces(); + va_end(va); + return true; +} + +void SimpleFile::skipSpaces() { + char c = ' '; + while (!eos() && Common::isSpace(c)) + safeRead(&c, 1); + + if (!eos()) + _inStream->seek(-1, SEEK_CUR); +} + +/*------------------------------------------------------------------------*/ + +bool StdCWadFile::open(const Common::String &filename) { + File f; + CString name = filename; + + // Check for whether it is indeed a file/resource pair + int idx = name.indexOf('#'); + + if (idx < 0) { + // Nope, so open up file for standard reading + assert(!name.empty()); + f.open(name); + + SimpleFile::open(f.readStream(f.size())); + return true; + } + + // Split up the name and resource, and get the resource index + CString fname = name.left(idx) + ".st"; + int extPos = name.lastIndexOf('.'); + CString resStr = name.mid(idx + 1, extPos - idx - 1); + int resIndex = resStr.readInt(); + + // Open up the index for access + f.open(fname); + int indexSize = f.readUint32LE() / 4; + assert(resIndex < indexSize); + + // Get the specific resource's offset, and size by also + // getting the offset of the following resource + f.seek(resIndex * 4); + uint resOffset = f.readUint32LE(); + uint nextOffset = (resIndex == (indexSize - 1)) ? f.size() : + f.readUint32LE(); + + // Read in the resource + f.seek(resOffset); + Common::SeekableReadStream *stream = f.readStream(nextOffset - resOffset); + SimpleFile::open(stream); + + f.close(); + return true; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/simple_file.h b/engines/titanic/support/simple_file.h new file mode 100644 index 0000000000..f5d0bc7c1b --- /dev/null +++ b/engines/titanic/support/simple_file.h @@ -0,0 +1,321 @@ +/* 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_SIMPLE_FILE_H +#define TITANIC_SIMPLE_FILE_H + +#include "common/file.h" +#include "titanic/support/rect.h" +#include "common/savefile.h" +#include "common/stream.h" +#include "common/zlib.h" +#include "titanic/support/string.h" + +namespace Titanic { + +class Decompressor; +class DecompressorData; + +/** + * Simple ScummVM File descendent that throws a wobbly if + * the file it tries to open isn't present + */ +class File : public Common::File { +public: + virtual bool open(const Common::String &filename); +}; + +/** + * This class implements basic reading and writing to files + */ +class SimpleFile { +private: + /** + * Skip over any pending spaces + */ + void skipSpaces(); +protected: + Common::SeekableReadStream *_inStream; + Common::OutSaveFile *_outStream; + int _lineCount; +public: + SimpleFile(); + virtual ~SimpleFile(); + + operator Common::SeekableReadStream &() { return *_inStream; } + operator Common::WriteStream &() { return *_outStream; } + + /** + * Set up a stream for read access + */ + virtual void open(Common::SeekableReadStream *stream); + + /** + * Set up a stream for write access + */ + virtual void open(Common::OutSaveFile *stream); + + /** + * Close the file + */ + virtual void close(); + + /** + * Read from the file with validation + */ + virtual void safeRead(void *dst, size_t count); + + /** + * Read from the file + */ + virtual size_t unsafeRead(void *dst, size_t count); + + /** + * Write out data + */ + virtual size_t write(const void *src, size_t count) const; + + /** + * Seek + */ + virtual void seek(int offset, int origin); + /** + * Read a byte + */ + byte readByte(); + + /** + * Read a 16-bit LE number + */ + uint readUint16LE(); + + /** + * Read a 32-bit LE number + */ + uint readUint32LE(); + + /** + * Read a string from the file + */ + CString readString(); + + /** + * Read a number from the file + */ + int readNumber(); + + /** + * Read a floating point number from the file + */ + double readFloat(); + + /** + * Read in a point + */ + Point readPoint(); + + /** + * Read in a rect + */ + Rect readRect(); + + /** + * Rect in a bounds + */ + Rect readBounds(); + + /** + * Read a string and copy it into an optionally passed buffer + */ + void readBuffer(char *buffer = nullptr, size_t count = 0); + + /** + * Scan in values from the file + */ + bool scanf(const char *format, ...); + + /** + * Write out a byte + */ + void writeByte(byte b) { write(&b, 1); } + + /** + * Write out a raw 16-bit LE number + */ + void writeUint16LE(uint val); + + /** + * Write out a raw 32-bit LE number + */ + void writeUint32LE(uint val); + + /** + * Write a string line + */ + void writeLine(const CString &str) const; + + /** + * Write a string + */ + void writeString(const CString &str) const; + + /** + * Write a quoted string + */ + void writeQuotedString(const CString &str) const; + + /** + * Write a quoted string line + */ + void writeQuotedLine(const CString &str, int indent) const; + + /** + * Write a number to file + */ + void writeNumber(int val) const; + + /** + * Write a number line to file + */ + void writeNumberLine(int val, int indent) const; + + /** + * Write a floating point number + */ + void writeFloat(double val) const; + + /** + * Write a floating point number as a line + */ + void writeFloatLine(double val, int indent) const; + + /** + * Write out a point line + */ + void writePoint(const Point &pt, int indent)const; + + /** + * Write out a rect line + */ + void writeRect(const Rect &r, int indent) const; + + /** + * Write out a bounds line + */ + void writeBounds(const Rect &r, int indent) const; + + /** + * Write out a string using a format specifier, just like fprintf + */ + void writeFormat(const char *format, ...) const; + + /** + * Write out a number of tabs to form an indent in the output + */ + void writeIndent(uint indent) const; + + /** + * Validates that the following non-space character is either + * an opening or closing squiggly bracket denoting a class + * definition start or end. Returns true if it's a class start + */ + bool IsClassStart(); + + /** + * Write the starting header for a class definition + */ + void writeClassStart(const CString &classStr, int indent); + + /** + * Write out the ending footer for a class definition + */ + void writeClassEnd(int indent); + + /** + * Return true if the stream has finished being read + */ + bool eos() const { + assert(_inStream); + return _inStream->pos() >= _inStream->size(); + } +}; + +/** + * Derived file that handles compressed files + */ +class CompressedFile : public SimpleFile { +public: + CompressedFile() : SimpleFile() {} + virtual ~CompressedFile() {} + + /** + * Set up a stream for read access + */ + virtual void open(Common::SeekableReadStream *stream) { + SimpleFile::open(Common::wrapCompressedReadStream(stream)); + } + + /** + * Set up a stream for write access + */ + virtual void open(Common::OutSaveFile *stream) { + SimpleFile::open(Common::wrapCompressedWriteStream(stream)); + } +}; + +/** + * Derived file that handles WAD archives containing multiple files + */ +class StdCWadFile : public SimpleFile { +public: + StdCWadFile() : SimpleFile() {} + virtual ~StdCWadFile() {} + + /** + * Open up the specified file + */ + virtual bool open(const Common::String &filename); + + /** + * Unsupported open method from parent class + */ + virtual void open(Common::SeekableReadStream *stream) {} + + /** + * Unsupported open method from parent class + */ + virtual void open(Common::OutSaveFile *stream) {} + + /** + * Return a reference to the read stream + */ + Common::SeekableReadStream *readStream() const { return _inStream; } +}; + +/** + * General purpose support method for reading an ASCIIZ string from a stream + */ +CString readStringFromStream(Common::SeekableReadStream *s); + +} // End of namespace Titanic + +#endif /* TITANIC_SIMPLE_FILE_H */ diff --git a/engines/titanic/support/string.cpp b/engines/titanic/support/string.cpp new file mode 100644 index 0000000000..cd39c03861 --- /dev/null +++ b/engines/titanic/support/string.cpp @@ -0,0 +1,125 @@ +/* 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 "common/algorithm.h" +#include "titanic/support/string.h" + +namespace Titanic { + +CString::CString(char c, uint32 len) : Common::String() { + ensureCapacity(len, false); + for (uint idx = 0; idx < len; ++idx) + (*this) += c; +} + +CString::CString(int val) : Common::String() { + *this = CString::format("%d", val); +} + +CString CString::left(uint count) const { + return (count > size()) ? CString() : CString(c_str(), c_str() + count); +} + +CString CString::right(uint count) const { + uint strSize = size(); + return (count > strSize) ? CString() : + CString(c_str() + strSize - count, c_str() + strSize); +} + +CString CString::mid(uint start, uint count) const { + if (start >= size()) + return CString(); + else + return CString(c_str() + start, MIN(count, size() - start)); +} + +CString CString::mid(uint start) const { + uint strSize = size(); + assert(start <= strSize); + return mid(start, strSize - start); +} + +int CString::indexOf(char c) const { + const char *charP = strchr(c_str(), c); + return charP ? charP - c_str() : -1; +} + +int CString::indexOf(const char *s) const { + const char *strP = strstr(c_str(), s); + return strP ? strP - c_str() : -1; +} + +int CString::lastIndexOf(char c) const { + const char *charP = strrchr(c_str(), c); + return charP ? charP - c_str() : -1; +} + +FileType CString::fileTypeSuffix() const { + CString ext = right(1); + if (ext == "0" || ext == "4") + return FILETYPE_IMAGE; + else if (ext == "1") + return FILETYPE_WAV; + else if (ext == "2" || ext == "3") + return FILETYPE_MOVIE; + + ext = right(3); + if (ext == "tga" || ext == "jpg") + return FILETYPE_IMAGE; + else if (ext == "wav") + return FILETYPE_WAV; + else if (ext == "avi" || ext == "mov") + return FILETYPE_MOVIE; + else if (ext == "dlg") + return FILETYPE_DLG; + else + return FILETYPE_UNKNOWN; +} + +ImageType CString::imageTypeSuffix() const { + CString ext = right(1); + if (ext == "0") + return IMAGETYPE_TARGA; + else if (ext == "4") + return IMAGETYPE_JPEG; + + ext = right(3); + if (ext == "tga") + return IMAGETYPE_TARGA; + else if (ext == "jpg") + return IMAGETYPE_JPEG; + else + return IMAGETYPE_UNKNOWN; +} + +CString CString::format(const char *fmt, ...) { + String output; + + va_list va; + va_start(va, fmt); + output = String::vformat(fmt, va); + va_end(va); + + return output; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/string.h b/engines/titanic/support/string.h new file mode 100644 index 0000000000..9550ce88a7 --- /dev/null +++ b/engines/titanic/support/string.h @@ -0,0 +1,114 @@ +/* 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_STRING_H +#define TITANIC_STRING_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "common/str.h" + +namespace Titanic { + +enum FileType { + FILETYPE_UNKNOWN = 0, FILETYPE_IMAGE = 1, FILETYPE_MOVIE = 2, + FILETYPE_WAV = 3, FILETYPE_DLG = 4 +}; + +enum ImageType { + IMAGETYPE_UNKNOWN = 0, IMAGETYPE_TARGA = 1, IMAGETYPE_JPEG = 2 +}; + +class CString : public Common::String { +public: + CString() : Common::String() {} + CString(const char *str) : Common::String(str) {} + CString(const char *str, uint32 len) : Common::String(str, len) {} + CString(const char *beginP, const char *endP) : Common::String(beginP, endP) {} + CString(const String &str) : Common::String(str) {} + CString(char c, uint32 len); + explicit CString(char c) : Common::String(c) {} + explicit CString(int val); + + /** + * Returns the left n characters of the string + */ + CString left(uint count) const; + + /** + * Returns the right n characters of the string + */ + CString right(uint count) const; + + /** + * Returns a substring from within the string + */ + CString mid(uint start, uint count) const; + + /** + * Returns a substring from within the string + */ + CString mid(uint start) const; + + /** + * Returns the index of the first occurance of a given character + */ + int indexOf(char c) const; + + /** + * Returns the index of the first occurance of a given string + */ + int indexOf(const char *s) const; + + /** + * Returns the index of the last occurance of a given character + */ + int lastIndexOf(char c) const; + + /** + * Returns the type of a filename based on it's extension + */ + FileType fileTypeSuffix() const; + + /** + * Returns the type of an image filename based on it's extension + */ + ImageType imageTypeSuffix() const; + + /** + * Parses the string as an integer and returns the value + */ + int readInt() const { + return atoi(c_str()); + } + + /** + * Format a string + */ + static CString format(const char *fmt, ...); +}; + +typedef Common::Array<CString> StringArray; + +} // End of namespace Titanic + +#endif /* TITANIC_STRING_H */ diff --git a/engines/titanic/support/text_cursor.cpp b/engines/titanic/support/text_cursor.cpp new file mode 100644 index 0000000000..ad3fe4ed26 --- /dev/null +++ b/engines/titanic/support/text_cursor.cpp @@ -0,0 +1,88 @@ +/* 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 "common/textconsole.h" +#include "titanic/support/text_cursor.h" +#include "titanic/support/screen_manager.h" +#include "titanic/titanic.h" + +namespace Titanic { + +CTextCursor::CTextCursor(CScreenManager *screenManager) : + _screenManager(screenManager), _active(false), _blinkVisible(false), + _backRenderSurface(nullptr), _frontRenderSurface(nullptr), + _blinkDelay(300), _size(2, 10), _priorBlinkTime(0), + _cursorR(0), _cursorG(0), _cursorB(0), _mode(-1) { + _surface = screenManager->createSurface(10, 10); +} + +CTextCursor::~CTextCursor() { + delete _surface; +} + +void CTextCursor::setColor(byte r, byte g, byte b) { + _cursorR = r; + _cursorG = g; + _cursorB = b; +} + +void CTextCursor::show() { + _backRenderSurface = _screenManager->getSurface(SURFACE_BACKBUFFER); + _frontRenderSurface = _screenManager->getFrontRenderSurface(); + _active = true; + _priorBlinkTime = g_vm->_events->getTicksCount(); +} + +void CTextCursor::hide() { + _active = false; +} + +void CTextCursor::draw() { + if (!_active) + return; + + // Handle updating whether the blinking cursor is visible or not + uint newTicks = g_vm->_events->getTicksCount(); + while (newTicks > (_priorBlinkTime + _blinkDelay)) { + _priorBlinkTime += _blinkDelay; + _blinkVisible = !_blinkVisible; + } + + 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); + + if (!cursorRect.isEmpty()) { + // Draw cursor onto the screen + _backRenderSurface->_ddSurface->fillRect(&cursorRect, + _cursorR, _cursorG, _cursorB); + } + + //_screenManager->blitFrom(SURFACE_BACKBUFFER, _surface, &_pos); + } +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/text_cursor.h b/engines/titanic/support/text_cursor.h new file mode 100644 index 0000000000..d8c6ac0653 --- /dev/null +++ b/engines/titanic/support/text_cursor.h @@ -0,0 +1,121 @@ +/* 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_TEXT_CURSOR_H +#define TITANIC_TEXT_CURSOR_H + +#include "common/scummsys.h" +#include "titanic/support/rect.h" + +namespace Titanic { + +class CScreenManager; +class CVideoSurface; + +class CTextCursor { +private: + CScreenManager *_screenManager; + CVideoSurface *_backRenderSurface; + CVideoSurface *_frontRenderSurface; + Point _pos; + Rect _screenBounds; + uint _blinkDelay; + bool _blinkVisible; + Point _size; + Point _screenTopLeft; + uint _priorBlinkTime; + byte _cursorR; + byte _cursorG; + byte _cursorB; + CVideoSurface *_surface; + int _mode; +public: + bool _active; +public: + CTextCursor(CScreenManager *screenManager); + ~CTextCursor(); + + /** + * Sets the position of the cursor + */ + void setPos(const Point &pt) { _pos = pt; } + + /** + * Sets the size of the cursor + */ + void setSize(const Point &size) { _size = size; } + + /** + * Returns the bounds for the cursor + */ + Rect getCursorBounds() const { + return Rect(_pos.x, _pos.y, _pos.x + _size.x, _pos.y + _size.y); + } + + /** + * Set bounds + */ + void setBounds(const Rect &r) { _screenBounds = r; } + + /** + * Clear the bounds + */ + void clearBounds() { _screenBounds.clear(); } + + /** + * Set the blinking rate + */ + void setBlinkRate(uint ticks) { _blinkDelay = ticks; } + + /** + * Set the cursor color + */ + void setColor(byte r, byte g, byte b); + + /** + * Returns whether the text cursor is active + */ + bool isActive() const { return _active; } + + int getMode() const { return _mode; } + + void setMode(int mode) { _mode = mode; } + + /** + * Show the text cursor + */ + void show(); + + /** + * Hide the text cursor + */ + void hide(); + + /** + * Update and draw the cursor if necessary + */ + void draw(); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_TEXT_CURSOR_H */ diff --git a/engines/titanic/support/time_event_info.cpp b/engines/titanic/support/time_event_info.cpp new file mode 100644 index 0000000000..0226223f1a --- /dev/null +++ b/engines/titanic/support/time_event_info.cpp @@ -0,0 +1,206 @@ +/* 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/time_event_info.h" +#include "titanic/core/game_object.h" +#include "titanic/core/project_item.h" +#include "titanic/messages/messages.h" + +namespace Titanic { + +void CTimeEventInfoList::postLoad(uint ticks, CProjectItem *project) { + for (iterator i = begin(); i != end(); ++i) + (*i)->postLoad(ticks, project); +} + +void CTimeEventInfoList::preSave(uint ticks) { + for (iterator i = begin(); i != end(); ++i) + (*i)->preSave(ticks); +} + +void CTimeEventInfoList::postSave() { + for (iterator i = begin(); i != end(); ++i) + (*i)->postSave(); +} + +void CTimeEventInfoList::update(uint ticks) { + // Remove any items that are done + for (iterator i = begin(); i != end(); ) { + CTimeEventInfo *item = *i; + if (item->_done) { + i = erase(i); + delete item; + } else { + ++i; + } + } + + // Handle updating the items + for (iterator i = begin(); i != end(); ) { + CTimeEventInfo *item = *i; + if (!item->update(ticks)) { + ++i; + } else { + i = erase(i); + delete item; + } + } +} + +void CTimeEventInfoList::stop(uint id) { + for (iterator i = begin(); i != end(); ++i) { + CTimeEventInfo *item = *i; + if (item->_id == id) { + item->_done = true; + return; + } + } +} + +void CTimeEventInfoList::setPersisent(uint id, bool flag) { + for (iterator i = begin(); i != end(); ++i) { + CTimeEventInfo *item = *i; + if (item->_id == id) { + item->setPersisent(flag); + return; + } + } +} + +/*------------------------------------------------------------------------*/ + +uint CTimeEventInfo::_nextId; + +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) { + _id = _nextId++; +} + +CTimeEventInfo::CTimeEventInfo(uint ticks, bool repeated, uint firstDuration, + uint repeatDuration, CTreeItem *target, int endVal, const CString &action) : + ListItem(), _lockCounter(0), _repeated(repeated), _firstDuration(firstDuration), + _repeatDuration(repeatDuration), _target(target), _actionVal(endVal), _done(false), + _timerCtr(0), _lastTimerTicks(ticks), _relativeTicks(0), _persisent(true) { + _id = _nextId++; +} + +void CTimeEventInfo::save(SimpleFile *file, int indent) { + file->writeNumberLine(0, indent); + + CString targetName; + if (_target) + targetName = _target->getName(); + file->writeQuotedLine(targetName, indent); + file->writeNumberLine(_id, indent); + file->writeNumberLine(_repeated, indent); + file->writeNumberLine(_firstDuration, indent); + file->writeNumberLine(_repeatDuration, indent); + file->writeNumberLine(_actionVal, indent); + file->writeQuotedLine(_action, indent); + file->writeNumberLine(_timerCtr, indent); + file->writeNumberLine(_relativeTicks, indent); + file->writeNumberLine(_done, indent); + file->writeNumberLine(_persisent, indent); +} + +void CTimeEventInfo::load(SimpleFile *file) { + lock(); + int val = file->readNumber(); + + if (!val) { + _targetName = file->readString(); + _id = file->readNumber(); + _repeated = file->readNumber(); + _firstDuration = file->readNumber(); + _repeatDuration = file->readNumber(); + _actionVal = file->readNumber(); + _action = file->readString(); + _timerCtr = file->readNumber(); + _relativeTicks = file->readNumber(); + _done = file->readNumber() != 0; + _persisent = file->readNumber() != 0; + _target = nullptr; + } +} + +void CTimeEventInfo::postLoad(uint ticks, CProjectItem *project) { + if (!_persisent || _targetName.empty()) + _done = true; + + // Get the timer's target + if (project) + _target = project->findByName(_targetName); + if (!_target) + _done = true; + + _lastTimerTicks = ticks + _relativeTicks; + if (_id >= _nextId) + _nextId = _id + 1; + + unlock(); +} + +void CTimeEventInfo::preSave(uint ticks) { + _relativeTicks = _lastTimerTicks - ticks; + lock(); +} + +void CTimeEventInfo::postSave() { + unlock(); +} + +bool CTimeEventInfo::update(uint ticks) { + if (_lockCounter) + return false; + + if (_timerCtr) { + if (ticks > (_lastTimerTicks + _repeatDuration)) { + ++_timerCtr; + _lastTimerTicks = ticks; + + if (_target) { + CTimerMsg timerMsg(ticks, _timerCtr, _actionVal, _action); + timerMsg.execute(_target); + } + } + } else { + if (ticks > (_lastTimerTicks + _firstDuration)) { + _timerCtr = 1; + _lastTimerTicks = ticks; + + if (_target) { + CTimerMsg timerMsg(ticks, _timerCtr, _actionVal, _action); + timerMsg.execute(_target); + } + + if (!_repeated) + // Event is done, and can be removed + return true; + } + } + + return false; +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/time_event_info.h b/engines/titanic/support/time_event_info.h new file mode 100644 index 0000000000..ebf5b54458 --- /dev/null +++ b/engines/titanic/support/time_event_info.h @@ -0,0 +1,138 @@ +/* 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_TIMER_H +#define TITANIC_TIMER_H + +#include "common/algorithm.h" +#include "titanic/core/list.h" + +namespace Titanic { + +class CTreeItem; +class CProjectItem; + +class CTimeEventInfo : public ListItem { +private: + /** + * Increments the counter + */ + void lock() { ++_lockCounter; } + + /** + * Called at the end of both post load and post save actions + */ + void unlock() { + _lockCounter = MAX(_lockCounter - 1, 0); + } +public: + static uint _nextId; +public: + int _lockCounter; + uint _id; + bool _repeated; + uint _firstDuration; + uint _repeatDuration; + CTreeItem *_target; + uint _actionVal; + CString _action; + uint _timerCtr; + uint _lastTimerTicks; + uint _relativeTicks; + bool _done; + bool _persisent; + CString _targetName; +public: + CLASSDEF; + CTimeEventInfo(); + CTimeEventInfo(uint ticks, bool repeated, uint firstDuration, uint repeatDuration, + CTreeItem *target, int endVal, const CString &action); + + /** + * Save the data for the class to file + */ + virtual void save(SimpleFile *file, int indent); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file); + + /** + * Called after loading a game has finished + */ + void postLoad(uint ticks, CProjectItem *project); + + /** + * Called when a game is about to be saved + */ + void preSave(uint ticks); + + /** + * Called when a game has finished being saved + */ + void postSave(); + + bool update(uint ticks); + + /** + * Flags whether the timer will be persisent across save & loads + */ + void setPersisent(bool val) { _persisent = val; } +}; + +class CTimeEventInfoList : public List<CTimeEventInfo> { +public: + /** + * Called after loading a game has finished + */ + void postLoad(uint ticks, CProjectItem *project); + + /** + * Called when a game is about to be saved + */ + void preSave(uint ticks); + + /** + * Called when a game has finished being saved + */ + void postSave(); + + /** + * Handles an update + */ + void update(uint ticks); + + /** + * Remove an item with the given Id + */ + void stop(uint id); + + /** + * Sets whether a timer with a given Id will be persisent across saves + */ + void setPersisent(uint id, bool flag); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_TIMER_H */ diff --git a/engines/titanic/support/video_surface.cpp b/engines/titanic/support/video_surface.cpp new file mode 100644 index 0000000000..594f660937 --- /dev/null +++ b/engines/titanic/support/video_surface.cpp @@ -0,0 +1,583 @@ +/* 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/video_surface.h" +#include "titanic/support/image_decoders.h" +#include "titanic/support/screen_manager.h" +#include "titanic/titanic.h" + +namespace Titanic { + +int CVideoSurface::_videoSurfaceCounter = 0; + +CVideoSurface::CVideoSurface(CScreenManager *screenManager) : + _screenManager(screenManager), _rawSurface(nullptr), _movie(nullptr), + _pendingLoad(false), _transBlitFlag(false), _fastBlitFlag(false), + _movieFrameSurface(nullptr), _transparencyMode(TRANS_DEFAULT), + _freeMovieSurface(DisposeAfterUse::NO), _hasFrame(true), _lockCount(0) { + _videoSurfaceNum = _videoSurfaceCounter++; +} + +CVideoSurface::~CVideoSurface() { + if (_ddSurface) + _videoSurfaceCounter -= freeSurface(); + --_videoSurfaceCounter; + + if (_freeMovieSurface == DisposeAfterUse::YES) + delete _movieFrameSurface; +} + +void CVideoSurface::setSurface(CScreenManager *screenManager, DirectDrawSurface *surface) { + _screenManager = screenManager; + _ddSurface = surface; +} + +void CVideoSurface::blitFrom(const Point &destPos, CVideoSurface *src, const Rect *srcRect) { + if (loadIfReady() && src->loadIfReady() && _ddSurface && src->_ddSurface) { + Rect srcBounds, destBounds; + clipBounds(srcBounds, destBounds, src, srcRect, &destPos); + + if (src->_transBlitFlag) + blitRect2(srcBounds, destBounds, src); + else + blitRect1(srcBounds, destBounds, src); + } +} + +void CVideoSurface::blitFrom(const Point &destPos, const Graphics::Surface *src) { + lock(); + _rawSurface->blitFrom(*src, destPos); + unlock(); +} + +void CVideoSurface::clipBounds(Rect &srcRect, Rect &destRect, + CVideoSurface *srcSurface, const Rect *subRect, const Point *destPos) { + // Figure out initial source rect and dest rect, based on whether + // specific subRect and/or destPos have been passed + if (destPos) { + destRect.left = destPos->x; + destRect.top = destPos->y; + } else { + destRect.left = destRect.top = 0; + } + + if (subRect) { + destRect.right = destRect.left + subRect->width(); + destRect.bottom = destRect.top + subRect->height(); + srcRect = *subRect; + } else { + srcRect.right = srcRect.left + srcSurface->getWidth(); + srcRect.bottom = srcRect.top + srcSurface->getHeight(); + srcRect = Rect(0, 0, srcSurface->getWidth(), srcSurface->getHeight()); + } + + // Clip destination rect to be on-screen + if (destRect.left < 0) { + srcRect.left -= destRect.left; + destRect.left = 0; + } + if (destRect.top < 0) { + srcRect.top -= destRect.top; + destRect.top = 0; + } + if (destRect.right > getWidth()) { + srcRect.right += getWidth() - destRect.right; + destRect.right = getWidth(); + } + if (destRect.bottom > getHeight()) { + srcRect.bottom += getHeight() - destRect.bottom; + destRect.bottom = getHeight(); + } + + // Clip source rect to be within the source surface + if (srcRect.left < 0) { + destRect.left -= srcRect.left; + srcRect.left = 0; + } + if (srcRect.top < 0) { + destRect.top -= srcRect.top; + srcRect.top = 0; + } + if (srcRect.right > srcSurface->getWidth()) { + destRect.right += srcSurface->getWidth() - srcRect.right; + srcRect.right = srcSurface->getWidth(); + } + if (srcRect.bottom > srcSurface->getHeight()) { + destRect.bottom += srcSurface->getHeight() - srcRect.bottom; + srcRect.bottom = srcSurface->getHeight(); + } + + // Validate that the resulting rects are valid + if (destRect.left >= destRect.right || destRect.top >= destRect.bottom + || srcRect.left >= srcRect.right || srcRect.top >= srcRect.bottom) + error("Invalid rect"); +} + +void CVideoSurface::blitRect1(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 (getMovieFrameSurface()) { + movieBlitRect(srcRect, destRect, src); + } else { + _rawSurface->transBlitFrom(*src->_rawSurface, srcRect, destRect, src->getTransparencyColor()); + } + + src->unlock(); + unlock(); +} + +void CVideoSurface::blitRect2(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { + if (getMovieFrameSurface()) { + movieBlitRect(srcRect, destRect, src); + } else { + src->lock(); + lock(); + + _rawSurface->blitFrom(*src->_rawSurface, srcRect, Point(destRect.left, destRect.top)); + + src->unlock(); + unlock(); + } +} + +void CVideoSurface::movieBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) { + // TODO +} + +uint CVideoSurface::getTransparencyColor() { + uint32 val = -(getPixelDepth() - 2); + val &= 0xFFFF8400; + val += 0xF81F; + return val; +} + +bool CVideoSurface::hasFrame() { + if (_hasFrame) { + _hasFrame = false; + return true; + } else if (_movie) { + return _movie->hasVideoFrame(); + } else { + return false; + } +} + +/*------------------------------------------------------------------------*/ + +byte OSVideoSurface::_palette1[32][32]; +byte OSVideoSurface::_palette2[32][32]; + +OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, DirectDrawSurface *surface) : + CVideoSurface(screenManager) { + _ddSurface = surface; +} + +OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, const CResourceKey &key, bool pendingLoad) : + CVideoSurface(screenManager) { + _ddSurface = nullptr; + _pendingLoad = pendingLoad; + + if (_pendingLoad) { + loadResource(key); + } else { + _resourceKey = key; + load(); + } +} + +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; + + if (hasSurface()) + load(); +} + +void OSVideoSurface::loadTarga(const CResourceKey &key) { + // Decode the image + CTargaDecode decoder; + decoder.decode(*this, key.getString()); + + if (getPixelDepth() == 2) + shiftColors(); + + _resourceKey = key; + +} + +void OSVideoSurface::loadJPEG(const CResourceKey &key) { + // Decode the image + CJPEGDecode decoder; + decoder.decode(*this, key.getString()); + + if (getPixelDepth() == 2) + shiftColors(); + + _resourceKey = key; +} + +void OSVideoSurface::loadTarga(const CString &name) { + CResourceKey key(name); + loadTarga(key); +} + +void OSVideoSurface::loadMovie(const CResourceKey &key, bool destroyFlag) { + // Delete any prior movie + if (_movie) { + delete _movie; + _movie = nullptr; + } + + // Create the new movie and load the first frame to the video surface + _movie = g_vm->_movieManager.createMovie(key, this); + _movie->setFrame(0); + + // If flagged to destroy, then immediately destroy movie instance + if (destroyFlag) { + delete _movie; + _movie = nullptr; + } + + _resourceKey = key; +} + +bool OSVideoSurface::lock() { + if (!loadIfReady()) + return false; + + ++_lockCount; + _rawSurface = _ddSurface->lock(nullptr, 0); + return true; +} + +void OSVideoSurface::unlock() { + if (!--_lockCount) { + if (_rawSurface) + _ddSurface->unlock(); + _rawSurface = nullptr; + } +} + +bool OSVideoSurface::hasSurface() { + return _ddSurface != nullptr; +} + +int OSVideoSurface::getWidth() { + if (!loadIfReady()) + error("Could not load resource"); + + return _ddSurface->getWidth(); +} + +int OSVideoSurface::getHeight() { + if (!loadIfReady()) + error("Could not load resource"); + + return _ddSurface->getHeight(); +} + +int OSVideoSurface::getPitch() { + if (!loadIfReady()) + error("Could not load resource"); + + return _ddSurface->getPitch(); +} + +int OSVideoSurface::getBpp() { + if (!loadIfReady()) + error("Could not load resource"); + + return getPixelDepth(); +} + +void OSVideoSurface::recreate(int width, int height) { + freeSurface(); + + _screenManager->resizeSurface(this, width, height); + if (_ddSurface) + _videoSurfaceCounter += _ddSurface->getSize(); +} + +void OSVideoSurface::resize(int width, int height) { + if (!_ddSurface || _ddSurface->getWidth() != width || + _ddSurface->getHeight() != height) + recreate(width, height); +} + +void OSVideoSurface::detachSurface() { + _ddSurface = nullptr; +} + +int OSVideoSurface::getPixelDepth() { + if (!loadIfReady()) + 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 + result = 0; + + unlock(); + return result; +} + +bool OSVideoSurface::load() { + if (!_resourceKey.scanForFile()) + return false; + + switch (_resourceKey.fileTypeSuffix()) { + case FILETYPE_IMAGE: + switch (_resourceKey.imageTypeSuffix()) { + case IMAGETYPE_TARGA: + loadTarga(_resourceKey); + break; + case IMAGETYPE_JPEG: + loadJPEG(_resourceKey); + break; + default: + break; + } + return true; + + case FILETYPE_MOVIE: + loadMovie(_resourceKey); + return true; + + default: + return false; + } +} + +uint16 OSVideoSurface::getPixel(const Common::Point &pt) { + if (!loadIfReady()) + return 0; + + if (pt.x >= 0 && pt.y >= 0 && pt.x < getWidth() && pt.y < getHeight()) { + lock(); + uint16 pixel = *(uint16 *)_rawSurface->getBasePtr(pt.x, pt.y); + unlock(); + return pixel; + } else { + return getTransparencyColor(); + } +} + +void OSVideoSurface::setPixel(const Point &pt, uint pixel) { + assert(getPixelDepth() == 2); + + uint16 *pixelP = (uint16 *)_rawSurface->getBasePtr(pt.x, pt.y); + *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; + + // Currently no further processing is needed, since for ScummVM, + // we already convert 16-bit surfaces as soon as they're loaded +} + +void OSVideoSurface::clear() { + if (!loadIfReady()) + error("Could not load resource"); + +} + +void OSVideoSurface::playMovie(uint flags, CGameObject *obj) { + if (loadIfReady() && _movie) + _movie->play(flags, obj); + + _ddSurface->fill(nullptr, 0); +} + +void OSVideoSurface::playMovie(uint startFrame, uint endFrame, uint flags, CGameObject *obj) { + if (loadIfReady() && _movie) { + _movie->play(startFrame, endFrame, flags, obj); + } +} + +void OSVideoSurface::playMovie(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) { + if (loadIfReady() && _movie) { + _movie->play(startFrame, endFrame, initialFrame, flags, obj); + } +} + +void OSVideoSurface::stopMovie() { + if (_movie) + _movie->stop(); +} + +void OSVideoSurface::setMovieFrame(uint frameNumber) { + if (loadIfReady() && _movie) + _movie->setFrame(frameNumber); +} + +void OSVideoSurface::addMovieEvent(int frameNumber, CGameObject *obj) { + if (_movie) + _movie->addEvent(frameNumber, obj); +} + +void OSVideoSurface::setMovieFrameRate(double rate) { + if (_movie) + _movie->setFrameRate(rate); +} + +const CMovieRangeInfoList *OSVideoSurface::getMovieRangeInfo() const { + return _movie ? _movie->getMovieRangeInfo() : nullptr; +} + +void OSVideoSurface::flipVertically(bool needsLock) { + if (!loadIfReady() || !_transBlitFlag) + return; + + if (needsLock) + lock(); + + byte lineBuffer[SCREEN_WIDTH * 2]; + int pitch = getBpp() * getWidth(); + assert(pitch < (SCREEN_WIDTH * 2)); + + for (int yp = 0; yp < (_rawSurface->h / 2); ++yp) { + byte *line1P = (byte *)_rawSurface->getBasePtr(0, yp); + byte *line2P = (byte *)_rawSurface->getBasePtr(0, _rawSurface->h - yp - 1); + + Common::copy(line1P, line1P + pitch, lineBuffer); + Common::copy(line2P, line2P + pitch, line1P); + Common::copy(lineBuffer, lineBuffer + pitch, line1P); + } + + _transBlitFlag = false; + if (needsLock) + unlock(); +} + +bool OSVideoSurface::loadIfReady() { + _videoSurfaceNum = _videoSurfaceCounter; + + if (hasSurface()) { + return true; + } else if (_pendingLoad) { + _hasFrame = true; + load(); + return true; + } else { + return false; + } +} + +void OSVideoSurface::transPixelate() { + if (!loadIfReady()) + return; + + lock(); + Graphics::ManagedSurface *surface = _rawSurface; + uint transColor = getTransparencyColor(); + // TODO: Check whether color is correct + uint pixelColor = surface->format.RGBToColor(0x50, 0, 0); + + for (int yp = 0; yp < surface->h; ++yp) { + uint16 *pixelsP = (uint16 *)surface->getBasePtr(0, yp); + bool bitFlag = (yp % 2) == 0; + int replaceCtr = yp & 3; + + for (int xp = 0; xp < surface->w; ++xp, ++pixelsP) { + if (bitFlag && *pixelsP == transColor && replaceCtr == 0) + *pixelsP = pixelColor; + + bitFlag = !bitFlag; + replaceCtr = (replaceCtr + 1) & 3; + } + } + + surface->markAllDirty(); + unlock(); +} + +Graphics::ManagedSurface *OSVideoSurface::dupMovieFrame() const { + return _movie ? _movie->duplicateFrame() : nullptr; +} + +int OSVideoSurface::freeSurface() { + if (!_ddSurface) + return 0; + int surfaceSize = _ddSurface->getSize(); + + delete _movie; + _movie = nullptr; + delete _ddSurface; + _ddSurface = nullptr; + + return surfaceSize; +} + +uint16 *OSVideoSurface::getBasePtr(int x, int y) { + assert(_rawSurface); + return (uint16 *)_rawSurface->getBasePtr(x, y); +} + +} // End of namespace Titanic diff --git a/engines/titanic/support/video_surface.h b/engines/titanic/support/video_surface.h new file mode 100644 index 0000000000..053eabb0f9 --- /dev/null +++ b/engines/titanic/support/video_surface.h @@ -0,0 +1,537 @@ +/* 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_VIDEO_SURFACE_H +#define TITANIC_VIDEO_SURFACE_H + +#include "common/scummsys.h" +#include "common/array.h" +#include "graphics/managed_surface.h" +#include "titanic/support/font.h" +#include "titanic/support/direct_draw.h" +#include "titanic/support/movie.h" +#include "titanic/support/movie_range_info.h" +#include "titanic/support/rect.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; + +class CVideoSurface : public ListItem { + friend class CJPEGDecode; + friend class CTargaDecode; +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 movieBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src); +protected: + static int _videoSurfaceCounter; +protected: + CScreenManager *_screenManager; + Graphics::ManagedSurface *_rawSurface; + bool _pendingLoad; + Graphics::ManagedSurface *_movieFrameSurface; + DisposeAfterUse::Flag _freeMovieSurface; + int _videoSurfaceNum; + bool _hasFrame; + int _lockCount; +public: + CMovie *_movie; + DirectDrawSurface *_ddSurface; + bool _fastBlitFlag; + bool _transBlitFlag; + CResourceKey _resourceKey; + TransparencyMode _transparencyMode; +public: + CVideoSurface(CScreenManager *screenManager); + virtual ~CVideoSurface(); + + /** + * Set the underlying surface for this video surface + */ + void setSurface(CScreenManager *screenManager, DirectDrawSurface *surface); + + /** + * Load the data for the class from file + */ + virtual void load(SimpleFile *file) { + ListItem::load(file); + } + + /** + * Load the surface with the passed resource + */ + virtual void loadResource(const CResourceKey &key) = 0; + + /** + * Loads a Targa image file specified by the resource key + */ + virtual void loadTarga(const CResourceKey &key) = 0; + + /** + * Loads a JPEG image file specified by the resource key + */ + virtual void loadJPEG(const CResourceKey &key) = 0; + + /** + * Loads a Targa image file specified by the given name + */ + virtual void loadTarga(const CString &name) = 0; + + /** + * Loads a movie file specified by the resource key. + * @param key Resource key for movie to load + * @param destroyFlag Immediately destroy movie after decoding first frame + */ + virtual void loadMovie(const CResourceKey &key, bool destroyFlag = false) = 0; + + /** + * Lock the surface for direct access to the pixels + */ + virtual bool lock() = 0; + + /** + * Unlocks the surface after prior calls to lock() + */ + virtual void unlock() = 0; + + /** + * Returns true if an underlying raw surface has been set + */ + virtual bool hasSurface() = 0; + + /** + * Returns the width of the surface + */ + virtual int getWidth() = 0; + + /** + * Returns the height of the surface + */ + virtual int getHeight() = 0; + + /** + * Returns the pitch of the surface in bytes + */ + virtual int getPitch() = 0; + + /** + * Returns the bytes per pixel of the surface + */ + virtual int getBpp() = 0; + + /** + * Recreates the surface + */ + virtual void recreate(int width, int height) = 0; + + /** + * Resizes the surface + */ + virtual void resize(int width, int height) = 0; + + /** + * Detachs the underlying raw surface + */ + virtual void detachSurface() = 0; + + /** + * Returns the number of bytes per pixel in the surface + */ + virtual int getPixelDepth() = 0; + + /** + * Gets the pixel at the specified position within the surface + */ + virtual uint16 getPixel(const Common::Point &pt) = 0; + + + /** + * Sets a pixel at a specified position within the surface + */ + 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; + + /** + * Clears the entire surface to black + */ + virtual void clear() = 0; + + /** + * Plays a movie, loading it from the specified _resource + * if not already loaded + */ + virtual void playMovie(uint flags, CGameObject *obj) = 0; + + /** + * Plays a movie, loading it from the specified _resource + * if not already loaded + */ + virtual void playMovie(uint startFrame, uint endFrame, uint flags, CGameObject *obj) = 0; + + /** + * Plays a movie, loading it from the specified _resource + * if not already loaded + */ + virtual void playMovie(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) = 0; + + /** + * Stops any movie currently attached to the surface + */ + virtual void stopMovie() = 0; + + /** + * Set the current movie frame number + */ + virtual void setMovieFrame(uint frameNumber) = 0; + + /** + * Adds a movie playback event + */ + virtual void addMovieEvent(int eventId, CGameObject *obj) = 0; + + /** + * Set the movie frame rate + */ + virtual void setMovieFrameRate(double rate) = 0; + + /** + * Return any movie range info associated with the surface's movie + */ + virtual const CMovieRangeInfoList *getMovieRangeInfo() const = 0; + + /** + * + */ + virtual void flipVertically(bool needsLock = true) = 0; + + /** + * Loads the surface's resource if there's one pending + */ + virtual bool loadIfReady() = 0; + + /** + * Loads the surface data based on the currently set resource key + */ + virtual bool load() = 0; + + /** + * Does a replacement of transparent pixels on certain lines at regular + * intervals. This is totally weird + */ + virtual void transPixelate() = 0; + + /** + * Returns true if there's a frame to display on the video surface + */ + virtual bool hasFrame(); + + /** + * Duplicates movie frame surface + */ + virtual Graphics::ManagedSurface *dupMovieFrame() const = 0; + + /** + * Frees the underlying surface + */ + virtual int freeSurface() { return 0; } + + /** + * Get a pointer into the underlying surface + */ + virtual uint16 *getBasePtr(int x, int y) = 0; + + /** + * Blit from another surface + */ + void blitFrom(const Point &destPos, CVideoSurface *src, const Rect *srcRect = nullptr); + + /** + * Blit from another surface + */ + void blitFrom(const Point &destPos, const Graphics::Surface *src); + + /** + * Sets the movie frame surface containing frame data from an active movie + */ + void setMovieFrameSurface(Graphics::ManagedSurface *frameSurface) { _movieFrameSurface = frameSurface; } + + /** + * Get the previously set movie frame surface + */ + Graphics::ManagedSurface *getMovieFrameSurface() const { return _movieFrameSurface; } + + /** + * Get the pixels associated with the surface. Only valid when the + * surface has been locked for access + */ + uint16 *getPixels() { return (uint16 *)_rawSurface->getPixels(); } + + /** + * Get a reference to the underlying surface. Only valid when the surface + * has been locked for access + */ + Graphics::ManagedSurface *getRawSurface() { return _rawSurface; } + + /** + * Returns the transparent color + */ + uint getTransparencyColor(); +}; + +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); + + /** + * Load the surface with the passed resource + */ + virtual void loadResource(const CResourceKey &key); + + /** + * Loads a Targa image file specified by the resource key + */ + virtual void loadTarga(const CResourceKey &key); + + /** + * Loads a JPEG image file specified by the resource key + */ + virtual void loadJPEG(const CResourceKey &key); + + /** + * Loads a Targa image file specified by the given name + */ + virtual void loadTarga(const CString &name); + + /** + * Loads a movie file specified by the resource key. + * @param key Resource key for movie to load + * @param destroyFlag Immediately destroy movie after decoding first frame + */ + virtual void loadMovie(const CResourceKey &key, bool destroyFlag = false); + + /** + * Lock the surface for direct access to the pixels + */ + virtual bool lock(); + + /** + * Unlocks the surface after prior calls to lock() + */ + virtual void unlock(); + + /** + * Returns true if an underlying raw surface has been set + */ + virtual bool hasSurface(); + + /** + * Returns the width of the surface + */ + virtual int getWidth(); + + /** + * Returns the height of the surface + */ + virtual int getHeight(); + + /** + * Returns the pitch of the surface in bytes + */ + virtual int getPitch(); + + /** + * Returns the bytes per pixel of the surface + */ + virtual int getBpp(); + + /** + * Recreates the surface with the designated size + */ + virtual void recreate(int width, int height); + + /** + * Resizes the surface + */ + virtual void resize(int width, int height); + + /** + * Detachs the underlying raw surface + */ + virtual void detachSurface(); + + /** + * Returns the number of bytes per pixel in the surface + */ + virtual int getPixelDepth(); + + /** + * Gets the pixel at the specified position within the surface + */ + virtual uint16 getPixel(const Point &pt); + + /** + * Sets a pixel at a specified position within the surface + */ + 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(); + + /** + * Clears the entire surface to black + */ + virtual void clear(); + + /** + * Plays a movie, loading it from the specified _resource + * if not already loaded + */ + virtual void playMovie(uint flags, CGameObject *obj); + + /** + * Plays a movie, loading it from the specified _resource + * if not already loaded + */ + virtual void playMovie(uint startFrame, uint endFrame, uint flags, CGameObject *obj); + + /** + * Plays a movie, loading it from the specified _resource + * if not already loaded + */ + virtual void playMovie(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj); + + /** + * Stops any movie currently attached to the surface + */ + virtual void stopMovie(); + + /** + * Sets the movie to the specified frame number + */ + virtual void setMovieFrame(uint frameNumber); + + /** + * Adds a movie playback event + */ + virtual void addMovieEvent(int frameNumber, CGameObject *obj); + + /** + * Set the movie frame rate + */ + virtual void setMovieFrameRate(double rate); + + /** + * Return any movie range info associated with the surface's movie + */ + virtual const CMovieRangeInfoList *getMovieRangeInfo() const; + + /** + * + */ + virtual void flipVertically(bool needsLock = true); + + /** + * Loads the surface's resource if there's one pending + */ + virtual bool loadIfReady(); + + /** + * Loads the surface data based on the currently set resource key + */ + virtual bool load(); + + /** + * Does a replacement of transparent pixels on certain lines at regular + * intervals. This is totally weird + */ + virtual void transPixelate(); + + /** + * Duplicates movie frame surface + */ + virtual Graphics::ManagedSurface *dupMovieFrame() const; + + + /** + * Frees the underlying surface + */ + virtual int freeSurface(); + + /** + * Get a pointer into the underlying surface + */ + virtual uint16 *getBasePtr(int x, int y); +}; + +} // End of namespace Titanic + +#endif /* TITANIC_VIDEO_SURFACE_H */ |