diff options
Diffstat (limited to 'engines')
-rw-r--r-- | engines/zvision/module.mk | 1 | ||||
-rw-r--r-- | engines/zvision/string_manager.cpp | 235 | ||||
-rw-r--r-- | engines/zvision/string_manager.h | 84 |
3 files changed, 320 insertions, 0 deletions
diff --git a/engines/zvision/module.mk b/engines/zvision/module.mk index 9fa119d353..cb4a3609e9 100644 --- a/engines/zvision/module.mk +++ b/engines/zvision/module.mk @@ -22,6 +22,7 @@ MODULE_OBJS := \ script_manager.o \ scripts.o \ single_value_container.o \ + string_manager.o \ timer_node.o \ truetype_font.o \ utility.o \ diff --git a/engines/zvision/string_manager.cpp b/engines/zvision/string_manager.cpp new file mode 100644 index 0000000000..818b60c732 --- /dev/null +++ b/engines/zvision/string_manager.cpp @@ -0,0 +1,235 @@ +/* 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/scummsys.h" + +#include "common/file.h" +#include "common/tokenizer.h" +#include "common/debug.h" + +#include "graphics/fontman.h" + +#include "zvision/string_manager.h" +#include "zvision/truetype_font.h" + + +namespace ZVision { + +const Graphics::PixelFormat StringManager::_pixelFormat565 = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0); + +StringManager::StringManager(ZVision *engine) + : _engine(engine) { +} + +StringManager::~StringManager() { + for (Common::HashMap<Common::String, TruetypeFont *>::iterator iter = _fonts.begin(); iter != _fonts.end(); iter++) { + delete (*iter)._value; + } +} + +void StringManager::initialize(ZVisionGameId gameId) { + if (gameId == ZorkNemesis) { + // TODO: Check this hardcoded filename against all versions of Nemesis + parseStrFile("nemesis.str"); + } else if (gameId == ZorkGrandInquisitor) { + // TODO: Check this hardcoded filename against all versions of Grand Inquisitor + parseStrFile("inquis.str"); + } +} + +void StringManager::parseStrFile(const Common::String &fileName) { + Common::File file; + if (!file.open(fileName)) { + warning("%s does not exist. String parsing failed", fileName.c_str()); + return; + } + + Common::String line = file.readLine(); + + uint lineNumber = 0; + while (!file.eos()) { + Common::String asciiLine = wideToASCII(line.c_str(), line.size()); + + char tagString[150]; + uint tagStringCursor = 0; + char textString[150]; + uint textStringCursor = 0; + bool inTag = false; + + for (uint i = 0; i < asciiLine.size(); i++) { + switch (asciiLine[i]) { + case '<': + inTag = true; + break; + case '>': + inTag = false; + parseTag(Common::String(tagString, tagStringCursor), Common::String(textString, textStringCursor), i); + tagStringCursor = 0; + textStringCursor = 0; + break; + default: + if (inTag) { + textString[tagStringCursor] = asciiLine[i]; + tagStringCursor++; + } else { + textString[textStringCursor] = asciiLine[i]; + textStringCursor++; + } + break; + } + } + + // STR files add a null character after the CR/LF. We need to skip over that before we can read another line + file.readByte(); + + line = file.readLine(); + lineNumber++; + } +} + +void StringManager::parseTag(const Common::String &tagString, const Common::String &textString, uint lineNumber) { + Common::StringTokenizer tokenizer(tagString); + + Common::String token = tokenizer.nextToken(); + + Common::String fontName; + bool bold = false; + Graphics::TextAlign align = Graphics::kTextAlignLeft; + int point = 12; + int red = 0; + int green = 0; + int blue = 0; + + while (!token.empty()) { + if (token.matchString("font", true)) { + fontName = tokenizer.nextToken(); + } else if (token.matchString("bold", true)) { + token = tokenizer.nextToken(); + if (token.matchString("on", false)) { + bold = true; + } + } else if (token.matchString("justify", true)) { + token = tokenizer.nextToken(); + if (token.matchString("center", false)) { + align = Graphics::kTextAlignCenter; + } else if (token.matchString("right", false)) { + align = Graphics::kTextAlignRight; + } + } else if (token.matchString("point", true)) { + point = atoi(tokenizer.nextToken().c_str()); + } else if (token.matchString("red", true)) { + red = atoi(tokenizer.nextToken().c_str()); + } else if (token.matchString("green", true)) { + green = atoi(tokenizer.nextToken().c_str()); + } else if (token.matchString("blue", true)) { + blue = atoi(tokenizer.nextToken().c_str()); + } + + token = tokenizer.nextToken(); + } + + Common::String newFontName; + if (fontName.matchString("times new roman", true)) { + if (bold) { + newFontName = "timesbd.ttf"; + } else { + newFontName = "times.ttf"; + } + } else if (fontName.matchString("courier new", true)) { + if (bold) { + newFontName = "courbd.ttf"; + } else { + newFontName = "cour.ttf"; + } + } else if (fontName.matchString("century schoolbook", true)) { + if (bold) { + newFontName = "censcbkbd.ttf"; + } else { + newFontName = "censcbk.ttf"; + } + } else if (fontName.matchString("times new roman", true)) { + if (bold) { + newFontName = "courbd.ttf"; + } else { + newFontName = "cour.ttf"; + } + } else { + debug("Could not identify font: %s. Reverting to Arial", fontName.c_str()); + if (bold) { + newFontName = "zorknorm.ttf"; + } else { + newFontName = "arial.ttf"; + } + } + + // Push an empty TextFragment onto the end of the list + // Creating the TextFragement before filling it prevents extra data copying during creation + _inGameText->fragments.push_back(TextFragment()); + TextFragment *fragment = &_inGameText->fragments.back(); + + Common::String fontKey = Common::String::format("%s-&d", newFontName.c_str(), point); + if (_fonts.contains(fontKey)) { + fragment->style.font = _fonts[fontKey]; + } else { + fragment->style.font = new TruetypeFont(_engine, point); + fragment->style.font->loadFile(newFontName); + } + + fragment->style.align = align; + fragment->style.color = _pixelFormat565.ARGBToColor(0, red, green, blue); + fragment->text = textString; +} + +Common::String StringManager::wideToASCII(const char *wideStr, uint arrayLength) { + // TODO: Contemplate using a largish static buffer instead of a dynamic heap buffer + uint newSize = arrayLength / 2; + char *asciiString = new char[newSize]; + + // Don't spam the user with warnings about UTF-16 support. + // Just do one warning per String + bool charOverflowWarning = false; + // Crush each octet pair to a single octet with a simple cast + for (uint i = 0; i < newSize; i++) { + uint16 value = READ_LE_UINT16(wideStr + (i * 2)); + if (value > 255) { + charOverflowWarning = true; + value = 255; + } + asciiString[i] = (char)value; + } + + if (charOverflowWarning) { + warning("UTF-16 is not supported. Characters greater than 255 are clamped to 255"); + } + + Common::String returnString(asciiString, newSize); + // Cleanup. Common::String constructor does a memmove() internally so we can safely delete + delete[] asciiString; + + return returnString; +} + +StringManager::TextStyle StringManager::getTextStyle(uint stringNumber) { + return _inGameText[stringNumber].fragments.front().style; +} + +} // End of namespace ZVision diff --git a/engines/zvision/string_manager.h b/engines/zvision/string_manager.h new file mode 100644 index 0000000000..a9d2dc1a1d --- /dev/null +++ b/engines/zvision/string_manager.h @@ -0,0 +1,84 @@ +/* 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 ZVISION_STRING_MANAGER_H +#define ZVISION_STRING_MANAGER_H + +#include "common/types.h" + +#include "zvision/detection.h" +#include "zvision/truetype_font.h" + + +namespace Graphics { +class FontManager; +} + +namespace ZVision { + +class ZVision; + +class StringManager { +public: + StringManager(ZVision *engine); + ~StringManager(); + +public: + struct TextStyle { + TruetypeFont *font; + uint16 color; // In RBG 565 + Graphics::TextAlign align; + }; + + struct TextFragment { + TextStyle style; + Common::String text; + }; + +private: + struct InGameText { + Common::List<TextFragment> fragments; + }; + +private: + ZVision *_engine; + // NOTE: We hardcode this number because we know ZNem uses 42 strings and ZGI uses 56 + InGameText _inGameText[56]; + Common::HashMap<Common::String, TruetypeFont *> _fonts; + + static const Graphics::PixelFormat _pixelFormat565; + +public: + void initialize(ZVisionGameId gameId); + StringManager::TextStyle getTextStyle(uint stringNumber); + +private: + void parseStrFile(const Common::String &fileName); + void parseTag(const Common::String &tagString, const Common::String &textString, uint lineNumber); + + static Common::String wideToASCII(const char *wideStr, uint arrayLength); +}; + +} // End of namespace ZVision + +#endif |