Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,575 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/avi_surface.h"
#include "titanic/support/screen_manager.h"
#include "titanic/support/video_surface.h"
#include "titanic/events.h"
#include "titanic/titanic.h"
#include "common/system.h"
#include "graphics/pixelformat.h"
#include "graphics/screen.h"
#include "video/avi_decoder.h"
#include "titanic/translation.h"
namespace Titanic {
#define DEFAULT_FPS 15.0
Video::AVIDecoder::AVIVideoTrack &AVIDecoder::getVideoTrack(uint idx) {
assert(idx < _videoTracks.size());
AVIVideoTrack *track = static_cast<AVIVideoTrack *>(_videoTracks[idx].track);
return *track;
}
AVISurface::AVISurface(const CResourceKey &key) : _movieName(key.getString()) {
_videoSurface = nullptr;
_streamCount = 0;
_movieFrameSurface[0] = _movieFrameSurface[1] = nullptr;
_framePixels = false;
_priorFrameTime = 0;
// Reset current frame. We need to keep track of frames separately from the decoder,
// since it needs to be able to go beyond the frame count or to negative to allow
// correct detection of when range playbacks have finished
_currentFrame = -1;
_priorFrame = -1;
// Create a decoder
_decoder = new AVIDecoder();
// Load the video into it
if (_movieName == TRANSLATE("y222.avi", "y237.avi")) {
// The y222.avi is the bells animation for the music room.
// It needs on the fly fixing for the video header
_decoder->loadStream(new y222());
} else if (!_decoder->loadFile(Common::Path(_movieName))) {
error("Could not open video - %s", key.getString().c_str());
}
_streamCount = _decoder->getTransparencyTrack() ? 2 : 1;
_soundManager = nullptr;
_hasAudio = false;
_frameRate = DEFAULT_FPS;
}
AVISurface::~AVISurface() {
if (_videoSurface)
_videoSurface->_flipVertically = false;
delete _movieFrameSurface[0];
delete _movieFrameSurface[1];
delete _decoder;
}
bool AVISurface::play(uint flags, CGameObject *obj) {
if (flags & MOVIE_REVERSE)
return play(_decoder->getFrameCount() - 1, 0, flags, obj);
else
return play(0, _decoder->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
bool isReversePlayback = _movieRangeInfo.front()->_endFrame < _movieRangeInfo.front()->_startFrame;
if (isReversed() != isReversePlayback)
setFrameRate(isReversePlayback ? -DEFAULT_FPS : DEFAULT_FPS);
return startAtFrame(initialFrame);
} else {
return true;
}
}
void AVISurface::stop() {
_decoder->stop();
_movieRangeInfo.destroyContents();
}
void AVISurface::pause() {
_decoder->pauseVideo(true);
}
void AVISurface::resume() {
if (_decoder->isPaused())
_decoder->pauseVideo(false);
}
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;
if (frameNumber == (int)_decoder->getFrameCount())
--frameNumber;
// Start the playback
_decoder->start();
// Seek to the starting frame
_currentFrame = -1;
seekToFrame(frameNumber);
// If we're in reverse playback, set the decoder to play in reverse
if (isReversed())
_decoder->setReverse(true);
setFrameRate(_frameRate);
// Render the first frame
renderFrame();
return true;
}
void AVISurface::seekToFrame(uint frameNumber) {
if (isReversed() && frameNumber == _decoder->getFrameCount())
--frameNumber;
if ((int)frameNumber != _currentFrame) {
if (!isReversed() && frameNumber > 0) {
_decoder->seekToFrame(frameNumber - 1);
renderFrame();
}
_decoder->seekToFrame(frameNumber);
_currentFrame = _priorFrame = (int)frameNumber;
}
}
bool AVISurface::handleEvents(CMovieEventList &events) {
if (!isPlaying())
return true;
CMovieRangeInfo *info = _movieRangeInfo.front();
_priorFrame = _currentFrame;
_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;
bool reversed = info->_endFrame < info->_startFrame;
if (isReversed() != reversed)
// Direction is different, so force frame seek below
_priorFrame = -1;
// Set the next clip's direction
setFrameRate(reversed ? -DEFAULT_FPS : DEFAULT_FPS);
}
}
}
if (isPlaying()) {
if (newFrame != getFrame())
// The frame has been changed, so move to new position
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 (_streamCount == 2) {
const Common::String &streamName = _decoder->getTransparencyTrack()->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() {
if (!_decoder)
return;
for (int idx = 0; idx < _streamCount; ++idx) {
Graphics::PixelFormat format = (idx == 0) ?
_decoder->getVideoTrack(0).getPixelFormat() :
_decoder->getTransparencyTrack()->getPixelFormat();
int decoderPitch = _decoder->getWidth() * format.bytesPerPixel;
bool flag = false;
if (idx == 0 && _videoSurface && _videoSurface->getPitch() == decoderPitch) {
const uint bitCount = _decoder->getVideoTrack(0).getBitCount();
const int vDepth = _videoSurface->getPixelDepth();
switch (bitCount) {
case 15:
flag = vDepth == 1;
break;
case 16:
flag = vDepth == 1 || vDepth == 2;
break;
case 24:
flag = vDepth == 3;
break;
default:
break;
}
}
if (!flag) {
_framePixels = true;
} else if (idx == 0) {
// The original developers used a vertical flipped playback to indicate
// an incompatibility between source video and dest surface bit-depths,
// which would result in poor playback performance
_videoSurface->_flipVertically = true;
}
}
// Set a default frame rate
_frameRate = DEFAULT_FPS;
}
void AVISurface::copyMovieFrame(const Graphics::Surface &src, Graphics::ManagedSurface &dest) {
// WORKAROUND: Handle rare cases where frame sizes don't match the video size
Common::Rect copyRect(0, 0, MIN(src.w, dest.w), MIN(src.h, dest.h));
if (src.format.bytesPerPixel == 1) {
// Paletted 8-bit, so convert to 16-bit and copy over
const byte *palette = _decoder->getPalette();
if (palette) {
Graphics::Surface *s = src.convertTo(dest.format, palette);
dest.blitFrom(*s, copyRect, Common::Point(0, 0));
s->free();
delete s;
}
} else if ((src.format.bytesPerPixel == 2) || (src.format.bytesPerPixel == 3)) {
// Source is 16-bit or 24-bit, with no alpha, so do a straight copy
dest.blitFrom(src, copyRect, Common::Point(0, 0));
} else {
// Source is 32-bit which may have transparent pixels. Copy over each
// pixel, replacing transparent pixels with the special transparency color
byte a, r, g, b;
assert(src.format.bytesPerPixel == 4 && dest.format.bytesPerPixel == 2);
uint16 transPixel = _videoSurface->getTransparencyColor();
for (uint y = 0; y < (uint)MIN(src.h, dest.h); ++y) {
const uint32 *pSrc = (const uint32 *)src.getBasePtr(0, y);
uint16 *pDest = (uint16 *)dest.getBasePtr(0, y);
for (uint x = 0; x < (uint)MIN(src.w, dest.w); ++x, ++pSrc, ++pDest) {
src.format.colorToARGB(*pSrc, a, r, g, b);
assert(a == 0 || a == 0xff);
*pDest = (a == 0 && _streamCount == 1) ? transPixel : dest.format.RGBToColor(r, g, b);
}
}
}
}
uint AVISurface::getWidth() const {
return _decoder->getWidth();
}
uint AVISurface::getHeight() const {
return _decoder->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)_decoder->getFrameCount())
frameNumber = _decoder->getFrameCount() - 1;
seekToFrame(frameNumber);
renderFrame();
}
bool AVISurface::isNextFrame() {
if (!_decoder->endOfVideo())
return _decoder->getTimeToNextFrame() == 0;
// We're at the end of the video, so we need to manually
// keep track of frame delays.
const uint FRAME_TIME = 1000 / DEFAULT_FPS;
uint32 currTime = g_system->getMillis();
if (currTime >= (_priorFrameTime + FRAME_TIME)) {
_priorFrameTime = currTime;
return true;
}
return false;
}
bool AVISurface::renderFrame() {
// Check there's a frame ready for display
if (!_decoder->needsUpdate())
return false;
// Make a copy of each decoder's video frame
for (int idx = 0; idx < _streamCount; ++idx) {
const Graphics::Surface *frame;
if (idx == 0) {
frame = _decoder->decodeNextFrame();
if (!_movieFrameSurface[0])
_movieFrameSurface[0] = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(),
g_system->getScreenFormat());
copyMovieFrame(*frame, *_movieFrameSurface[0]);
} else {
frame = _decoder->decodeNextTransparency();
if (!_movieFrameSurface[1])
_movieFrameSurface[1] = new Graphics::ManagedSurface(_decoder->getWidth(), _decoder->getHeight(),
Graphics::PixelFormat::createFormatCLUT8());
_movieFrameSurface[1]->blitFrom(*frame);
}
}
if (!_framePixels) {
if (_videoSurface->lock()) {
// Blit the frame directly to the video surface
assert(_streamCount == 1);
_videoSurface->blitFrom(Point(0, 0), &_movieFrameSurface[0]->rawSurface());
_videoSurface->unlock();
}
} else {
const Graphics::Surface &frameSurface = _movieFrameSurface[0]->rawSurface();
_videoSurface->lock();
if (frameSurface.format.bytesPerPixel == 1) {
// For paletted 8-bit surfaces, we need to convert it to 16-bit,
// since the blitting method we're using doesn't support palettes
Graphics::Surface *s = frameSurface.convertTo(g_system->getScreenFormat(),
_decoder->getPalette());
_videoSurface->getRawSurface()->blitFrom(*s);
s->free();
delete s;
} else {
_videoSurface->getRawSurface()->blitFrom(frameSurface);
}
_videoSurface->unlock();
}
return false;
}
bool AVISurface::addEvent(int *frameNumber, CGameObject *obj) {
if (!_movieRangeInfo.empty()) {
CMovieRangeInfo *tail = _movieRangeInfo.back();
assert(frameNumber);
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) {
// Store the new frame rate
_frameRate = rate;
if (_decoder->isPlaying()) {
// Convert rate from fps to relative to 1.0 (normal speed)
const int PRECISION = 10000;
double playRate = rate / DEFAULT_FPS;
Common::Rational pRate((int)(playRate * PRECISION), PRECISION);
_decoder->setRate(pRate);
}
}
Graphics::ManagedSurface *AVISurface::getSecondarySurface() {
return _streamCount <= 1 ? nullptr : _movieFrameSurface[1];
}
Graphics::ManagedSurface *AVISurface::duplicateTransparency() const {
if (_streamCount <= 1) {
return nullptr;
} else {
Graphics::ManagedSurface *dest = new Graphics::ManagedSurface(_movieFrameSurface[1]->w,
_movieFrameSurface[1]->h, Graphics::PixelFormat::createFormatCLUT8());
dest->blitFrom(*_movieFrameSurface[1]);
return dest;
}
}
bool AVISurface::playCutscene(const Rect &r, uint startFrame, uint endFrame) {
if (g_vm->shouldQuit())
return false;
// TODO: Fixes slight "jumping back" when rotating in place in Top Of Well
// balcony between two elevators. Need a more generalized fix at some point
if (_movieName == "z48.avi")
_currentFrame = -1;
if (_currentFrame != ((int)startFrame - 1) || startFrame == 0) {
// Start video playback at the desired starting frame
if (startFrame > 0) {
// Give a chance for a key frame just prior to the start frame
// to be loaded first
setFrame(startFrame - 1);
}
setFrame(startFrame);
startAtFrame(startFrame);
_currentFrame = startFrame;
} else {
// Already in position, so pick up where we left off
_decoder->start();
}
bool isDifferent = _movieFrameSurface[0]->w != r.width() ||
_movieFrameSurface[0]->h != r.height();
bool isFinished = true;
while (_currentFrame < (int)endFrame && !g_vm->shouldQuit()) {
if (isNextFrame()) {
renderFrame();
++_currentFrame;
if (isDifferent) {
// Clear the destination area, and use the transBlitFrom method,
// which supports arbitrary scaling, to reduce to the desired size
g_vm->_screen->fillRect(r, 0);
g_vm->_screen->transBlitFrom(*_movieFrameSurface[0],
Common::Rect(0, 0, _movieFrameSurface[0]->w, _movieFrameSurface[0]->h), r);
} else {
g_vm->_screen->blitFrom(*_movieFrameSurface[0], Common::Point(r.left, r.top));
}
g_vm->_screen->update();
g_vm->_events->pollEvents();
}
// Brief wait, and check at the same time for clicks to abort the clip
if (g_vm->_events->waitForPress(10)) {
isFinished = false;
break;
}
}
stop();
return isFinished && !g_vm->shouldQuit();
}
uint AVISurface::getBitDepth() const {
return _decoder->getVideoTrack(0).getBitCount();
}
/*------------------------------------------------------------------------*/
y222::y222() {
_innerStream = new File();
_innerStream->open(TRANSLATE("y222.avi", "y237.avi"));
}
y222::~y222() {
delete _innerStream;
}
uint32 y222::read(void *dataPtr, uint32 dataSize) {
int32 currPos = pos();
uint32 bytesRead = _innerStream->read(dataPtr, dataSize);
if (currPos <= 48 && (currPos + bytesRead) >= 52) {
byte *framesP = (byte *)dataPtr + (48 - currPos);
if (READ_LE_UINT32(framesP) == 1)
WRITE_LE_UINT32(framesP, 1085);
}
return bytesRead;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,273 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_AVI_SURFACE_H
#define TITANIC_AVI_SURFACE_H
#include "common/stream.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, // Repeat movie
MOVIE_STOP_PREVIOUS = 2, // Stop any prior movie playing on the object
MOVIE_NOTIFY_OBJECT = 4, // Notify the object when the movie finishes
MOVIE_REVERSE = 8, // Play the movie in reverse
MOVIE_WAIT_FOR_FINISH = 0x10 // Let finish before playing next movie for object
};
/**
* This implements a special read stream for the y222.avi video
* that fixes that totalFrames field of the header from it's
* incorrect value of 1 to a correct 1085.
*/
class y222 : virtual public Common::SeekableReadStream {
private:
File *_innerStream;
public:
y222();
~y222() override;
uint32 read(void *dataPtr, uint32 dataSize) override;
bool eos() const override { return _innerStream->eos(); }
int64 pos() const override { return _innerStream->pos(); }
int64 size() const override { return _innerStream->size(); }
bool seek(int64 offset, int whence = SEEK_SET) override {
return _innerStream->seek(offset, whence);
}
bool skip(uint32 offset) override {
return _innerStream->skip(offset);
}
char *readLine(char *s, size_t bufSize, bool handleCR = true) override {
return _innerStream->readLine(s, bufSize, handleCR);
}
Common::String readLine(bool handleCR = true) override {
return _innerStream->readLine(handleCR);
}
};
class AVIDecoder : public Video::AVIDecoder {
public:
AVIDecoder() {}
AVIDecoder(const Common::Rational &frameRateOverride) :
Video::AVIDecoder(frameRateOverride) {}
/**
* Returns the number of video tracks the decoder has
*/
uint videoTrackCount() const { return _videoTracks.size(); }
/**
* Returns the specified video track
*/
Video::AVIDecoder::AVIVideoTrack &getVideoTrack(uint idx);
/**
* Returns the transparency video track, if present
*/
AVIVideoTrack *getTransparencyTrack() {
return static_cast<AVIVideoTrack *>(_transparencyTrack.track);
}
};
class AVISurface {
private:
AVIDecoder *_decoder;
CVideoSurface *_videoSurface;
CMovieRangeInfoList _movieRangeInfo;
int _streamCount;
Graphics::ManagedSurface *_movieFrameSurface[2];
bool _framePixels;
double _frameRate;
int _currentFrame, _priorFrame;
uint32 _priorFrameTime;
Common::String _movieName;
private:
/**
* Render a frame to the video surface
*/
bool renderFrame();
/**
* Sets up for video decompression
*/
void setupDecompressor();
/**
* Copys a movie frame into a local 16-bit frame surface
* @param src Source raw movie frame
* @param dest Destination 16-bit copy of the frame
* @remarks The important thing this methods different from a straight
* copy is that any pixels marked as fully transparent are replaced with
* the special transparent color value.
*/
void copyMovieFrame(const Graphics::Surface &src, Graphics::ManagedSurface &dest);
protected:
/**
* Start playback at the specified frame
*/
bool startAtFrame(int frameNumber);
/**
* Seeks to a given frame number in the video
*/
virtual void seekToFrame(uint frameNumber);
public:
CSoundManager *_soundManager;
bool _hasAudio;
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();
/**
* Pauses video playback
*/
virtual void pause();
/**
* Resumes the video if it's paused
*/
virtual void resume();
/**
* Return true if a video is currently playing
*/
virtual bool isPlaying() const {
return _decoder->isPlaying();
}
/**
* Sets whether the video is playing (versus paused)
*/
virtual void setPlaying(bool playingFlag) {
_decoder->pauseVideo(!playingFlag);
}
/**
* Handle any movie events relevant 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 _priorFrame; }
/**
* 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 transparency mask for the frame, if the movie includes it
*/
Graphics::ManagedSurface *duplicateTransparency() const;
/**
* Returns true if it's time for the next
*/
bool isNextFrame();
/**
* Plays an interruptable cutscene
* @returns True if the cutscene was not interrupted
*/
bool playCutscene(const Rect &r, uint startFrame, uint endFrame);
/**
* Returns the pixel depth of the movie in bits
*/
uint getBitDepth() const;
/**
* Returns true if the movie is to play backwards
*/
bool isReversed() const { return _frameRate < 0.0; }
};
} // End of namespace Titanic
#endif /* TITANIC_AVI_SURFACE_H */

View File

@@ -0,0 +1,263 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/credit_text.h"
#include "titanic/core/game_object.h"
#include "titanic/events.h"
#include "titanic/support/files_manager.h"
#include "titanic/support/screen_manager.h"
#include "titanic/titanic.h"
namespace Titanic {
#define FRAMES_PER_CYCLE 16
CCreditText::CCreditText() : _screenManagerP(nullptr), _ticks(0),
_fontHeight(1), _objectP(nullptr), _yOffset(0),
_priorInc(0), _textR(0), _textG(0), _textB(0), _deltaR(0),
_deltaG(0), _deltaB(0), _counter(0) {
}
void CCreditText::clear() {
_groups.destroyContents();
_objectP = nullptr;
}
void CCreditText::load(CGameObject *obj, CScreenManager *screenManager,
const Rect &rect) {
_objectP = obj;
_screenManagerP = screenManager;
_rect = rect;
setup();
_ticks = g_vm->_events->getTicksCount();
_priorInc = 0;
_textR = 0xFF;
_textG = 0xFF;
_textB = 0xFF;
_deltaR = 0;
_deltaG = 0;
_deltaB = 0;
_counter = 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);
if (hasDots)
handleDots(group);
}
_screenManagerP->setFontNumber(oldFontNumber);
_groupIt = _groups.begin();
_lineIt = (*_groupIt)->_lines.begin();
_yOffset = _objectP->_bounds.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() {
if (_groupIt == _groups.end())
return false;
if (++_counter >= FRAMES_PER_CYCLE) {
_textR += _deltaR;
_textG += _deltaG;
_textB += _deltaB;
_deltaR = g_vm->getRandomNumber(63) + 192 - _textR;
_deltaG = g_vm->getRandomNumber(63) + 192 - _textG;
_deltaB = g_vm->getRandomNumber(63) + 192 - _textB;
_counter = 0;
}
// Positioning adjustment, changing lines and/or group if necessary
int yDiff = (int)(g_vm->_events->getTicksCount() - _ticks) / 22 - _priorInc;
while (yDiff > 0) {
if (_yOffset > 0) {
if (yDiff < _yOffset) {
_yOffset -= yDiff;
_priorInc += yDiff;
yDiff = 0;
} else {
yDiff -= _yOffset;
_priorInc += _yOffset;
_yOffset = 0;
}
} else {
if (yDiff < _fontHeight)
break;
++_lineIt;
yDiff -= _fontHeight;
_priorInc += _fontHeight;
if (_lineIt == (*_groupIt)->_lines.end()) {
// Move to next line group
++_groupIt;
if (_groupIt == _groups.end())
// Reached end of groups
return false;
_lineIt = (*_groupIt)->_lines.begin();
_yOffset = _fontHeight * 3 / 2;
}
}
}
int oldFontNumber = _screenManagerP->setFontNumber(3);
CCreditLineGroups::iterator groupIt = _groupIt;
CCreditLines::iterator lineIt = _lineIt;
Point textPos;
for (textPos.y = _rect.top + _yOffset - yDiff; textPos.y <= _rect.bottom;
textPos.y += _fontHeight) {
int textR = _textR + _deltaR * _counter / FRAMES_PER_CYCLE;
int textG = _textG + _deltaG * _counter / FRAMES_PER_CYCLE;
int textB = _textB + _deltaB * _counter / FRAMES_PER_CYCLE;
// Single iteration loop to figure out RGB values for the line
do {
int percent = 0;
if (textPos.y < (_rect.top + 2 * _fontHeight)) {
percent = (textPos.y - _rect.top) * 100 / (_fontHeight * 2);
if (percent < 0)
percent = 0;
} else {
int bottom = _rect.bottom - 2 * _fontHeight;
if (textPos.y < bottom)
break;
percent = (_rect.bottom - textPos.y) * 100
/ (_fontHeight * 2);
}
// Adjust the RGB to the specified percentage intensity
textR = textR * percent / 100;
textG = textG * percent / 100;
textB = textB * percent / 100;
} while (0);
// Write out the line
_screenManagerP->setFontColor(textR, textG, textB);
textPos.x = _rect.left + (_rect.width() - (*lineIt)->_lineWidth) / 2;
_screenManagerP->writeString(SURFACE_BACKBUFFER, textPos,
_rect, (*lineIt)->_line, (*lineIt)->_lineWidth);
// Move to next line
++lineIt;
if (lineIt == (*groupIt)->_lines.end()) {
++groupIt;
if (groupIt == _groups.end())
// Finished all lines
break;
lineIt = (*groupIt)->_lines.begin();
textPos.y += _fontHeight * 3 / 2;
}
}
_objectP->makeDirty();
_screenManagerP->setFontNumber(oldFontNumber);
return true;
}
} // End of namespace Titanic

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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;
CCreditLineGroups _groups;
uint _ticks;
int _fontHeight;
CGameObject *_objectP;
CCreditLineGroups::iterator _groupIt;
CCreditLines::iterator _lineIt;
int _yOffset;
int _priorInc;
int _textR, _textG, _textB;
int _deltaR, _deltaG, _deltaB;
int _counter;
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);
/**
* Draw the item
*/
bool draw();
};
} // End of namespace Titanic
#endif /* TITANIC_CREDIT_TEXT_H */

View File

@@ -0,0 +1,98 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/direct_draw.h"
#include "titanic/debugger.h"
#include "titanic/titanic.h"
#include "common/debug.h"
#include "engines/util.h"
#include "graphics/pixelformat.h"
#include "graphics/screen.h"
namespace Titanic {
DirectDraw::DirectDraw() : _windowed(false), _width(0), _height(0),
_bpp(0), _numBackSurfaces(0) {
}
void DirectDraw::setDisplayMode(int width, int height, int bpp, int refreshRate) {
debugC(DEBUG_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, &pixelFormat);
}
void DirectDraw::diagnostics() {
debugC(DEBUG_BASIC, kDebugGraphics, "Running DirectDraw Diagnostic...");
}
DirectDrawSurface *DirectDraw::createSurfaceFromDesc(const DDSurfaceDesc &desc) {
DirectDrawSurface *surface = new DirectDrawSurface();
surface->create(desc._w, desc._h, desc._bpp);
return surface;
}
/*------------------------------------------------------------------------*/
DirectDrawManager::DirectDrawManager(TitanicEngine *vm, bool windowed) {
_mainSurface = nullptr;
_backSurfaces[0] = _backSurfaces[1] = nullptr;
_directDraw._windowed = windowed;
}
void DirectDrawManager::initVideo(int width, int height, int bpp, int numBackSurfaces) {
debugC(DEBUG_BASIC, kDebugGraphics, "Initialising video surfaces");
assert(numBackSurfaces == 0);
_directDraw._width = width;
_directDraw._numBackSurfaces = numBackSurfaces;
_directDraw._height = height;
_directDraw._bpp = bpp;
if (_directDraw._windowed) {
initWindowed();
} else {
initFullScreen();
}
}
void DirectDrawManager::initFullScreen() {
debugC(DEBUG_BASIC, kDebugGraphics, "Creating surfaces");
_directDraw.setDisplayMode(_directDraw._width, _directDraw._height,
_directDraw._bpp, 0);
// Set up the main surface to point to the screen
_mainSurface = new DirectDrawSurface();
_mainSurface->create(g_vm->_screen);
}
DirectDrawSurface *DirectDrawManager::createSurface(int w, int h, int bpp, int surfaceNum) {
if (surfaceNum)
return nullptr;
assert(_mainSurface);
return _directDraw.createSurfaceFromDesc(DDSurfaceDesc(w, h, bpp));
}
} // End of namespace Titanic

View File

@@ -0,0 +1,94 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 {
public:
bool _windowed;
int _width;
int _height;
int _bpp;
int _numBackSurfaces;
public:
DirectDraw();
/**
* 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);
/**
* 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 bpp, int surfaceNum);
};
} // End of namespace Titanic
#endif /* TITANIC_DIRECT_DRAW_H */

View File

@@ -0,0 +1,103 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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, int bpp) {
assert(bpp == 16 || bpp == 32);
Graphics::PixelFormat pixelFormat = (bpp == 32) ?
Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0) :
Graphics::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

View File

@@ -0,0 +1,127 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 _bpp;
int _flags;
int _caps;
DDSurfaceDesc(int w, int h, int bpp) : _w(w), _h(h), _bpp(bpp),
_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, int bpp);
/**
* 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 */

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/exe_resources.h"
#include "titanic/true_talk/script_handler.h"
#include "titanic/titanic.h"
namespace Titanic {
CExeResources::CExeResources() : _owner(nullptr), _field4(0), _field8(0),
_fieldC(0), _field10(0), _field14(0), _vocabMode(VOCAB_MODE_NONE) {
}
void CExeResources::reset(CScriptHandler *owner, int val1, VocabMode vocabMode) {
_owner = owner;
_vocabMode = vocabMode;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,60 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 };
enum VocabMode { VOCAB_MODE_NONE = 0, VOCAB_MODE_EN = 3, VOCAB_MODE_DE = 5 };
class CExeResources {
public:
CScriptHandler *_owner;
int _field4;
int _field8;
int _fieldC;
int _field10;
int _field14;
VocabMode _vocabMode;
public:
CExeResources();
void reset(CScriptHandler *owner, int val1, VocabMode vocabMode);
/**
* Tests whether the vocab mode equals the passed mode
*/
bool isVocabMode(int mode) const { return _vocabMode == mode; }
/**
* Returns the vocab mode
*/
VocabMode getVocabMode() const { return _vocabMode; }
};
} // End of namespace Titanic
#endif /* TITANIC_EXE_RESOURCES_H */

View File

@@ -0,0 +1,154 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/file.h"
#include "common/memstream.h"
#include "common/compression/deflate.h"
#include "titanic/support/files_manager.h"
#include "titanic/game_manager.h"
#include "titanic/titanic.h"
namespace Titanic {
CFilesManager::CFilesManager(TitanicEngine *vm) : _vm(vm), _gameManager(nullptr),
_assetsPath("Assets"), _drive(-1), _version(0) {
}
CFilesManager::~CFilesManager() {
_datFile.close();
}
bool CFilesManager::loadResourceIndex() {
if (!_datFile.open("titanic.dat")) {
GUIErrorMessage("Could not find titanic.dat data file");
return false;
}
uint headerId = _datFile.readUint32BE();
_version = _datFile.readUint16LE();
if (headerId != MKTAG('S', 'V', 'T', 'N')) {
GUIErrorMessage("titanic.dat has invalid contents");
return false;
}
if (_version != 5) {
GUIErrorMessage("titanic.dat is out of date");
return false;
}
// Read in entries
uint offset, size, flags;
char c;
Common::String resourceName;
for (;;) {
offset = _datFile.readUint32LE();
size = _datFile.readUint32LE();
flags = (_version == 1) ? 0 : _datFile.readUint16LE();
if (offset == 0 && size == 0)
break;
Common::String resName;
while ((c = _datFile.readByte()) != '\0')
resName += c;
_resources[resName] = ResourceEntry(offset, size, flags);
}
return true;
}
bool CFilesManager::fileExists(const CString &name) {
return Common::File::exists(Common::Path(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 roomChange
// method, which handles all active scene objects freeing their resources
if (_gameManager)
_gameManager->roomChange();
return false;
}
void CFilesManager::loadDrive() {
assert(_drive == -1);
resetView();
}
void CFilesManager::insertCD(CScreenManager *screenManager) {
// We don't support running the game directly from the original CDs,
// so this method can remain stubbed
}
void CFilesManager::resetView() {
if (_gameManager) {
_gameManager->_gameState.setMode(GSMODE_INTERACTIVE);
_gameManager->markAllDirty();
}
}
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];
// If we're running the German version, check for the existence of
// a German specific version of the given resource
if (_vm->isGerman() && _resources.contains(str + "/DE"))
resEntry = _resources[str + "/DE"];
_datFile.seek(resEntry._offset);
Common::SeekableReadStream *stream = (resEntry._size > 0) ?
_datFile.readStream(resEntry._size) :
new Common::MemoryReadStream(nullptr, 0);
if (resEntry._flags & FLAG_COMPRESSED)
stream = Common::wrapCompressedReadStream(stream);
return stream;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,113 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 {
enum ResourceFlag { FLAG_COMPRESSED = 1 };
class TitanicEngine;
class CGameManager;
class CFilesManagerList : public List<ListItem> {
};
class CFilesManager {
struct ResourceEntry {
uint _offset;
uint _size;
uint _flags;
ResourceEntry() : _offset(0), _size(0), _flags(0) {}
ResourceEntry(uint offset, uint size, uint flags) :
_offset(offset), _size(size), _flags(flags) {}
};
typedef Common::HashMap<Common::String, ResourceEntry> ResourceHash;
private:
TitanicEngine *_vm;
CGameManager *_gameManager;
Common::File _datFile;
ResourceHash _resources;
CFilesManagerList _list;
int _drive;
const CString _assetsPath;
int _version;
public:
CFilesManager(TitanicEngine *vm);
~CFilesManager();
/**
* Opens up the titanic.dat support file and loads it's index
*/
bool loadResourceIndex();
/**
* 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();
/**
* Shows a dialog for inserting a new CD
*/
void insertCD(CScreenManager *screenManager);
/**
* Resets the view being displayed
*/
void resetView();
/**
* 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 */

View File

@@ -0,0 +1,142 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_FIXED_QUEUE_H
#define TITANIC_FIXED_QUEUE_H
#include "common/scummsys.h"
#include "common/array.h"
namespace Titanic {
/**
* Extremely simple fixed size queue class.
*/
template<class T, uint MAX_SIZE = 10>
class FixedQueue {
typedef uint size_type;
protected:
Common::Array<T> _data;
size_type _topIndex;
public:
FixedQueue() : _topIndex(0) {
_data.reserve(MAX_SIZE);
}
/**
* Returns the size of the queue in use
*/
size_type size() const { return _data.size() - _topIndex; }
/**
* Returns the amount of free remaining space in the queue
*/
size_type freeSize() const { return MAX_SIZE - size(); }
/**
* Returns true if the queue is empty
*/
bool empty() const {
return size() == 0;
}
/**
* Returns true if the queue is full
*/
bool full() const {
return freeSize() == 0;
}
/**
* Clears the queue
*/
void clear() {
_data.clear();
_topIndex = 0;
}
/**
* If the tail of the queue in use has reached the end of the internal
* array, pushes all pending data back to the start of the array
*/
void compact() {
if (_data.size() == MAX_SIZE && _topIndex > 0) {
if (_topIndex < MAX_SIZE)
Common::copy(&_data[_topIndex], &_data[0] + MAX_SIZE, &_data[0]);
_data.resize(size());
_topIndex = 0;
}
}
/**
* Adds a value to the end of the queue
*/
void push(const T &v) {
assert(size() < MAX_SIZE);
compact();
_data.push_back(v);
}
/**
* Returns the top value on the queue
*/
const T &top() const {
assert(size() > 0);
return _data[_topIndex];
}
/**
* Returns the top value on the queue
*/
T &top() {
assert(size() > 0);
return _data[_topIndex];
}
/**
* Pops the top value off the queue
*/
T pop() {
T tmp = top();
++_topIndex;
return tmp;
}
/**
* Returns values from within the queue without popping them
*/
T &operator[](size_type i) {
assert(i < size());
return _data[_topIndex + i];
}
/**
* Returns values from within the queue without popping them
*/
const T &operator[](size_type i) const {
assert(i < size());
return _data[_topIndex + i];
}
};
} // End of namespace Titanic
#endif

View File

@@ -0,0 +1,341 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 for line 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 for line 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;
}
void STFont::writeString(CVideoSurface *surface, const Point &destPos, Rect &clipRect,
const CString &str, int lineWidth) {
if (!_fontHeight || !_dataPtr || str.empty())
return;
if (!lineWidth)
// No line width specified, so get in the width
lineWidth = stringWidth(str);
Rect textRect(0, 0, lineWidth, _fontHeight);
Point textPt = destPos;
// Perform clipping as necessary if the text will fall outside clipping area
if (textPt.y > clipRect.bottom)
return;
if ((textPt.y + textRect.height()) > clipRect.bottom)
textRect.bottom = textRect.top - textPt.y + clipRect.bottom;
if (textPt.y < clipRect.top) {
if ((textPt.y + textRect.height()) < clipRect.top)
return;
textRect.top += clipRect.top - textPt.y;
textPt.y = clipRect.top;
}
// Iterate through each character of the string
for (const byte *srcP = (const byte *)str.c_str(); *srcP; ++srcP) {
byte c = *srcP;
if (c == 0xE9)
c = '$';
// Form a rect of the area of the next character to draw
Rect charRect(_chars[c]._offset, textRect.top,
_chars[c]._offset + _chars[c]._width, textRect.bottom);
int textX = textPt.x;
if (textPt.x < clipRect.left) {
// Character is either partially or entirely left off-screen
if ((textPt.x + charRect.width()) < clipRect.left) {
textPt.x += _chars[c]._width;
continue;
}
// Partially clipped on left-hand side
charRect.left = clipRect.left - textPt.x;
textPt.x = clipRect.left;
} else if ((textPt.x + charRect.width()) > clipRect.right) {
if (textPt.x > clipRect.right)
// Now entirely off right-hand side, so stop drawing
break;
// Partially clipped on right-hand side
charRect.right += clipRect.right - textPt.x - charRect.width();
}
// At this point, we know we've got to draw at least part of a character,
// and have figured out the area of the character to draw
copyRect(surface, textPt, charRect);
textPt.x = textX + _chars[c]._width;
}
}
WriteCharacterResult STFont::writeChar(CVideoSurface *surface, unsigned char c, const Point &pt,
const Rect &destRect, const Rect *srcRect) {
if (c == 233)
c = '$';
Rect charRect(_chars[c]._offset, 0,
_chars[c]._offset + _chars[c]._width, _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 + charRect.height()) > srcRect->bottom) {
charRect.bottom += srcRect->bottom - (destPos.y + charRect.height());
}
if (destPos.y < srcRect->top) {
if ((charRect.height() + destPos.y) < srcRect->top)
return WC_OUTSIDE_TOP;
charRect.top += srcRect->top - destPos.y;
destPos.y = srcRect->top;
}
if (destPos.x < srcRect->left) {
if ((charRect.width() + destPos.x) < srcRect->left)
return WC_OUTSIDE_LEFT;
charRect.left += srcRect->left - destPos.x;
destPos.x = srcRect->left;
} else {
if ((destPos.x + charRect.width()) > srcRect->right) {
if (destPos.x > srcRect->right)
return WC_OUTSIDE_RIGHT;
charRect.right += srcRect->right - destPos.x - charRect.width();
}
}
copyRect(surface, destPos, charRect);
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 *transP = _dataPtr + yp * _dataWidth + xp;
surface->copyPixel(destP, &color, *transP >> 3,
surface->getRawSurface()->format, 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;
// Loop forward getting the width of the word (including preceding space)
// until a space is encountered following at least one character
for (const char *srcPtr = str; *srcPtr && (*srcPtr != ' ' || !flag); ++srcPtr) {
if (*srcPtr == TEXTCMD_NPC) {
srcPtr += 3;
} else if (*srcPtr == TEXTCMD_SET_COLOR) {
srcPtr += 4;
} else {
totalWidth += _chars[(byte)*srcPtr]._width;
flag = true;
}
}
if ((textSize.x + totalWidth) >= maxWidth && totalWidth < maxWidth) {
// Word wrap
textSize.x = 0;
textSize.y += _fontHeight;
++str;
}
}
} // End of namespace Titanic

View File

@@ -0,0 +1,128 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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);
/**
* Write a string to the specified surface
*/
void writeString(CVideoSurface *surface, const Point &destPos, Rect &clipRect,
const CString &str, int lineWidth = 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 (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 */

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/image.h"
#include "titanic/support/files_manager.h"
#include "image/bmp.h"
#include "titanic/titanic.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 Graphics::Palette &palette = decoder.getPalette();
Graphics::Surface *surface = src->convertTo(scrFormat, palette.data(), palette.size());
create(surface->w, surface->h, scrFormat);
blitFrom(*surface);
surface->free();
delete surface;
}
}
} // End of namespace Titanic

View File

@@ -0,0 +1,42 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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:
~Image() override {}
void load(const CString &resName);
};
} // End of namespace Titanic
#endif /* TITANIC_IMAGE_H */

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/system.h"
#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 ScummVM decoder to decode it
setOutputPixelFormat(g_system->getScreenFormat());
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, 16);
// Copy the decoded surface
surface.lock();
assert(srcSurf->format == surface._rawSurface->format);
Common::copy((const byte *)srcSurf->getPixels(), (const byte *)srcSurf->getPixels() +
surface.getPitch() * surface.getHeight(), (byte *)surface._rawSurface->getPixels());
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, 16);
// 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

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 */

View File

@@ -0,0 +1,200 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/mouse_cursor.h"
#include "titanic/support/screen_manager.h"
#include "titanic/support/transparency_surface.h"
#include "titanic/support/video_surface.h"
#include "titanic/events.h"
#include "titanic/input_handler.h"
#include "titanic/messages/mouse_messages.h"
#include "titanic/titanic.h"
#include "graphics/cursorman.h"
#include "graphics/screen.h"
namespace Titanic {
#define CURSOR_SIZE 64
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 _surface;
}
CMouseCursor::CMouseCursor(CScreenManager *screenManager) :
_screenManager(screenManager), _cursorId(CURSOR_HOURGLASS), _hideCounter(0),
_busyCount(0), _cursorSuppressed(false), _setCursorCount(0), _inputEnabled(true), _fieldE8(0) {
loadCursorImages();
setCursor(CURSOR_ARROW);
CursorMan.showMouse(true);
}
CMouseCursor::~CMouseCursor() {
}
void CMouseCursor::loadCursorImages() {
const CResourceKey key("ycursors.avi");
// 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(CURSOR_SIZE, CURSOR_SIZE);
// Open the cursors video and move to the given frame
OSMovie *movie = new OSMovie(key, surface);
movie->setFrame(idx);
Graphics::ManagedSurface *transSurface = movie->duplicateTransparency();
// Create a managed surface to hold the RGBA version of the cursor
Graphics::PixelFormat rgbaFormat(4, 8, 8, 8, 8, 24, 16, 8, 0);
_cursors[idx]._surface = new Graphics::ManagedSurface(CURSOR_SIZE, CURSOR_SIZE, rgbaFormat);
// Copy the cursor from the movie's video surface
surface->lock();
_cursors[idx]._surface->blitFrom(*surface->getRawSurface());
surface->unlock();
// We need to separately merge in the transparency surface
for (int y = 0; y < CURSOR_SIZE; ++y) {
const byte *srcP = (const byte *)transSurface->getBasePtr(0, y);
uint32 *destP = (uint32 *)_cursors[idx]._surface->getBasePtr(0, y);
for (int x = 0; x < CURSOR_SIZE; ++x, ++srcP, ++destP)
*destP = (*destP & ~0xff) | *srcP;
}
delete movie;
delete transSurface;
delete surface;
}
}
void CMouseCursor::incBusyCount() {
if (_busyCount == 0)
setCursor(CURSOR_HOURGLASS);
++_busyCount;
}
void CMouseCursor::decBusyCount() {
assert(_busyCount > 0);
if (--_busyCount == 0)
setCursor(CURSOR_ARROW);
}
void CMouseCursor::incHideCounter() {
if (_hideCounter++ == 0)
CursorMan.showMouse(false);
}
void CMouseCursor::decHideCounter() {
--_hideCounter;
assert(_hideCounter >= 0);
if (_hideCounter == 0)
CursorMan.showMouse(true);
}
void CMouseCursor::suppressCursor() {
_cursorSuppressed = true;
CursorMan.showMouse(false);
}
void CMouseCursor::unsuppressCursor() {
_cursorSuppressed = false;
if (_hideCounter == 0)
CursorMan.showMouse(true);
}
void CMouseCursor::setCursor(CursorId cursorId) {
++_setCursorCount;
if (cursorId != _cursorId && _busyCount == 0) {
const CursorEntry &ce = _cursors[cursorId - 1];
_cursorId = cursorId;
// Set the cursor
CursorMan.replaceCursor(*ce._surface, ce._centroid.x, ce._centroid.y, 0, false);
}
}
void CMouseCursor::update() {
if (!_inputEnabled && _moveStartTime) {
uint32 time = CLIP(g_system->getMillis(), _moveStartTime, _moveEndTime);
Common::Point pt(
_moveStartPos.x + (_moveDestPos.x - _moveStartPos.x) *
(int)(time - _moveStartTime) / (int)(_moveEndTime - _moveStartTime),
_moveStartPos.y + (_moveDestPos.y - _moveStartPos.y) *
(int)(time - _moveStartTime) / (int)(_moveEndTime - _moveStartTime)
);
if (pt != g_vm->_events->getMousePos()) {
g_vm->_events->setMousePos(pt);
CInputHandler &inputHandler = *CScreenManager::_screenManagerPtr->_inputHandler;
CMouseMoveMsg msg(pt, 0);
inputHandler.handleMessage(msg, false);
}
if (time == _moveEndTime)
_moveStartTime = _moveEndTime = 0;
}
}
void CMouseCursor::disableControl() {
_inputEnabled = false;
CScreenManager::_screenManagerPtr->_inputHandler->incLockCount();
}
void CMouseCursor::enableControl() {
_inputEnabled = true;
_fieldE8 = 0;
CScreenManager::_screenManagerPtr->_inputHandler->decLockCount();
}
void CMouseCursor::setPosition(const Point &pt, double duration) {
_moveStartPos = g_vm->_events->getMousePos();
_moveDestPos = pt;
_moveStartTime = g_system->getMillis();
_moveEndTime = _moveStartTime + (int)duration;
update();
}
} // End of namespace Titanic

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_MOUSE_CURSOR_H
#define TITANIC_MOUSE_CURSOR_H
#include "common/scummsys.h"
#include "graphics/managed_surface.h"
#include "titanic/support/rect.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_LOOK_UP = 5,
CURSOR_LOOK_DOWN = 6,
CURSOR_MOVE_THROUGH = 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 {
Graphics::ManagedSurface *_surface;
Common::Point _centroid;
CursorEntry() : _surface(nullptr) {}
~CursorEntry();
};
private:
CScreenManager *_screenManager;
CursorId _cursorId;
CursorEntry _cursors[NUM_CURSORS];
uint _setCursorCount;
int _hideCounter;
int _busyCount;
bool _cursorSuppressed;
int _fieldE8;
Common::Point _moveStartPos;
Common::Point _moveDestPos;
uint32 _moveStartTime, _moveEndTime;
/**
* Load the images for each cursor
*/
void loadCursorImages();
public:
bool _inputEnabled;
public:
CMouseCursor(CScreenManager *screenManager);
~CMouseCursor();
/**
* Increment the busy count for the cursor, showing an hourglass
*/
void incBusyCount();
/**
* Decrements the busy count, resetting back to an arrow cursor
* when the count reaches zero
*/
void decBusyCount();
/**
* Decrements the hide counter, and shows the mouse if
* it's reached zero
*/
void incHideCounter();
/**
* Increments the hide counter, hiding the mouse if it's the first call
*/
void decHideCounter();
/**
* Suppresses the cursor. When suppressed, the cursor isn't drawn,
* even if it's not otherwise being hidden
*/
void suppressCursor();
/**
* Unflags the cursor as being suppressed, allowing it to be drawn
* again if it's enabled
*/
void unsuppressCursor();
/**
* 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; }
/**
* Disables user control of the mouse
*/
void disableControl();
/**
* Re-enables user control of the mouse
*/
void enableControl();
/**
* Move the mouse to a new position
*/
void setPosition(const Point &pt, double duration);
};
} // End of namespace Titanic
#endif /* TITANIC_MOUSE_CURSOR_H */

View File

@@ -0,0 +1,209 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/movie.h"
#include "titanic/core/game_object.h"
#include "titanic/events.h"
#include "titanic/messages/messages.h"
#include "titanic/support/avi_surface.h"
#include "titanic/support/screen_manager.h"
#include "titanic/support/video_surface.h"
#include "titanic/sound/sound_manager.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) {
}
CMovie::~CMovie() {
removeFromPlayingMovies();
}
void CMovie::init() {
_playingMovies = new CMovieList();
_movieSurface = nullptr;
}
void CMovie::deinit() {
// At this point, there shouldn't be any playing movies left,
// since their owning objects should have freed them
assert(_playingMovies->empty());
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();
}
bool OSMovie::playCutscene(const Rect &drawRect, uint startFrame, uint endFrame) {
if (!_movieSurface)
_movieSurface = CScreenManager::_screenManagerPtr->createSurface(600, 340, 32);
// Set a new event target whilst the clip plays, so standard scene drawing isn't called
CEventTarget eventTarget;
g_vm->_events->addTarget(&eventTarget);
bool result = _aviSurface.playCutscene(drawRect, startFrame, endFrame);
g_vm->_events->removeTarget();
return result;
}
void OSMovie::pause() {
_aviSurface.pause();
}
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->setTransparencySurface(_aviSurface.getSecondarySurface());
}
bool OSMovie::handleEvents(CMovieEventList &events) {
// WORKAROUND: If a movie is paused as part of initial
// scene loading, now's the time to un-pause it
_aviSurface.resume();
if (!_aviSurface.isPlaying())
return false;
// Handle updating the frame
while (_aviSurface.isPlaying() && _aviSurface.isNextFrame()) {
_aviSurface.handleEvents(events);
_videoSurface->setTransparencySurface(_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);
}
void OSMovie::setPlaying(bool playingFlag) {
_aviSurface.setPlaying(playingFlag);
}
Graphics::ManagedSurface *OSMovie::duplicateTransparency() const {
return _aviSurface.duplicateTransparency();
}
} // End of namespace Titanic

View File

@@ -0,0 +1,265 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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;
public:
static CMovieList *_playingMovies;
static CVideoSurface *_movieSurface;
/**
* Initializes statics
*/
static void init();
/**
* Deinitializes statics
*/
static void deinit();
public:
CMovie();
~CMovie() override;
/**
* 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, and doesn't return until either
* the playback ends or a key has been pressed
* @returns True if the cutscene was not interrupted
*/
virtual bool playCutscene(const Rect &drawRect, uint startFrame, uint endFrame) = 0;
/**
* Pauses a movie
* @remarks Acts a workaround for our video decoder, since some movies started
* as part of a scene load need to be paused until the scene is interactive,
* or else they get played back too quickly
*/
virtual void pause() = 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;
/**
* Sets whether the video is playing (versus paused)
*/
virtual void setPlaying(bool playingFlag) = 0;
/**
* Creates a duplicate of the transparency surface
*/
virtual Graphics::ManagedSurface *duplicateTransparency() 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);
~OSMovie() override;
/**
* Starts playing the movie
*/
void play(uint flags, CGameObject *obj) override;
/**
* Starts playing the movie
*/
void play(uint startFrame, uint endFrame, uint flags, CGameObject *obj) override;
/**
* Starts playing the movie
*/
void play(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) override;
/**
* Plays a sub-section of a movie, and doesn't return until either
* the playback ends or a key has been pressed
* @returns True if the cutscene was not interrupted
*/
bool playCutscene(const Rect &drawRect, uint startFrame, uint endFrame) override;
/**
* Pauses a movie
* @remarks Acts a workaround for our video decoder, since some movies started
* as part of a scene load need to be paused until the scene is interactive,
* or else they get played back too quickly
*/
void pause() override;
/**
* Stops the movie
*/
void stop() override;
/**
* Add a playback event
*/
void addEvent(int eventId, CGameObject *obj) override;
/**
* Set the current frame number
*/
void setFrame(uint frameNumber) override;
/**
* Handle any pending movie events
*/
bool handleEvents(CMovieEventList &events) override;
/**
* Get the current frame number
*/
int getFrame() const override;
/**
* Return any movie range info associated with the movie
*/
const CMovieRangeInfoList *getMovieRangeInfo() const override;
/**
* Set the sound manager reference
*/
void setSoundManager(CSoundManager *soundManager) override;
/**
* Set the frame rate for the movie
*/
void setFrameRate(double rate) override;
/**
* Sets whether the video is playing (versus paused)
*/
void setPlaying(bool playingFlag) override;
/**
* Creates a duplicate of the transparency surface
*/
Graphics::ManagedSurface *duplicateTransparency() const override;
};
} // End of namespace Titanic
#endif /* TITANIC_MOVIE_H */

View File

@@ -0,0 +1,99 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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

View File

@@ -0,0 +1,91 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
/**
* 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 */

View File

@@ -0,0 +1,63 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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);
~CMovieEvent() override {}
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
};
class CMovieEventList : public List<CMovieEvent> {
};
class CSharedMovieEventList : public Common::List<CMovieEvent> {
};
} // End of namespace Titanic
#endif /* TITANIC_MOVIE_EVENT_H */

View File

@@ -0,0 +1,34 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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) {}
~CMovieManager() override {}
/**
* Create a new movie and return it
*/
CMovie *createMovie(const CResourceKey &key, CVideoSurface *surface) override;
/**
* 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 */

View File

@@ -0,0 +1,115 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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);
ListItem::save(file, indent);
}
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);
}
ListItem::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 (_isRepeat)
flags |= MOVIE_REPEAT;
if (_isReversed)
flags |= MOVIE_REVERSE;
for (CMovieEventList::iterator i = _events.begin(); i != _events.end(); ++i) {
CMovieEvent *movieEvent = *i;
if (movieEvent->_type == MET_MOVIE_END) {
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

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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:
CLASSDEF;
CMovieRangeInfo();
CMovieRangeInfo(const CMovieRangeInfo *src);
~CMovieRangeInfo() override;
/**
* Save the data for the class to file
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
/**
* 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 */

View File

@@ -0,0 +1,62 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/rect.h"
namespace Titanic {
void Rect::combine(const Rect &r) {
if (isEmpty()) {
*this = r;
} else if (!r.isEmpty()) {
Common::Rect::extend(r);
}
}
void Rect::constrain(const Rect &r) {
if (!isEmpty()) {
if (r.isEmpty()) {
clear();
} else {
Common::Rect::clip(r);
}
}
}
Point Rect::getPoint(Quadrant quadrant) {
if (isEmpty())
return Point(left, top);
switch (quadrant) {
case Q_LEFT:
return Point(MIN(left + 10, (int)right), (top + bottom) / 2);
case Q_RIGHT:
return Point(MAX(right - 10, (int)left), (top + bottom) / 2);
case Q_TOP:
return Point((left + right) / 2, MIN(top + 10, (int)bottom));
case Q_BOTTOM:
return Point((left + right) / 2, MAX(bottom - 10, (int)top));
default:
return Point((left + right) / 2, (top + bottom) / 2);
}
}
} // End of namespace Titanic

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_RECT_H
#define TITANIC_RECT_H
#include "common/rect.h"
namespace Titanic {
enum Quadrant {
Q_CENTER = 0, Q_LEFT, Q_RIGHT, Q_TOP, Q_BOTTOM
};
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 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);
/**
* Returns a center point for a given edge or center of the rect
*/
Point getPoint(Quadrant quadrant);
};
} // End of namespace Titanic
#endif /* TITANIC_RECT_H */

View File

@@ -0,0 +1,356 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/screen_manager.h"
#include "titanic/support/video_surface.h"
#include "titanic/titanic.h"
#include "graphics/screen.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;
_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;
else if (surfaceNum == SURFACE_PRIMARY)
_frontSurfaceBounds = r;
}
int CScreenManager::setFontNumber(int fontNumber) {
int oldFontNumber = _fontNumber;
_fontNumber = fontNumber;
return oldFontNumber;
}
void CScreenManager::preLoad() {
if (_textCursor)
_textCursor->hide();
}
/*------------------------------------------------------------------------*/
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;
}
// Constrain the fill area to the set modification area of the surface
Rect surfaceBounds = (surfaceNum == SURFACE_PRIMARY) ? _frontSurfaceBounds :
_backSurfaces[surfaceNum]._bounds;
if (!surfaceBounds.isEmpty())
tempRect.constrain(surfaceBounds);
// If there is any area defined, clear it
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;
Rect surfaceBounds = (surfaceNum == SURFACE_PRIMARY) ? _frontSurfaceBounds :
_backSurfaces[surfaceNum]._bounds;
if (!surfaceBounds.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(surfaceBounds);
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 == SURFACE_PRIMARY) {
surface = _frontRenderSurface;
bounds = _frontSurfaceBounds;
} else {
return -1;
}
return _fonts[_fontNumber].writeString(surface, destRect, bounds,
yOffset, str, textCursor);
}
void OSScreenManager::writeString(int surfaceNum, const Point &destPos,
const Rect &clipRect, const CString &str, int lineWidth) {
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;
}
Rect destRect = clipRect;
destRect.constrain(bounds);
_fonts[_fontNumber].writeString(surface, destPos, destRect, str, lineWidth);
}
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, int bpp) {
DirectDrawSurface *ddSurface = _directDrawManager.createSurface(width, height, bpp, 0);
surface->setSurface(this, ddSurface);
}
CVideoSurface *OSScreenManager::createSurface(int w, int h, int bpp) {
DirectDrawSurface *ddSurface = _directDrawManager.createSurface(w, h, bpp, 0);
return new OSVideoSurface(this, ddSurface);
}
CVideoSurface *OSScreenManager::createSurface(const CResourceKey &key) {
return new OSVideoSurface(this, key);
}
void OSScreenManager::showCursor() {
CScreenManager::_screenManagerPtr->_mouseCursor->unsuppressCursor();
}
void OSScreenManager::hideCursor() {
CScreenManager::_screenManagerPtr->_mouseCursor->suppressCursor();
}
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);
if (!_textCursor) {
_textCursor = new CTextCursor(this);
}
}
} // End of namespace Titanic

View File

@@ -0,0 +1,400 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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;
Rect _frontSurfaceBounds;
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 destPos Position to start writing text at
* @param clipRect Clipping area to constrain text to
* @param str Line or lines to write
* @param maxWidth Maximum allowed line width
*/
virtual void writeString(int surfaceNum, const Point &destPos,
const Rect &clipRect, const CString &str, int maxWidth) = 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, int bpp = 16) = 0;
/**
* Creates a surface of a given size
*/
virtual CVideoSurface *createSurface(int w, int h, int bpp = 16) = 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);
/**
* Called when a game is about to be loaded
*/
void preLoad();
};
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);
~OSScreenManager() override;
/**
* Sets the video mode
*/
void setMode(int width, int height, int bpp, uint numBackSurfaces, bool flag2) override;
/**
* Handles drawing the cursors
*/
void drawCursors() override;
/**
* Locks a specified surface number for access and returns a pointer to it
*/
CVideoSurface *lockSurface(SurfaceNum surfaceNum) override;
/**
* Unlocks a previously locked surface
*/
void unlockSurface(CVideoSurface *surface) override;
/**
* Gets a specified surface number
*/
CVideoSurface *getSurface(SurfaceNum surfaceNum) const override;
/**
* Return the front render surface
*/
CVideoSurface *getFrontRenderSurface() const override {
return _frontRenderSurface;
}
/**
* Fill an area with a specific color
*/
void fillRect(SurfaceNum surfaceNum, Rect *rect, byte r, byte g, byte b) override;
/**
* Blits a surface onto one of the screen surfaces
*/
void blitFrom(SurfaceNum surfaceNum, CVideoSurface *src, const Point *destPos,
const Rect *srcRect = nullptr) override;
/**
* Blits a surface onto one of the screen surfaces
*/
void blitFrom(SurfaceNum surfaceNum, const Rect *rect, CVideoSurface *src, int v = 0) override;
/**
* 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
*/
int writeString(int surfaceNum, const Rect &destRect,
int yOffset, const CString &str, CTextCursor *textCursor) override;
/**
* Write a string
* @param surfaceNum Destination surface
* @param destPos Position to start writing text at
* @param clipRect Clipping area to constrain text to
* @param str Line or lines to write
* @param lineWidth Width in pixels of the string, if known.
*/
void writeString(int surfaceNum, const Point &destPos,
const Rect &clipRect, const CString &str, int lineWidth = 0) override;
/**
* Set the font color
*/
void setFontColor(byte r, byte g, byte b) override;
/**
* 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
*/
int getTextBounds(const CString &str, int maxWidth, Point *sizeOut = nullptr) const override;
/**
* Get the current font height
*/
int getFontHeight() const override;
/**
* Returns the width of a given string in pixels
*/
int stringWidth(const CString &str) override;
/**
* Draws a frame enclosing the specified area
*/
void frameRect(SurfaceNum surfaceNum, const Rect &rect, byte r, byte g, byte b) override;
/**
* Clear a portion of the screen surface
*/
void clearSurface(SurfaceNum surfaceNum, Rect *bounds) override;
/**
* Resize the passed surface
*/
void resizeSurface(CVideoSurface *surface, int width, int height, int bpp = 16) override;
/**
* Creates a surface of a given size
*/
CVideoSurface *createSurface(int w, int h, int bpp = 16) override;
/**
* Creates a surface from a specified resource
*/
CVideoSurface *createSurface(const CResourceKey &key) override;
/**
* Show the mouse cursor
*/
void showCursor() override;
/**
* Hide the mouse cursor
*/
void hideCursor() override;
};
} // End of namespace Titanic
#endif /* TITANIC_SCREEN_MANAGER_H */

View File

@@ -0,0 +1,516 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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::Path &filename) {
if (!Common::File::open(filename))
error("Could not open file - %s", filename.toString(Common::Path::kNativeSeparator).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)) {
va_end(va);
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) {
Common::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());
if (!f.open(Common::Path(name)))
return false;
SimpleFile::open(f.readStream(f.size()));
f.close();
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
if (!f.open(Common::Path(fname)))
return false;
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

View File

@@ -0,0 +1,320 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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/compression/deflate.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:
bool open(const Common::Path &filename) override;
};
/**
* 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() {}
~CompressedFile() override {}
/**
* Set up a stream for read access
*/
void open(Common::SeekableReadStream *stream) override {
SimpleFile::open(Common::wrapCompressedReadStream(stream));
}
/**
* Set up a stream for write access
*/
void open(Common::OutSaveFile *stream) override {
SimpleFile::open(new Common::OutSaveFile(Common::wrapCompressedWriteStream(stream)));
}
};
/**
* Derived file that handles WAD archives containing multiple files
*/
class StdCWadFile : public SimpleFile {
public:
StdCWadFile() : SimpleFile() {}
~StdCWadFile() override {}
/**
* Open up the specified file
*/
virtual bool open(const Common::String &filename);
/**
* Unsupported open method from parent class
*/
void open(Common::SeekableReadStream *stream) override {}
/**
* Unsupported open method from parent class
*/
void open(Common::OutSaveFile *stream) override {}
/**
* 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 */

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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);
}
CString CString::deleteRight(uint count) const {
return (count >= size()) ? CString() : left(size() - count);
}
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;
}
bool CString::containsIgnoreCase(const CString &str) const {
CString lowerStr = *this;
CString subStr = str;
lowerStr.toLowercase();
subStr.toLowercase();
return lowerStr.contains(subStr);
}
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;
}
bool CString::operator==(const CString &x) const {
return compareToIgnoreCase(x) == 0;
}
bool CString::operator==(const char *x) const {
return compareToIgnoreCase(x) == 0;
}
bool CString::operator!=(const CString &x) const {
return compareToIgnoreCase(x) != 0;
}
bool CString::operator!=(const char *x) const {
return compareToIgnoreCase(x) != 0;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,129 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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);
bool operator==(const CString &x) const;
bool operator==(const char *x) const;
bool operator!=(const CString &x) const;
bool operator!=(const char *x) const;
/**
* 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 a substring consisting of the entire string
* except for a specified number of characters at the end
*/
CString deleteRight(uint count) const;
/**
* Returns the index of the first occurrence of a given character
*/
int indexOf(char c) const;
/**
* Returns the index of the first occurrence of a given string
*/
int indexOf(const char *s) const;
/**
* Returns the index of the last occurrence of a given character
*/
int lastIndexOf(char c) const;
/**
* Returns true if the string contains a specified substring, ignoring case
*/
bool containsIgnoreCase(const CString &str) 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 */

View File

@@ -0,0 +1,96 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/string_parser.h"
#include "common/util.h"
namespace Titanic {
void CStringParser::skipSeparators(const CString &separatorChars) {
for (; _index < size(); ++_index) {
char c = (*this)[_index];
if (separatorChars.indexOf(c) == -1)
break;
}
}
bool CStringParser::parse(CString &resultStr, const CString &separatorChars, bool allowQuotes) {
if (_index >= size())
return false;
resultStr.clear();
bool quoteFlag = false;
while (_index < size()) {
char c = (*this)[_index];
if (!quoteFlag && separatorChars.indexOf(c) >= 0)
break;
if (allowQuotes) {
if (quoteFlag) {
if (c == '"') {
// End of quoted string
++_index;
break;
}
} else {
if (c == '"') {
// Start of quoted string
++_index;
quoteFlag = true;
continue;
}
}
}
resultStr += c;
++_index;
}
return true;
}
uint CStringParser::readInt() {
// Get digits from the string
CString numStr;
while (Common::isDigit(currentChar()))
numStr += getNextChar();
// Throw a wobbly if there wasn't a number
if (numStr.empty())
error("ReadInt(): No number to read");
return atoi(numStr.c_str());
}
char CStringParser::currentChar() const {
return (_index >= size()) ? '\0' : (*this)[_index];
}
char CStringParser::getNextChar() {
return (_index >= size()) ? '\0' : (*this)[_index++];
}
void CStringParser::skipSpaces() {
while (_index < size() && Common::isSpace(currentChar()))
++_index;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,75 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_STRING_PARSER_H
#define TITANIC_STRING_PARSER_H
#include "titanic/support/string.h"
namespace Titanic {
class CStringParser : public CString {
private:
uint _index;
private:
/**
* Gets the character at the current index
*/
char currentChar() const;
/**
* Gets the next character, and increments the parsing index
*/
char getNextChar();
/**
* Skips over any spaces
*/
void skipSpaces();
public:
CStringParser() : CString(), _index(0) {}
CStringParser(const CString &str) : CString(str), _index(0) {}
/**
* Skips over any specified separator characters in our string
* at the current index
*/
void skipSeparators(const CString &separatorChars);
/**
* Parses out a string from a source string at the current index
* @param resultStr String to hold the resulting sring
* @param separatorChras List of characters that separate string values
* @param allowQuotes If true, handles double-quoted substrings
* @returns True if a string entry was extracted
*/
bool parse(CString &resultStr, const CString &separatorChars, bool allowQuotes = false);
/**
* Reads an integer from the string
*/
uint readInt();
};
} // End of namespace Titanic
#endif /* TITANIC_STRING_PARSER_H */

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/strings.h"
#include "titanic/support/files_manager.h"
#include "titanic/titanic.h"
namespace Titanic {
void Strings::load() {
Common::SeekableReadStream *r = g_vm->_filesManager->getResource("TEXT/STRINGS");
while (r->pos() < r->size())
push_back(readStringFromStream(r));
delete r;
}
} // End of namespace Titanic

View File

@@ -0,0 +1,244 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_STRINGS_H
#define TITANIC_STRINGS_H
#include "common/str-array.h"
namespace Titanic {
enum StringId {
BLANK,
STANDING_OUTSIDE_PELLERATOR,
BOT_BLOCKING_PELLERATOR,
FROZEN_PELLERATOR,
SUCCUBUS_IS_IN_STANDBY,
NOTHING_TO_DELIVER,
NOTHING_IN_SUCCUBUS_TRAY,
SUCCUBUS_SINGLE_DELIVERY,
ONE_ALLOCATED_CHICKEN_PER_CUSTOMER,
ONE_CHICKEN_PER_CUSTOMER,
UPGRADED_TO_FIRST_CLASS,
UPGRADED_TO_SECOND_CLASS,
ROOM_RESERVED_FOR_FIRST_CLASS,
NO_LOSERS,
CLASS_NOT_PERMITTED_IN_AREA,
EXIT_FROM_OTHER_SIDE,
TRANSPORT_OUT_OF_ORDER,
FAN_HAS_BLOWN_A_FUSE,
POKE_WITH_LONG_STICK,
TOO_SHORT_TO_REACH_BRANCHES,
OUTSIDE_ELEVATOR_NUM,
BOT_BLOCKING_ELEVATOR,
ELEVATOR_NON_FUNCTIONAL,
LIGHT_IS_LOOSE,
LUMI_GLOW_LIGHTS,
ALREADY_HAVE_STICK,
GLASS_IS_UNBREAKABLE,
FOR_STICK_BREAK_GLASS,
DISPENSOR_HAS_UNBREAKABLE_GLASS,
CHICKEN_IS_CLEAN,
ADJUST_VIEWING_APPARATUS,
CANNOT_TAKE_CAGE_LOCKED,
ALREADY_AT_DESTINATION,
CLASS_NOT_ALLOWED_AT_DEST,
AT_LEAST_3RD_CLASS_FOR_HELP,
NO_ROOM_ASSIGNED,
ELEVATOR_NOT_BELOW_27,
SELECT_GAME_TO_LOAD,
SELECT_GAME_TO_SAVE,
SUPPLY_GALACTIC_REFERENCE,
LOCKED_MUSIC_SYSTEM,
STUCK_TO_BRANCH,
FROZEN_TO_BRANCH,
CHECK_IN_AT_RECEPTION,
FOODSTUFF_ALREADY_GARNISHED,
DISPENSOR_IS_EMPTY,
PUT_FOOD_UNDER_DISPENSOR,
SEASONAL_SWITCH_NOT_WORKING,
YOUR_STATEROOM,
BED_NOT_SUPPORT_YOUR_WEIGHT,
NOT_YOUR_ASSIGNED_ROOM,
OUT_OF_REACH,
SUCCUBUS_DESCRIPTION,
CANAL_CLOSED_FOR_WINTER,
AREA_OFF_LIMIT_TO_PASSENGERS,
GO_WHERE,
NICE_IF_TAKE_BUT_CANT,
BOWL_OF_NUTS,
NOT_A_BOWL_OF_NUTS,
CANT_SUMMON_DOORBOT,
CANT_SUMMON_BELLBOT,
NO_ONE_TO_TALK_TO,
TALKING_TO,
DOORBOT_NAME,
DESKBOT_NAME,
LIFTBOT_NAME,
PARROT_NAME,
BARBOT_NAME,
CHATTERBOT_NAME,
BELLBOT_NAME,
MAITRED_NAME,
SUCCUBUS_NAME,
UNKNOWN_NAME,
ARM_ALREADY_HOLDING,
YOU_CANT_GET_THIS,
DOESNT_DO_ANYTHING,
DOESNT_WANT_THIS,
DOES_NOT_REACH,
CHICKEN_ALREADY_CLEAN,
HOSE_INCOMPATIBLE,
INCORRECTLY_CALIBRATED,
GONDOLIERS_FIRST_CLASS_ONLY,
NOTHING_ON_CHANNEL,
TELEVISION_CONTROL,
OPERATE_ENTERTAINMENT,
OPERATE_LIGHTS,
DEPLOY_FLORAL_ENHANCEMENT,
DEPLOY_FULLY_RELAXATION,
DEPLOY_COMFORT_WORKSTATION,
DEPLOY_MINOR_STORAGE,
DEPLOY_MAJOR_RELAXATION,
INFLATE_RELAXATION_DEVICE,
DEPLOY_MAINTENANCE_HUB,
DEPLOY_EXECUTIVE_SURFACE,
DEPLOY_MINOR_RELAXATION,
DEPLOY_SINK,
DEPLOY_MAJOR_STORAGE,
SUCCUBUS_DELIVERY_SYSTEM,
NAVIGATION_CONTROLLER,
SKIP_NAVIGATION,
SUMMON_ELEVATOR,
SUMMON_PELLERATOR,
GO_TO_BOTTOM_OF_WELL,
GO_TO_TOP_OF_WELL,
GO_TO_STATEROOM,
GO_TO_BAR,
GO_TO_PROMENADE_DECK,
GO_TO_ARBORETUM,
GO_TO_MUSIC_ROOM,
GO_TO_1ST_CLASS_RESTAURANT,
THE_PARROT_LOBBY,
THE_CREATORS_CHAMBER,
THE_BRIDGE,
THE_BILGE_ROOM,
THE_SCULPTURE_CHAMBER,
THE_ARBORETUM,
THE_BOTTOM_OF_THE_WELL,
THE_PROMENADE_DECK,
RESTAURANT_1ST_CLASS,
TITANIAS_ROOM,
THE_BAR,
THE_EMBARKATION_LOBBY,
THE_MUSIC_ROOM,
UNKNOWN_ROOM,
THE_SERVICE_ELEVATOR,
SGT_LEISURE_LOUNGE,
THE_ELEVATOR,
THE_DOME,
THE_PELLERATOR,
THE_TOP_OF_THE_WELL,
NOWHERE_TO_GO,
CLASS_1,
CLASS_2,
CLASS_3,
CLASS_NONE,
YOUR_ASSIGNED_ROOM,
PREVIOUSLY_ASSIGNED_ROOM,
SAVED_CHEVRON,
CURRENT_LOCATION,
ELEVATOR_NUM,
FLOOR_NUM,
ROOM_NUM,
SHIFT_CLICK_TO_EDIT,
A_HOT,
A_COLD,
LOAD_THE_GAME,
SAVE_THE_GAME,
EMPTY,
QUIT_THE_GAME,
SURE_YOU_WANT_TO_QUIT,
CHANGE_VOLUME_SETTINGS,
MASTER_VOLUME,
MUSIC_VOLUME,
PARROT_VOLUME,
SPEECH_VOLUME,
// German version only
DE_SUMMER,
DE_AUTUMN,
DE_WINTER,
DE_SPRING,
DE_SUMMER_ARBORETUM,
DE_AUTUMN_ARBORETUM,
DE_WINTER_ARBORETUM,
DE_SPRING_ARBORETUM,
DE_ARBORETUM_MSG1,
DE_ARBORETUM_MSG2,
DE_BRIDGE_MSG1,
DE_BRIDGE_MSG2,
DE_BRIDGE_MSG3,
DE_BRIDGE_MSG4,
DE_BRIDGE_MSG5,
DE_BRIDGE_MSG6,
DE_BRIDGE_MSG7,
DE_BRIDGE_MSG8,
DE_BRIDGE_MSG9,
DE_BRIDGE_MSG10,
DE_PROMENADE_DECK_MSG1,
DE_PROMENADE_DECK_MSG2,
DE_PROMENADE_DECK_MSG3,
DE_PROMENADE_DECK_MSG4,
DE_PROMENADE_DECK_MSG5,
DE_PROMENADE_DECK_MSG6,
DE_PROMENADE_DECK_MSG7,
DE_PROMENADE_DECK_MSG8,
DE_PROMENADE_DECK_MSG9,
DE_PROMENADE_DECK_MSG10,
DE_SGTLOBBY_MSG1,
DE_SGTLOBBY_MSG2,
DE_SGTLOBBY_MSG3,
DE_SGTLOBBY_MSG4,
DE_SGTLOBBY_MSG5,
DE_SGTLOBBY_MSG6,
DE_SGTLOBBY_MSG7,
DE_SGTLOBBY_MSG8,
DE_TITANIA_MSG1,
DE_TITANIA_MSG2,
DE_TITANIA_MSG3,
DE_TITANIA_MSG4,
DE_TITANIA_MSG5,
DE_TITANIA_MSG6,
DE_TITANIA_MSG7,
DE_TITANIA_MSG8
};
class Strings : public Common::StringArray {
public:
void load();
};
} // End of namespace Titanic
#endif /* TITANIC_STRINGS_H */

View File

@@ -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 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/text_cursor.h"
#include "titanic/events.h"
#include "titanic/support/screen_manager.h"
#include "titanic/titanic.h"
#include "common/textconsole.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, 16);
}
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

View File

@@ -0,0 +1,120 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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 */

View File

@@ -0,0 +1,205 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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), _action(action),
_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

View File

@@ -0,0 +1,137 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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
*/
void save(SimpleFile *file, int indent) override;
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override;
/**
* 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 */

View File

@@ -0,0 +1,59 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/transparency_surface.h"
#include "common/algorithm.h"
#include "common/textconsole.h"
namespace Titanic {
CTransparencySurface::CTransparencySurface(const Graphics::Surface *surface,
TransparencyMode transMode) : _surface(surface) {
_pitch = 0;
_runLength = 0;
_flag = false;
_opaqueColor = 0;
_transparentColor = 0xff;
switch (transMode) {
case TRANS_MASK0:
case TRANS_ALPHA0:
_transparentColor = 0;
_opaqueColor = 0xff;
break;
case TRANS_MASK255:
case TRANS_ALPHA255:
_transparentColor = 0xff;
_opaqueColor = 0;
break;
case TRANS_DEFAULT:
// If top left pixel is low, then 0 is the transparent color
if (*(const byte *)surface->getPixels() < 0x80) {
_opaqueColor = 0xff;
_transparentColor = 0;
}
break;
default:
break;
}
}
} // End of namespace Titanic

View File

@@ -0,0 +1,107 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef TITANIC_TRANSPARENCY_SURFACE_H
#define TITANIC_TRANSPARENCY_SURFACE_H
#include "common/rect.h"
#include "graphics/surface.h"
namespace Titanic {
enum TransparencyMode {
TRANS_MASK0 = 0, TRANS_MASK255 = 1, TRANS_ALPHA0 = 2,
TRANS_ALPHA255 = 3, TRANS_DEFAULT = 4
};
class CTransparencySurface {
private:
const Graphics::Surface *_surface;
Common::Point _pos;
int _pitch;
int _runLength;
bool _flag;
byte _transparentColor;
byte _opaqueColor;
private:
/**
* Returns a a pixel from the transparency surface
*/
inline uint getPixel() const {
byte pixel = *(const byte *)_surface->getBasePtr(_pos.x, _pos.y);
return pixel;
}
public:
/**
* Constructor
*/
CTransparencySurface(const Graphics::Surface *surface, TransparencyMode transMode);
/**
* Sets the row to get transparencies from
*/
inline void setRow(int yp) { _pos.y = yp; }
/**
* Sets the column to get transparencies from
*/
inline void setCol(int xp) { _pos.x = xp; }
/**
* Moves reading position horizontally by a single pixel
*/
inline int moveX() {
if (++_pos.x >= _surface->w) {
_pos.x = 0;
++_pos.y;
}
return 1;
}
/**
* Returns the alpha value for the pixel (0-31)
*/
inline uint getAlpha() const {
byte pixel = getPixel();
return _opaqueColor ? 0xFF - pixel : pixel;
}
/**
* Returns true if the pixel is opaque
*/
inline bool isPixelOpaque() const {
byte pixel = getPixel();
return _opaqueColor ? pixel >= 0xf0 : pixel < 0x10;
}
/**
* Returns true if the pixel is completely transparent
*/
inline bool isPixelTransparent() const {
byte pixel = getPixel();
return _transparentColor ? pixel >= 0xf0 : pixel < 0x10;
}
};
} // End of namespace Titanic
#endif /* TITANIC_TRANSPARENCY_SURFACE_H */

View File

@@ -0,0 +1,664 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "titanic/support/video_surface.h"
#include "titanic/support/image_decoders.h"
#include "titanic/support/screen_manager.h"
#include "titanic/support/transparency_surface.h"
#include "titanic/titanic.h"
namespace Titanic {
int CVideoSurface::_videoSurfaceCounter = 0;
byte CVideoSurface::_palette1[32][32];
byte CVideoSurface::_palette2[32][32];
CVideoSurface::CVideoSurface(CScreenManager *screenManager) :
_screenManager(screenManager), _rawSurface(nullptr), _movie(nullptr),
_pendingLoad(false), _flipVertically(false), _fastBlitFlag(false),
_transparencySurface(nullptr), _transparencyMode(TRANS_DEFAULT),
_freeTransparencySurface(DisposeAfterUse::NO), _hasFrame(true), _lockCount(0) {
_videoSurfaceNum = _videoSurfaceCounter++;
}
CVideoSurface::~CVideoSurface() {
--_videoSurfaceCounter;
if (_freeTransparencySurface == DisposeAfterUse::YES)
delete _transparencySurface;
}
void CVideoSurface::setupPalette(byte palette[32][32], byte val) {
for (uint idx1 = 0; idx1 < 32; ++idx1) {
for (uint idx2 = 0, base = 0; idx2 < 32; ++idx2, base += idx1) {
uint v = base / 31;
palette[idx1][idx2] = (byte)v;
if (val != 0xff && v != idx2) {
assert(0);
}
}
}
}
void CVideoSurface::setSurface(CScreenManager *screenManager, DirectDrawSurface *surface) {
_screenManager = screenManager;
_ddSurface = surface;
}
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->_flipVertically)
flippedBlitRect(srcBounds, destBounds, src);
else
blitRect(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::blitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) {
src->lock();
lock();
if (src->_fastBlitFlag) {
_rawSurface->blitFrom(*src->_rawSurface, srcRect, Point(destRect.left, destRect.top));
} else if (src->getTransparencySurface()) {
transBlitRect(srcRect, destRect, src, false);
} else if (lock()) {
if (src->lock()) {
const Graphics::ManagedSurface *srcSurface = src->_rawSurface;
Graphics::ManagedSurface *destSurface = _rawSurface;
const uint transColor = src->getTransparencyColor();
destSurface->transBlitFrom(*srcSurface, srcRect, destRect, transColor);
src->unlock();
}
unlock();
}
}
void CVideoSurface::flippedBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src) {
if (src->getTransparencySurface()) {
transBlitRect(srcRect, destRect, src, true);
} else if (lock()) {
if (src->lock()) {
Graphics::ManagedSurface *srcSurface = src->_rawSurface;
Graphics::ManagedSurface *destSurface = _rawSurface;
const Graphics::Surface srcArea = srcSurface->getSubArea(srcRect);
const uint transColor = src->getTransparencyColor();
// Vertically flip the source area
Graphics::ManagedSurface flippedArea(srcArea.w, srcArea.h, srcArea.format);
for (int y = 0; y < srcArea.h; ++y) {
const byte *pSrc = (const byte *)srcArea.getBasePtr(0, y);
byte *pDest = (byte *)flippedArea.getBasePtr(0, flippedArea.h - y - 1);
Common::copy(pSrc, pSrc + srcArea.pitch, pDest);
}
destSurface->transBlitFrom(flippedArea,
Common::Point(destRect.left, destRect.top), transColor);
src->unlock();
}
unlock();
}
}
void CVideoSurface::transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src, bool flipFlag) {
assert(srcRect.width() == destRect.width() && srcRect.height() == destRect.height());
assert(src->getPixelDepth() == 2);
if (lock()) {
if (src->lock()) {
Graphics::ManagedSurface *srcSurface = src->_rawSurface;
Graphics::ManagedSurface *destSurface = _rawSurface;
Graphics::Surface destArea = destSurface->getSubArea(destRect);
const uint16 *srcPtr = (const uint16 *)srcSurface->getBasePtr(
srcRect.left, flipFlag ? srcRect.top : srcRect.bottom - 1);
uint16 *destPtr = (uint16 *)destArea.getBasePtr(0, destArea.h - 1);
bool isAlpha = src->_transparencyMode == TRANS_ALPHA0 ||
src->_transparencyMode == TRANS_ALPHA255;
CTransparencySurface transSurface(src->getTransparencySurface(), src->_transparencyMode);
for (int yCtr = 0; yCtr < srcRect.height(); ++yCtr) {
// Prepare for copying the line
const uint16 *lineSrcP = srcPtr;
uint16 *lineDestP = destPtr;
transSurface.setRow(flipFlag ? srcRect.top + yCtr : srcRect.bottom - yCtr - 1);
transSurface.setCol(srcRect.left);
for (int srcX = srcRect.left; srcX < srcRect.right; ++srcX) {
if (transSurface.isPixelOpaque())
*lineDestP = *lineSrcP;
else if (!transSurface.isPixelTransparent())
copyPixel(lineDestP, lineSrcP, transSurface.getAlpha() >> 3, srcSurface->format, isAlpha);
++lineSrcP;
++lineDestP;
transSurface.moveX();
}
// Move to next line
srcPtr = flipFlag ? srcPtr + (src->getPitch() / 2) :
srcPtr - (src->getPitch() / 2);
destPtr -= destArea.pitch / 2;
}
src->unlock();
}
unlock();
}
}
uint CVideoSurface::getTransparencyColor() {
return getPixelDepth() == 2 ? 0xf81f : 0x7c1f;
}
bool CVideoSurface::hasFrame() {
if (_hasFrame) {
_hasFrame = false;
return true;
} else if (_movie) {
return _movie->hasVideoFrame();
} else {
return false;
}
}
#define RGB_SHIFT 3
void CVideoSurface::copyPixel(uint16 *destP, const uint16 *srcP, byte alpha,
const Graphics::PixelFormat &srcFormat, bool isAlpha) {
const Graphics::PixelFormat destFormat = _ddSurface->getFormat();
alpha &= 0xff;
assert(alpha < 32);
// Get the source color
byte r, g, b;
srcFormat.colorToRGB(*srcP, r, g, b);
r >>= RGB_SHIFT;
g >>= RGB_SHIFT;
b >>= RGB_SHIFT;
if (isAlpha) {
r = _palette1[31 - alpha][r];
g = _palette1[31 - alpha][g];
b = _palette1[31 - alpha][b];
}
byte r2, g2, b2;
destFormat.colorToRGB(*destP, r2, g2, b2);
r2 >>= RGB_SHIFT;
g2 >>= RGB_SHIFT;
b2 >>= RGB_SHIFT;
r2 = _palette1[alpha][r2];
g2 = _palette1[alpha][g2];
b2 = _palette1[alpha][b2];
*destP = destFormat.RGBToColor((r + r2) << RGB_SHIFT,
(g + g2) << RGB_SHIFT, (b + b2) << RGB_SHIFT);
}
/*------------------------------------------------------------------------*/
OSVideoSurface::OSVideoSurface(CScreenManager *screenManager, DirectDrawSurface *surface) :
CVideoSurface(screenManager) {
_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();
}
}
OSVideoSurface::~OSVideoSurface() {
if (_ddSurface)
_videoSurfaceCounter -= OSVideoSurface::freeSurface();
}
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, int bpp) {
freeSurface();
_screenManager->resizeSurface(this, width, height, bpp);
if (_ddSurface)
_videoSurfaceCounter += _ddSurface->getSize();
}
void OSVideoSurface::resize(int width, int height, int bpp) {
if (!_ddSurface || _ddSurface->getWidth() != width ||
_ddSurface->getHeight() != height)
recreate(width, height, bpp);
}
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()) {
if (_transparencySurface) {
// WORKAROUND: Original had the setRow _flipVertically check in reverse.
// Pretty sure putting it the way is below is the correct way
CTransparencySurface transSurface(&_transparencySurface->rawSurface(), _transparencyMode);
transSurface.setRow(_flipVertically ? getHeight() - pt.y - 1 : pt.y);
transSurface.setCol(pt.x);
if (transSurface.isPixelTransparent())
return getTransparencyColor();
}
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::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");
_ddSurface->fill(nullptr, 0);
}
void OSVideoSurface::playMovie(uint flags, CGameObject *obj) {
if (loadIfReady() && _movie)
_movie->play(flags, obj);
}
void OSVideoSurface::playMovie(uint startFrame, uint endFrame, uint flags, CGameObject *obj) {
if (loadIfReady() && _movie) {
_movie->play(startFrame, endFrame, flags, obj);
_movie->pause();
}
}
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() || !_flipVertically)
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);
}
_flipVertically = 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::dupMovieTransparency() const {
return _movie ? _movie->duplicateTransparency() : 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

View File

@@ -0,0 +1,544 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#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/support/transparency_surface.h"
#include "titanic/core/list.h"
#include "titanic/core/resource_key.h"
namespace Titanic {
class CScreenManager;
class CJPEGDecode;
class CTargaDecode;
class CVideoSurface : public ListItem {
friend class CJPEGDecode;
friend class CTargaDecode;
private:
static byte _palette1[32][32];
static byte _palette2[32][32];
/**
* Setup the shading palettes
*/
static void setupPalette(byte palette[32][32], byte val);
public:
/**
* Setup statics
*/
static void setup() {
setupPalette(_palette1, 0xff);
}
private:
/**
* Calculates blitting bounds
*/
void clipBounds(Rect &srcRect, Rect &destRect, CVideoSurface *srcSurface,
const Rect *subRect = nullptr, const Point *destPos = nullptr);
/**
* Copies a rect from a given source surface
*/
void blitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src);
/**
* Copies a rect from a given source surface and draws it vertically flipped
*/
void flippedBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src);
void transBlitRect(const Rect &srcRect, const Rect &destRect, CVideoSurface *src, bool flipFlag);
protected:
static int _videoSurfaceCounter;
protected:
CScreenManager *_screenManager;
Graphics::ManagedSurface *_rawSurface;
bool _pendingLoad;
Graphics::ManagedSurface *_transparencySurface;
DisposeAfterUse::Flag _freeTransparencySurface;
int _videoSurfaceNum;
bool _hasFrame;
int _lockCount;
public:
CMovie *_movie;
DirectDrawSurface *_ddSurface;
bool _fastBlitFlag;
bool _flipVertically;
CResourceKey _resourceKey;
TransparencyMode _transparencyMode;
public:
CVideoSurface(CScreenManager *screenManager);
~CVideoSurface() override;
/**
* Set the underlying surface for this video surface
*/
void setSurface(CScreenManager *screenManager, DirectDrawSurface *surface);
/**
* Load the data for the class from file
*/
void load(SimpleFile *file) override {
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, int bpp = 16) = 0;
/**
* Resizes the surface
*/
virtual void resize(int width, int height, int bpp = 16) = 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;
/**
* 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 transparency surface
*/
virtual Graphics::ManagedSurface *dupMovieTransparency() 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 a raw surface to use as a transparency mask for the surface
*/
void setTransparencySurface(Graphics::ManagedSurface *surface) { _transparencySurface = surface; }
/**
* Get the previously set transparency mask surface
*/
const Graphics::Surface *getTransparencySurface() const {
return _transparencySurface ? &_transparencySurface->rawSurface() : nullptr;
}
/**
* 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();
/**
* Copies a pixel, handling transparency
* @param destP Dest pointer to 16-bit pixel
* @param srcP Source pointer to 16-bit pixel
* @param alpha Alpha (0-31). At 0, it's completely opaque,
* and overwrites the dest pixel. Through to 31, which is completely
* transparent, and ignores the source pixel.
* @param srcFormat The source surface format
* @param isAlpha If true, has alpha channel
*/
void copyPixel(uint16 *destP, const uint16 *srcP, byte alpha,
const Graphics::PixelFormat &srcFormat, bool isAlpha);
};
class OSVideoSurface : public CVideoSurface {
friend class OSMovie;
public:
OSVideoSurface(CScreenManager *screenManager, DirectDrawSurface *surface);
OSVideoSurface(CScreenManager *screenManager, const CResourceKey &key, bool flag = false);
~OSVideoSurface() override;
/**
* Load the surface with the passed resource
*/
void loadResource(const CResourceKey &key) override;
/**
* Loads a Targa image file specified by the resource key
*/
void loadTarga(const CResourceKey &key) override;
/**
* Loads a JPEG image file specified by the resource key
*/
void loadJPEG(const CResourceKey &key) override;
/**
* Loads a Targa image file specified by the given name
*/
void loadTarga(const CString &name) override;
/**
* 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
*/
void loadMovie(const CResourceKey &key, bool destroyFlag = false) override;
/**
* Lock the surface for direct access to the pixels
*/
bool lock() override;
/**
* Unlocks the surface after prior calls to lock()
*/
void unlock() override;
/**
* Returns true if an underlying raw surface has been set
*/
bool hasSurface() override;
/**
* Returns the width of the surface
*/
int getWidth() override;
/**
* Returns the height of the surface
*/
int getHeight() override;
/**
* Returns the pitch of the surface in bytes
*/
int getPitch() override;
/**
* Returns the bytes per pixel of the surface
*/
int getBpp() override;
/**
* Recreates the surface with the designated size
*/
void recreate(int width, int height, int bpp = 16) override;
/**
* Resizes the surface
*/
void resize(int width, int height, int bpp = 16) override;
/**
* Detachs the underlying raw surface
*/
void detachSurface() override;
/**
* Returns the number of bytes per pixel in the surface
*/
int getPixelDepth() override;
/**
* Gets the pixel at the specified position within the surface
*/
uint16 getPixel(const Point &pt) override;
/**
* Sets a pixel at a specified position within the surface
*/
void setPixel(const Point &pt, uint pixel) override;
/**
* Shifts the colors of the surface.. maybe greys it out?
*/
void shiftColors() override;
/**
* Clears the entire surface to black
*/
void clear() override;
/**
* Plays a movie, loading it from the specified _resource
* if not already loaded
*/
void playMovie(uint flags, CGameObject *obj) override;
/**
* Plays a movie, loading it from the specified _resource
* if not already loaded
*/
void playMovie(uint startFrame, uint endFrame, uint flags, CGameObject *obj) override;
/**
* Plays a movie, loading it from the specified _resource
* if not already loaded
*/
void playMovie(uint startFrame, uint endFrame, uint initialFrame, uint flags, CGameObject *obj) override;
/**
* Stops any movie currently attached to the surface
*/
void stopMovie() override;
/**
* Sets the movie to the specified frame number
*/
void setMovieFrame(uint frameNumber) override;
/**
* Adds a movie playback event
*/
void addMovieEvent(int frameNumber, CGameObject *obj) override;
/**
* Set the movie frame rate
*/
void setMovieFrameRate(double rate) override;
/**
* Return any movie range info associated with the surface's movie
*/
const CMovieRangeInfoList *getMovieRangeInfo() const override;
/**
*
*/
void flipVertically(bool needsLock = true) override;
/**
* Loads the surface's resource if there's one pending
*/
bool loadIfReady() override;
/**
* Loads the surface data based on the currently set resource key
*/
bool load() override;
/**
* Does a replacement of transparent pixels on certain lines at regular
* intervals. This is totally weird
*/
void transPixelate() override;
/**
* Duplicates movie transparency surface
*/
Graphics::ManagedSurface *dupMovieTransparency() const override;
/**
* Frees the underlying surface
*/
int freeSurface() override;
/**
* Get a pointer into the underlying surface
*/
uint16 *getBasePtr(int x, int y) override;
};
} // End of namespace Titanic
#endif /* TITANIC_VIDEO_SURFACE_H */