aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/sword1/animation.cpp186
-rw-r--r--engines/sword1/animation.h35
-rw-r--r--engines/sword1/logic.cpp2
-rw-r--r--engines/sword1/text.cpp16
-rw-r--r--engines/sword1/text.h8
5 files changed, 196 insertions, 51 deletions
diff --git a/engines/sword1/animation.cpp b/engines/sword1/animation.cpp
index 5a381e7393..6893d122ad 100644
--- a/engines/sword1/animation.cpp
+++ b/engines/sword1/animation.cpp
@@ -25,6 +25,7 @@
#include "sword1/sword1.h"
#include "sword1/animation.h"
#include "sword1/credits.h"
+#include "sword1/text.h"
#include "sound/vorbis.h"
#include "common/config-manager.h"
@@ -62,11 +63,13 @@ static const char *sequenceList[20] = {
// Basic movie player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer::MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys)
- : _scr(scr), _snd(snd), _system(sys) {
+MoviePlayer::MoviePlayer(Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)
+ : _screen(screen), _textMan(textMan), _snd(snd), _system(system) {
_bgSoundStream = NULL;
_ticks = 0;
- _frameBuffer = NULL;
+ _textSpriteBuf = NULL;
+ _black = 1;
+ _white = 255;
_currentFrame = 0;
_forceFrame = false;
_framesSkipped = 0;
@@ -78,15 +81,36 @@ MoviePlayer::~MoviePlayer(void) {
void MoviePlayer::updatePalette(byte *pal, bool packed) {
byte palette[4 * 256];
byte *p = palette;
+
+ uint32 maxWeight = 0;
+ uint32 minWeight = 0xFFFFFFFF;
+
for (int i = 0; i < 256; i++) {
- *p++ = *pal++;
- *p++ = *pal++;
- *p++ = *pal++;
+ int r = *pal++;
+ int g = *pal++;
+ int b = *pal++;
+
if (!packed)
- *p++ = *pal++;
- else
- *p++ = 0;
+ pal++;
+
+ uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b;
+
+ if (weight >= maxWeight) {
+ _white = i;
+ maxWeight = weight;
+ }
+
+ if (weight <= minWeight) {
+ _black = i;
+ minWeight = i;
+ }
+
+ *p++ = r;
+ *p++ = g;
+ *p++ = b;
+ *p++ = 0;
}
+
_system->setPalette(palette, 0, 256);
_forceFrame = true;
}
@@ -148,16 +172,58 @@ bool MoviePlayer::syncFrame(void) {
* @param id the id of the file
*/
bool MoviePlayer::load(uint32 id) {
+ Common::File f;
+ char fileName[20];
+
_id = id;
_bgSoundStream = NULL;
+
+ if (SwordEngine::_systemVars.showText) {
+ sprintf(fileName, "%s.txt", sequenceList[id]);
+ if (f.open(fileName)) {
+ char line[120];
+ int lineNo = 0;
+ int lastEnd = -1;
+
+ _movieTexts.clear();
+ while (f.readLine(line, sizeof(line))) {
+ lineNo++;
+ if (line[0] == '#' || line[0] == 0) {
+ continue;
+ }
+
+ char *ptr = line;
+
+ // TODO: Better error handling
+ int startFrame = strtoul(ptr, &ptr, 10);
+ int endFrame = strtoul(ptr, &ptr, 10);
+
+ while (*ptr && isspace(*ptr))
+ ptr++;
+
+ if (startFrame > endFrame) {
+ warning("%s:%d: startFrame (%d) > endFrame (%d)", fileName, lineNo, startFrame, endFrame);
+ continue;
+ }
+
+ if (startFrame <= lastEnd) {
+ warning("%s:%d startFrame (%d) <= lastEnd (%d)", fileName, lineNo, startFrame, lastEnd);
+ continue;
+ }
+
+ _movieTexts.push_back(new MovieText(startFrame, endFrame, ptr));
+ lastEnd = endFrame;
+ }
+ }
+ }
+
if (SwordEngine::_systemVars.cutscenePackVersion == 1) {
if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) {
#ifdef USE_VORBIS
// these sequences are language specific
- char sndName[20];
- sprintf(sndName, "%s.snd", sequenceList[id]);
+ sprintf(fileName, "%s.snd", sequenceList[id]);
Common::File *oggSource = new Common::File();
- if (oggSource->open(sndName)) {
+ if (oggSource->open(fileName)) {
SplittedAudioStream *sStream = new SplittedAudioStream();
uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2.
// for each segment and each of the 7 languages, we've got fileoffset and size
@@ -170,13 +236,13 @@ bool MoviePlayer::load(uint32 id) {
Common::MemoryReadStream *stream = oggSource->readStream(segSize);
Audio::AudioStream *apStream = Audio::makeVorbisStream(stream, true);
if (!apStream)
- error("Can't create Vorbis Stream from file %s", sndName);
+ error("Can't create Vorbis Stream from file %s", fileName);
sStream->appendStream(apStream);
}
free(header);
_bgSoundStream = sStream;
} else
- warning("Sound file \"%s\" not found", sndName);
+ warning("Sound file \"%s\" not found", fileName);
delete oggSource;
#endif
initOverlays(id);
@@ -186,7 +252,7 @@ bool MoviePlayer::load(uint32 id) {
}
void MoviePlayer::play(void) {
- _scr->clearScreen();
+ _screen->clearScreen();
_framesSkipped = 0;
_ticks = _system->getMillis();
_bgSoundStream = Audio::AudioStream::openStreamFile(sequenceList[_id]);
@@ -197,6 +263,24 @@ void MoviePlayer::play(void) {
bool terminated = false;
Common::EventManager *eventMan = _system->getEventManager();
while (!terminated && decodeFrame()) {
+ if (!_movieTexts.empty()) {
+ if (_currentFrame == _movieTexts[0]->_startFrame) {
+ _textMan->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL);
+
+ FrameHeader *frame = _textMan->giveSpriteData(2);
+ _textWidth = frame->width;
+ _textHeight = frame->height;
+ _textX = 320 - _textWidth / 2;
+ _textY = 420 - _textHeight;
+ _textSpriteBuf = (byte *)calloc(_textHeight, _textWidth);
+ }
+ if (_currentFrame == _movieTexts[0]->_endFrame) {
+ _textMan->releaseText(2);
+ free(_textSpriteBuf);
+ _textSpriteBuf = NULL;
+ delete _movieTexts.remove_at(0);
+ }
+ }
processFrame();
if (syncFrame())
updateScreen();
@@ -221,6 +305,11 @@ void MoviePlayer::play(void) {
}
}
}
+
+ while (!_movieTexts.empty()) {
+ delete _movieTexts.remove_at(_movieTexts.size() - 1);
+ }
+
while (_snd->isSoundHandleActive(_bgSoundHandle))
_system->delayMillis(100);
@@ -301,14 +390,13 @@ int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) {
// Movie player for the new DXA movies
///////////////////////////////////////////////////////////////////////////////
-MoviePlayerDXA::MoviePlayerDXA(Screen *src, Audio::Mixer *snd, OSystem *sys)
- : MoviePlayer(src, snd, sys) {
+MoviePlayerDXA::MoviePlayerDXA(Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)
+ : MoviePlayer(screen, textMan, snd, system) {
debug(0, "Creating DXA cutscene player");
}
MoviePlayerDXA::~MoviePlayerDXA(void) {
closeFile();
- // free(_frameBuffer);
}
bool MoviePlayerDXA::load(uint32 id) {
@@ -348,13 +436,51 @@ bool MoviePlayerDXA::decodeFrame(void) {
}
void MoviePlayerDXA::processFrame(void) {
- // TODO
+ // TODO: Handle the advanced cutscene packs. Do they really exist?
+
+ // We cannot draw the text to _drawBuffer, sinzce ethat's one of the
+ // decoder's internal buffers. Instead, we copy part of _drawBuffer
+ // to the text sprite.
+
+ if (_textSpriteBuf) {
+ memset(_textSpriteBuf, 0, _textWidth * _textHeight);
+
+ // FIXME: This is inefficient
+ int x, y;
+
+ for (y = _textY; y < _textY + _textHeight; y++) {
+ for (x = _textX; x < _textX + _textWidth; x++) {
+ if (x >= _frameX && x <= _frameX + _frameWidth && y >= _frameY && y <= _frameY + _frameWidth) {
+ _textSpriteBuf[(y - _textY) * _textWidth + x - _textX] = _drawBuffer[(y - _frameY) * _frameWidth + x - _frameX];
+ }
+ }
+ }
+
+ byte *src = (byte *)_textMan->giveSpriteData(2) + sizeof(FrameHeader);
+ byte *dst = _textSpriteBuf;
+
+ for (y = 0; y < _textHeight; y++) {
+ for (x = 0; x < _textWidth; x++) {
+ switch (src[x]) {
+ case BORDER_COL:
+ dst[x] = _black;
+ break;
+ case LETTER_COL:
+ dst[x] = _white;
+ break;
+ }
+ }
+ src += _textWidth;
+ dst += _textWidth;
+ }
+ }
}
void MoviePlayerDXA::updateScreen(void) {
- // Using _drawBuffer directly should work, as long as we don't do any
- // post-processing of the frame.
_system->copyRectToScreen(_drawBuffer, _frameWidth, _frameX, _frameY, _frameWidth, _frameHeight);
+ if (_textSpriteBuf) {
+ _system->copyRectToScreen(_textSpriteBuf, _textWidth, _textX, _textY, _textWidth, _textHeight);
+ }
_system->updateScreen();
}
@@ -366,8 +492,8 @@ void MoviePlayerDXA::updateScreen(void) {
// Movie player for the old MPEG movies
///////////////////////////////////////////////////////////////////////////////
-MoviePlayerMPEG::MoviePlayerMPEG(Screen *src, Audio::Mixer *snd, OSystem *sys)
- : MoviePlayer(src, snd, sys) {
+MoviePlayerMPEG::MoviePlayerMPEG(Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system)
+ : MoviePlayer(screen, textMan, snd, system) {
#ifdef BACKEND_8BIT
debug(0, "Creating MPEG cutscene player (8-bit)");
#else
@@ -399,7 +525,7 @@ void MoviePlayerMPEG::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor
bool MoviePlayerMPEG::load(uint32 id) {
if (MoviePlayer::load(id)) {
- _anim = new AnimationState(this, _scr, _system);
+ _anim = new AnimationState(this, _screen, _system);
return _anim->init(sequenceList[id]);
}
return false;
@@ -454,8 +580,8 @@ void MoviePlayerMPEG::processFrame(void) {
#endif
}
-AnimationState::AnimationState(MoviePlayer *player, Screen *scr, OSystem *sys)
- : BaseAnimationState(sys, 640, 400), _player(player), _scr(scr) {
+AnimationState::AnimationState(MoviePlayer *player, Screen *screen, OSystem *system)
+ : BaseAnimationState(system, 640, 400), _player(player), _screen(screen) {
}
AnimationState::~AnimationState(void) {
@@ -472,7 +598,7 @@ void AnimationState::drawYUV(int width, int height, byte *const *dat) {
_frameHeight = height;
#ifdef BACKEND_8BIT
- _scr->plotYUV(_lut, width, height, dat);
+ _screen->plotYUV(_lut, width, height, dat);
#else
plotYUV(width, height, dat);
#endif
@@ -499,7 +625,7 @@ Audio::AudioStream *AnimationState::createAudioStream(const char *name, void *ar
// Factory function for creating the appropriate cutscene player
///////////////////////////////////////////////////////////////////////////////
-MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem *sys) {
+MoviePlayer *makeMoviePlayer(uint32 id, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system) {
#if defined(USE_ZLIB) || defined(USE_MPEG2)
char filename[20];
#endif
@@ -508,7 +634,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem
snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]);
if (Common::File::exists(filename)) {
- return new MoviePlayerDXA(scr, snd, sys);
+ return new MoviePlayerDXA(screen, textMan, snd, system);
}
#endif
@@ -516,7 +642,7 @@ MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem
snprintf(filename, sizeof(filename), "%s.mp2", sequenceList[id]);
if (Common::File::exists(filename)) {
- return new MoviePlayerMPEG(scr, snd, sys);
+ return new MoviePlayerMPEG(screen, textMan, snd, system);
}
#endif
diff --git a/engines/sword1/animation.h b/engines/sword1/animation.h
index 34f05d0a11..4e76c200c5 100644
--- a/engines/sword1/animation.h
+++ b/engines/sword1/animation.h
@@ -58,9 +58,24 @@ enum {
#define INTRO_LOGO_OVLS 12
#define INTRO_TEXT_OVLS 8
+class MovieText {
+public:
+ uint16 _startFrame;
+ uint16 _endFrame;
+ char *_text;
+ MovieText(int startFrame, int endFrame, char *text) {
+ _startFrame = startFrame;
+ _endFrame = endFrame;
+ _text = strdup(text);
+ }
+ ~MovieText() {
+ free(_text);
+ }
+};
+
class MoviePlayer {
public:
- MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys);
+ MoviePlayer(Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
virtual ~MoviePlayer(void);
virtual bool load(uint32 id);
void play(void);
@@ -68,13 +83,17 @@ public:
private:
bool checkSkipFrame(void);
protected:
- Screen *_scr;
+ Screen *_screen;
+ Text *_textMan;
Audio::Mixer *_snd;
OSystem *_system;
+ Common::Array<MovieText *> _movieTexts;
+ byte *_textSpriteBuf;
+ int _textX, _textY, _textWidth, _textHeight;
+ byte _black, _white;
uint32 _id;
- byte *_frameBuffer;
uint _currentFrame;
int _framesSkipped;
bool _forceFrame;
@@ -100,7 +119,7 @@ class MoviePlayerDXA : public MoviePlayer, ::Graphics::DXAPlayer {
protected:
virtual void setPalette(byte *pal);
public:
- MoviePlayerDXA(Screen *scr, Audio::Mixer *snd, OSystem *sys);
+ MoviePlayerDXA(Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
virtual ~MoviePlayerDXA(void);
bool load(uint32 id);
protected:
@@ -117,10 +136,10 @@ protected:
class AnimationState : public Graphics::BaseAnimationState {
private:
MoviePlayer *_player;
- Screen *_scr;
+ Screen *_screen;
public:
- AnimationState(MoviePlayer *player, Screen *scr, OSystem *sys);
+ AnimationState(MoviePlayer *player, Screen *screen, OSystem *system);
~AnimationState(void);
OverlayColor *giveRgbBuffer(void);
@@ -137,7 +156,7 @@ protected:
class MoviePlayerMPEG : public MoviePlayer {
public:
- MoviePlayerMPEG(Screen *scr, Audio::Mixer *snd, OSystem *sys);
+ MoviePlayerMPEG(Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
virtual ~MoviePlayerMPEG(void);
bool load(uint32 id);
protected:
@@ -173,7 +192,7 @@ private:
FileQueue *_queue;
};
-MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem *sys);
+MoviePlayer *makeMoviePlayer(uint32 id, Screen *screen, Text *textMan, Audio::Mixer *snd, OSystem *system);
} // End of namespace Sword1
diff --git a/engines/sword1/logic.cpp b/engines/sword1/logic.cpp
index f0c4f18cc5..1f6a648a9e 100644
--- a/engines/sword1/logic.cpp
+++ b/engines/sword1/logic.cpp
@@ -957,7 +957,7 @@ int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int3
CreditsPlayer player(_system, _mixer);
player.play();
} else {
- MoviePlayer *player = makeMoviePlayer(sequenceId, _screen, _mixer, _system);
+ MoviePlayer *player = makeMoviePlayer(sequenceId, _screen, _textMan, _mixer, _system);
if (player) {
if (player->load(sequenceId))
player->play();
diff --git a/engines/sword1/text.cpp b/engines/sword1/text.cpp
index 3b28ed5691..f55eed52b0 100644
--- a/engines/sword1/text.cpp
+++ b/engines/sword1/text.cpp
@@ -34,9 +34,6 @@ namespace Sword1 {
#define OVERLAP 3
#define SPACE ' '
-#define BORDER_COL 200
-#define LETTER_COL 193
-#define NO_COL 0 // sprite background - 0 for transparency
#define MAX_LINES 30
@@ -49,14 +46,13 @@ Text::Text(ObjectMan *pObjMan, ResMan *pResMan, bool czechVersion) {
_joinWidth = charWidth( SPACE ) - 2 * OVERLAP;
_charHeight = _resMan->getUint16(_resMan->fetchFrame(_font, 0)->height); // all chars have the same height
- _textBlocks[0] = _textBlocks[1] = NULL;
+ for (int i = 0; i < MAX_TEXT_OBS; i++)
+ _textBlocks[i] = NULL;
}
Text::~Text(void) {
- if (_textBlocks[0])
- free(_textBlocks[0]);
- if (_textBlocks[1])
- free(_textBlocks[1]);
+ for (int i = 0; i < MAX_TEXT_OBS; i++)
+ free(_textBlocks[i]);
//_resMan->resClose(_fontId); => wiped automatically by _resMan->flush();
}
@@ -175,14 +171,14 @@ FrameHeader *Text::giveSpriteData(uint32 textTarget) {
// textTarget is the resource ID of the Compact linking the textdata.
// that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
textTarget &= ITM_ID;
- assert(textTarget <= 1);
+ assert(textTarget < MAX_TEXT_OBS);
return _textBlocks[textTarget];
}
void Text::releaseText(uint32 id) {
id &= ITM_ID;
- assert(id <= 1);
+ assert(id < MAX_TEXT_OBS);
if (_textBlocks[id]) {
free(_textBlocks[id]);
_textBlocks[id] = NULL;
diff --git a/engines/sword1/text.h b/engines/sword1/text.h
index c5d10fbf0c..dc3f48eb77 100644
--- a/engines/sword1/text.h
+++ b/engines/sword1/text.h
@@ -28,7 +28,11 @@
namespace Sword1 {
-#define MAX_TEXT_OBS 2
+#define MAX_TEXT_OBS 3
+
+#define BORDER_COL 200
+#define LETTER_COL 193
+#define NO_COL 0 // sprite background - 0 for transparency
class ObjectMan;
class ResMan;
@@ -44,10 +48,10 @@ public:
~Text(void);
FrameHeader *giveSpriteData(uint32 textTarget);
uint32 lowTextManager(uint8 *text, int32 width, uint8 pen);
+ void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);
void releaseText(uint32 id);
private:
- void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);
uint16 analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *info);
uint16 charWidth(uint8 ch);
uint16 copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen);