mirror of
https://github.com/libretro/scummvm.git
synced 2025-01-27 13:42:02 +00:00
555afa8136
Iconv is used to convert from CP 932 to Unicode. Since iconv support is not yet included in ResidualVM, this does not work properly, but at least it does not crash anymore. The game does not provide the TTF font required to render the Japanese characters. The user must provide a font named "msgothic.ttf".
255 lines
6.8 KiB
C++
255 lines
6.8 KiB
C++
/* ResidualVM - A 3D game interpreter
|
|
*
|
|
* ResidualVM is the legal property of its developers, whose names
|
|
* are too numerous to list here. Please refer to the AUTHORS
|
|
* 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 "engines/myst3/subtitles.h"
|
|
#include "engines/myst3/myst3.h"
|
|
#include "engines/myst3/state.h"
|
|
|
|
#ifdef USE_ICONV
|
|
#include "common/iconv.h"
|
|
#endif
|
|
|
|
#include "graphics/fontman.h"
|
|
#include "graphics/font.h"
|
|
#include "graphics/fonts/ttf.h"
|
|
|
|
namespace Myst3 {
|
|
|
|
Subtitles *Subtitles::create(Myst3Engine *vm, uint32 id) {
|
|
Subtitles *s = new Subtitles(vm);
|
|
|
|
s->loadFontSettings(1100);
|
|
|
|
if (!s->loadSubtitles(id)) {
|
|
delete s;
|
|
return 0;
|
|
}
|
|
|
|
s->loadFont();
|
|
s->createTexture();
|
|
|
|
return s;
|
|
}
|
|
|
|
Subtitles::Subtitles(Myst3Engine *vm) :
|
|
_vm(vm),
|
|
_surface(0),
|
|
_texture(0),
|
|
_frame(-1),
|
|
_font(0) {
|
|
}
|
|
|
|
Subtitles::~Subtitles() {
|
|
if (_surface) {
|
|
_surface->free();
|
|
delete _surface;
|
|
}
|
|
if (_texture) {
|
|
_vm->_gfx->freeTexture(_texture);
|
|
}
|
|
|
|
delete _font;
|
|
}
|
|
|
|
void Subtitles::loadFontSettings(int32 id) {
|
|
// Load font settings
|
|
const DirectorySubEntry *fontNums = _vm->getFileDescription("NUMB", id, 0, DirectorySubEntry::kNumMetadata);
|
|
|
|
if (!fontNums)
|
|
error("Unable to load font settings values");
|
|
|
|
_fontSize = fontNums->getMiscData(0);
|
|
_fontBold = fontNums->getMiscData(1);
|
|
_surfaceHeight = fontNums->getMiscData(2);
|
|
_singleLineTop = fontNums->getMiscData(3);
|
|
_line1Top = fontNums->getMiscData(4);
|
|
_line2Top = fontNums->getMiscData(5);
|
|
_surfaceTop = fontNums->getMiscData(6) + Renderer::kTopBorderHeight + Renderer::kFrameHeight;
|
|
_fontCharsetCode = fontNums->getMiscData(7);
|
|
|
|
// We draw the subtitles in the adequate resolution so that they are not
|
|
// scaled up. This is the scale factor of the current resolution
|
|
// compared to the original
|
|
Common::Rect screen = _vm->_gfx->viewport();
|
|
_scale = screen.width() / Renderer::kOriginalWidth;
|
|
|
|
const DirectorySubEntry *fontText = _vm->getFileDescription("TEXT", id, 0, DirectorySubEntry::kTextMetadata);
|
|
|
|
if (!fontText)
|
|
error("Unable to load font face");
|
|
|
|
_fontFace = fontText->getTextData(0);
|
|
|
|
if (_fontCharsetCode == 0) {
|
|
// No game-provided charset for the Japanese version
|
|
const DirectorySubEntry *fontCharset = _vm->getFileDescription("CHAR", id, 0, DirectorySubEntry::kRawData);
|
|
|
|
if (!fontCharset)
|
|
error("Unable to load font charset");
|
|
|
|
Common::MemoryReadStream *data = fontCharset->getData();
|
|
data->read(_charset, sizeof(_charset));
|
|
delete data;
|
|
}
|
|
}
|
|
|
|
void Subtitles::loadFont() {
|
|
#ifdef USE_FREETYPE2
|
|
Common::String ttfFile;
|
|
if (_fontFace == "Arial Narrow") {
|
|
// Use the TTF font provided by the game if TTF support is available
|
|
ttfFile = "arir67w.ttf";
|
|
} else if (_fontFace == "MS Gothic") {
|
|
// The Japanese font has to be supplied by the user
|
|
ttfFile = "msgothic.ttf";
|
|
} else {
|
|
error("Unknown subtitles font face '%s'", _fontFace.c_str());
|
|
}
|
|
|
|
Common::SeekableReadStream *s = SearchMan.createReadStreamForMember(ttfFile);
|
|
if (s) {
|
|
_font = Graphics::loadTTFFont(*s, _fontSize * _scale);
|
|
delete s;
|
|
} else {
|
|
warning("Unable to load the subtitles font '%s'", ttfFile.c_str());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
bool Subtitles::loadSubtitles(int32 id) {
|
|
// Subtitles may be overridden using a variable
|
|
const DirectorySubEntry *desc;
|
|
if (_vm->_state->getMovieOverrideSubtitles()) {
|
|
id = _vm->_state->getMovieOverrideSubtitles();
|
|
_vm->_state->setMovieOverrideSubtitles(0);
|
|
|
|
desc = _vm->getFileDescription("IMGR", 100000 + id, 0, DirectorySubEntry::kText);
|
|
} else {
|
|
desc = _vm->getFileDescription(0, 100000 + id, 0, DirectorySubEntry::kText);
|
|
}
|
|
|
|
if (!desc)
|
|
return false;
|
|
|
|
Common::MemoryReadStream *crypted = desc->getData();
|
|
|
|
// Read the frames and associated text offsets
|
|
while (true) {
|
|
Phrase s;
|
|
s.frame = crypted->readUint32LE();
|
|
s.offset = crypted->readUint32LE();
|
|
|
|
if (!s.frame)
|
|
break;
|
|
|
|
_phrases.push_back(s);
|
|
}
|
|
|
|
// Read and decrypt the frames subtitles
|
|
for (uint i = 0; i < _phrases.size(); i++) {
|
|
crypted->seek(_phrases[i].offset);
|
|
|
|
uint8 key = 35;
|
|
while (true) {
|
|
uint8 c = crypted->readByte() ^ key++;
|
|
|
|
if (c >= 32 && _fontCharsetCode == 0)
|
|
c = _charset[c - 32];
|
|
|
|
if (!c)
|
|
break;
|
|
|
|
_phrases[i].string += c;
|
|
}
|
|
}
|
|
|
|
delete crypted;
|
|
|
|
return true;
|
|
}
|
|
|
|
void Subtitles::createTexture() {
|
|
// Create a surface to draw the subtitles on
|
|
// Use RGB 565 to allow use of BDF fonts
|
|
_surface = new Graphics::Surface();
|
|
_surface->create(Renderer::kOriginalWidth * _scale, _surfaceHeight * _scale, Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0));
|
|
|
|
_texture = _vm->_gfx->createTexture(_surface);
|
|
}
|
|
|
|
void Subtitles::setFrame(int32 frame) {
|
|
const Phrase *phrase = 0;
|
|
|
|
for (uint i = 0; i < _phrases.size(); i++) {
|
|
if (_phrases[i].frame > frame)
|
|
break;
|
|
|
|
phrase = &_phrases[i];
|
|
}
|
|
|
|
if (phrase == 0
|
|
|| phrase->frame == _frame)
|
|
return;
|
|
|
|
_frame = phrase->frame;
|
|
|
|
|
|
const Graphics::Font *font;
|
|
if (_font)
|
|
font = _font;
|
|
else
|
|
font = FontMan.getFontByUsage(Graphics::FontManager::kLocalizedFont);
|
|
|
|
if (!font)
|
|
error("No available font");
|
|
|
|
// Draw the new text
|
|
memset(_surface->getPixels(), 0, _surface->pitch * _surface->h);
|
|
|
|
if (_fontCharsetCode == 0) {
|
|
font->drawString(_surface, phrase->string, 0, _singleLineTop * _scale, _surface->w, 0xFFFFFFFF, Graphics::kTextAlignCenter);
|
|
} else if (_fontCharsetCode == 1) {
|
|
// The Japanese subtitles are encoded in CP 932 / Shift JIS
|
|
#ifdef USE_ICONV
|
|
Common::U32String unicode = Common::convertToU32String("cp932", phrase->string);
|
|
font->drawString(_surface, unicode, 0, _singleLineTop * _scale, _surface->w, 0xFFFFFFFF, Graphics::kTextAlignCenter);
|
|
#else
|
|
warning("Unable to display Japanese subtitles, iconv support is not compiled in.");
|
|
#endif
|
|
} else {
|
|
error("Unknown font charset code '%d', fontface '%s'", _fontCharsetCode, _fontFace.c_str());
|
|
}
|
|
|
|
// Update the texture
|
|
_texture->update(_surface);
|
|
}
|
|
|
|
void Subtitles::drawOverlay() {
|
|
Common::Rect textureRect = Common::Rect(_texture->width, _texture->height);
|
|
Common::Rect bottomBorder = Common::Rect(Renderer::kOriginalWidth, _surfaceHeight);
|
|
bottomBorder.translate(0, _surfaceTop);
|
|
|
|
_vm->_gfx->drawTexturedRect2D(bottomBorder, textureRect, _texture);
|
|
}
|
|
|
|
} // End of namespace Myst3
|