mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-03 15:41:41 +00:00
added support for an international BS1 cutscene pack (which we didn't release yet)
svn-id: r15983
This commit is contained in:
parent
095549125b
commit
5d32a2c034
@ -46,7 +46,7 @@ BaseAnimationState::~BaseAnimationState() {
|
||||
}
|
||||
|
||||
|
||||
bool BaseAnimationState::init(const char *name) {
|
||||
bool BaseAnimationState::init(const char *name, void *audioArg) {
|
||||
#ifdef USE_MPEG2
|
||||
char tempFile[512];
|
||||
|
||||
@ -130,7 +130,7 @@ bool BaseAnimationState::init(const char *name) {
|
||||
ticks = _sys->getMillis();
|
||||
|
||||
// Play audio
|
||||
bgSoundStream = AudioStream::openStreamFile(name);
|
||||
bgSoundStream = createAudioStream(name, audioArg);
|
||||
|
||||
if (bgSoundStream != NULL) {
|
||||
_snd->playInputStream(&bgSound, bgSoundStream, false, -1, 255, 0, false);
|
||||
@ -144,6 +144,10 @@ bool BaseAnimationState::init(const char *name) {
|
||||
#endif
|
||||
}
|
||||
|
||||
AudioStream *BaseAnimationState::createAudioStream(const char *name, void *arg) {
|
||||
return AudioStream::openStreamFile(name);
|
||||
}
|
||||
|
||||
bool BaseAnimationState::decodeFrame() {
|
||||
#ifdef USE_MPEG2
|
||||
mpeg2_state_t state;
|
||||
|
@ -117,7 +117,7 @@ public:
|
||||
BaseAnimationState(SoundMixer *snd, OSystem *sys, int width, int height);
|
||||
virtual ~BaseAnimationState();
|
||||
|
||||
bool init(const char *name);
|
||||
bool init(const char *name, void *audioArg = NULL);
|
||||
bool decodeFrame();
|
||||
#ifndef BACKEND_8BIT
|
||||
void invalidateLookup(bool rebuild);
|
||||
@ -126,6 +126,7 @@ public:
|
||||
protected:
|
||||
bool checkPaletteSwitch();
|
||||
virtual void drawYUV(int width, int height, byte *const *dat) = 0;
|
||||
virtual AudioStream *createAudioStream(const char *name, void *arg);
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
void buildLookup(int p, int lines);
|
||||
|
@ -21,12 +21,14 @@
|
||||
|
||||
#include "common/stdafx.h"
|
||||
#include "common/file.h"
|
||||
#include "sword1/sword1.h"
|
||||
#include "sword1/animation.h"
|
||||
#include "sound/audiostream.h"
|
||||
|
||||
#include "sword1/credits.h"
|
||||
#include "sound/vorbis.h"
|
||||
|
||||
#include "common/config-manager.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
AnimationState::AnimationState(Screen *scr, SoundMixer *snd, OSystem *sys)
|
||||
@ -38,11 +40,9 @@ AnimationState::~AnimationState() {
|
||||
|
||||
|
||||
#ifdef BACKEND_8BIT
|
||||
|
||||
void AnimationState::setPalette(byte *pal) {
|
||||
_sys->setPalette(pal, 0, 256);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
void AnimationState::drawYUV(int width, int height, byte *const *dat) {
|
||||
@ -50,28 +50,95 @@ void AnimationState::drawYUV(int width, int height, byte *const *dat) {
|
||||
_scr->plotYUV(lut, width, height, dat);
|
||||
#else
|
||||
plotYUV(lookup, width, height, dat);
|
||||
#endif
|
||||
}
|
||||
|
||||
void AnimationState::updateScreen(void) {
|
||||
#ifndef BACKEND_8BIT
|
||||
_sys->copyRectToOverlay(overlay, MOVIE_WIDTH, 0, 40, MOVIE_WIDTH, MOVIE_HEIGHT);
|
||||
#endif
|
||||
_sys->updateScreen();
|
||||
}
|
||||
|
||||
OverlayColor *AnimationState::giveRgbBuffer(void) {
|
||||
#ifdef BACKEND_8BIT
|
||||
return NULL;
|
||||
#else
|
||||
return overlay;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool AnimationState::soundFinished(void) {
|
||||
return !bgSound.isActive();
|
||||
}
|
||||
|
||||
AudioStream *AnimationState::createAudioStream(const char *name, void *arg) {
|
||||
if (arg)
|
||||
return (AudioStream*)arg;
|
||||
else
|
||||
return AudioStream::openStreamFile(name);
|
||||
}
|
||||
|
||||
MoviePlayer::MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys)
|
||||
: _scr(scr), _snd(snd), _sys(sys) {
|
||||
for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++)
|
||||
_logoOvls[cnt] = NULL;
|
||||
_introPal = NULL;
|
||||
}
|
||||
|
||||
MoviePlayer::~MoviePlayer(void) {
|
||||
if (_introPal)
|
||||
free(_introPal);
|
||||
for (uint8 cnt = 0; cnt < INTRO_LOGO_OVLS; cnt++)
|
||||
if (_logoOvls[cnt])
|
||||
free(_logoOvls[cnt]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Plays an animated cutscene.
|
||||
* @param filename the file name of the cutscene file
|
||||
* @param id the id of the file
|
||||
*/
|
||||
void MoviePlayer::play(const char *filename) {
|
||||
void MoviePlayer::play(uint32 id) {
|
||||
#ifdef USE_MPEG2
|
||||
AnimationState *anim = new AnimationState(_scr, _snd, _sys);
|
||||
bool initOK = anim->init(filename);
|
||||
AudioStream *stream = NULL;
|
||||
if (SwordEngine::_systemVars.cutscenePackVersion == 1) {
|
||||
if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) {
|
||||
// these sequences are language specific
|
||||
char sndName[20];
|
||||
sprintf(sndName, "%s.snd", _sequenceList[id]);
|
||||
File *oggSource = new File();
|
||||
if (oggSource->open(sndName)) {
|
||||
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
|
||||
uint32 *header = (uint32*)malloc(numSegs * 7 * 2 * 4);
|
||||
for (uint32 cnt = 0; cnt < numSegs * 7 * 2; cnt++)
|
||||
header[cnt] = oggSource->readUint32LE();
|
||||
for (uint32 segCnt = 0; segCnt < numSegs; segCnt++) {
|
||||
oggSource->seek( header[SwordEngine::_systemVars.language * 2 + 0 + segCnt * 14]);
|
||||
uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14];
|
||||
AudioStream *apStream = makeVorbisStream(oggSource, segSize);
|
||||
if (!apStream)
|
||||
error("Can't create Vorbis Stream from file %s", sndName);
|
||||
sStream->appendStream(apStream);
|
||||
}
|
||||
free(header);
|
||||
stream = sStream;
|
||||
} else
|
||||
warning("Sound file \"%s\" not found", sndName);
|
||||
initOverlays(id);
|
||||
oggSource->decRef();
|
||||
}
|
||||
}
|
||||
bool initOK = anim->init(_sequenceList[id], stream);
|
||||
|
||||
uint32 frameCount = 0;
|
||||
if (initOK) {
|
||||
while (anim->decodeFrame()) {
|
||||
#ifndef BACKEND_8BIT
|
||||
_sys->updateScreen();
|
||||
#endif
|
||||
processFrame(id, anim, frameCount);
|
||||
anim->updateScreen();
|
||||
frameCount++;
|
||||
OSystem::Event event;
|
||||
while (_sys->pollEvent(event)) {
|
||||
switch (event.event_code) {
|
||||
@ -95,10 +162,143 @@ void MoviePlayer::play(const char *filename) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (!anim->soundFinished())
|
||||
_sys->delayMillis(100);
|
||||
delete anim;
|
||||
#endif // USE_MPEG2
|
||||
}
|
||||
|
||||
void MoviePlayer::insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal) {
|
||||
if (ovl != NULL)
|
||||
for (uint32 cnt = 0; cnt < 640 * 400; cnt++)
|
||||
if (ovl[cnt])
|
||||
buf[cnt] = pal[ovl[cnt]];
|
||||
}
|
||||
|
||||
void MoviePlayer::processFrame(uint32 animId, AnimationState *anim, uint32 frameNo) {
|
||||
#if defined(USE_MPEG2) && !defined(BACKEND_8BIT)
|
||||
if ((animId != 4) || (SwordEngine::_systemVars.cutscenePackVersion == 0))
|
||||
return;
|
||||
OverlayColor *buf = anim->giveRgbBuffer();
|
||||
if ((frameNo > 397) && (frameNo < 444)) { // Broken Sword Logo
|
||||
if (frameNo <= 403)
|
||||
insertOverlay(buf, _logoOvls[frameNo - 398], _introPal); // fade up
|
||||
else if (frameNo <= 437)
|
||||
insertOverlay(buf, _logoOvls[(frameNo - 404) % 6 + 6], _introPal); // animation
|
||||
else {
|
||||
insertOverlay(buf, _logoOvls[5 - (frameNo - 438)], _introPal); // fade down
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool MoviePlayer::initOverlays(uint32 id) {
|
||||
#if defined(USE_MPEG2) && !defined(BACKEND_8BIT)
|
||||
if (id == SEQ_INTRO) {
|
||||
ArcFile ovlFile;
|
||||
if (!ovlFile.open("intro.dat")) {
|
||||
warning("\"intro.dat\" not found");
|
||||
return false;
|
||||
}
|
||||
ovlFile.enterPath(SwordEngine::_systemVars.language);
|
||||
for (uint8 fcnt = 0; fcnt < 12; fcnt++) {
|
||||
_logoOvls[fcnt] = ovlFile.decompressFile(fcnt);
|
||||
if (fcnt > 0)
|
||||
for (uint32 cnt = 0; cnt < 640 * 400; cnt++)
|
||||
if (_logoOvls[fcnt - 1][cnt] && !_logoOvls[fcnt][cnt])
|
||||
_logoOvls[fcnt][cnt] = _logoOvls[fcnt - 1][cnt];
|
||||
}
|
||||
uint8 *pal = ovlFile.fetchFile(12);
|
||||
_introPal = (OverlayColor*)malloc(256 * sizeof(OverlayColor));
|
||||
for (uint16 cnt = 0; cnt < 256; cnt++)
|
||||
_introPal[cnt] = _sys->RGBToColor(pal[cnt * 3 + 0], pal[cnt * 3 + 1], pal[cnt * 3 + 2]);
|
||||
}
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
SplittedAudioStream::SplittedAudioStream(void) {
|
||||
_queue = NULL;
|
||||
}
|
||||
|
||||
SplittedAudioStream::~SplittedAudioStream(void) {
|
||||
while (_queue) {
|
||||
delete _queue->stream;
|
||||
FileQueue *que = _queue->next;
|
||||
delete _queue;
|
||||
_queue = que;
|
||||
}
|
||||
}
|
||||
|
||||
int SplittedAudioStream::getRate(void) const {
|
||||
if (_queue)
|
||||
return _queue->stream->getRate();
|
||||
else
|
||||
return 22050;
|
||||
}
|
||||
|
||||
void SplittedAudioStream::appendStream(AudioStream *stream) {
|
||||
FileQueue **que = &_queue;
|
||||
while (*que)
|
||||
que = &((*que)->next);
|
||||
*que = new FileQueue;
|
||||
(*que)->stream = stream;
|
||||
(*que)->next = NULL;
|
||||
}
|
||||
|
||||
bool SplittedAudioStream::endOfData(void) const {
|
||||
if (_queue)
|
||||
return _queue->stream->endOfData();
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SplittedAudioStream::isStereo(void) const {
|
||||
if (_queue)
|
||||
return _queue->stream->isStereo();
|
||||
else
|
||||
return false; // all the BS1 files are mono, anyways.
|
||||
}
|
||||
|
||||
int SplittedAudioStream::readBuffer(int16 *buffer, const int numSamples) {
|
||||
int retVal = 0;
|
||||
int needSamples = numSamples;
|
||||
while (needSamples && _queue) {
|
||||
int retSmp = _queue->stream->readBuffer(buffer, needSamples);
|
||||
needSamples -= retSmp;
|
||||
retVal += retSmp;
|
||||
buffer += retSmp;
|
||||
if (_queue->stream->endOfData()) {
|
||||
delete _queue->stream;
|
||||
FileQueue *que = _queue->next;
|
||||
delete _queue;
|
||||
_queue = que;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
const char * MoviePlayer::_sequenceList[20] = {
|
||||
"ferrari", // 0 CD2 ferrari running down fitz in sc19
|
||||
"ladder", // 1 CD2 george walking down ladder to dig sc24->sc$
|
||||
"steps", // 2 CD2 george walking down steps sc23->sc24
|
||||
"sewer", // 3 CD1 george entering sewer sc2->sc6
|
||||
"intro", // 4 CD1 intro sequence ->sc1
|
||||
"river", // 5 CD1 george being thrown into river by flap & g$
|
||||
"truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4
|
||||
"grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $
|
||||
"montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25
|
||||
"tapestry", // 9 CD2 tapestry room beyond spain well, sc61
|
||||
"ireland", // 10 CD2 ireland establishing shot europe_map->sc19
|
||||
"finale", // 11 CD2 grand finale at very end, from sc73
|
||||
"history", // 12 CD1 George's history lesson from Nico, in sc10
|
||||
"spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$
|
||||
"well", // 14 CD2 first time being lowered down well in Spai$
|
||||
"candle", // 15 CD2 Candle burning down in Spain mausoleum sc59
|
||||
"geodrop", // 16 CD2 from sc54, George jumping down onto truck
|
||||
"vulture", // 17 CD2 from sc54, vultures circling George's dead body
|
||||
"enddemo", // 18 --- for end of single CD demo
|
||||
"credits", // 19 CD2 credits, to follow "finale" sequence
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
@ -26,11 +26,36 @@
|
||||
|
||||
#include "sword1/screen.h"
|
||||
#include "sword1/sound.h"
|
||||
|
||||
|
||||
#include "sound/audiostream.h"
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum {
|
||||
SEQ_FERRARI = 0,
|
||||
SEQ_LADDER,
|
||||
SEQ_STEPS,
|
||||
SEQ_SEWER,
|
||||
SEQ_INTRO,
|
||||
SEQ_RIVER,
|
||||
SEQ_TRUCK,
|
||||
SEQ_GRAVE,
|
||||
SEQ_MONTFCON,
|
||||
SEQ_TAPESTRY,
|
||||
SEQ_IRELAND,
|
||||
SEQ_FINALE,
|
||||
SEQ_HISTORY,
|
||||
SEQ_SPANISH,
|
||||
SEQ_WELL,
|
||||
SEQ_CANDLE,
|
||||
SEQ_GEODROP,
|
||||
SEQ_VULTURE,
|
||||
SEQ_ENDDEMO,
|
||||
SEQ_CREDITS
|
||||
};
|
||||
|
||||
#define INTRO_LOGO_OVLS 12
|
||||
#define INTRO_TEXT_OVLS 8
|
||||
|
||||
class AnimationState : public Graphics::BaseAnimationState {
|
||||
private:
|
||||
Screen *_scr;
|
||||
@ -38,6 +63,9 @@ private:
|
||||
public:
|
||||
AnimationState(Screen *scr, SoundMixer *snd, OSystem *sys);
|
||||
~AnimationState();
|
||||
void updateScreen();
|
||||
OverlayColor *giveRgbBuffer(void);
|
||||
bool soundFinished();
|
||||
|
||||
private:
|
||||
void drawYUV(int width, int height, byte *const *dat);
|
||||
@ -45,19 +73,48 @@ private:
|
||||
#ifdef BACKEND_8BIT
|
||||
void setPalette(byte *pal);
|
||||
#endif
|
||||
|
||||
protected:
|
||||
virtual AudioStream *createAudioStream(const char *name, void *arg);
|
||||
};
|
||||
|
||||
class MoviePlayer {
|
||||
public:
|
||||
MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys);
|
||||
~MoviePlayer(void);
|
||||
void play(uint32 id);
|
||||
private:
|
||||
void insertOverlay(OverlayColor *buf, uint8 *ovl, OverlayColor *pal);
|
||||
void processFrame(uint32 animId, AnimationState *anim, uint32 frameNo);
|
||||
bool initOverlays(uint32 id);
|
||||
void decompressRle(uint8 *src, uint8 *dest, uint32 srcSize);
|
||||
Screen *_scr;
|
||||
SoundMixer *_snd;
|
||||
OSystem *_sys;
|
||||
|
||||
public:
|
||||
MoviePlayer(Screen *scr, SoundMixer *snd, OSystem *sys);
|
||||
void play(const char *filename);
|
||||
static const char *_sequenceList[20];
|
||||
uint8 *_logoOvls[INTRO_LOGO_OVLS];
|
||||
OverlayColor *_introPal;
|
||||
};
|
||||
|
||||
} // End of namespace Sword2
|
||||
struct FileQueue {
|
||||
AudioStream *stream;
|
||||
FileQueue *next;
|
||||
};
|
||||
|
||||
class SplittedAudioStream : public AudioStream {
|
||||
public:
|
||||
SplittedAudioStream(void);
|
||||
~SplittedAudioStream(void);
|
||||
void appendStream(AudioStream *stream);
|
||||
virtual int readBuffer(int16 *buffer, const int numSamples);
|
||||
virtual bool isStereo(void) const;
|
||||
virtual bool endOfData(void) const;
|
||||
virtual int getRate(void) const;
|
||||
private:
|
||||
FileQueue *_queue;
|
||||
};
|
||||
|
||||
} // End of namespace Sword1
|
||||
|
||||
#endif
|
||||
|
339
sword1/credits.cpp
Normal file
339
sword1/credits.cpp
Normal file
@ -0,0 +1,339 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2003-2004 The ScummVM project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Header$
|
||||
*
|
||||
*/
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "credits.h"
|
||||
#include "screen.h"
|
||||
#include "common/file.h"
|
||||
#include "sound/mixer.h"
|
||||
#include "common/util.h"
|
||||
#include "sound/audiostream.h"
|
||||
|
||||
#include "sword1.h"
|
||||
|
||||
#define CREDITS_X 480
|
||||
#define CREDITS_Y 300
|
||||
#define BUFSIZE_Y 640
|
||||
|
||||
#define START_X ((640 - CREDITS_X) / 2)
|
||||
#define START_Y ((480 - CREDITS_Y) / 2)
|
||||
|
||||
#define SCROLL_TIMING (2000 / 59) // 29.5 frames per second
|
||||
|
||||
#define LOGO_FADEUP_TIME (133 * 1000)
|
||||
#define LOGO_FADEDOWN_TIME (163 * 1000)
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
enum {
|
||||
FONT_PAL = 0,
|
||||
FONT,
|
||||
TEXT,
|
||||
REVO_PAL,
|
||||
REVO_LOGO,
|
||||
F_EOF
|
||||
};
|
||||
|
||||
enum {
|
||||
FNT_LFT = 0, // left column
|
||||
FNT_RGT, // right column
|
||||
FNT_CEN, // centered
|
||||
FNT_BIG = 64, // big font
|
||||
FNT_EOL = 128, // linebreak
|
||||
FNT_EOB = 255 // end of textblock
|
||||
};
|
||||
|
||||
|
||||
CreditsPlayer::CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer) {
|
||||
_system = pSystem;
|
||||
_mixer = pMixer;
|
||||
_smlFont = _bigFont = NULL;
|
||||
}
|
||||
|
||||
bool spaceInBuf(uint16 blitSta, uint16 blitEnd, uint16 renderDest) {
|
||||
if (blitEnd > blitSta) {
|
||||
if ((renderDest > blitEnd) || (renderDest + 15 < blitSta))
|
||||
return true;
|
||||
} else {
|
||||
if ((renderDest > blitEnd) && (renderDest + 15 < blitSta))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void CreditsPlayer::play(void) {
|
||||
AudioStream *bgSoundStream = AudioStream::openStreamFile("credits");
|
||||
if (bgSoundStream == NULL) {
|
||||
warning("\"credits.ogg\" not found, skipping credits sequence");
|
||||
return;
|
||||
}
|
||||
ArcFile credFile;
|
||||
if (!credFile.open("credits.dat")) {
|
||||
warning("\"credits.dat\" not found, skipping credits sequence");
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 *palSrc = credFile.fetchFile(FONT_PAL, &_palLen);
|
||||
for (uint32 cnt = 0; cnt < _palLen; cnt++)
|
||||
_palette[(cnt / 3) * 4 + cnt % 3] = palSrc[cnt];
|
||||
_palLen /= 3;
|
||||
|
||||
generateFonts(&credFile);
|
||||
|
||||
uint8 *textData = credFile.fetchFile(TEXT);
|
||||
textData += READ_LE_UINT32(textData + SwordEngine::_systemVars.language * 4);
|
||||
|
||||
uint8 *screenBuf = (uint8*)malloc(CREDITS_X * BUFSIZE_Y);
|
||||
memset(screenBuf, 0, CREDITS_X * BUFSIZE_Y);
|
||||
_system->copyRectToScreen(screenBuf, 640, 0, 0, 640, 480);
|
||||
_system->setPalette(_palette, 0, _palLen);
|
||||
_system->updateScreen();
|
||||
|
||||
// everything's initialized, time to render and show the credits.
|
||||
PlayingSoundHandle bgSound;
|
||||
_mixer->playInputStream(&bgSound, bgSoundStream, true, 0);
|
||||
|
||||
int relDelay = 0;
|
||||
uint16 scrollY = 0;
|
||||
uint16 renderY = BUFSIZE_Y / 2;
|
||||
uint16 clearY = 0xFFFF;
|
||||
bool clearLine = false;
|
||||
while (((*textData != FNT_EOB) || (scrollY != renderY)) && !SwordEngine::_systemVars.engineQuit) {
|
||||
if ((int32)_mixer->getSoundElapsedTime(bgSound) - relDelay < (SCROLL_TIMING * 2)) { // sync to audio
|
||||
if (scrollY < BUFSIZE_Y - CREDITS_Y)
|
||||
_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, CREDITS_Y);
|
||||
else {
|
||||
_system->copyRectToScreen(screenBuf + scrollY * CREDITS_X, CREDITS_X, START_X, START_Y, CREDITS_X, BUFSIZE_Y - scrollY);
|
||||
_system->copyRectToScreen(screenBuf, CREDITS_X, START_X, START_Y + BUFSIZE_Y - scrollY, CREDITS_X, CREDITS_Y - (BUFSIZE_Y - scrollY));
|
||||
}
|
||||
_system->updateScreen();
|
||||
} else
|
||||
warning("frame skipped");
|
||||
|
||||
while (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY) && (*textData != FNT_EOB)) {
|
||||
if (*textData & FNT_EOL) {
|
||||
renderY = (renderY + 16) % BUFSIZE_Y; // linebreak
|
||||
clearLine = true;
|
||||
*textData &= ~FNT_EOL;
|
||||
}
|
||||
if (spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, renderY)) {
|
||||
if (clearLine)
|
||||
memset(screenBuf + renderY * CREDITS_X, 0, 16 * CREDITS_X);
|
||||
clearLine = false;
|
||||
renderLine(screenBuf, textData + 1, renderY, *textData);
|
||||
if (*textData & FNT_BIG)
|
||||
renderY += 16;
|
||||
while (*++textData != 0) // search for the start of next string
|
||||
;
|
||||
textData++;
|
||||
}
|
||||
if (*textData == FNT_EOB)
|
||||
clearY = renderY;
|
||||
}
|
||||
if ((*textData == FNT_EOB) && spaceInBuf(scrollY, (scrollY + CREDITS_Y) % BUFSIZE_Y, clearY)) {
|
||||
memset(screenBuf + clearY * CREDITS_X, 0, 16 * CREDITS_X);
|
||||
clearY = (clearY + 16) % BUFSIZE_Y;
|
||||
}
|
||||
|
||||
relDelay += SCROLL_TIMING;
|
||||
delay(relDelay - (int32)_mixer->getSoundElapsedTime(bgSound));
|
||||
scrollY = (scrollY + 1) % BUFSIZE_Y;
|
||||
}
|
||||
free(_smlFont);
|
||||
free(_bigFont);
|
||||
_smlFont = _bigFont = NULL;
|
||||
free(screenBuf);
|
||||
|
||||
// credits done, now show the revolution logo
|
||||
uint8 *revoBuf = credFile.decompressFile(REVO_LOGO);
|
||||
uint8 *revoPal = credFile.fetchFile(REVO_PAL, &_palLen);
|
||||
_palLen /= 3;
|
||||
while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEUP_TIME) && !SwordEngine::_systemVars.engineQuit) {
|
||||
_system->updateScreen();
|
||||
delay(100);
|
||||
}
|
||||
memset(_palette, 0, 256 * 4);
|
||||
_system->setPalette(_palette, 0, 256);
|
||||
_system->copyRectToScreen(revoBuf, 480, START_X, START_Y, CREDITS_X, CREDITS_Y);
|
||||
_system->updateScreen();
|
||||
|
||||
fadePalette(revoPal, true, _palLen);
|
||||
while ((_mixer->getSoundElapsedTime(bgSound) < LOGO_FADEDOWN_TIME) && !SwordEngine::_systemVars.engineQuit) {
|
||||
_system->updateScreen();
|
||||
delay(100);
|
||||
}
|
||||
fadePalette(revoPal, false, _palLen);
|
||||
delay(3000);
|
||||
|
||||
if (SwordEngine::_systemVars.engineQuit)
|
||||
_mixer->stopAll();
|
||||
free(revoBuf);
|
||||
}
|
||||
|
||||
void CreditsPlayer::fadePalette(uint8 *srcPal, bool fadeup, uint16 len) {
|
||||
int8 fadeDir = fadeup ? 1 : -1;
|
||||
int fadeStart = fadeup ? 0 : 12;
|
||||
|
||||
int relDelay = _system->getMillis();
|
||||
for (int fadeStep = fadeStart; (fadeStep >= 0) && (fadeStep <= 12) && !SwordEngine::_systemVars.engineQuit; fadeStep += fadeDir) {
|
||||
for (uint16 cnt = 0; cnt < len * 3; cnt++)
|
||||
_palette[(cnt / 3) * 4 + (cnt % 3)] = (srcPal[cnt] * fadeStep) / 12;
|
||||
_system->setPalette(_palette, 0, 256);
|
||||
_system->updateScreen();
|
||||
relDelay += 1000 / 12;
|
||||
delay(relDelay - _system->getMillis());
|
||||
}
|
||||
}
|
||||
|
||||
void CreditsPlayer::renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags) {
|
||||
uint8 *font;
|
||||
uint16 fntSize = 16;
|
||||
if (flags & FNT_BIG) {
|
||||
font = _bigFont;
|
||||
fntSize = 32;
|
||||
flags &= ~FNT_BIG;
|
||||
} else
|
||||
font = _smlFont;
|
||||
|
||||
uint16 width = getWidth(font, line);
|
||||
uint16 xBufPos = (flags == FNT_CEN) ? (CREDITS_X - width) / 2 : ((flags == FNT_LFT) ? (234 - width) : 255);
|
||||
uint8 *bufDest = screenBuf + yBufPos * CREDITS_X + xBufPos;
|
||||
while (*line) {
|
||||
uint8 *chrSrc = font + _numChars + (*line - 1) * fntSize * fntSize;
|
||||
for (uint16 cnty = 0; cnty < fntSize; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < fntSize; cntx++)
|
||||
bufDest[cnty * CREDITS_X + cntx] = chrSrc[cntx];
|
||||
chrSrc += fntSize;
|
||||
}
|
||||
bufDest += font[*line++ - 1];
|
||||
}
|
||||
}
|
||||
|
||||
uint16 CreditsPlayer::getWidth(uint8 *font, uint8 *line) {
|
||||
uint16 width = 0;
|
||||
while (*line)
|
||||
width += font[*line++ - 1];
|
||||
return width;
|
||||
}
|
||||
|
||||
void CreditsPlayer::generateFonts(ArcFile *arcFile) {
|
||||
_bigFont = arcFile->decompressFile(FONT);
|
||||
_numChars = *_bigFont;
|
||||
memmove(_bigFont, _bigFont + 1, _numChars * (32 * 32 + 1));
|
||||
_smlFont = (uint8*)malloc(_numChars * (32 * 32 + 1));
|
||||
uint8 *src = _bigFont + _numChars;
|
||||
uint8 *dst = _smlFont + _numChars;
|
||||
for (uint16 cnt = 0; cnt < _numChars; cnt++) {
|
||||
_smlFont[cnt] = (_bigFont[cnt]++ + 1) / 2; // width table
|
||||
for (uint16 cnty = 0; cnty < 16; cnty++) {
|
||||
for (uint16 cntx = 0; cntx < 16; cntx++) {
|
||||
uint8 resR = (uint8)((_palette[src[0] * 4 + 0] + _palette[src[1] * 4 + 0] + _palette[src[32] * 4 + 0] + _palette[src[33] * 4 + 0]) >> 2);
|
||||
uint8 resG = (uint8)((_palette[src[0] * 4 + 1] + _palette[src[1] * 4 + 1] + _palette[src[32] * 4 + 1] + _palette[src[33] * 4 + 1]) >> 2);
|
||||
uint8 resB = (uint8)((_palette[src[0] * 4 + 2] + _palette[src[1] * 4 + 2] + _palette[src[32] * 4 + 2] + _palette[src[33] * 4 + 2]) >> 2);
|
||||
*dst++ = getPalIdx(resR, resG, resB);
|
||||
src += 2;
|
||||
}
|
||||
src += 32;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8 CreditsPlayer::getPalIdx(uint8 r, uint8 g, uint8 b) {
|
||||
for (uint16 cnt = 0; cnt < _palLen; cnt++)
|
||||
if ((_palette[cnt * 4 + 0] == r) && (_palette[cnt * 4 + 1] == g) && (_palette[cnt * 4 + 2] == b))
|
||||
return (uint8)cnt;
|
||||
assert(_palLen < 256);
|
||||
_palette[_palLen * 4 + 0] = r;
|
||||
_palette[_palLen * 4 + 1] = g;
|
||||
_palette[_palLen * 4 + 2] = b;
|
||||
return (uint8)_palLen++;
|
||||
}
|
||||
|
||||
void CreditsPlayer::delay(int msecs) {
|
||||
|
||||
OSystem::Event event;
|
||||
uint32 start = _system->getMillis();
|
||||
do {
|
||||
while (_system->pollEvent(event)) {
|
||||
switch (event.event_code) {
|
||||
case OSystem::EVENT_QUIT:
|
||||
SwordEngine::_systemVars.engineQuit = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (msecs > 0)
|
||||
_system->delayMillis(10);
|
||||
} while ((_system->getMillis() < start + msecs) && !SwordEngine::_systemVars.engineQuit);
|
||||
}
|
||||
|
||||
ArcFile::ArcFile(void) {
|
||||
_buf = NULL;
|
||||
}
|
||||
|
||||
ArcFile::~ArcFile(void) {
|
||||
if (_buf)
|
||||
free(_buf);
|
||||
}
|
||||
|
||||
bool ArcFile::open(const char *name) {
|
||||
File arc;
|
||||
if (!arc.open(name))
|
||||
return false;
|
||||
_bufPos = _buf = (uint8*)malloc(arc.size());
|
||||
arc.read(_buf, arc.size());
|
||||
arc.close();
|
||||
return true;
|
||||
}
|
||||
|
||||
void ArcFile::enterPath(uint32 id) {
|
||||
_bufPos += READ_LE_UINT32(_bufPos + id * 4);
|
||||
}
|
||||
|
||||
uint8 *ArcFile::fetchFile(uint32 fileId, uint32 *size) {
|
||||
if (size)
|
||||
*size = READ_LE_UINT32(_bufPos + (fileId + 1) * 4) - READ_LE_UINT32(_bufPos + fileId * 4);
|
||||
return _bufPos + READ_LE_UINT32(_bufPos + fileId * 4);
|
||||
}
|
||||
|
||||
uint8 *ArcFile::decompressFile(uint32 fileId) {
|
||||
uint32 size;
|
||||
uint8 *srcBuf = fetchFile(fileId, &size);
|
||||
uint8 *dstBuf = (uint8*)malloc(READ_LE_UINT32(srcBuf));
|
||||
uint8 *srcPos = srcBuf + 4;
|
||||
uint8 *dstPos = dstBuf;
|
||||
while (srcPos < srcBuf + size) {
|
||||
uint16 len = READ_LE_UINT16(srcPos);
|
||||
memset(dstPos, 0, len);
|
||||
dstPos += len;
|
||||
srcPos += 2;
|
||||
if (srcPos < srcBuf + size) {
|
||||
uint8 len = *srcPos++;
|
||||
memcpy(dstPos, srcPos, len);
|
||||
dstPos += len;
|
||||
srcPos += len;
|
||||
}
|
||||
}
|
||||
return dstBuf;
|
||||
}
|
||||
|
||||
}; // end of namespace Sword1
|
68
sword1/credits.h
Normal file
68
sword1/credits.h
Normal file
@ -0,0 +1,68 @@
|
||||
/* ScummVM - Scumm Interpreter
|
||||
* Copyright (C) 2003-2004 The ScummVM project
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* $Header$
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef BS1CREDITS_H
|
||||
#define BS1CREDITS_H
|
||||
|
||||
#include "common/util.h"
|
||||
class SoundMixer;
|
||||
class OSystem;
|
||||
|
||||
namespace Sword1 {
|
||||
|
||||
class ArcFile {
|
||||
public:
|
||||
ArcFile(void);
|
||||
~ArcFile(void);
|
||||
bool open(const char *name);
|
||||
uint8 *fetchFile(uint32 fileId, uint32 *size = NULL);
|
||||
uint8 *decompressFile(uint32 fileId);
|
||||
void enterPath(uint32 id);
|
||||
void backToRoot(void) { _bufPos = _buf; };
|
||||
private:
|
||||
uint8 *_bufPos;
|
||||
uint8 *_buf;
|
||||
};
|
||||
|
||||
class CreditsPlayer {
|
||||
public:
|
||||
CreditsPlayer(OSystem *pSystem, SoundMixer *pMixer);
|
||||
void play(void);
|
||||
private:
|
||||
void generateFonts(ArcFile *arcFile);
|
||||
void renderLine(uint8 *screenBuf, uint8 *line, uint16 yBufPos, uint8 flags);
|
||||
void fadePalette(uint8 *srcPal, bool fadeup, uint16 len);
|
||||
void delay(int msecs);
|
||||
uint16 getWidth(uint8 *font, uint8 *line);
|
||||
uint8 getPalIdx(uint8 r, uint8 g, uint8 b);
|
||||
uint8 _palette[256 * 4];
|
||||
uint32 _palLen;
|
||||
uint8 _numChars;
|
||||
|
||||
OSystem *_system;
|
||||
SoundMixer *_mixer;
|
||||
|
||||
uint8 *_smlFont, *_bigFont;
|
||||
};
|
||||
|
||||
}; // end of namespace Sword1
|
||||
|
||||
#endif // BS1CREDITS_H
|
@ -34,6 +34,7 @@
|
||||
#include "sword1/music.h"
|
||||
#include "sword1/swordres.h"
|
||||
#include "sword1/animation.h"
|
||||
#include "sword1/credits.h"
|
||||
|
||||
#include "sword1/debug.h"
|
||||
|
||||
@ -940,37 +941,13 @@ int Logic::fnSetPaletteToCut(Object *cpt, int32 id, int32 c, int32 d, int32 e, i
|
||||
|
||||
int Logic::fnPlaySequence(Object *cpt, int32 id, int32 sequenceId, int32 d, int32 e, int32 f, int32 z, int32 x) {
|
||||
|
||||
static const char *sequence_list[20] = {
|
||||
"ferrari", // 0 CD2 ferrari running down fitz in sc19
|
||||
"ladder", // 1 CD2 george walking down ladder to dig sc24->sc$
|
||||
"steps", // 2 CD2 george walking down steps sc23->sc24
|
||||
"sewer", // 3 CD1 george entering sewer sc2->sc6
|
||||
"intro", // 4 CD1 intro sequence ->sc1
|
||||
"river", // 5 CD1 george being thrown into river by flap & g$
|
||||
"truck", // 6 CD2 truck arriving at bull's head sc45->sc53/4
|
||||
"grave", // 7 BOTH george's grave in scotland, from sc73 + from sc38 $
|
||||
"montfcon", // 8 CD2 monfaucon clue in ireland dig, sc25
|
||||
"tapestry", // 9 CD2 tapestry room beyond spain well, sc61
|
||||
"ireland", // 10 CD2 ireland establishing shot europe_map->sc19
|
||||
"finale", // 11 CD2 grand finale at very end, from sc73
|
||||
"history", // 12 CD1 George's history lesson from Nico, in sc10
|
||||
"spanish", // 13 CD2 establishing shot for 1st visit to Spain, europe_m$
|
||||
"well", // 14 CD2 first time being lowered down well in Spai$
|
||||
"candle", // 15 CD2 Candle burning down in Spain mausoleum sc59
|
||||
"geodrop", // 16 CD2 from sc54, George jumping down onto truck
|
||||
"vulture", // 17 CD2 from sc54, vultures circling George's dead body
|
||||
"enddemo", // 18 --- for end of single CD demo
|
||||
"credits", // 19 CD2 credits, to follow "finale" sequence
|
||||
// etc.
|
||||
};
|
||||
|
||||
MoviePlayer player(_screen, _mixer, _system);
|
||||
|
||||
player.play(sequence_list[sequenceId]);
|
||||
|
||||
//_scriptVars[NEW_PALETTE] = 1;
|
||||
/* the logic usually calls fnFadeDown before playing the sequence, so we have to
|
||||
set NEW_PALETTE now to force a palette refresh */
|
||||
if ((SwordEngine::_systemVars.cutscenePackVersion == 1) && (sequenceId == SEQ_CREDITS)) {
|
||||
CreditsPlayer player(_system, _mixer);
|
||||
player.play();
|
||||
} else {
|
||||
MoviePlayer player(_screen, _mixer, _system);
|
||||
player.play(sequenceId);
|
||||
}
|
||||
return SCRIPT_CONT;
|
||||
}
|
||||
|
||||
|
@ -1134,6 +1134,15 @@ void SwordEngine::checkCdFiles(void) { // check if we're running from cd, hdd or
|
||||
error(msg);
|
||||
}
|
||||
}
|
||||
|
||||
// check cutscene pack version
|
||||
_systemVars.cutscenePackVersion = 0;
|
||||
#ifdef USE_MPEG2
|
||||
if (test.open("intro.snd")) {
|
||||
_systemVars.cutscenePackVersion = 1;
|
||||
test.close();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int SwordEngine::go() {
|
||||
|
@ -63,6 +63,8 @@ struct SystemVars {
|
||||
uint8 showText;
|
||||
uint8 language;
|
||||
bool isDemo;
|
||||
|
||||
uint8 cutscenePackVersion;
|
||||
};
|
||||
|
||||
class SwordEngine : public Engine {
|
||||
|
Loading…
Reference in New Issue
Block a user