Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,383 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima.h"
#include "ultima/ultima8/misc/debugger.h"
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/font.h"
namespace Ultima {
namespace Ultima8 {
Font::Font() : _highRes(false) {
}
Font::~Font() {
}
void Font::getTextSize(const Std::string &text,
int32 &resultwidth, int32 &resultheight,
unsigned int &remaining,
int32 width, int32 height, TextAlign align,
bool u8specials, bool pagebreaks) {
Std::list<PositionedText> tmp;
tmp = typesetText<Traits>(this, text, remaining,
width, height, align, u8specials, pagebreaks,
resultwidth, resultheight);
}
//static
bool Font::Traits::canBreakAfter(Std::string::const_iterator &i) {
// It's not really relevant what we do here, because this probably will
// not be used at normal font sizes.
return true;
}
//static
bool Font::SJISTraits::canBreakAfter(Std::string::const_iterator &i) {
Std::string::const_iterator j = i;
uint32 u1 = unicode(j);
// See: https://wiki.wesnoth.org/index.php?title=JapaneseTranslation&oldid=23480#Word-Wrapping
// and: https://ja.wikipedia.org/wiki/%E7%A6%81%E5%89%87
switch (u1) {
case 0xff08:
case 0x3014:
case 0xff3b:
case 0xff5b:
case 0x3008:
case 0x300a:
case 0x300c:
case 0x300e:
case 0x3010:
case 0x2018:
case 0x201c:
return false;
default:
break;
}
uint32 u2 = unicode(j);
switch (u2) {
case 0x3001:
case 0x3002:
case 0xff0c:
case 0xff0e:
case 0xff09:
case 0x3015:
case 0xff3d:
case 0xff5d:
case 0x3009:
case 0x300b:
case 0x300d:
case 0x300f:
case 0x3011:
case 0x2019:
case 0x201d:
case 0x309d:
case 0x309e:
case 0x30fd:
case 0x30fe:
case 0x3005:
case 0xff1f:
case 0xff01:
case 0xff1a:
case 0xff1b:
case 0x3041:
case 0x3043:
case 0x3045:
case 0x3047:
case 0x3049:
case 0x3083:
case 0x3085:
case 0x3087:
case 0x308e:
case 0x30a1:
case 0x30a3:
case 0x30a5:
case 0x30a7:
case 0x30a9:
case 0x30e3:
case 0x30e5:
case 0x30e7:
case 0x30ee:
case 0x3063:
case 0x30f5:
case 0x30c3:
case 0x30f6:
case 0x30fb:
case 0x2026:
case 0x30fc:
return false;
default:
break;
}
// Also don't allow breaking between roman characters
if (((u1 >= 'A' && u1 <= 'Z') || (u1 >= 'a' && u1 <= 'z')) &&
((u2 >= 'A' && u2 <= 'Z') || (u2 >= 'a' && u2 <= 'z'))) {
return false;
}
return true;
}
template<class T>
static void findWordEnd(const Std::string &text,
Std::string::const_iterator &iter, bool u8specials) {
while (iter != text.end()) {
if (T::isSpace(iter, u8specials)) return;
T::advance(iter);
}
}
template<class T>
static void passSpace(const Std::string &text,
Std::string::const_iterator &iter, bool u8specials) {
while (iter != text.end()) {
if (!T::isSpace(iter, u8specials)) return;
T::advance(iter);
}
return;
}
/*
Special characters in U8:
@ = bullet for conversation options
~ = line break
% = tab
* = line break on graves and plaques, possibly page break in books
CHECKME: any others? (page breaks for books?)
*/
template<class T>
Std::list<PositionedText> typesetText(Font *font,
const Std::string &text, unsigned int &remaining, int32 width, int32 height,
Font::TextAlign align, bool u8specials, bool pagebreaks, int32 &resultwidth,
int32 &resultheight, Std::string::size_type cursor) {
debugC(kDebugGraphics, "typeset (%d, %d) %s", width, height, text.c_str());
// be optimistic and assume everything will fit
remaining = text.size();
Std::string curline;
int totalwidth = 0;
int totalheight = 0;
Std::list<PositionedText> lines;
PositionedText line;
Std::string::const_iterator iter = text.begin();
Std::string::const_iterator cursoriter = text.begin();
if (cursor != Std::string::npos) cursoriter += cursor;
Std::string::const_iterator curlinestart = text.begin();
bool breakhere = false;
while (true) {
if (iter == text.end() || breakhere || T::isBreak(iter, u8specials)) {
// break here
bool atpagebreak = pagebreaks && T::isPageBreak(iter, u8specials);
int32 stringwidth = 0, stringheight = 0;
font->getStringSize(curline, stringwidth, stringheight);
line._dims.left = 0;
line._dims.top = totalheight;
line._dims.setWidth(stringwidth);
line._dims.setHeight(stringheight);
line._text = curline;
line._cursor = Std::string::npos;
if (cursor != Std::string::npos && cursoriter >= curlinestart &&
(cursoriter < iter || (!breakhere && cursoriter == iter))) {
line._cursor = cursoriter - curlinestart;
if (line._dims.width() == 0) {
stringwidth = 2;
line._dims.setWidth(stringwidth);
}
}
lines.push_back(line);
if (stringwidth > totalwidth) totalwidth = stringwidth;
totalheight += font->getBaselineSkip();
curline = "";
if (iter == text.end())
break; // done
if (breakhere) {
breakhere = false;
curlinestart = iter;
} else {
T::advance(iter);
curlinestart = iter;
}
if (atpagebreak || (height != 0 && totalheight + font->getHeight() > height)) {
// next line won't fit
remaining = curlinestart - text.begin();
break;
}
} else {
// see if next word still fits on the current line
Std::string::const_iterator nextword = iter;
passSpace<T>(text, nextword, u8specials);
// process spaces
bool foundLF = false;
Std::string spaces;
for (; iter < nextword; T::advance(iter)) {
if (T::isBreak(iter, u8specials)) {
foundLF = true;
break;
} else if (T::isTab(iter, u8specials)) {
// ignore tabs at beginning of line when centered
if (!(curline.empty() && align == Font::TEXT_CENTER))
spaces.append(" ");
} else if (!curline.empty()) {
spaces.append(" ");
}
}
// no next word?
if (foundLF || nextword == text.end()) continue;
// process word
Std::string::const_iterator endofnextword = iter;
findWordEnd<T>(text, endofnextword, u8specials);
int32 stringwidth = 0, stringheight = 0;
Std::string newline = curline + spaces +
text.substr(nextword - text.begin(), endofnextword - nextword);
font->getStringSize(newline, stringwidth, stringheight);
// if not, break line before this word
if (width != 0 && stringwidth > width) {
if (!curline.empty()) {
iter = nextword;
} else {
// word is longer than the line; have to break in mid-word
// FIXME: this is rather inefficient; binary search?
// FIXME: clean up...
iter = nextword;
Std::string::const_iterator saveiter = nextword; // Dummy initialization
Std::string::const_iterator saveiter_fail;
Std::string curline_fail;
newline = spaces;
bool breakok = true;
int breakcount = -1;
do {
if (breakok) {
curline = newline;
saveiter = iter;
breakcount++;
}
curline_fail = newline;
saveiter_fail = iter;
if (iter == text.end()) break;
breakok = T::canBreakAfter(iter);
// try next character
T::advance(iter);
newline = spaces + text.substr(nextword - text.begin(),
iter - nextword);
font->getStringSize(newline, stringwidth, stringheight);
} while (stringwidth <= width);
if (breakcount > 0) {
iter = saveiter;
} else {
iter = saveiter_fail;
curline = curline_fail;
}
}
breakhere = true;
continue;
} else {
// copy next word into curline
curline = newline;
iter = endofnextword;
}
}
}
if (lines.size() == 1 && align == Font::TEXT_LEFT) {
// only one line, so use the actual text width
width = totalwidth;
}
if (width != 0) totalwidth = width;
// adjust total height
totalheight -= font->getBaselineSkip();
totalheight += font->getHeight();
// fixup x coordinates of lines
for (auto &l : lines) {
switch (align) {
case Font::TEXT_LEFT:
break;
case Font::TEXT_RIGHT:
l._dims.moveTo(totalwidth - l._dims.width(), l._dims.top);
break;
case Font::TEXT_CENTER:
l._dims.moveTo((totalwidth - l._dims.width()) / 2, l._dims.top);
break;
}
debugC(kDebugGraphics, "%d, %d, %d, %d: %s", l._dims.left, l._dims.top,
l._dims.width(), l._dims.height(), l._text.c_str());
}
resultwidth = totalwidth;
resultheight = totalheight;
return lines;
}
// explicit instantiations
template
Std::list<PositionedText> typesetText<Font::Traits>
(Font *font, const Std::string &text,
unsigned int &remaining, int32 width, int32 height,
Font::TextAlign align, bool u8specials, bool pagebreaks,
int32 &resultwidth, int32 &resultheight, Std::string::size_type cursor);
template
Std::list<PositionedText> typesetText<Font::SJISTraits>
(Font *font, const Std::string &text,
unsigned int &remaining, int32 width, int32 height,
Font::TextAlign align, bool u8specials, bool pagebreaks,
int32 &resultwidth, int32 &resultheight, Std::string::size_type cursor);
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,180 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_FONT_H
#define ULTIMA8_GFX_FONTS_FONT_H
#include "common/rect.h"
#include "ultima/shared/std/containers.h"
#include "ultima/shared/std/string.h"
#include "ultima/ultima8/misc/encoding.h"
namespace Ultima {
namespace Ultima8 {
class RenderedText;
struct PositionedText {
Std::string _text;
Common::Rect32 _dims;
Std::string::size_type _cursor;
};
class Font {
public:
Font();
virtual ~Font();
enum TextAlign {
TEXT_LEFT,
TEXT_CENTER,
TEXT_RIGHT
};
//! get the height of the font
virtual int getHeight() = 0;
//! get the baseline of the font (relative from the top)
virtual int getBaseline() = 0;
//! get the baselineskip of the font (distance between two baselines)
virtual int getBaselineSkip() = 0;
//! get the dimensions of a string (not containing any newlines)
//! \param text The string
//! \param width Returns the width
//! \param height Returns the height
virtual void getStringSize(const Std::string &text,
int32 &width, int32 &height) = 0;
//! render a string
//! \param text The text
//! \param remaining Returns index of the first character not printed
//! \param width The width of the target rectangle, or 0 for unlimited
//! \param height The height of the target rectangle, or 0 for unlimited
//! \param align Alignment of the text (left, right, center)
//! \param u8specials If true, interpret the special characters U8 uses
//! \param pagebreaks If true (and u8specials too), stop at U8 pagebreaks
//! \return the rendered text in a RenderedText object
virtual RenderedText *renderText(const Std::string &text,
unsigned int &remaining, int32 width = 0, int32 height = 0,
TextAlign align = TEXT_LEFT, bool u8specials = false,
bool pagebreaks = false,
Std::string::size_type cursor = Std::string::npos) = 0;
//! get the dimensions of a rendered string
//! \param text The text
//! \param resultwidth Returns the resulting width
//! \param resultheight Returns the resulting height
//! \param remaining Returns index of the first character not printed
//! \param width The width of the target rectangle, or 0 for unlimited
//! \param height The height of the target rectangle, or 0 for unlimited
//! \param align Alignment of the text (left, right, center)
//! \param u8specials If true, interpret the special characters U8 uses
//! \param pagebreaks If true (and u8specials too), stop at U8 pagebreaks
virtual void getTextSize(const Std::string &text,
int32 &resultwidth, int32 &resultheight, unsigned int &remaining,
int32 width = 0, int32 height = 0, TextAlign align = TEXT_LEFT,
bool u8specials = false, bool pagebreaks = false);
void setHighRes(bool hr) {
_highRes = hr;
}
bool isHighRes() const {
return _highRes;
}
protected:
bool _highRes;
struct Traits {
static bool isSpace(Std::string::const_iterator &i, bool u8specials) {
char c = *i;
return (c == ' ' || c == '\t' || c == '\n' || c == '\r' ||
(u8specials && (c == '%' || c == '~' || c == '*' || c == '^')));
}
static bool isTab(Std::string::const_iterator &i, bool u8specials) {
char c = *i;
return (c == '\t' ||
(u8specials && (c == '\t' || c == '%')));
}
static bool isBreak(Std::string::const_iterator &i, bool u8specials) {
char c = *i;
return (c == '\n' ||
(u8specials && (c == '\n' || c == '~' || c == '*')));
}
static bool isPageBreak(Std::string::const_iterator &i, bool u8specials) {
char c = *i;
return (u8specials && c == '*');
}
static bool canBreakAfter(Std::string::const_iterator &i);
static void advance(Std::string::const_iterator &i) {
++i;
}
static Std::string::size_type length(const Std::string &t) {
return t.size();
}
static uint32 unicode(Std::string::const_iterator &i) {
return encoding[static_cast<uint8>(*i++)];
}
};
struct SJISTraits : public Traits {
static bool canBreakAfter(Std::string::const_iterator &i);
static void advance(Std::string::const_iterator &i) {
// FIXME: this can advance past the end of a malformed string
uint8 c = *i;
i++;
if (c >= 0x80) i++;
}
static Std::string::size_type length(const Std::string &t) {
Std::string::size_type l = 0;
Std::string::const_iterator iter = t.begin();
while (iter != t.end()) {
advance(iter);
l++;
}
return l;
}
static uint32 unicode(Std::string::const_iterator &i) {
uint16 s = static_cast<uint8>(*i);
i++;
if (s >= 0x80) {
uint16 t = static_cast<uint8>(*i++);
s |= (t << 8);
}
return shiftjis_to_unicode(s);
}
};
};
template<class T>
Std::list<PositionedText> typesetText(Font *font,
const Std::string &text, unsigned int &remaining,
int32 width, int32 height, Font::TextAlign align,
bool u8specials, bool pagebreaks,
int32 &resultwidth, int32 &resultheight,
Std::string::size_type cursor = Std::string::npos);
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,212 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "common/config-manager.h"
#include "common/file.h"
#include "ultima/ultima.h"
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/font_manager.h"
#include "ultima/ultima8/games/game_data.h"
#include "ultima/ultima8/gfx/fonts/shape_font.h"
#include "ultima/ultima8/gfx/fonts/font_shape_archive.h"
#include "ultima/ultima8/gfx/fonts/tt_font.h"
#include "ultima/ultima8/gfx/fonts/jp_font.h"
#include "ultima/ultima8/gfx/palette.h"
#include "ultima/ultima8/gfx/palette_manager.h"
#include "graphics/fonts/ttf.h"
namespace Ultima {
namespace Ultima8 {
FontManager *FontManager::_fontManager = nullptr;
FontManager::FontManager() {
debug(1, "Creating Font Manager...");
_fontManager = this;
ConfMan.registerDefault("font_highres", true);
}
FontManager::~FontManager() {
debug(1, "Destroying Font Manager...");
resetGameFonts();
assert(_fontManager == this);
_fontManager = nullptr;
}
// Reset the font manager
void FontManager::resetGameFonts() {
for (unsigned int i = 0; i < _overrides.size(); ++i)
delete _overrides[i];
_overrides.clear();
for (unsigned int i = 0; i < _ttFonts.size(); ++i)
delete _ttFonts[i];
_ttFonts.clear();
for (auto &i : _ttfFonts)
delete i._value;
_ttfFonts.clear();}
Font *FontManager::getGameFont(unsigned int fontnum,
bool allowOverride) {
if (allowOverride && fontnum < _overrides.size() && _overrides[fontnum])
return _overrides[fontnum];
return GameData::get_instance()->getFonts()->getFont(fontnum);
}
Font *FontManager::getTTFont(unsigned int fontnum) {
if (fontnum >= _ttFonts.size())
return nullptr;
return _ttFonts[fontnum];
}
Graphics::Font *FontManager::getTTF_Font(const Common::Path &filename, int pointsize, bool antialiasing) {
#ifdef USE_FREETYPE2
TTFId id;
id._filename = filename;
id._pointSize = pointsize;
TTFFonts::iterator iter;
iter = _ttfFonts.find(id);
if (iter != _ttfFonts.end())
return iter->_value;
Common::File* fontids = new Common::File();
if (!fontids->open(filename)) {
warning("Failed to open TTF: %s", filename.toString().c_str());
delete fontids;
return nullptr;
}
// open font using ScummVM TTF API
// Note: The RWops and ReadStream will be deleted by the TTF_Font
Graphics::TTFRenderMode mode = antialiasing ? Graphics::kTTFRenderModeNormal : Graphics::kTTFRenderModeMonochrome;
Graphics::Font *font = Graphics::loadTTFFont(fontids, DisposeAfterUse::YES, pointsize, Graphics::kTTFSizeModeCharacter, 0, 0, mode, 0, false);
if (!font) {
warning("Failed to open TTF: %s", filename.toString().c_str());
delete fontids;
return nullptr;
}
_ttfFonts[id] = font;
debugC(kDebugGraphics, "Opened TTF: %s.", filename.toString().c_str());
return font;
#else // !USE_FREETYPE2
return nullptr;
#endif
}
void FontManager::setOverride(unsigned int fontnum, Font *newFont) {
if (fontnum >= _overrides.size())
_overrides.resize(fontnum + 1);
if (_overrides[fontnum])
delete _overrides[fontnum];
_overrides[fontnum] = newFont;
}
bool FontManager::addTTFOverride(unsigned int fontnum, const Common::Path &filename,
int pointsize, uint32 rgb, int bordersize,
bool SJIS) {
bool antialiasing = ConfMan.getBool("font_antialiasing");
Graphics::Font *f = getTTF_Font(filename, pointsize, antialiasing);
if (!f)
return false;
TTFont *font = new TTFont(f, rgb, bordersize, antialiasing, SJIS);
bool highres = ConfMan.getBool("font_highres");
font->setHighRes(highres);
setOverride(fontnum, font);
debugC(kDebugGraphics, "Added TTF override for font %u", fontnum);
return true;
}
bool FontManager::addJPOverride(unsigned int fontnum,
unsigned int jpfont, uint32 rgb) {
ShapeFont *jf = dynamic_cast<ShapeFont *>(GameData::get_instance()->getFonts()->getFont(jpfont));
if (!jf)
return false;
JPFont *font = new JPFont(jf, fontnum);
setOverride(fontnum, font);
PaletteManager *palman = PaletteManager::get_instance();
PaletteManager::PalIndex fontpal = static_cast<PaletteManager::PalIndex>
(PaletteManager::Pal_JPFontStart + fontnum);
palman->duplicate(PaletteManager::Pal_Game, fontpal);
Palette *pal = palman->getPalette(fontpal);
// TODO: maybe a small gradient
// the main text uses index 3
// indices 1,2 and 3 are in use for the bullets for conversation options
for (int i = 1; i < 4; ++i) {
pal->set(i, (rgb >> 16) & 0xFF, (rgb >> 8) & 0xFF, (rgb) & 0xFF);
}
palman->updatedPalette(fontpal);
debugC(kDebugGraphics, "Added JP override for font %u", fontnum);
return true;
}
bool FontManager::loadTTFont(unsigned int fontnum, const Common::Path &filename,
int pointsize, uint32 rgb, int bordersize) {
bool antialiasing = ConfMan.getBool("font_antialiasing");
Graphics::Font *f = getTTF_Font(filename, pointsize, antialiasing);
if (!f)
return false;
TTFont *font = new TTFont(f, rgb, bordersize, antialiasing, false);
// TODO: check if this is indeed what we want for non-gamefonts
bool highres = ConfMan.getBool("font_highres");
font->setHighRes(highres);
if (fontnum >= _ttFonts.size())
_ttFonts.resize(fontnum + 1);
if (_ttFonts[fontnum])
delete _ttFonts[fontnum];
_ttFonts[fontnum] = font;
return true;
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,126 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_FONTMANAGER_H
#define ULTIMA8_GFX_FONTS_FONTMANAGER_H
#include "ultima/shared/std/containers.h"
#include "ultima/shared/std/string.h"
#include "common/path.h"
#include "graphics/font.h"
namespace Ultima {
namespace Ultima8 {
class Font;
// This is TTF_Font struct
typedef struct _TTF_Font TTF_Font;
class TTFont;
class FontManager {
private:
struct TTFId {
Common::Path _filename;
int _pointSize;
bool operator<(const TTFId &other) const {
return (_pointSize < other._pointSize ||
(_pointSize == other._pointSize &&
_filename < other._filename));
}
};
struct TTFHash {
uint operator()(const TTFId &x) const {
// TODO: See if something better can be used as a hash key
int64 val = (int64)&x;
return (uint)val;
}
};
struct TTFEqual {
bool operator()(const TTFId &x, const TTFId &y) const {
return x._filename == y._filename && x._pointSize == y._pointSize;
}
};
typedef Common::HashMap<TTFId, Graphics::Font *, TTFHash, TTFEqual> TTFFonts;
TTFFonts _ttfFonts;
//! Get a (possibly cached) TTF_Font structure for filename/pointsize,
//! loading it if necessary.
Graphics::Font *getTTF_Font(const Common::Path &filename, int pointsize, bool antialiasing);
//! Override fontnum with specified font
void setOverride(unsigned int fontnum, Font *newFont);
Std::vector<Font *> _overrides;
Std::vector<Font *> _ttFonts;
static FontManager *_fontManager;
public:
FontManager();
~FontManager();
static FontManager *get_instance() {
return _fontManager;
}
//! get a Font by fontnum (for game fonts)
//! \param fontnum the number of the font
//! \param allowOverride if true, allow an override font to be used
Font *getGameFont(unsigned int fontnum,
bool allowOverride = false);
//! get a TTF font (for non-game fonts)
Font *getTTFont(unsigned int ttfnum);
//! override a game font with a TTF.
//! \param fontnum the font to override
//! \param filename the filename of the TTF
//! \param pointsize the pointsize to use
//! \param rgb the color to use for the font
//! \param bordersize the size of the black border to add
//! \param SJIS true for a Japanese game font
bool addTTFOverride(unsigned int fontnum, const Common::Path &filename,
int pointsize, uint32 rgb, int bordersize,
bool SJIS = false);
//! override a game font with a Japanese font.
//! \param fontnum the font to override
//! \param jpfont the fontnum of the Japanese font to use
//! \param rgb the color to use
bool addJPOverride(unsigned int fontnum, unsigned int jpfont, uint32 rgb);
//! load a TTF (for non-game fonts)
bool loadTTFont(unsigned int ttfnum, const Common::Path &filename,
int pointsize, uint32 rgb, int bordersize);
// Reset the game fonts
void resetGameFonts();
};
} // End of namespace Ultima8
} // End of namespace Ultima // End of namespace Ultima8
#endif

View File

@@ -0,0 +1,90 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/debugger.h"
#include "ultima/ultima8/gfx/fonts/font_shape_archive.h"
#include "ultima/ultima8/misc/util.h"
#include "ultima/ultima8/gfx/fonts/shape_font.h"
#include "ultima/ultima8/conf/config_file_manager.h"
namespace Ultima {
namespace Ultima8 {
ShapeFont *FontShapeArchive::getFont(uint32 fontnum) {
return dynamic_cast<ShapeFont *>(getShape(fontnum));
}
void FontShapeArchive::cache(uint32 shapenum) {
if (shapenum >= _count) return;
if (_shapes.empty()) _shapes.resize(_count);
if (_shapes[shapenum]) return;
uint32 shpsize;
uint8 *data = getRawObject(shapenum, &shpsize);
if (!data || shpsize == 0) return;
// Auto detect format
if (!_format)
_format = Shape::DetectShapeFormat(data, shpsize);
if (!_format) {
delete [] data;
warning("Unable to detect shape format for flex.");
return;
}
Shape *shape = new ShapeFont(data, shpsize, _format, _id, shapenum);
if (_palette) shape->setPalette(_palette);
_shapes[shapenum] = shape;
}
void FontShapeArchive::setHVLeads() {
ConfigFileManager *config = ConfigFileManager::get_instance();
KeyMap leadkeyvals = config->listKeyValues("game", "fontleads");
for (const auto &i : leadkeyvals) {
int fontnum = atoi(i._key.c_str());
Std::string leaddesc = i._value;
Std::vector<Std::string> vals;
SplitString(leaddesc, ',', vals);
if (vals.size() != 2) {
warning("Invalid hlead/vlead description: %s", leaddesc.c_str());
continue;
}
int hlead = atoi(vals[0].c_str());
int vlead = atoi(vals[1].c_str());
ShapeFont *font = getFont(fontnum);
if (font) {
font->setHLead(hlead);
font->setVLead(vlead);
}
}
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,54 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_FONTSHAPEARCHIVE_H
#define ULTIMA8_GFX_FONTS_FONTSHAPEARCHIVE_H
#include "ultima/ultima8/gfx/shape_archive.h"
namespace Ultima {
namespace Ultima8 {
class ShapeFont;
class FontShapeArchive : public ShapeArchive {
public:
FontShapeArchive(uint16 id, Palette *pal = 0,
const ConvertShapeFormat *format = 0)
: ShapeArchive(id, pal, format) { }
FontShapeArchive(Common::SeekableReadStream *rs, uint16 id, Palette *pal = 0,
const ConvertShapeFormat *format = 0)
: ShapeArchive(rs, id, pal, format) { }
~FontShapeArchive() override { }
//! load HVLeads from u8.ini
void setHVLeads();
ShapeFont *getFont(uint32 fontnum);
void cache(uint32 fontnum) override;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,105 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/debugger.h"
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/jp_font.h"
#include "ultima/ultima8/gfx/fonts/shape_font.h"
#include "ultima/ultima8/gfx/shape_frame.h"
#include "ultima/ultima8/gfx/fonts/jp_rendered_text.h"
namespace Ultima {
namespace Ultima8 {
JPFont::JPFont(ShapeFont *jpfont, unsigned int fontnum)
: _fontNum(fontnum), _shapeFont(jpfont) {
assert(_shapeFont->frameCount() > 256);
}
JPFont::~JPFont() {
}
int JPFont::getWidth(int c) {
return _shapeFont->getFrame(c)->_width;
}
int JPFont::getHeight() {
return _shapeFont->getHeight();
}
int JPFont::getBaseline() {
return _shapeFont->getBaseline();
}
int JPFont::getBaselineSkip() {
return _shapeFont->getBaselineSkip();
}
void JPFont::getStringSize(const Std::string &text, int32 &width, int32 &height) {
int hlead = _shapeFont->getHlead();
width = hlead;
height = getHeight();
for (unsigned int i = 0; i < text.size(); ++i) {
if (text[i] == '\n' || text[i] == '\r') {
// ignore
} else {
uint16 sjis = text[i] & 0xFF;
if (sjis >= 0x80) {
uint16 t = text[++i] & 0xFF;
sjis += (t << 8);
}
width += getWidth(shiftjis_to_ultima8(sjis)) - hlead;
}
}
}
void JPFont::getTextSize(const Std::string &text,
int32 &resultwidth, int32 &resultheight,
unsigned int &remaining,
int32 width, int32 height, TextAlign align,
bool u8specials, bool pagebreaks) {
Std::list<PositionedText> tmp;
tmp = typesetText<SJISTraits>(this, text, remaining,
width, height, align, u8specials, pagebreaks,
resultwidth, resultheight);
}
RenderedText *JPFont::renderText(const Std::string &text,
unsigned int &remaining,
int32 width, int32 height, TextAlign align,
bool u8specials, bool pagebreaks,
Std::string::size_type cursor) {
int32 resultwidth, resultheight;
Std::list<PositionedText> lines;
lines = typesetText<SJISTraits>(this, text, remaining,
width, height, align, u8specials, pagebreaks,
resultwidth, resultheight,
cursor);
return new JPRenderedText(lines, resultwidth, resultheight,
_shapeFont->getVlead(), _shapeFont, _fontNum);
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,65 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_JPFONT_H
#define ULTIMA8_GFX_FONTS_JPFONT_H
#include "ultima/ultima8/gfx/fonts/font.h"
namespace Ultima {
namespace Ultima8 {
class ShapeFont;
class JPFont : public Font {
public:
JPFont(ShapeFont *jpfont, unsigned int fontnum);
~JPFont() override;
int getWidth(int c);
int getHeight() override;
int getBaseline() override;
int getBaselineSkip() override;
void getStringSize(const Std::string &text,
int32 &width, int32 &height) override;
void getTextSize(const Std::string &text, int32 &resultwidth,
int32 &resultheight, unsigned int &remaining, int32 width = 0,
int32 height = 0, TextAlign align = TEXT_LEFT,
bool u8specials = false, bool pagebreaks = false) override;
RenderedText *renderText(const Std::string &text,
unsigned int &remaining, int32 width = 0, int32 height = 0,
TextAlign align = TEXT_LEFT, bool u8specials = false,
bool pagebreaks = false,
Std::string::size_type cursor = Std::string::npos) override;
protected:
unsigned int _fontNum;
ShapeFont *_shapeFont;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,127 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/debugger.h"
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/jp_rendered_text.h"
#include "ultima/ultima8/gfx/fonts/shape_font.h"
#include "ultima/ultima8/gfx/render_surface.h"
#include "ultima/ultima8/gfx/shape_frame.h"
#include "ultima/ultima8/gfx/palette_manager.h"
#include "ultima/ultima8/gfx/texture.h"
namespace Ultima {
namespace Ultima8 {
JPRenderedText::JPRenderedText(Std::list<PositionedText> &lines, int width, int height,
int vLead, ShapeFont *font, unsigned int fontNum)
: _lines(lines), _font(font), _fontNum(fontNum) {
_width = width;
_height = height;
_vLead = vLead;
}
JPRenderedText::~JPRenderedText() {
}
void JPRenderedText::draw(RenderSurface *surface, int x, int y, bool /*destmasked*/) {
// TODO support masking here??
PaletteManager *palman = PaletteManager::get_instance();
PaletteManager::PalIndex fontpal = static_cast<PaletteManager::PalIndex>
(PaletteManager::Pal_JPFontStart + _fontNum);
Palette *pal = palman->getPalette(fontpal);
const Palette *savepal = _font->getPalette();
_font->setPalette(pal);
uint32 color = TEX32_PACK_RGB(0, 0, 0);
for (const auto &line : _lines) {
int line_x = x + line._dims.left;
int line_y = y + line._dims.top;
size_t textsize = line._text.size();
for (size_t i = 0; i < textsize; ++i) {
uint16 sjis = line._text[i] & 0xFF;
if (sjis >= 0x80) {
uint16 t = line._text[++i] & 0xFF;
sjis += (t << 8);
}
uint16 u8char = shiftjis_to_ultima8(sjis);
surface->Paint(_font, u8char, line_x, line_y);
if (i == line._cursor) {
surface->fill32(color, line_x, line_y - _font->getBaseline(),
1, line._dims.height());
}
line_x += (_font->getFrame(u8char))->_width - _font->getHlead();
}
if (line._cursor == textsize) {
surface->fill32(color, line_x, line_y - _font->getBaseline(),
1, line._dims.height());
}
}
_font->setPalette(savepal);
}
void JPRenderedText::drawBlended(RenderSurface *surface, int x, int y,
uint32 col, bool /*destmasked*/) {
// TODO Support masking here??
PaletteManager *palman = PaletteManager::get_instance();
PaletteManager::PalIndex fontpal = static_cast<PaletteManager::PalIndex>
(PaletteManager::Pal_JPFontStart + _fontNum);
Palette *pal = palman->getPalette(fontpal);
const Palette *savepal = _font->getPalette();
_font->setPalette(pal);
Std::list<PositionedText>::const_iterator iter;
for (const auto &line : _lines) {
int line_x = x + line._dims.left;
int line_y = y + line._dims.top;
size_t textsize = line._text.size();
for (size_t i = 0; i < textsize; ++i) {
uint16 sjis = line._text[i] & 0xFF;
if (sjis >= 0x80) {
uint16 t = line._text[++i] & 0xFF;
sjis += (t << 8);
}
uint16 u8char = shiftjis_to_ultima8(sjis);
surface->PaintHighlight(_font, u8char, line_x, line_y,
false, false, col);
line_x += (_font->getFrame(u8char))->_width - _font->getHlead();
}
}
_font->setPalette(savepal);
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,52 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_JPRENDEREDTEXT_H
#define ULTIMA8_GFX_FONTS_JPRENDEREDTEXT_H
#include "ultima/ultima8/gfx/fonts/rendered_text.h"
#include "ultima/ultima8/gfx/fonts/font.h"
namespace Ultima {
namespace Ultima8 {
class ShapeFont;
class JPRenderedText : public RenderedText {
public:
JPRenderedText(Std::list<PositionedText> &lines,
int width, int height, int vlead, ShapeFont *font,
unsigned int fontnum);
~JPRenderedText() override;
void draw(RenderSurface *surface, int x, int y, bool destmasked = false) override;
void drawBlended(RenderSurface *surface, int x, int y, uint32 col, bool destmasked = false) override;
protected:
Std::list<PositionedText> _lines;
ShapeFont *_font;
unsigned int _fontNum;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,37 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/rendered_text.h"
namespace Ultima {
namespace Ultima8 {
RenderedText::RenderedText()
: _width(-1), _height(-1), _vLead(0) {
}
RenderedText::~RenderedText() {
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,65 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_RENDEREDTEXT_H
#define ULTIMA8_GFX_FONTS_RENDEREDTEXT_H
namespace Ultima {
namespace Ultima8 {
class RenderSurface;
class RenderedText {
public:
RenderedText();
virtual ~RenderedText();
//! Draw self to a rendersurface.
//! \param surface The surface to draw to
//! \param x X coordinate of target
//! \param y Y coordinate of target. This will be the top baseline.
virtual void draw(RenderSurface *surface, int x, int y, bool destmasked = false) = 0;
//! Draw self to a rendersurface blended (0xAABBGGRR, alpha is blend level)
virtual void drawBlended(RenderSurface *surface, int x, int y, uint32 col, bool destmasked = false) = 0;
//! Get dimensions.
//! \param x Returns the width
//! \param y Returns the height
virtual void getSize(int &x, int &y) const {
x = _width;
y = _height;
}
//! Get vlead
virtual int getVlead() {
return _vLead;
}
protected:
int _width, _height;
int _vLead;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,137 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/ultima8.h"
#include "ultima/ultima8/gfx/fonts/shape_font.h"
#include "ultima/ultima8/gfx/shape_frame.h"
#include "ultima/ultima8/gfx/fonts/shape_rendered_text.h"
namespace Ultima {
namespace Ultima8 {
ShapeFont::ShapeFont(const uint8 *data, uint32 size,
const ConvertShapeFormat *format,
const uint16 flexId, const uint32 shapeNum)
: Font(), Shape(data, size, format, flexId, shapeNum),
_height(0), _baseLine(0), _vLead(-1), _hLead(0) {
_crusaderCharMap = GAME_IS_CRUSADER && shapeNum == 1;
}
ShapeFont::~ShapeFont() {
}
int ShapeFont::getWidth(char c) {
const ShapeFrame *frame = getFrame(charToFrameNum(c));
if (frame)
return frame->_width;
else
return 7; // small space..
}
int ShapeFont::getHeight() {
if (_height == 0) {
for (uint32 i = 0; i < frameCount(); i++) {
const ShapeFrame *frame = getFrame(i);
if (!frame)
continue;
int h = frame->_height;
if (h > _height) _height = h;
}
}
return _height;
}
int ShapeFont::getBaseline() {
if (_baseLine == 0) {
for (uint32 i = 0; i < frameCount(); i++) {
int b = getFrame(i)->_yoff;
if (b > _baseLine) _baseLine = b;
}
}
return _baseLine;
}
int ShapeFont::getBaselineSkip() {
return getHeight() + getVlead();
}
void ShapeFont::getStringSize(const Std::string &text, int32 &width, int32 &height) {
width = _hLead;
height = getHeight();
for (unsigned int i = 0; i < text.size(); ++i) {
if (text[i] == '\n' || text[i] == '\r') {
// ignore
} else {
width += getWidth(text[i]) - _hLead;
}
}
}
int ShapeFont::charToFrameNum(char c) const {
if (_crusaderCharMap) {
if (c < 41)
// ( and ) are combined into a single shape
return c;
// weirdly X and Y are swapped in both upper and lowercase
else if (c == 'X')
return 'X';
else if (c == 'Y')
return 'W';
else if (c < 96)
return c - 1;
else if (c == 96)
// no backquote char
return charToFrameNum('\'');
else if (c == 'x')
return 'w';
else if (c == 'y')
return 'v';
else
return c - 2;
} else {
return static_cast<unsigned char>(c);
}
}
RenderedText *ShapeFont::renderText(const Std::string &text,
unsigned int &remaining,
int32 width, int32 height, TextAlign align,
bool u8specials, bool pagebreaks,
Std::string::size_type cursor) {
int32 resultwidth, resultheight;
Std::list<PositionedText> lines;
lines = typesetText<Traits>(this, text, remaining,
width, height, align, u8specials, pagebreaks,
resultwidth, resultheight, cursor);
return new ShapeRenderedText(lines, resultwidth, resultheight,
getVlead(), this);
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,77 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_SHAPEFONT_H
#define ULTIMA8_GFX_FONTS_SHAPEFONT_H
#include "ultima/ultima8/gfx/fonts/font.h"
#include "ultima/ultima8/gfx/shape.h"
namespace Ultima {
namespace Ultima8 {
class ShapeFont : public Font, public Shape {
int _height;
int _baseLine;
int _vLead;
int _hLead;
bool _crusaderCharMap;
public:
ShapeFont(const uint8 *data, uint32 size, const ConvertShapeFormat *format,
const uint16 flexId, const uint32 shapenum);
~ShapeFont() override;
int getHeight() override;
int getBaseline() override;
int getBaselineSkip() override;
int getWidth(char c);
int getVlead() const {
return _vLead;
}
int getHlead() const {
return _hLead;
}
void setVLead(int vl) {
_vLead = vl;
}
void setHLead(int hl) {
_hLead = hl;
}
int charToFrameNum(char c) const;
void getStringSize(const Std::string &text,
int32 &width, int32 &height) override;
RenderedText *renderText(const Std::string &text,
unsigned int &remaining, int32 width = 0, int32 height = 0,
TextAlign align = TEXT_LEFT, bool u8specials = false,
bool pagebreaks = false,
Std::string::size_type cursor = Std::string::npos) override;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,102 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/debugger.h"
#include "ultima/ultima8/gfx/fonts/shape_rendered_text.h"
#include "ultima/ultima8/gfx/fonts/shape_font.h"
#include "ultima/ultima8/gfx/render_surface.h"
#include "ultima/ultima8/gfx/texture.h"
namespace Ultima {
namespace Ultima8 {
ShapeRenderedText::ShapeRenderedText(const Std::list<PositionedText> &lines,
int width, int height, int vLead,
ShapeFont *font)
: _lines(lines), _font(font) {
_width = width;
_height = height;
_vLead = vLead;
}
ShapeRenderedText::~ShapeRenderedText() {
}
void ShapeRenderedText::draw(RenderSurface *surface, int x, int y, bool /*destmasked*/) {
// TODO support masking here???
uint32 color = TEX32_PACK_RGB(0, 0, 0);
Std::list<PositionedText>::const_iterator iter;
surface->BeginPainting();
for (const auto &line : _lines) {
int line_x = x + line._dims.left;
int line_y = y + line._dims.top;
size_t textsize = line._text.size();
for (size_t i = 0; i < textsize; ++i) {
surface->Paint(_font, _font->charToFrameNum(line._text[i]),
line_x, line_y);
if (i == line._cursor) {
surface->fill32(color, line_x, line_y - _font->getBaseline(),
1, line._dims.height());
}
line_x += _font->getWidth(line._text[i]) - _font->getHlead();
}
if (line._cursor == textsize) {
surface->fill32(color, line_x, line_y - _font->getBaseline(),
1, line._dims.height());
}
}
surface->EndPainting();
}
void ShapeRenderedText::drawBlended(RenderSurface *surface, int x, int y,
uint32 col, bool /*destmasked*/) {
// TODO Support masking here ????
Std::list<PositionedText>::const_iterator iter;
for (const auto &line : _lines) {
int line_x = x + line._dims.left;
int line_y = y + line._dims.top;
size_t textsize = line._text.size();
for (size_t i = 0; i < textsize; ++i) {
surface->PaintHighlight(_font,
static_cast<unsigned char>(line._text[i]),
line_x, line_y, false, false, col);
line_x += _font->getWidth(line._text[i]) - _font->getHlead();
}
}
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,50 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_SHAPERENDEREDTEXT_H
#define ULTIMA8_GFX_FONTS_SHAPERENDEREDTEXT_H
#include "ultima/ultima8/gfx/fonts/rendered_text.h"
#include "ultima/ultima8/gfx/fonts/font.h"
namespace Ultima {
namespace Ultima8 {
class ShapeFont;
class ShapeRenderedText : public RenderedText {
public:
ShapeRenderedText(const Std::list<PositionedText> &lines,
int width, int height, int vlead, ShapeFont *font);
~ShapeRenderedText() override;
void draw(RenderSurface *surface, int x, int y, bool destmasked = false) override;
void drawBlended(RenderSurface *surface, int x, int y, uint32 col, bool destmasked = false) override;
protected:
Std::list<PositionedText> _lines;
ShapeFont *_font;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,299 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/tt_font.h"
#include "ultima/ultima8/gfx/fonts/ttf_rendered_text.h"
#include "ultima/ultima8/gfx/texture.h"
//include iomanip
namespace Ultima {
namespace Ultima8 {
// various unicode characters which look like small black circles
static const uint16 BULLETS[] = { 0x2022, 0x30FB, 0x25CF, 0 };
TTFont::TTFont(Graphics::Font *font, uint32 rgb, int borderSize,
bool antiAliased, bool SJIS) :
_borderSize(borderSize), _ttfFont(font), _antiAliased(antiAliased), _SJIS(SJIS),
_PF_RGBA(Graphics::PixelFormat(4, 8, 8, 8, 8, 24, 16, 8, 0)) {
_color = _PF_RGBA.RGBToColor((rgb >> 16) & 0xFF, (rgb >> 8) & 0xff, rgb & 0xff);
_bullet = 0;
// scan for a character to use as a conversation option _bullet
for (int i = 0; BULLETS[i]; ++i) {
Common::Rect box = font->getBoundingBox(BULLETS[i]);
if (!box.isEmpty()) {
_bullet = BULLETS[i];
break;
}
}
if (_bullet == 0) {
_bullet = '*';
}
}
TTFont::~TTFont() {
}
int TTFont::getHeight() {
return _ttfFont->getFontHeight() + 2 * _borderSize; // constant (border)
}
int TTFont::getBaseline() {
Common::Rect box = _ttfFont->getBoundingBox('W');
return box.bottom;
}
int TTFont::getBaselineSkip() {
// TODO: Come up with something more generic than just hardcoding 2 pixel line separation
return getHeight() + 2;
}
template<class T>
static Common::U32String toUnicode(const Std::string &text, uint16 bullet) {
Std::string::size_type len = T::length(text);
Common::U32String result = Common::U32String(text.c_str(), len);
Std::string::const_iterator iter = text.begin();
for (uint idx = 0; idx < len; ++idx) {
uint32 u = T::unicode(iter);
if (u == '@') {
result.setChar(bullet, idx);
} else {
result.setChar(u, idx);
}
}
return result;
}
void TTFont::getStringSize(const Std::string &text, int32 &width, int32 &height) {
// convert to unicode
Common::U32String unicodeText;
if (!_SJIS)
unicodeText = toUnicode<Traits>(text, _bullet);
else
unicodeText = toUnicode<SJISTraits>(text, _bullet);
width = _ttfFont->getStringWidth(unicodeText);
height = _ttfFont->getFontHeight();
width += 2 * _borderSize;
height += 2 * _borderSize;
}
void TTFont::getTextSize(const Std::string &text,
int32 &resultWidth, int32 &resultHeight,
unsigned int &remaining,
int32 width, int32 height, TextAlign align,
bool u8specials, bool pagebreaks) {
Std::list<PositionedText> tmp;
if (!_SJIS)
tmp = typesetText<Traits>(this, text, remaining,
width, height, align, u8specials, pagebreaks,
resultWidth, resultHeight);
else
tmp = typesetText<SJISTraits>(this, text, remaining,
width, height, align, u8specials, pagebreaks,
resultWidth, resultHeight);
}
void TTFont::addTextBorder(Graphics::ManagedSurface &textSurf, uint32 *texBuf, const Common::Rect32 &dims, int32 resultWidth, int32 resultHeight, uint32 borderColor) {
uint8 bA, bR, bG, bB;
_PF_RGBA.colorToARGB(borderColor, bA, bR, bG, bB);
int sqrSize = _borderSize * _borderSize;
int sqrEdge = (_borderSize + 1) * (_borderSize + 1);
for (int y = 0; y < textSurf.h; y++) {
const byte* surfrow = (const byte*)textSurf.getBasePtr(0, y);
for (int x = 0; x < textSurf.w; x++) {
if (_antiAliased) {
uint32 sColor = *((const uint32 *)(surfrow + x * 4));
uint8 sR, sG, sB, sA;
_PF_RGBA.colorToARGB(sColor, sA, sR, sG, sB);
if (sA == 0x00)
continue;
for (int dx = -_borderSize; dx <= _borderSize; dx++) {
for (int dy = -_borderSize; dy <= _borderSize; dy++) {
int tx = dims.left + x + _borderSize + dx;
int ty = dims.top + y + _borderSize + dy;
if (tx >= 0 && tx < resultWidth && ty >= 0 && ty < resultHeight) {
uint32 dColor = texBuf[ty * resultWidth + tx];
if (borderColor != dColor) {
int sqrDist = (dx * dx) + (dy * dy);
if (sqrDist < sqrSize) {
texBuf[ty * resultWidth + tx] = borderColor;
}
else if (sqrDist < sqrEdge) {
// Blend border color at source intensity with destination
uint8 dA, dR, dG, dB;
_PF_RGBA.colorToARGB(dColor, dA, dR, dG, dB);
double bAlpha = (double)bA / 255.0;
double sAlpha = (double)sA / 255.0;
double dAlpha = (double)dA / 255.0;
dAlpha *= (1.0 - sAlpha);
dR = static_cast<uint8>((bR * sAlpha + dR * dAlpha) / (sAlpha + dAlpha));
dG = static_cast<uint8>((bG * sAlpha + dG * dAlpha) / (sAlpha + dAlpha));
dB = static_cast<uint8>((bB * sAlpha + dB * dAlpha) / (sAlpha + dAlpha));
dA = static_cast<uint8>(255. * bAlpha * (sAlpha + dAlpha));
texBuf[ty * resultWidth + tx] = _PF_RGBA.ARGBToColor(dA, dR, dG, dB);
}
}
}
}
}
}
else if (surfrow[x] == 1) {
for (int dx = -_borderSize; dx <= _borderSize; dx++) {
for (int dy = -_borderSize; dy <= _borderSize; dy++) {
int tx = dims.left + x + _borderSize + dx;
int ty = dims.top + y + _borderSize + dy;
if (tx >= 0 && tx < resultWidth && ty >= 0 && ty < resultHeight) {
int sqrDist = (dx * dx) + (dy * dy);
if (sqrDist < sqrEdge) {
texBuf[ty * resultWidth + tx] = borderColor;
}
}
}
}
}
}
}
}
RenderedText *TTFont::renderText(const Std::string &text, unsigned int &remaining,
int32 width, int32 height, TextAlign align, bool u8specials, bool pagebreaks,
Std::string::size_type cursor) {
int32 resultWidth, resultHeight, lineHeight;
Std::list<PositionedText> lines;
if (!_SJIS)
lines = typesetText<Traits>(this, text, remaining, width, height, align, u8specials, pagebreaks,
resultWidth, resultHeight, cursor);
else
lines = typesetText<SJISTraits>(this, text, remaining, width, height, align, u8specials, pagebreaks,
resultWidth, resultHeight, cursor);
lineHeight = _ttfFont->getFontHeight();
uint32 borderColor = _PF_RGBA.ARGBToColor(0xFF, 0x00, 0x00, 0x00);
Graphics::ManagedSurface *texture = new Graphics::ManagedSurface(resultWidth, resultHeight, _PF_RGBA);
uint32 *texBuf = (uint32 *)texture->getPixels();
for (const auto &line : lines) {
// convert to unicode
Common::U32String unicodeText;
if (!_SJIS)
unicodeText = toUnicode<Traits>(line._text, _bullet);
else
unicodeText = toUnicode<SJISTraits>(line._text, _bullet);
// Create a surface and render the text
Graphics::ManagedSurface textSurf;
if (!_antiAliased) {
// When not in antialiased mode, use a paletted surface where '1' is
// used for pixels of the text
textSurf.create(resultWidth, lineHeight, Graphics::PixelFormat::createFormatCLUT8());
_ttfFont->drawString(&textSurf, unicodeText, 0, 0, resultWidth, 1);
} else {
// Use a high color surface with the specified _color color for text
textSurf.create(resultWidth, lineHeight, _PF_RGBA);
_ttfFont->drawString(&textSurf, unicodeText, 0, 0, resultWidth, _color);
};
// Add border within radius. Pixels on the edge are alpha blended if antialiased
if (_borderSize > 0) {
addTextBorder(textSurf, texBuf, line._dims, resultWidth, resultHeight, borderColor);
}
// render the text surface into our texture buffer
for (int y = 0; y < textSurf.h; y++) {
const byte *surfrow = (const byte *)textSurf.getBasePtr(0, y);
int ty = line._dims.top + y + _borderSize;
for (int x = 0; x < textSurf.w; x++) {
int tx = line._dims.left + x + _borderSize;
if (_antiAliased) {
uint32 sColor = *((const uint32 *)(surfrow + x * 4));
uint8 sR, sG, sB, sA;
_PF_RGBA.colorToARGB(sColor, sA, sR, sG, sB);
if (sA == 0xFF) {
texBuf[ty * resultWidth + tx] = sColor;
}
else if (sA != 0x00) {
// Blend color with destination
int32 dColor = texBuf[ty * resultWidth + tx];
uint8 dA, dR, dG, dB;
_PF_RGBA.colorToARGB(dColor, dA, dR, dG, dB);
double sAlpha = (double)sA / 255.0;
double dAlpha = (double)dA / 255.0;
dAlpha *= (1.0 - sAlpha);
dR = static_cast<uint8>((sR * sAlpha + dR * dAlpha) / (sAlpha + dAlpha));
dG = static_cast<uint8>((sG * sAlpha + dG * dAlpha) / (sAlpha + dAlpha));
dB = static_cast<uint8>((sB * sAlpha + dB * dAlpha) / (sAlpha + dAlpha));
dA = static_cast<uint8>(255. * (sAlpha + dAlpha));
texBuf[ty * resultWidth + tx] = _PF_RGBA.ARGBToColor(dA, dR, dG, dB);
}
}
else if (surfrow[x] == 1) {
texBuf[ty * resultWidth + tx] = _color;
}
}
}
if (line._cursor != Std::string::npos) {
assert(line._cursor <= line._text.size());
unicodeText = unicodeText.substr(0, line._cursor);
int w = _ttfFont->getStringWidth(unicodeText);
for (int y = 0; y < line._dims.height(); y++) {
int tx = line._dims.left + w + _borderSize;
int ty = line._dims.top + y;
texBuf[ty * resultWidth + tx] = borderColor;
}
}
}
return new TTFRenderedText(texture, resultWidth, resultHeight,
getBaselineSkip() - getHeight(), getBaseline(), isAntialiased());
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,76 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_TTFONT_H
#define ULTIMA8_GFX_FONTS_TTFONT_H
#include "ultima/ultima8/gfx/fonts/font.h"
#include "graphics/font.h"
#include "graphics/pixelformat.h"
namespace Ultima {
namespace Ultima8 {
class TTFont : public Font {
public:
TTFont(Graphics::Font *font, uint32 rgb, int bordersize,
bool antiAliased, bool SJIS);
~TTFont() override;
int getHeight() override;
int getBaseline() override;
int getBaselineSkip() override;
bool isAntialiased() {
return _antiAliased;
}
void getStringSize(const Std::string &text,
int32 &width, int32 &height) override;
void getTextSize(const Std::string &text,
int32 &resultwidth, int32 &resultheight, unsigned int &remaining,
int32 width = 0, int32 height = 0, TextAlign align = TEXT_LEFT,
bool u8specials = false, bool pagebreaks = false) override;
RenderedText *renderText(const Std::string &text,
unsigned int &remaining, int32 width = 0, int32 height = 0,
TextAlign align = TEXT_LEFT, bool u8specials = false,
bool pagebreaks = false,
Std::string::size_type cursor = Std::string::npos) override;
protected:
Graphics::Font *_ttfFont;
uint32 _color;
int _borderSize;
bool _antiAliased;
bool _SJIS;
Graphics::PixelFormat _PF_RGBA;
uint16 _bullet;
void addTextBorder(Graphics::ManagedSurface &textSurf, uint32 *texBuf, const Common::Rect32 &dims, int32 resultWidth, int32 resultHeight, uint32 borderColor);
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,61 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/ultima8/misc/common_types.h"
#include "ultima/ultima8/gfx/fonts/ttf_rendered_text.h"
#include "ultima/ultima8/gfx/fonts/tt_font.h"
#include "ultima/ultima8/gfx/render_surface.h"
namespace Ultima {
namespace Ultima8 {
TTFRenderedText::TTFRenderedText(Graphics::ManagedSurface *texture, int width, int height,
int vLead, int baseline, bool antiAliased) : _texture(texture), _baseline(baseline), _antiAliased(antiAliased) {
_width = width;
_height = height;
_vLead = vLead;
}
TTFRenderedText::~TTFRenderedText() {
delete _texture;
}
void TTFRenderedText::draw(RenderSurface *surface, int x, int y, bool destmasked) {
if (!_width)
return;
Common::Rect srcRect(_width, _height);
if (!destmasked)
surface->Blit(*_texture, srcRect, x, y - _baseline, _antiAliased);
else
surface->MaskedBlit(*_texture, srcRect, x, y - _baseline, 0, _antiAliased);
}
void TTFRenderedText::drawBlended(RenderSurface *surface, int x, int y,
uint32 col, bool destmasked) {
Common::Rect srcRect(_width, _height);
if (!destmasked)
surface->FadedBlit(*_texture, srcRect, x, y - _baseline, col, _antiAliased);
else
surface->MaskedBlit(*_texture, srcRect, x, y - _baseline, col, _antiAliased);
}
} // End of namespace Ultima8
} // End of namespace Ultima

View File

@@ -0,0 +1,55 @@
/* 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 3 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, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef ULTIMA8_GFX_FONTS_SHAPERENDEREDTEXT_H
#define ULTIMA8_GFX_FONTS_SHAPERENDEREDTEXT_H
#include "ultima/ultima8/gfx/fonts/rendered_text.h"
#include "ultima/ultima8/gfx/fonts/font.h"
#include "graphics/managed_surface.h"
namespace Ultima {
namespace Ultima8 {
class TTFont;
class Texture;
class TTFRenderedText : public RenderedText {
public:
TTFRenderedText(Graphics::ManagedSurface *texture, int width, int height, int vlead,
int baseline, bool antiAliased);
~TTFRenderedText() override;
void draw(RenderSurface *surface, int x, int y,
bool destmasked = false) override;
void drawBlended(RenderSurface *surface, int x, int y, uint32 col,
bool destmasked = false) override;
protected:
Graphics::ManagedSurface *_texture;
int _baseline;
bool _antiAliased;
};
} // End of namespace Ultima8
} // End of namespace Ultima
#endif