Ticket #8605: sword1-subtitles.diff
File sword1-subtitles.diff, 13.2 KB (added by , 18 years ago) |
---|
-
engines/sword1/animation.h
58 58 #define INTRO_LOGO_OVLS 12 59 59 #define INTRO_TEXT_OVLS 8 60 60 61 class MovieText { 62 public: 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 61 76 class MoviePlayer { 62 77 public: 63 MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys);78 MoviePlayer(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys); 64 79 virtual ~MoviePlayer(void); 65 80 virtual bool load(uint32 id); 66 81 void play(void); … … 69 84 bool checkSkipFrame(void); 70 85 protected: 71 86 Screen *_scr; 87 Text *_text; 72 88 Audio::Mixer *_snd; 73 89 OSystem *_sys; 90 Common::Array<MovieText *> _movieTexts; 91 byte *_textSpriteBuf; 92 int _textX, _textY, _textWidth, _textHeight; 93 byte _black, _white; 74 94 75 95 uint32 _id; 76 96 … … 100 120 protected: 101 121 virtual void setPalette(byte *pal); 102 122 public: 103 MoviePlayerDXA(Screen *scr, Audio::Mixer *snd, OSystem *sys);123 MoviePlayerDXA(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys); 104 124 virtual ~MoviePlayerDXA(void); 105 125 bool load(uint32 id); 106 126 protected: … … 137 157 138 158 class MoviePlayerMPEG : public MoviePlayer { 139 159 public: 140 MoviePlayerMPEG(Screen *scr, Audio::Mixer *snd, OSystem *sys);160 MoviePlayerMPEG(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys); 141 161 virtual ~MoviePlayerMPEG(void); 142 162 bool load(uint32 id); 143 163 protected: … … 173 193 FileQueue *_queue; 174 194 }; 175 195 176 MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem *sys);196 MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys); 177 197 178 198 } // End of namespace Sword1 179 199 -
engines/sword1/text.h
28 28 29 29 namespace Sword1 { 30 30 31 #define MAX_TEXT_OBS 231 #define MAX_TEXT_OBS 3 32 32 33 #define BORDER_COL 200 34 #define LETTER_COL 193 35 #define NO_COL 0 // sprite background - 0 for transparency 36 33 37 class ObjectMan; 34 38 class ResMan; 35 39 … … 44 48 ~Text(void); 45 49 FrameHeader *giveSpriteData(uint32 textTarget); 46 50 uint32 lowTextManager(uint8 *text, int32 width, uint8 pen); 51 void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen); 47 52 void releaseText(uint32 id); 48 53 49 54 private: 50 void makeTextSprite(uint8 slot, uint8 *text, uint16 maxWidth, uint8 pen);51 55 uint16 analyzeSentence(uint8 *text, uint16 maxWidth, LineInfo *info); 52 56 uint16 charWidth(uint8 ch); 53 57 uint16 copyChar(uint8 ch, uint8 *sprPtr, uint16 sprWidth, uint8 pen); -
engines/sword1/animation.cpp
25 25 #include "sword1/sword1.h" 26 26 #include "sword1/animation.h" 27 27 #include "sword1/credits.h" 28 #include "sword1/text.h" 28 29 #include "sound/vorbis.h" 29 30 30 31 #include "common/config-manager.h" … … 61 62 // Basic movie player 62 63 /////////////////////////////////////////////////////////////////////////////// 63 64 64 MoviePlayer::MoviePlayer(Screen *scr, Audio::Mixer *snd, OSystem *sys)65 : _scr(scr), _ snd(snd), _sys(sys) {65 MoviePlayer::MoviePlayer(Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys) 66 : _scr(scr), _text(text), _snd(snd), _sys(sys) { 66 67 _bgSoundStream = NULL; 67 68 _ticks = 0; 68 _frameBuffer = NULL; 69 _textSpriteBuf = NULL; 70 _black = 1; 71 _white = 255; 69 72 _currentFrame = 0; 70 73 _forceFrame = false; 71 74 _framesSkipped = 0; … … 77 80 void MoviePlayer::updatePalette(byte *pal, bool packed) { 78 81 byte palette[4 * 256]; 79 82 byte *p = palette; 83 84 uint32 maxWeight = 0; 85 uint32 minWeight = 0xFFFFFFFF; 86 80 87 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 84 92 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; 88 111 } 112 89 113 _sys->setPalette(palette, 0, 256); 90 114 _forceFrame = true; 91 115 } … … 146 170 * @param id the id of the file 147 171 */ 148 172 bool MoviePlayer::load(uint32 id) { 173 Common::File f; 174 char fileName[20]; 175 149 176 _id = id; 150 177 _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 151 217 if (SwordEngine::_systemVars.cutscenePackVersion == 1) { 152 218 if ((id == SEQ_INTRO) || (id == SEQ_FINALE) || (id == SEQ_HISTORY) || (id == SEQ_FERRARI)) { 153 219 #ifdef USE_VORBIS 154 220 // these sequences are language specific 155 char sndName[20]; 156 sprintf(sndName, "%s.snd", sequenceList[id]); 221 sprintf(fileName, "%s.snd", sequenceList[id]); 157 222 Common::File *oggSource = new Common::File(); 158 if (oggSource->open( sndName)) {223 if (oggSource->open(fileName)) { 159 224 SplittedAudioStream *sStream = new SplittedAudioStream(); 160 225 uint32 numSegs = oggSource->readUint32LE(); // number of audio segments, either 1 or 2. 161 226 // for each segment and each of the 7 languages, we've got fileoffset and size … … 167 232 uint32 segSize = header[SwordEngine::_systemVars.language * 2 + 1 + segCnt * 14]; 168 233 Audio::AudioStream *apStream = Audio::makeVorbisStream(oggSource, segSize); 169 234 if (!apStream) 170 error("Can't create Vorbis Stream from file %s", sndName);235 error("Can't create Vorbis Stream from file %s", fileName); 171 236 sStream->appendStream(apStream); 172 237 } 173 238 free(header); 174 239 _bgSoundStream = sStream; 175 240 } else 176 warning("Sound file \"%s\" not found", sndName);241 warning("Sound file \"%s\" not found", fileName); 177 242 oggSource->decRef(); 178 243 #endif 179 244 initOverlays(id); … … 193 258 _currentFrame = 0; 194 259 bool terminated = false; 195 260 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 } 196 279 processFrame(); 197 280 syncFrame(); 198 281 updateScreen(); … … 217 300 } 218 301 } 219 302 } 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 220 311 while (_snd->isSoundHandleActive(_bgSoundHandle)) 221 312 _sys->delayMillis(100); 222 313 … … 297 388 // Movie player for the new DXA movies 298 389 /////////////////////////////////////////////////////////////////////////////// 299 390 300 MoviePlayerDXA::MoviePlayerDXA(Screen *src, Audio::Mixer *snd, OSystem *sys)301 : MoviePlayer(src, snd, sys) {391 MoviePlayerDXA::MoviePlayerDXA(Screen *src, Text *text, Audio::Mixer *snd, OSystem *sys) 392 : MoviePlayer(src, text, snd, sys) { 302 393 debug(0, "Creating DXA cutscene player"); 303 394 } 304 395 305 396 MoviePlayerDXA::~MoviePlayerDXA(void) { 306 397 closeFile(); 307 // free(_frameBuffer);308 398 } 309 399 310 400 bool MoviePlayerDXA::load(uint32 id) { … … 344 434 } 345 435 346 436 void 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 } 348 475 } 349 476 350 477 void MoviePlayerDXA::updateScreen(void) { 351 // Using _drawBuffer directly should work, as long as we don't do any352 // post-processing of the frame.353 478 _sys->copyRectToScreen(_drawBuffer, _frameWidth, _frameX, _frameY, _frameWidth, _frameHeight); 479 if (_textSpriteBuf) { 480 _sys->copyRectToScreen(_textSpriteBuf, _textWidth, _textX, _textY, _textWidth, _textHeight); 481 } 354 482 _sys->updateScreen(); 355 483 } 356 484 … … 362 490 // Movie player for the old MPEG movies 363 491 /////////////////////////////////////////////////////////////////////////////// 364 492 365 MoviePlayerMPEG::MoviePlayerMPEG(Screen *src, Audio::Mixer *snd, OSystem *sys)366 : MoviePlayer(src, snd, sys) {493 MoviePlayerMPEG::MoviePlayerMPEG(Screen *src, Text *text, Audio::Mixer *snd, OSystem *sys) 494 : MoviePlayer(src, text, snd, sys) { 367 495 #ifdef BACKEND_8BIT 368 496 debug(0, "Creating MPEG cutscene player (8-bit)"); 369 497 #else … … 495 623 // Factory function for creating the appropriate cutscene player 496 624 /////////////////////////////////////////////////////////////////////////////// 497 625 498 MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Audio::Mixer *snd, OSystem *sys) {626 MoviePlayer *makeMoviePlayer(uint32 id, Screen *scr, Text *text, Audio::Mixer *snd, OSystem *sys) { 499 627 #if defined(USE_ZLIB) || defined(USE_MPEG2) 500 628 char filename[20]; 501 629 #endif … … 504 632 snprintf(filename, sizeof(filename), "%s.dxa", sequenceList[id]); 505 633 506 634 if (Common::File::exists(filename)) { 507 return new MoviePlayerDXA(scr, snd, sys);635 return new MoviePlayerDXA(scr, text, snd, sys); 508 636 } 509 637 #endif 510 638 … … 512 640 snprintf(filename, sizeof(filename), "%s.mp2", sequenceList[id]); 513 641 514 642 if (Common::File::exists(filename)) { 515 return new MoviePlayerMPEG(scr, snd, sys);643 return new MoviePlayerMPEG(scr, text, snd, sys); 516 644 } 517 645 #endif 518 646 -
engines/sword1/text.cpp
34 34 35 35 #define OVERLAP 3 36 36 #define SPACE ' ' 37 #define BORDER_COL 20038 #define LETTER_COL 19339 #define NO_COL 0 // sprite background - 0 for transparency40 37 #define MAX_LINES 30 41 38 42 39 … … 49 46 50 47 _joinWidth = charWidth( SPACE ) - 2 * OVERLAP; 51 48 _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; 53 51 } 54 52 55 53 Text::~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]); 60 56 //_resMan->resClose(_fontId); => wiped automatically by _resMan->flush(); 61 57 } 62 58 … … 175 171 // textTarget is the resource ID of the Compact linking the textdata. 176 172 // that's 0x950000 for slot 0 and 0x950001 for slot 1. easy, huh? :) 177 173 textTarget &= ITM_ID; 178 assert(textTarget < = 1);174 assert(textTarget < MAX_TEXT_OBS); 179 175 180 176 return _textBlocks[textTarget]; 181 177 } 182 178 183 179 void Text::releaseText(uint32 id) { 184 180 id &= ITM_ID; 185 assert(id < = 1);181 assert(id < MAX_TEXT_OBS); 186 182 if (_textBlocks[id]) { 187 183 free(_textBlocks[id]); 188 184 _textBlocks[id] = NULL; -
engines/sword1/logic.cpp
957 957 CreditsPlayer player(_system, _mixer); 958 958 player.play(); 959 959 } else { 960 MoviePlayer *player = makeMoviePlayer(sequenceId, _screen, _ mixer, _system);960 MoviePlayer *player = makeMoviePlayer(sequenceId, _screen, _textMan, _mixer, _system); 961 961 if (player) { 962 962 if (player->load(sequenceId)) 963 963 player->play();