Instead of pre-rendering all subtitles and pre-loading all sounds for a movie

cutscene, render the text and play the speech when needed. It probably won't
play as nicely from CD now, but using less memory seems more important to me.

svn-id: r25428
This commit is contained in:
Torbjörn Andersson 2007-02-08 21:55:37 +00:00
parent 65dfc335ef
commit 98a8e88f61
7 changed files with 170 additions and 317 deletions

View File

@ -30,6 +30,7 @@
#include "sword2/sword2.h"
#include "sword2/defs.h"
#include "sword2/header.h"
#include "sword2/logic.h"
#include "sword2/maketext.h"
#include "sword2/mouse.h"
#include "sword2/resman.h"
@ -65,11 +66,11 @@ const MovieInfo MoviePlayer::_movies[19] = {
{ "enddemo", 110, false }
};
MoviePlayer::MoviePlayer(Sword2Engine *vm) {
MoviePlayer::MoviePlayer(Sword2Engine *vm, const char *name) {
_vm = vm;
_name = strdup(name);
_mixer = _vm->_mixer;
_system = _vm->_system;
_name = NULL;
_textSurface = NULL;
_bgSoundStream = NULL;
_ticks = 0;
@ -86,7 +87,6 @@ MoviePlayer::MoviePlayer(Sword2Engine *vm) {
_seamless = false;
_framesSkipped = 0;
_forceFrame = false;
_textList = NULL;
_currentText = 0;
}
@ -202,84 +202,121 @@ void MoviePlayer::drawFrame() {
_system->copyRectToScreen(_frameBuffer + _frameY * screenWidth + _frameX, screenWidth, _frameX, _frameY, _frameWidth, _frameHeight);
}
void MoviePlayer::openTextObject(MovieTextObject *t) {
if (t->textSprite) {
_vm->_screen->createSurface(t->textSprite, &_textSurface);
void MoviePlayer::openTextObject(SequenceTextInfo *t) {
// Pull out the text line to get the official text number (for WAV id)
uint32 res = t->textNumber / SIZE;
uint32 localText = t->textNumber & 0xffff;
// Open text resource and get the line
byte *text = _vm->fetchTextLine(_vm->_resman->openResource(res), localText);
_textObject.speechId = READ_LE_UINT16(text);
// Is it speech or subtitles, or both?
// If we want subtitles, or there was no sound
if (_vm->getSubtitles() || !_textObject.speechId) {
_textObject.textMem = _vm->_fontRenderer->makeTextSprite(text + 2, 600, 255, _vm->_speechFontId, 1);
}
_vm->_resman->closeResource(res);
if (_textObject.textMem) {
FrameHeader frame;
frame.read(_textObject.textMem);
_textObject.textSprite.x = 320 - frame.width / 2;
_textObject.textSprite.y = 440 - frame.height;
_textObject.textSprite.w = frame.width;
_textObject.textSprite.h = frame.height;
_textObject.textSprite.type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION;
_textObject.textSprite.data = _textObject.textMem + FrameHeader::size();
_vm->_screen->createSurface(&_textObject.textSprite, &_textSurface);
}
}
void MoviePlayer::closeTextObject(MovieTextObject *t) {
void MoviePlayer::closeTextObject() {
free(_textObject.textMem);
_textObject.textMem = NULL;
_textObject.speechId = 0;
if (_textSurface) {
_vm->_screen->deleteSurface(_textSurface);
_textSurface = NULL;
}
}
void MoviePlayer::calcTextPosition(MovieTextObject *t, int &xPos, int &yPos) {
xPos = 320 - t->textSprite->w / 2;
yPos = 420 - t->textSprite->h;
void MoviePlayer::calcTextPosition(int &xPos, int &yPos) {
xPos = 320 - _textObject.textSprite.w / 2;
yPos = 420 - _textObject.textSprite.h;
}
void MoviePlayer::drawTextObject(MovieTextObject *t) {
if (t->textSprite && _textSurface) {
void MoviePlayer::drawTextObject() {
if (_textObject.textMem && _textSurface) {
int screenWidth = _vm->_screen->getScreenWide();
byte *src = t->textSprite->data;
byte *src = _textObject.textSprite.data;
uint16 width = _textObject.textSprite.w;
uint16 height = _textObject.textSprite.h;
int xPos, yPos;
calcTextPosition(t, xPos, yPos);
calcTextPosition(xPos, yPos);
byte *dst = _frameBuffer + yPos * screenWidth + xPos;
for (int y = 0; y < t->textSprite->h; y++) {
for (int x = 0; x < t->textSprite->w; x++) {
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
if (src[x] == 1)
dst[x] = _black;
else if (src[x] == 255)
dst[x] = _white;
}
src += t->textSprite->w;
src += width;
dst += screenWidth;
}
if (yPos + t->textSprite->h > _frameY + _frameHeight || t->textSprite->w > _frameWidth) {
_system->copyRectToScreen(_frameBuffer + yPos * screenWidth + xPos, screenWidth, xPos, yPos, t->textSprite->w, t->textSprite->h);
if (yPos + height > _frameY + _frameHeight || width > _frameWidth) {
_system->copyRectToScreen(_frameBuffer + yPos * screenWidth + xPos, screenWidth, xPos, yPos, width, height);
}
}
}
void MoviePlayer::undrawTextObject(MovieTextObject *t) {
if (t->textSprite) {
void MoviePlayer::undrawTextObject() {
if (_textObject.textMem) {
int xPos, yPos;
calcTextPosition(t, xPos, yPos);
calcTextPosition(xPos, yPos);
uint16 width = _textObject.textSprite.w;
uint16 height = _textObject.textSprite.h;
// We only need to undraw the text if it's outside the frame.
// Otherwise the next frame will cover the old text anyway.
if (yPos + t->textSprite->h > _frameY + _frameHeight || t->textSprite->w > _frameWidth) {
if (yPos + height > _frameY + _frameHeight || width > _frameWidth) {
int screenWidth = _vm->_screen->getScreenWide();
byte *dst = _frameBuffer + yPos * screenWidth + xPos;
for (int y = 0; y < t->textSprite->h; y++) {
memset(dst, 0, t->textSprite->w);
for (int y = 0; y < height; y++) {
memset(dst, 0, width);
dst += screenWidth;
}
_system->copyRectToScreen(_frameBuffer + yPos * screenWidth + xPos, screenWidth, xPos, yPos, t->textSprite->w, t->textSprite->h);
_system->copyRectToScreen(_frameBuffer + yPos * screenWidth + xPos, screenWidth, xPos, yPos, width, height);
}
}
}
bool MoviePlayer::load(const char *name, MovieTextObject *text[]) {
bool MoviePlayer::load() {
_bgSoundStream = NULL;
_textList = text;
_currentText = 0;
_currentFrame = 0;
_name = strdup(name);
for (int i = 0; i < ARRAYSIZE(_movies); i++) {
if (scumm_stricmp(name, _movies[i].name) == 0) {
if (scumm_stricmp(_name, _movies[i].name) == 0) {
_seamless = _movies[i].seamless;
_numFrames = _movies[i].frames;
if (_numFrames > 60)
@ -304,26 +341,24 @@ bool MoviePlayer::load(const char *name, MovieTextObject *text[]) {
return false;
}
void MoviePlayer::play(int32 leadIn, int32 leadOut) {
void MoviePlayer::play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut) {
bool terminate = false;
bool textVisible = false;
bool startNextText = false;
uint32 flags = Audio::Mixer::FLAG_16BITS;
// This happens if the user quits during the "eye" cutscene.
if (_vm->_quit)
return;
_numSpeechLines = numLines;
_firstSpeechFrame = (numLines > 0) ? textList[0].startFrame : 0;
if (leadIn) {
_vm->_sound->playMovieSound(leadIn, kLeadInSound);
}
savePalette();
#ifndef SCUMM_BIG_ENDIAN
flags |= Audio::Mixer::FLAG_LITTLE_ENDIAN;
#endif
_framesSkipped = 0;
_ticks = _system->getMillis();
_bgSoundStream = Audio::AudioStream::openStreamFile(_name);
@ -338,32 +373,32 @@ void MoviePlayer::play(int32 leadIn, int32 leadOut) {
// The frame has been decoded. Now draw the subtitles, if any,
// before drawing it to the screen.
if (_textList && _textList[_currentText]) {
MovieTextObject *t = _textList[_currentText];
if (_currentText < numLines) {
SequenceTextInfo *t = &textList[_currentText];
if (_currentFrame == t->startFrame) {
openTextObject(t);
textVisible = true;
if (t->speech) {
if (_textObject.speechId) {
startNextText = true;
}
}
if (startNextText && !_mixer->isSoundHandleActive(_speechHandle)) {
_mixer->playRaw(Audio::Mixer::kSpeechSoundType, &_speechHandle, t->speech, t->speechBufferSize, 22050, flags);
if (startNextText && _vm->_sound->amISpeaking() == RDSE_QUIET) {
_vm->_sound->playCompSpeech(_textObject.speechId, 16, 0);
startNextText = false;
}
if (_currentFrame == t->endFrame) {
undrawTextObject(t);
closeTextObject(t);
undrawTextObject();
closeTextObject();
_currentText++;
textVisible = false;
}
if (textVisible)
drawTextObject(t);
drawTextObject();
}
if (leadOut && _currentFrame == _leadOutFrame) {
@ -404,8 +439,8 @@ void MoviePlayer::play(int32 leadIn, int32 leadOut) {
// If the sound is still playing, draw the subtitles one final
// time. This happens in the "carib" cutscene.
if (textVisible && _mixer->isSoundHandleActive(_speechHandle)) {
drawTextObject(_textList[_currentText]);
if (textVisible && _vm->_sound->amISpeaking() == RDSE_SPEAKING) {
drawTextObject();
}
drawFrame();
@ -418,19 +453,17 @@ void MoviePlayer::play(int32 leadIn, int32 leadOut) {
// mid-sentence, and - even more importantly - that we don't
// free the sound buffer while it's still in use.
while (_mixer->isSoundHandleActive(_speechHandle) || _mixer->isSoundHandleActive(_bgSoundHandle)) {
while (_vm->_sound->amISpeaking() == RDSE_SPEAKING || _mixer->isSoundHandleActive(_bgSoundHandle)) {
_system->delayMillis(100);
}
} else {
_mixer->stopHandle(_speechHandle);
_vm->_sound->stopSpeech();
_mixer->stopHandle(_bgSoundHandle);
}
// The current text object may still be open
if (_textList && _textList[_currentText]) {
undrawTextObject(_textList[_currentText]);
closeTextObject(_textList[_currentText]);
}
undrawTextObject();
closeTextObject();
if (!_seamless) {
clearFrame();
@ -448,7 +481,8 @@ void MoviePlayer::play(int32 leadIn, int32 leadOut) {
// Movie player for the new DXA movies
///////////////////////////////////////////////////////////////////////////////
MoviePlayerDXA::MoviePlayerDXA(Sword2Engine *vm) : MoviePlayer(vm) {
MoviePlayerDXA::MoviePlayerDXA(Sword2Engine *vm, const char *name)
: MoviePlayer(vm, name) {
debug(0, "Creating DXA cutscene player");
}
@ -466,13 +500,13 @@ bool MoviePlayerDXA::decodeFrame() {
return true;
}
bool MoviePlayerDXA::load(const char *name, MovieTextObject *text[]) {
if (!MoviePlayer::load(name, text))
bool MoviePlayerDXA::load() {
if (!MoviePlayer::load())
return false;
char filename[20];
snprintf(filename, sizeof(filename), "%s.dxa", name);
snprintf(filename, sizeof(filename), "%s.dxa", _name);
if (loadFile(filename)) {
// The Broken Sword games always use external audio tracks.
@ -501,7 +535,8 @@ bool MoviePlayerDXA::load(const char *name, MovieTextObject *text[]) {
// Movie player for the old MPEG movies
///////////////////////////////////////////////////////////////////////////////
MoviePlayerMPEG::MoviePlayerMPEG(Sword2Engine *vm) : MoviePlayer(vm) {
MoviePlayerMPEG::MoviePlayerMPEG(Sword2Engine *vm, const char *name)
: MoviePlayer(vm, name) {
#ifdef BACKEND_8BIT
debug(0, "Creating MPEG cutscene player (8-bit)");
#else
@ -514,13 +549,13 @@ MoviePlayerMPEG::~MoviePlayerMPEG() {
_anim = NULL;
}
bool MoviePlayerMPEG::load(const char *name, MovieTextObject *text[]) {
if (!MoviePlayer::load(name, text))
bool MoviePlayerMPEG::load() {
if (!MoviePlayer::load())
return false;
_anim = new AnimationState(_vm, this);
if (!_anim->init(name)) {
if (!_anim->init(_name)) {
delete _anim;
_anim = NULL;
return false;
@ -579,13 +614,13 @@ void MoviePlayerMPEG::updateScreen() {
_anim->updateScreen();
}
void MoviePlayerMPEG::drawTextObject(MovieTextObject *t) {
if (t->textSprite && _textSurface) {
_anim->drawTextObject(t->textSprite, _textSurface);
void MoviePlayerMPEG::drawTextObject() {
if (_textObject.textMem && _textSurface) {
_anim->drawTextObject(&_textObject.textSprite, _textSurface);
}
}
void MoviePlayerMPEG::undrawTextObject(MovieTextObject *t) {
void MoviePlayerMPEG::undrawTextObject() {
// As long as we only have subtitles for full-sized cutscenes, we don't
// really need to implement this function.
}
@ -689,15 +724,16 @@ void AnimationState::drawYUV(int width, int height, byte *const *dat) {
// Dummy player for subtitled speech only
///////////////////////////////////////////////////////////////////////////////
MoviePlayerDummy::MoviePlayerDummy(Sword2Engine *vm) : MoviePlayer(vm) {
MoviePlayerDummy::MoviePlayerDummy(Sword2Engine *vm, const char *name)
: MoviePlayer(vm, name) {
debug(0, "Creating Dummy cutscene player");
}
MoviePlayerDummy::~MoviePlayerDummy() {
}
bool MoviePlayerDummy::load(const char *name, MovieTextObject *text[]) {
if (!MoviePlayer::load(name, text))
bool MoviePlayerDummy::load() {
if (!MoviePlayer::load())
return false;
_frameBuffer = _vm->_screen->getScreen();
@ -711,7 +747,7 @@ bool MoviePlayerDummy::load(const char *name, MovieTextObject *text[]) {
}
bool MoviePlayerDummy::decodeFrame() {
if (_currentFrame == 0 && _textList) {
if (_currentFrame == 0 && _numSpeechLines > 0) {
byte dummyPalette[] = {
0, 0, 0, 0,
255, 255, 255, 0,
@ -767,7 +803,7 @@ bool MoviePlayerDummy::decodeFrame() {
// If we have played the final voice-over, skip ahead to the lead out
if (_textList && !_textList[_currentText] && !_mixer->isSoundHandleActive(_speechHandle) && _leadOutFrame != (uint)-1 && _currentFrame < _leadOutFrame) {
if (_currentText >= _numSpeechLines && _vm->_sound->amISpeaking() == RDSE_QUIET && _leadOutFrame != (uint)-1 && _currentFrame < _leadOutFrame) {
_currentFrame = _leadOutFrame - 1;
}
@ -775,7 +811,7 @@ bool MoviePlayerDummy::decodeFrame() {
}
void MoviePlayerDummy::syncFrame() {
if (!_textList || _currentFrame < _textList[0]->startFrame) {
if (_numSpeechLines == 0 || _currentFrame < _firstSpeechFrame) {
_ticks = _system->getMillis();
return;
}
@ -786,16 +822,16 @@ void MoviePlayerDummy::syncFrame() {
void MoviePlayerDummy::drawFrame() {
}
void MoviePlayerDummy::drawTextObject(MovieTextObject *t) {
if (t->textSprite && _textSurface) {
_vm->_screen->drawSurface(t->textSprite, _textSurface);
void MoviePlayerDummy::drawTextObject() {
if (_textObject.textMem && _textSurface) {
_vm->_screen->drawSurface(&_textObject.textSprite, _textSurface);
}
}
void MoviePlayerDummy::undrawTextObject(MovieTextObject *t) {
if (t->textSprite && _textSurface) {
memset(_textSurface, 1, t->textSprite->w * t->textSprite->h);
drawTextObject(t);
void MoviePlayerDummy::undrawTextObject() {
if (_textObject.textMem && _textSurface) {
memset(_textSurface, 1, _textObject.textSprite.w * _textObject.textSprite.h);
drawTextObject();
}
}
@ -804,13 +840,13 @@ void MoviePlayerDummy::undrawTextObject(MovieTextObject *t) {
///////////////////////////////////////////////////////////////////////////////
MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) {
char filename[20];
static char filename[20];
#ifdef USE_ZLIB
snprintf(filename, sizeof(filename), "%s.dxa", name);
if (Common::File::exists(filename)) {
return new MoviePlayerDXA(vm);
return new MoviePlayerDXA(vm, name);
}
#endif
@ -818,11 +854,11 @@ MoviePlayer *makeMoviePlayer(Sword2Engine *vm, const char *name) {
snprintf(filename, sizeof(filename), "%s.mp2", name);
if (Common::File::exists(filename)) {
return new MoviePlayerMPEG(vm);
return new MoviePlayerMPEG(vm, name);
}
#endif
return new MoviePlayerDummy(vm);
return new MoviePlayerDummy(vm, name);
}
} // End of namespace Sword2

View File

@ -26,20 +26,25 @@
#include "graphics/mpeg_player.h"
#include "sound/mixer.h"
#include "sword2/screen.h"
namespace Sword2 {
struct SpriteInfo;
// This is the structure which is passed to the sequence player. It includes
// the smack to play, and any text lines which are to be displayed over the top
// of the sequence.
struct MovieTextObject {
struct SequenceTextInfo {
uint32 textNumber;
uint16 startFrame;
uint16 endFrame;
SpriteInfo *textSprite;
uint32 speechBufferSize;
uint16 *speech;
};
struct MovieTextObject {
byte *textMem;
SpriteInfo textSprite;
uint16 speechId;
MovieTextObject() {
textMem = NULL;
speechId = 0;
}
};
struct MovieInfo {
@ -61,9 +66,11 @@ protected:
byte _originalPalette[4 * 256];
uint32 _numSpeechLines;
uint32 _firstSpeechFrame;
MovieTextObject _textObject;
byte *_textSurface;
Audio::SoundHandle _speechHandle;
Audio::SoundHandle _bgSoundHandle;
Audio::AudioStream *_bgSoundStream;
@ -85,15 +92,14 @@ protected:
static const MovieInfo _movies[];
MovieTextObject **_textList;
int _currentText;
uint32 _currentText;
void savePalette();
void restorePalette();
void openTextObject(MovieTextObject *t);
void closeTextObject(MovieTextObject *t);
void calcTextPosition(MovieTextObject *t, int &xPos, int &yPos);
void openTextObject(SequenceTextInfo *t);
void closeTextObject();
void calcTextPosition(int &xPos, int &yPos);
virtual void handleScreenChanged() {}
@ -102,16 +108,16 @@ protected:
virtual bool decodeFrame() = 0;
virtual void syncFrame();
virtual void drawFrame();
virtual void drawTextObject(MovieTextObject *t);
virtual void undrawTextObject(MovieTextObject *t);
virtual void drawTextObject();
virtual void undrawTextObject();
public:
MoviePlayer(Sword2Engine *vm);
MoviePlayer(Sword2Engine *vm, const char *name);
virtual ~MoviePlayer();
void updatePalette(byte *pal, bool packed = true);
virtual bool load(const char *name, MovieTextObject *text[]);
void play(int32 leadIn, int32 leadOut);
virtual bool load();
void play(SequenceTextInfo *textList, uint32 numLines, int32 leadIn, int32 leadOut);
};
class MoviePlayerDummy : public MoviePlayer {
@ -119,14 +125,14 @@ protected:
bool decodeFrame();
void syncFrame();
void drawFrame();
void drawTextObject(MovieTextObject *t);
void undrawTextObject(MovieTextObject *t);
void drawTextObject();
void undrawTextObject();
public:
MoviePlayerDummy(Sword2Engine *vm);
MoviePlayerDummy(Sword2Engine *vm, const char *name);
virtual ~MoviePlayerDummy();
bool load(const char *name, MovieTextObject *text[]);
bool load();
};
#ifdef USE_MPEG2
@ -164,15 +170,15 @@ protected:
void clearFrame();
void drawFrame();
void updateScreen();
void drawTextObject(MovieTextObject *t);
void undrawTextObject(MovieTextObject *t);
void drawTextObject();
void undrawTextObject();
#endif
public:
MoviePlayerMPEG(Sword2Engine *vm);
MoviePlayerMPEG(Sword2Engine *vm, const char *name);
~MoviePlayerMPEG();
bool load(const char *name, MovieTextObject *text[]);
bool load();
};
#endif
@ -183,10 +189,10 @@ protected:
bool decodeFrame();
public:
MoviePlayerDXA(Sword2Engine *vm);
MoviePlayerDXA(Sword2Engine *vm, const char *name);
~MoviePlayerDXA();
bool load(const char *name, MovieTextObject *text[]);
bool load();
};
#endif

View File

@ -179,131 +179,4 @@ void Router::setSpriteShading(byte *ob_graph, uint32 type) {
obGraph.setType((obGraph.getType() & 0x0000ffff) | type);
}
void Logic::createSequenceSpeech(MovieTextObject *sequenceText[]) {
uint32 line;
uint32 local_text;
uint32 text_res;
byte *text;
uint32 wavId; // ie. offical text number (actor text number)
bool speechRunning;
// for each sequence text line that's been logged
for (line = 0; line < _sequenceTextLines; line++) {
// allocate this structure
sequenceText[line] = new MovieTextObject;
sequenceText[line]->startFrame = _sequenceTextList[line].startFrame;
sequenceText[line]->endFrame = _sequenceTextList[line].endFrame;
// pull out the text line to get the official text number
// (for wav id)
text_res = _sequenceTextList[line].textNumber / SIZE;
local_text = _sequenceTextList[line].textNumber & 0xffff;
// open text resource & get the line
text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
wavId = (int32)READ_LE_UINT16(text);
// now ok to close the text file
_vm->_resman->closeResource(text_res);
// 1st word of text line is the official line number
debug(5,"(%d) SEQUENCE TEXT: %s", READ_LE_UINT16(text), text + 2);
// is it to be speech or subtitles or both?
// assume speech is not running until know otherwise
speechRunning = false;
_sequenceTextList[line].speech_mem = NULL;
sequenceText[line]->speech = NULL;
if (!_vm->_sound->isSpeechMute()) {
_sequenceTextList[line].speechBufferSize = _vm->_sound->preFetchCompSpeech(wavId, &_sequenceTextList[line].speech_mem);
if (_sequenceTextList[line].speechBufferSize) {
// ok, we've got speech!
speechRunning = true;
}
}
// if we want subtitles, or speech failed to load
if (_vm->getSubtitles() || !speechRunning) {
// open text resource & get the line
text = _vm->fetchTextLine(_vm->_resman->openResource(text_res), local_text);
// make the sprite
// 'text+2' to skip the first 2 bytes which form the
// line reference number
// NB. The mem block containing the text sprite is
// currently FLOATING!
// When rendering text over a sequence we need a
// different colour for the border.
_sequenceTextList[line].text_mem = _vm->_fontRenderer->makeTextSprite(text + 2, 600, 255, _vm->_speechFontId, 1);
// ok to close the text resource now
_vm->_resman->closeResource(text_res);
} else {
_sequenceTextList[line].text_mem = NULL;
sequenceText[line]->textSprite = NULL;
}
}
// for drivers: NULL-terminate the array of pointers to
// MovieTextObject's
sequenceText[_sequenceTextLines] = NULL;
for (line = 0; line < _sequenceTextLines; line++) {
// if we've made a text sprite for this line...
if (_sequenceTextList[line].text_mem) {
// now fill out the SpriteInfo structure in the
// MovieTextObjectStructure
FrameHeader frame;
frame.read(_sequenceTextList[line].text_mem);
sequenceText[line]->textSprite = new SpriteInfo;
// center text at bottom of screen
sequenceText[line]->textSprite->x = 320 - frame.width / 2;
sequenceText[line]->textSprite->y = 440 - frame.height;
sequenceText[line]->textSprite->w = frame.width;
sequenceText[line]->textSprite->h = frame.height;
sequenceText[line]->textSprite->type = RDSPR_DISPLAYALIGN | RDSPR_NOCOMPRESSION;
sequenceText[line]->textSprite->data = _sequenceTextList[line].text_mem + FrameHeader::size();
}
// if we've loaded a speech sample for this line...
if (_sequenceTextList[line].speech_mem) {
// for drivers: set up pointer to decompressed wav in
// memory
sequenceText[line]->speechBufferSize = _sequenceTextList[line].speechBufferSize;
sequenceText[line]->speech = _sequenceTextList[line].speech_mem;
}
}
}
void Logic::clearSequenceSpeech(MovieTextObject *sequenceText[]) {
for (uint i = 0; i < _sequenceTextLines; i++) {
// free up the memory used by this MovieTextObject
delete sequenceText[i];
// free up the mem block containing this text sprite
if (_sequenceTextList[i].text_mem)
free(_sequenceTextList[i].text_mem);
// free up the mem block containing this speech sample
if (_sequenceTextList[i].speech_mem)
free(_sequenceTextList[i].speech_mem);
}
// IMPORTANT! Reset the line count ready for the next sequence!
_sequenceTextLines = 0;
}
} // End of namespace Sword2

View File

@ -2102,7 +2102,6 @@ int32 Logic::fnPlaySequence(int32 *params) {
// 1 number of frames in the sequence, used for PSX.
char filename[30];
MovieTextObject *sequenceSpeechArray[MAX_SEQUENCE_TEXT_LINES + 1];
// The original code had some #ifdef blocks for skipping or muting the
// cutscenes - fondly described as "the biggest fudge in the history
@ -2118,12 +2117,7 @@ int32 Logic::fnPlaySequence(int32 *params) {
// Write to walkthrough file (zebug0.txt)
debug(5, "PLAYING SEQUENCE \"%s\"", filename);
// now create the text sprites, if any
if (_sequenceTextLines)
createSequenceSpeech(sequenceSpeechArray);
// don't want to carry on streaming game music when smacker starts!
// don't want to carry on streaming game music when cutscene starts!
fnStopMusic(NULL);
// pause sfx during sequence
@ -2131,10 +2125,12 @@ int32 Logic::fnPlaySequence(int32 *params) {
MoviePlayer *player = makeMoviePlayer(_vm, filename);
if (player->load(filename, (_sequenceTextLines && !readVar(DEMO)) ? sequenceSpeechArray : NULL)) {
player->play(_smackerLeadIn, _smackerLeadOut);
if (player->load()) {
player->play(_sequenceTextList, _sequenceTextLines, _smackerLeadIn, _smackerLeadOut);
}
_sequenceTextLines = 0;
delete player;
// unpause sound fx again, in case we're staying in same location
@ -2143,11 +2139,6 @@ int32 Logic::fnPlaySequence(int32 *params) {
_smackerLeadIn = 0;
_smackerLeadOut = 0;
// now clear the text sprites, if any
if (_sequenceTextLines)
clearSequenceSpeech(sequenceSpeechArray);
// now clear the screen in case the Sequence was quitted (using ESC)
// rather than fading down to black
@ -2219,12 +2210,15 @@ int32 Logic::fnAddSequenceText(int32 *params) {
// 1 frame number to start the text displaying
// 2 frame number to stop the text dispalying
assert(_sequenceTextLines < MAX_SEQUENCE_TEXT_LINES);
if (!readVar(DEMO)) {
assert(_sequenceTextLines < MAX_SEQUENCE_TEXT_LINES);
_sequenceTextList[_sequenceTextLines].textNumber = params[0];
_sequenceTextList[_sequenceTextLines].startFrame = params[1];
_sequenceTextList[_sequenceTextLines].endFrame = params[2];
_sequenceTextLines++;
}
_sequenceTextList[_sequenceTextLines].textNumber = params[0];
_sequenceTextList[_sequenceTextLines].startFrame = params[1];
_sequenceTextList[_sequenceTextLines].endFrame = params[2];
_sequenceTextLines++;
return IR_CONT;
}

View File

@ -24,13 +24,12 @@
#ifndef SWORD2_LOGIC_H
#define SWORD2_LOGIC_H
#include "sword2/memory.h"
#include "common/endian.h"
#include "sword2/animation.h"
#include "sword2/memory.h"
namespace Sword2 {
struct MovieTextObject;
#define MAX_events 10
#define TREE_SIZE 3
@ -79,22 +78,8 @@ private:
// keeps count of number of text lines to disaply during the sequence
uint32 _sequenceTextLines;
// FOR TEXT LINES IN SEQUENCE PLAYER
struct SequenceTextInfo {
uint32 textNumber;
uint16 startFrame;
uint16 endFrame;
byte *text_mem;
uint32 speechBufferSize;
uint16 *speech_mem;
};
SequenceTextInfo _sequenceTextList[MAX_SEQUENCE_TEXT_LINES];
void createSequenceSpeech(MovieTextObject *sequenceText[]);
void clearSequenceSpeech(MovieTextObject *sequenceText[]);
// when not playing a wav we calculate the speech time based upon
// length of ascii

View File

@ -704,46 +704,6 @@ int32 Sound::amISpeaking() {
return RDSE_QUIET;
}
/**
* This function loads and decompresses a list of speech from a cluster, but
* does not play it. This is used for cutscene voice-overs, presumably to
* avoid having to read from more than one file on the CD during playback.
* @param speechId the text line id used to reference the speech
* @param buf a pointer to the buffer that will be allocated for the sound
*/
uint32 Sound::preFetchCompSpeech(uint32 speechId, uint16 **buf) {
int cd = _vm->_resman->getCD();
uint32 numSamples;
SoundFileHandle *fh = (cd == 1) ? &_speechFile[0] : &_speechFile[1];
Audio::AudioStream *input = getAudioStream(fh, "speech", cd, speechId, &numSamples);
if (!input)
return 0;
*buf = NULL;
// Decompress data into speech buffer.
uint32 bufferSize = 2 * numSamples;
*buf = (uint16 *)malloc(bufferSize);
if (!*buf) {
delete input;
fh->file.close();
return 0;
}
uint32 readSamples = input->readBuffer((int16 *)*buf, numSamples);
fh->file.close();
delete input;
return 2 * readSamples;
}
/**
* This function loads, decompresses and plays a line of speech. An error
* occurs if speech is already playing.

View File

@ -269,7 +269,6 @@ public:
int32 getSpeechStatus();
int32 amISpeaking();
int32 playCompSpeech(uint32 speechId, uint8 vol, int8 pan);
uint32 preFetchCompSpeech(uint32 speechId, uint16 **buf);
int32 stopSpeech();
int32 streamCompMusic(uint32 musicId, bool loop);