Ticket #8605: sword1-subtitles.diff

File sword1-subtitles.diff, 13.2 KB (added by eriktorbjorn, 14 years ago)

Patch against current SVN

  • engines/sword1/animation.h

     
    5858#define INTRO_LOGO_OVLS 12
    5959#define INTRO_TEXT_OVLS 8
    6060
     61class MovieText {
     62public:
     63        uint16 _startFrame;
     64        uint16 _endFrame;
     65        char *_text;
     66        MovieText(int startFrame, int endFrame, char *text) {
     67                _startFrame = startFrame;
     68                _endFrame = endFrame;
     69                _text = strdup(text);
     70        }
     71        ~MovieText() {
     72                free(_text);
     73        }
     74};
     75
    6176class MoviePlayer {
    6277public:
    63         MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys);
     78        MoviePlayer(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys);
    6479        virtual ~MoviePlayer(void);
    6580        virtual bool load(uint32 id);
    6681        void play(void);
     
    6984        bool checkSkipFrame(void);
    7085protected:
    7186        Screen *_scr;
     87        Text *_text;
    7288        Audio::Mixer *_snd;
    7389        OSystem *_sys;
     90        Common::Array<MovieText *> _movieTexts;
     91        byte *_textSpriteBuf;
     92        int _textX, _textY, _textWidth, _textHeight;
     93        byte _black, _white;
    7494
    7595        uint32 _id;
    7696
     
    100120protected:
    101121        virtual void setPalette(byte *pal);
    102122public:
    103         MoviePlayerDXA(Screen *scr, Audio::Mixer *snd, OSystem *sys);
     123        MoviePlayerDXA(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys);
    104124        virtual ~MoviePlayerDXA(void);
    105125        bool load(uint32 id);
    106126protected:
     
    137157
    138158class MoviePlayerMPEG : public MoviePlayer {
    139159public:
    140         MoviePlayerMPEG(Screen *scr, Audio::Mixer *snd, OSystem *sys);
     160        MoviePlayerMPEG(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys);
    141161        virtual ~MoviePlayerMPEG(void);
    142162        bool load(uint32 id);
    143163protected:
     
    173193        FileQueue *_queue;
    174194};
    175195
    176 MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem *sys);
     196MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys);
    177197
    178198} // End of namespace Sword1
    179199
  • engines/sword1/text.h

     
    2828
    2929namespace Sword1 {
    3030
    31 #define MAX_TEXT_OBS 2
     31#define MAX_TEXT_OBS 3
    3232
     33#define BORDER_COL              200
     34#define LETTER_COL              193
     35#define NO_COL                  0               // sprite background - 0 for transparency
     36
    3337class ObjectMan;
    3438class ResMan;
    3539
     
    4448        ~Text(void);
    4549        FrameHeader *giveSpriteData(uint32 textTarget);
    4650        uint32 lowTextManager(uint8 *text, int32 width, uint8 pen);
     51        void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);
    4752        void releaseText(uint32 id);
    4853
    4954private:
    50         void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);
    5155        uint16 analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *info);
    5256        uint16 charWidth(uint8 ch);
    5357        uint16 copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen);
  • engines/sword1/animation.cpp

     
    2525#include "sword1/sword1.h"
    2626#include "sword1/animation.h"
    2727#include "sword1/credits.h"
     28#include "sword1/text.h"
    2829#include "sound/vorbis.h"
    2930
    3031#include "common/config-manager.h"
     
    6162// Basic movie player
    6263///////////////////////////////////////////////////////////////////////////////
    6364
    64 MoviePlayer::MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys)
    65         : _scr(scr), _snd(snd), _sys(sys) {
     65MoviePlayer::MoviePlayer(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys)
     66        : _scr(scr), _text(text), _snd(snd), _sys(sys) {
    6667        _bgSoundStream = NULL;
    6768        _ticks = 0;
    68         _frameBuffer = NULL;
     69        _textSpriteBuf = NULL;
     70        _black = 1;
     71        _white = 255;
    6972        _currentFrame = 0;
    7073        _forceFrame = false;
    7174        _framesSkipped = 0;
     
    7780void MoviePlayer::updatePalette(byte *pal, bool packed) {
    7881        byte palette[4 * 256];
    7982        byte *p = palette;
     83
     84        uint32 maxWeight = 0;
     85        uint32 minWeight = 0xFFFFFFFF;
     86
    8087        for (int i = 0; i < 256; i++) {
    81                 *p++ = *pal++;
    82                 *p++ = *pal++;
    83                 *p++ = *pal++;
     88                int r = *pal++;
     89                int g = *pal++;
     90                int b = *pal++;
     91
    8492                if (!packed)
    85                         *p++ = *pal++;
    86                 else
    87                         *p++ = 0;
     93                        pal++;
     94
     95                uint32 weight = 3 * r * r + 6 * g * g + 2 * b * b;
     96
     97                if (weight >= maxWeight) {
     98                        _white = i;
     99                        maxWeight = weight;
     100                }
     101
     102                if (weight <= minWeight) {
     103                        _black = i;
     104                        minWeight = i;
     105                }
     106
     107                *p++ = r;
     108                *p++ = g;
     109                *p++ = b;
     110                *p++ = 0;
    88111        }
     112
    89113        _sys->setPalette(palette, 0, 256);
    90114        _forceFrame = true;
    91115}
     
    146170 * @param id the id of the file
    147171 */
    148172bool MoviePlayer::load(uint32 id) {
     173        Common::File f;
     174        char fileName[20];
     175
    149176        _id = id;
    150177        _bgSoundStream = NULL;
     178
     179        if (SwordEngine::_systemVars.showText) {
     180        sprintf(fileName, "%s.txt", sequenceList[id]);
     181                if (f.open(fileName)) {
     182                        char line[120];
     183                        int lineNo = 0;
     184                        int lastEnd = -1;
     185
     186                        _movieTexts.clear();
     187                        while (f.readLine(line, sizeof(line))) {
     188                                lineNo++;
     189                                if (line[0] == '#' || line[0] == 0) {
     190                                        continue;
     191                                }
     192
     193                                char *ptr = line;
     194
     195                                // TODO: Better error handling
     196                                int startFrame = strtoul(ptr, &ptr, 10);
     197                                int endFrame = strtoul(ptr, &ptr, 10);
     198
     199                                while (*ptr && isspace(*ptr))
     200                                        ptr++;
     201
     202                                if (startFrame > endFrame) {
     203                                        warning("%s:%d: startFrame (%d) > endFrame (%d)", fileName, lineNo, startFrame, endFrame);
     204                                        continue;
     205                                }
     206                                if (startFrame <= lastEnd) {
     207                                        warning("%s:%d: startFrame (%d) <= lastEnd (%d)", fileName, lineNo, startFrame, lastEnd);
     208                                        continue;
     209                                }
     210                                MovieText *textObj = new MovieText(startFrame, endFrame, ptr);
     211                                _movieTexts.push_back(textObj);
     212                                lastEnd = endFrame;
     213                        }
     214                }
     215        }
     216
    151217        if (SwordEngine::_systemVars.cutscenePackVersion == 1) {
    152218                if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) {
    153219#ifdef USE_VORBIS
    154220                        // these sequences are language specific
    155                         char sndName[20];
    156                         sprintf(sndName, "%s.snd", sequenceList[id]);
     221                        sprintf(fileName, "%s.snd", sequenceList[id]);
    157222                        Common::File *oggSource = new Common::File();
    158                         if (oggSource->open(sndName)) {
     223                        if (oggSource->open(fileName)) {
    159224                                SplittedAudioStream *sStream = new SplittedAudioStream();
    160225                                uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2.
    161226                                // for each segment and each of the 7 languages, we've got fileoffset and size
     
    167232                                        uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14];
    168233                                        Audio::AudioStream *apStream = Audio::makeVorbisStream(oggSource, segSize);
    169234                                        if (!apStream)
    170                                                 error("Can't create Vorbis Stream from file %s", sndName);
     235                                                error("Can't create Vorbis Stream from file %s", fileName);
    171236                                        sStream->appendStream(apStream);
    172237                                }
    173238                                free(header);
    174239                                _bgSoundStream = sStream;
    175240                        } else
    176                                 warning("Sound file \"%s\" not found", sndName);
     241                                warning("Sound file \"%s\" not found", fileName);
    177242                        oggSource->decRef();
    178243#endif
    179244                        initOverlays(id);
     
    193258        _currentFrame = 0;
    194259        bool terminated = false;
    195260        while (!terminated && decodeFrame()) {
     261                if (!_movieTexts.empty()) {
     262                        if (_currentFrame == _movieTexts[0]->_startFrame) {
     263                                _text->makeTextSprite(2, (uint8 *)_movieTexts[0]->_text, 600, LETTER_COL);
     264
     265                                FrameHeader *frame = _text->giveSpriteData(2);
     266                                _textWidth = frame->width;
     267                                _textHeight = frame->height;
     268                                _textX = 320 - _textWidth / 2;
     269                                _textY = 420 - _textHeight;
     270                                _textSpriteBuf = (byte *)calloc(_textHeight, _textWidth);
     271                        }
     272                        if (_currentFrame == _movieTexts[0]->_endFrame) {
     273                                _text->releaseText(2);
     274                                free(_textSpriteBuf);
     275                                _textSpriteBuf = NULL;
     276                                _movieTexts.remove_at(0);
     277                        }
     278                }
    196279                processFrame();
    197280                syncFrame();
    198281                updateScreen();
     
    217300                        }
    218301                }
    219302        }
     303
     304        if (!_movieTexts.empty()) {
     305                for (int i = _movieTexts.size() - 1; i >= 0; i--) {
     306                        free(_movieTexts[i]->_text);
     307                }
     308                _movieTexts.clear();
     309        }
     310
    220311        while (_snd->isSoundHandleActive(_bgSoundHandle))
    221312                _sys->delayMillis(100);
    222313
     
    297388// Movie player for the new DXA movies
    298389///////////////////////////////////////////////////////////////////////////////
    299390
    300 MoviePlayerDXA::MoviePlayerDXA(Screen *src, Audio::Mixer *snd, OSystem *sys)
    301         : MoviePlayer(src, snd, sys) {
     391MoviePlayerDXA::MoviePlayerDXA(Screen *src, Text *text, Audio::Mixer *snd, OSystem *sys)
     392        : MoviePlayer(src, text, snd, sys) {
    302393        debug(0, "Creating DXA cutscene player");
    303394}
    304395
    305396MoviePlayerDXA::~MoviePlayerDXA(void) {
    306397        closeFile();
    307         // free(_frameBuffer);
    308398}
    309399
    310400bool MoviePlayerDXA::load(uint32 id) {
     
    344434}
    345435
    346436void MoviePlayerDXA::processFrame(void) {
    347         // TODO
     437        // TODO: Handle the advanced cutscene packs. Do they really exist?
     438
     439        // We cannot draw the text to _drawBuffer, since that's one of the
     440        // decoder's internal buffers. Instead, we copy part of _drawBuffer
     441        // to the text sprite.
     442
     443        if (_textSpriteBuf) {
     444                memset(_textSpriteBuf, 0, _textWidth * _textHeight);
     445
     446                // FIXME: This is inefficient.
     447                int x, y;
     448
     449                for (y = _textY; y < _textY + _textHeight; y++) {
     450                        for (x = _textX; x < _textX + _textWidth; x++) {
     451                                if (x >= _frameX && x <= _frameX + _frameWidth && y >= _frameY && y <= _frameY + _frameWidth) {
     452                                        _textSpriteBuf[(y - _textY) * _textWidth + x - _textX] = _drawBuffer[(y - _frameY) * _frameWidth + x - _frameX];
     453                                }
     454                        }
     455                }
     456
     457                byte *src = (byte *)_text->giveSpriteData(2) + sizeof(FrameHeader);
     458                byte *dst = _textSpriteBuf;
     459
     460                for (y = 0; y < _textHeight; y++) {
     461                        for (x = 0; x < _textWidth; x++) {
     462                                switch (src[x]) {
     463                                case BORDER_COL:
     464                                        dst[x] = _black;
     465                                        break;
     466                                case LETTER_COL:
     467                                        dst[x] = _white;
     468                                        break;
     469                                }
     470                        }
     471                        src += _textWidth;
     472                        dst += _textWidth;
     473                }
     474        }
    348475}
    349476
    350477void MoviePlayerDXA::updateScreen(void) {
    351         // Using _drawBuffer directly should work, as long as we don't do any
    352         // post-processing of the frame.
    353478        _sys->copyRectToScreen(_drawBuffer, _frameWidth, _frameX, _frameY, _frameWidth, _frameHeight);
     479        if (_textSpriteBuf) {
     480                _sys->copyRectToScreen(_textSpriteBuf, _textWidth, _textX, _textY, _textWidth, _textHeight);
     481        }
    354482        _sys->updateScreen();
    355483}
    356484
     
    362490// Movie player for the old MPEG movies
    363491///////////////////////////////////////////////////////////////////////////////
    364492
    365 MoviePlayerMPEG::MoviePlayerMPEG(Screen *src, Audio::Mixer *snd, OSystem *sys)
    366         : MoviePlayer(src, snd, sys) {
     493MoviePlayerMPEG::MoviePlayerMPEG(Screen *src, Text *text, Audio::Mixer *snd, OSystem *sys)
     494        : MoviePlayer(src, text, snd, sys) {
    367495#ifdef BACKEND_8BIT
    368496        debug(0, "Creating MPEG cutscene player (8-bit)");
    369497#else
     
    495623// Factory function for creating the appropriate cutscene player
    496624///////////////////////////////////////////////////////////////////////////////
    497625
    498 MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem *sys) {
     626MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys) {
    499627#if defined(USE_ZLIB) || defined(USE_MPEG2)
    500628        char filename[20];
    501629#endif
     
    504632        snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]);
    505633
    506634        if (Common::File::exists(filename)) {
    507                 return new MoviePlayerDXA(scr, snd, sys);
     635                return new MoviePlayerDXA(scr, text, snd, sys);
    508636        }
    509637#endif
    510638
     
    512640        snprintf(filename, sizeof(filename), "%s.mp2", sequenceList[id]);
    513641
    514642        if (Common::File::exists(filename)) {
    515                 return new MoviePlayerMPEG(scr, snd, sys);
     643                return new MoviePlayerMPEG(scr, text, snd, sys);
    516644        }
    517645#endif
    518646
  • engines/sword1/text.cpp

     
    3434
    3535#define OVERLAP 3
    3636#define SPACE ' '
    37 #define BORDER_COL              200
    38 #define LETTER_COL              193
    39 #define NO_COL                  0               // sprite background - 0 for transparency
    4037#define MAX_LINES               30
    4138
    4239
     
    4946
    5047        _joinWidth = charWidth( SPACE ) - 2 * OVERLAP;
    5148        _charHeight = _resMan->getUint16(_resMan->fetchFrame(_font, 0)->height); // all chars have the same height
    52         _textBlocks[0] = _textBlocks[1] = NULL;
     49        for (int i = 0; i < MAX_TEXT_OBS; i++)
     50                _textBlocks[i] = NULL;
    5351}
    5452
    5553Text::~Text(void) {
    56         if (_textBlocks[0])
    57                 free(_textBlocks[0]);
    58         if (_textBlocks[1])
    59                 free(_textBlocks[1]);
     54        for (int i = 0; i < MAX_TEXT_OBS; i++)
     55                free(_textBlocks[i]);
    6056        //_resMan->resClose(_fontId); => wiped automatically by _resMan->flush();
    6157}
    6258
     
    175171        // textTarget is the resource ID of the Compact linking the textdata.
    176172        // that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :)
    177173        textTarget &= ITM_ID;
    178         assert(textTarget <= 1);
     174        assert(textTarget < MAX_TEXT_OBS);
    179175
    180176        return _textBlocks[textTarget];
    181177}
    182178
    183179void Text::releaseText(uint32 id) {
    184180        id &= ITM_ID;
    185         assert(id <= 1);
     181        assert(id < MAX_TEXT_OBS);
    186182        if (_textBlocks[id]) {
    187183                free(_textBlocks[id]);
    188184                _textBlocks[id] = NULL;
  • engines/sword1/logic.cpp

     
    957957                CreditsPlayer player(_system, _mixer);
    958958                player.play();
    959959        } else {
    960                 MoviePlayer *player = makeMoviePlayer(sequenceId, _screen, _mixer, _system);
     960                MoviePlayer *player = makeMoviePlayer(sequenceId, _screen, _textMan, _mixer, _system);
    961961                if (player) {
    962962                        if (player->load(sequenceId))
    963963                                player->play();