From 83285746b0cbaa7223592fa008af22b31484e0d6 Mon Sep 17 00:00:00 2001 From: BLooperZ Date: Thu, 1 Aug 2019 00:21:07 +0300 Subject: TOON: add support for cutscene subtitles --- engines/toon/font.cpp | 4 +- engines/toon/font.h | 2 +- engines/toon/module.mk | 3 +- engines/toon/movie.cpp | 40 ++++++++++++++++++- engines/toon/movie.h | 3 ++ engines/toon/subtitles.cpp | 97 ++++++++++++++++++++++++++++++++++++++++++++++ engines/toon/subtitles.h | 59 ++++++++++++++++++++++++++++ engines/toon/toon.cpp | 13 ++++++- engines/toon/toon.h | 3 ++ 9 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 engines/toon/subtitles.cpp create mode 100644 engines/toon/subtitles.h diff --git a/engines/toon/font.cpp b/engines/toon/font.cpp index 9b08e432fc..29dbf40b8b 100644 --- a/engines/toon/font.cpp +++ b/engines/toon/font.cpp @@ -191,7 +191,7 @@ void FontRenderer::setFontColor(int32 fontColor1, int32 fontColor2, int32 fontCo _currentFontColor[3] = fontColor3; } -void FontRenderer::renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode) { +void FontRenderer::renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode, Graphics::Surface& frame) { debugC(5, kDebugFont, "renderMultiLineText(%d, %d, %s, %d)", x, y, origText.c_str(), mode); // divide the text in several lines @@ -289,7 +289,7 @@ void FontRenderer::renderMultiLineText(int16 x, int16 y, const Common::String &o while (*line) { byte curChar = textToFont(*line); - if (curChar != 32) _currentFont->drawFontFrame(_vm->getMainSurface(), curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor); + if (curChar != 32) _currentFont->drawFontFrame(frame, curChar, curX + _vm->state()->_currentScrollValue, curY, _currentFontColor); curX = curX + MAX(_currentFont->getFrameWidth(curChar) - 2, 0); //height = MAX(height, _currentFont->getFrameHeight(curChar)); line++; diff --git a/engines/toon/font.h b/engines/toon/font.h index bbbccd09c8..48d4b8531d 100644 --- a/engines/toon/font.h +++ b/engines/toon/font.h @@ -35,7 +35,7 @@ public: void setFont(Animation *font); void computeSize(const Common::String &origText, int16 *retX, int16 *retY); void renderText(int16 x, int16 y, const Common::String &origText, int32 mode); - void renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode); + void renderMultiLineText(int16 x, int16 y, const Common::String &origText, int32 mode, Graphics::Surface& frame); void setFontColorByCharacter(int32 characterId); void setFontColor(int32 fontColor1, int32 fontColor2, int32 fontColor3); protected: diff --git a/engines/toon/module.mk b/engines/toon/module.mk index 7796203d00..411b8e7ddf 100644 --- a/engines/toon/module.mk +++ b/engines/toon/module.mk @@ -20,7 +20,8 @@ MODULE_OBJS := \ state.o \ text.o \ tools.o \ - toon.o + toon.o \ + subtitles.o # This module can be built as a plugin ifeq ($(ENABLE_TOON), DYNAMIC_PLUGIN) diff --git a/engines/toon/movie.cpp b/engines/toon/movie.cpp index 498e4021e2..634135d813 100644 --- a/engines/toon/movie.cpp +++ b/engines/toon/movie.cpp @@ -31,6 +31,7 @@ #include "toon/audio.h" #include "toon/movie.h" #include "toon/toon.h" +#include "toon/subtitles.h" namespace Toon { @@ -67,6 +68,7 @@ Movie::Movie(ToonEngine *vm , ToonstruckSmackerDecoder *decoder) { _vm = vm; _playing = false; _decoder = decoder; + _subtitle = new SubtitleRenderer(_vm); } Movie::~Movie() { @@ -87,6 +89,7 @@ void Movie::play(const Common::String &video, int32 flags) { _vm->getAudioManager()->setMusicVolume(0); if (!_decoder->loadFile(video.c_str())) error("Unable to play video %s", video.c_str()); + _subtitle->load(video.c_str()); playVideo(isFirstIntroVideo); _vm->flushPalette(true); if (flags & 1) @@ -103,6 +106,7 @@ void Movie::playVideo(bool isFirstIntroVideo) { while (!_vm->shouldQuit() && !_decoder->endOfVideo()) { if (_decoder->needsUpdate()) { const Graphics::Surface *frame = _decoder->decodeNextFrame(); + byte unused = 0; if (frame) { if (_decoder->isLowRes()) { // handle manually 2x scaling here @@ -115,9 +119,31 @@ void Movie::playVideo(bool isFirstIntroVideo) { } else { _vm->_system->copyRectToScreen(frame->getPixels(), frame->pitch, 0, 0, frame->w, frame->h); + int32 currentFrame = _decoder->getCurFrame(); + + int len = frame->w * frame->h; + byte pixels[310000] = {0}; + memcpy(pixels, frame->getPixels(), len); + for (byte i = 1; i < 256; i++) + { + int j; + for (j = 0; j < len; j++) { + if (pixels[j] == i) { + break; + } + } + + if (j == len && i != 255) { + unused = i; + break; + } + } + + _subtitle->render(*frame, currentFrame, unused); + // WORKAROUND: There is an encoding glitch in the first intro video. This hides this using the adjacent pixels. if (isFirstIntroVideo) { - int32 currentFrame = _decoder->getCurFrame(); + // int32 currentFrame = _decoder->getCurFrame(); if (currentFrame >= 956 && currentFrame <= 1038) { debugC(1, kDebugMovie, "Triggered workaround for glitch in first intro video..."); _vm->_system->copyRectToScreen(frame->getBasePtr(frame->w-188, 123), frame->pitch, frame->w-188, 124, 188, 1); @@ -128,7 +154,17 @@ void Movie::playVideo(bool isFirstIntroVideo) { } } } - _vm->_system->getPaletteManager()->setPalette(_decoder->getPalette(), 0, 256); + + byte palette[768] = {0}; + memcpy(palette, _decoder->getPalette(), 768); + + if (unused) { + palette[3 * unused] = 0xff; + palette[3 * unused + 1] = 0xff; + palette[3 * unused + 2] = 0x0; + } + + _vm->_system->getPaletteManager()->setPalette(palette, 0, 256); _vm->_system->updateScreen(); } diff --git a/engines/toon/movie.h b/engines/toon/movie.h index 54d4fd4dc7..4bbd0a9afb 100644 --- a/engines/toon/movie.h +++ b/engines/toon/movie.h @@ -28,6 +28,8 @@ namespace Toon { +class SubtitleRenderer; + class ToonstruckSmackerDecoder : public Video::SmackerDecoder { public: ToonstruckSmackerDecoder(); @@ -57,6 +59,7 @@ protected: ToonEngine *_vm; ToonstruckSmackerDecoder *_decoder; bool _playing; + SubtitleRenderer *_subtitle; }; } // End of namespace Toon diff --git a/engines/toon/subtitles.cpp b/engines/toon/subtitles.cpp new file mode 100644 index 0000000000..1349778753 --- /dev/null +++ b/engines/toon/subtitles.cpp @@ -0,0 +1,97 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "common/debug.h" +#include "common/rect.h" +#include "common/system.h" + +#include "toon/subtitles.h" + +namespace Toon { +SubtitleRenderer::SubtitleRenderer(ToonEngine *vm) : _vm(vm) { + _subSurface = new Graphics::Surface(); + _subSurface->create(TOON_SCREEN_WIDTH, TOON_SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); + _hasSubtitles = false; +} + +SubtitleRenderer::~SubtitleRenderer() { +} + + +void SubtitleRenderer::render(const Graphics::Surface& frame, uint32 frameNumber, char color) { + if (!_hasSubtitles || _index > _last) { + return; + } + + _subSurface->copyFrom(frame); + // char strf[384] = {0}; + // sprintf(strf, "Time passed: %d", frameNumber); + // _vm->drawCostumeLine(0, 0, strf, _subSurface); + // _vm->_system->copyRectToScreen(_subSurface->getBasePtr(0, 0), _subSurface->pitch, 0, 0, _subSurface->w, _subSurface->h); + + if (frameNumber > _tw[_index].fend) { + _index++; + if (_index > _last) { + return; + } + _currentLine = (char*)_fileData + _tw[_index].foffset; + } + + if (frameNumber < _tw[_index].fstart) { + return; + } + + _vm->drawCustomText(TOON_SCREEN_WIDTH / 2, TOON_SCREEN_HEIGHT, _currentLine, _subSurface, color); + _vm->_system->copyRectToScreen(_subSurface->getBasePtr(0, 0), _subSurface->pitch, 0, 0, _subSurface->w, _subSurface->h); +} + +bool SubtitleRenderer::load(const Common::String &video) { + warning(video.c_str()); + + _hasSubtitles = false; + _index = 0; + + char srtfile[20] = {0}; + strcpy(srtfile, video.c_str()); + int ln = strlen(srtfile); + srtfile[ln - 3] = 't'; + srtfile[ln - 2] = 's'; + srtfile[ln - 1] = 's'; + + uint32 fileSize = 0; + uint8 *fileData = _vm->resources()->getFileData(srtfile, &fileSize); + if (!fileData) { + return false; + } + + uint32 numOflines = *((uint32*) fileData); + uint32 idx_size = numOflines * sizeof(TimeWindow); + memcpy(_tw, sizeof(numOflines) + fileData, idx_size); + _fileData = sizeof(numOflines) + fileData + idx_size; + _last = numOflines - 1; + + _currentLine = (char*)_fileData + _tw[0].foffset; + _hasSubtitles = true; + return _hasSubtitles; +} + +} \ No newline at end of file diff --git a/engines/toon/subtitles.h b/engines/toon/subtitles.h new file mode 100644 index 0000000000..7eb7fe12f0 --- /dev/null +++ b/engines/toon/subtitles.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef TOON_SUBTITLES_H +#define TOON_SUBTITLES_H + +#include "toon/toon.h" +#include "graphics/surface.h" + +namespace Toon { + +typedef struct { + uint32 fstart; + uint32 fend; + uint32 foffset; +} TimeWindow; + +class SubtitleRenderer { +public: + SubtitleRenderer(ToonEngine *vm); + ~SubtitleRenderer(); + + bool load(const Common::String &video); + void render(const Graphics::Surface& frame, uint32 frameNumber, char color); +protected: + ToonEngine *_vm; + Graphics::Surface* _subSurface; + bool _hasSubtitles; + + char* _lines[384]; + TimeWindow _tw[384]; + uint8 *_fileData; + uint16 _index; + uint16 _last; + char* _currentLine; +}; + +} // End of namespace Toon + +#endif \ No newline at end of file diff --git a/engines/toon/toon.cpp b/engines/toon/toon.cpp index 46132a4fd2..4d2578ee59 100644 --- a/engines/toon/toon.cpp +++ b/engines/toon/toon.cpp @@ -3290,7 +3290,18 @@ void ToonEngine::drawConversationLine() { if (_currentTextLine && _showConversationText) { _fontRenderer->setFontColorByCharacter(_currentTextLineCharacterId); _fontRenderer->setFont(_currentFont); - _fontRenderer->renderMultiLineText(_currentTextLineX, _currentTextLineY, _currentTextLine, 0); + _fontRenderer->renderMultiLineText(_currentTextLineX, _currentTextLineY, _currentTextLine, 0, *_mainSurface); + } +} + +void ToonEngine::drawCustomText(int16 x, int16 y, char* line, Graphics::Surface* frame, char color) { + if (line) { + byte col = color; // 0xce + _fontRenderer->setFontColor(0, col, col); + //_fontRenderer->setFontColorByCharacter(_currentTextLineCharacterId); + _gameState->_currentScrollValue = 0; + _fontRenderer->setFont(_currentFont); + _fontRenderer->renderMultiLineText(x, y, line, 0, *frame); } } diff --git a/engines/toon/toon.h b/engines/toon/toon.h index efb473fef8..cbabaff129 100644 --- a/engines/toon/toon.h +++ b/engines/toon/toon.h @@ -33,6 +33,7 @@ #include "toon/state.h" #include "toon/picture.h" #include "toon/anim.h" +#include "toon/subtitles.h" #include "toon/movie.h" #include "toon/font.h" #include "toon/text.h" @@ -212,6 +213,8 @@ public: void waitForScriptStep(); void doMagnifierEffect(); + void drawCustomText(int16 x, int16 y, char* line, Graphics::Surface* frame, char color); + bool canSaveGameStateCurrently(); bool canLoadGameStateCurrently(); void pauseEngineIntern(bool pause); -- cgit v1.2.3