TETRAEDGE: Add loading support for tef font format

Still needs some fixes on the rendering side, but loading is working.
This commit is contained in:
Matthew Duggan 2023-05-04 10:23:42 +09:00
parent c011652f8a
commit 1072856f89
16 changed files with 605 additions and 207 deletions

View File

@ -36,6 +36,7 @@
#include "tetraedge/te/te_core.h"
#include "tetraedge/te/te_resource_manager.h"
#include "tetraedge/te/te_renderer.h"
#include "tetraedge/te/te_font2.h"
#include "tetraedge/te/te_font3.h"
#include "tetraedge/te/te_input_mgr.h"
#include "tetraedge/te/te_sound_manager.h"
@ -119,12 +120,23 @@ void Application::create() {
TeResourceManager *resmgr = g_engine->getResourceManager();
TeCore *core = g_engine->getCore();
_fontComic = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/ComicRelief.ttf"));
_fontArgh = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/Argh.ttf"));
_fontArial = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/arial.ttf"));
_fontChaucer = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/CHAUCER.TTF"));
_fontColaborate = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/Colaborate-Regular.otf"));
_fontProDisplay = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/ProDisplay.ttf"));
// Cache some fonts
if (g_engine->gameIsAmerzone()) {
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/Arial_r_10.tef"));
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/Arial_r_12.tef"));
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/Arial_r_16.tef"));
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/Colaborate-Regular_r_16.tef"));
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/Colaborate-Regular_r_24.tef"));
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/Credits.tef"));
resmgr->getResource<TeFont2>(core->findFile("Common/Fonts/FontLoadingMenu.tef"));
} else {
_fontComic = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/ComicRelief.ttf"));
_fontArgh = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/Argh.ttf"));
_fontArial = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/arial.ttf"));
_fontChaucer = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/CHAUCER.TTF"));
_fontColaborate = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/Colaborate-Regular.otf"));
_fontProDisplay = resmgr->getResource<TeFont3>(core->findFile("Common/Fonts/ProDisplay.ttf"));
}
// The app prebuilds some fonts.. cover letters, numbers, a few accented chars, and punctuation.
// Skip that here.

View File

@ -56,13 +56,18 @@ void Notifier::launchNextnotifier() {
if (_notifierDataArray.empty())
return;
TeVariant textformat = _gui.value("textFormat");
Common::String formattedName = Common::String::format(textformat.toString().c_str(), _notifierDataArray[0]._name.c_str());
Common::String textformat = _gui.value("textFormat").toString();
Common::String formattedName;
if (!textformat.empty())
formattedName = Common::String::format(textformat.c_str(), _notifierDataArray[0]._name.c_str());
else
formattedName = _notifierDataArray[0]._name;
TeITextLayout *text = _gui.textLayout("text");
text->setText(formattedName);
if (!_notifierDataArray[0]._imgpath.empty() && !g_engine->gameIsAmerzone()) {
if (!_notifierDataArray[0]._imgpath.empty()) {
assert(!g_engine->gameIsAmerzone());
_gui.spriteLayoutChecked("image")->load(_notifierDataArray[0]._imgpath);
}

View File

@ -69,11 +69,13 @@ MODULE_OBJS := \
te/te_color.o \
te/te_core.o \
te/te_extended_text_layout.o \
te/te_font2.o \
te/te_font3.o \
te/te_frame_anim.o \
te/te_free_move_zone.o \
te/te_frustum.o \
te/te_i_3d_object2.o \
te/te_i_font.o \
te/te_i_layout.o \
te/te_i_loc.o \
te/te_i_text_layout.o \

View File

@ -0,0 +1,206 @@
/* 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 "tetraedge/te/te_font2.h"
#include "tetraedge/tetraedge.h"
#include "tetraedge/te/te_3d_object2.h"
#include "tetraedge/te/te_core.h"
namespace Tetraedge {
bool operator==(const KernChars &l, const KernChars &r) {
return l._c1 == r._c1 && l._c2 == r._c2;
}
TeFont2::TeFont2() : _numChars(0), _hasKernData(false), _maxHeight(0) {
}
TeFont2::~TeFont2() {
}
bool TeFont2::load(const Common::String &path) {
if (_loadedPath == path)
return true; // already open
TeCore *core = g_engine->getCore();
Common::FSNode node = core->findFile(path);
return load(node);
}
bool TeFont2::load(const Common::FSNode &node) {
const Common::String path = node.getPath();
unload();
setAccessName(path);
_loadedPath = path;
if (!node.isReadable()) {
warning("TeFont2::load: Can't read from %s", path.c_str());
return false;
}
Common::File file;
file.open(node);
if (!Te3DObject2::loadAndCheckFourCC(file, "TESF")) {
warning("TeFont2::load: Invalid magic in %s", path.c_str());
return false;
}
_numChars = file.readUint32LE();
if (_numChars > 65535)
error("TeFont2::load: improbable number of char points %d", _numChars);
TeVector2s32::deserialize(file, _somePt);
TeVector3f32::deserialize(file, _someVec);
_hasKernData = (file.readByte() != 0);
if (_hasKernData) {
uint32 numKernData = file.readUint32LE();
if (numKernData > 10000)
error("TeFont2::load: improbable number of kerning points %d", numKernData);
for (uint32 i = 0; i < numKernData; i++) {
KernChars kc;
TeVector3f32 vec;
kc._c1 = file.readUint32LE();
kc._c2 = file.readUint32LE();
vec.x() = file.readFloatLE();
vec.y() = file.readFloatLE();
_kernData[kc] = vec;
//debug("KernChars: '%c'-'%c' (%.2f, %.2f)", (char)kc._c1, (char)kc._c2, vec.x(), vec.y());
}
}
for (uint32 i = 0; i < _numChars; i++) {
GlyphData2 g;
g._xSz = file.readFloatLE();
g._ySz = file.readFloatLE();
_maxHeight = MAX(_maxHeight, g._ySz);
g._xOff = file.readFloatLE();
g._yOff = file.readFloatLE();
g._xAdvance = file.readFloatLE();
// TODO: What are these other floats?
for (uint j = 0; j < 3; j++)
g._floats[j] = file.readFloatLE();
g._vec.x() = file.readFloatLE();
g._vec.y() = file.readFloatLE();
_glyphs.push_back(g);
uint32 charNo = file.readUint32LE();
_uintArray.push_back(charNo);
/*
if (i >= 35 && i <= 127)
debug("Char data %c: sz (%.1f %.1f) off (%.1f %.1f) xadv %.1f %.1f %.1f %.1f texloc (%.1f, %.1f) %d", (char)i,
g._xSz, g._ySz, g._xOff, g._yOff, g._xAdvance, g._floats[0], g._floats[1], g._floats[2],
g._vec.x(), g._vec.y(), charNo);
*/
}
if (!_texture.load(file, "png")) {
warning("Invalid png data in %s", path.c_str());
return false;
}
return true;
}
void TeFont2::unload() {
_texture.free();
_uintArray.clear();
_glyphs.clear();
_kernData.clear();
_numChars = 0;
}
int TeFont2::getFontHeight() const {
return _maxHeight;
}
int TeFont2::getMaxCharWidth() const {
int maxWidth = 0;
for (auto &glyph : _glyphs) {
maxWidth = MAX(maxWidth, (int)glyph._xAdvance);
}
return maxWidth;
}
int TeFont2::getCharWidth(uint32 chr) const {
if (chr >= _glyphs.size())
return 0;
return (int)_glyphs[chr]._xAdvance;
}
void TeFont2::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
if (chr >= _glyphs.size())
return;
if (_texture.empty())
error("Call to TeFont2::drawChar but no texture loaded");
const GlyphData2 g = _glyphs[chr];
Common::Rect srcRect;
srcRect.left = (int)g._vec.x();
srcRect.top = _texture.h - (int)g._vec.y();
srcRect.right = srcRect.left + g._xSz;
srcRect.bottom = srcRect.top + g._ySz;
int dstX = x + g._xOff;
int dstY = _maxHeight - g._yOff;
dst->copyRectToSurface(_texture, dstX, dstY, srcRect);
}
int TeFont2::getKerningOffset(uint32 left, uint32 right) const {
KernChars kc { left, right };
if (_kernData.contains(kc))
return (int)_kernData[kc].x();
return 0;
}
TeVector3f32 TeFont2::kerning(uint pxSize, uint isocode1, uint isocode2) {
KernChars kc { isocode1, isocode2 };
if (_kernData.contains(kc))
return _kernData[kc];
return TeVector3f32();
}
Common::Rect TeFont2::getBoundingBox(const Common::String &str, int fontSize) {
Common::Rect rect;
for (uint i = 0; i < str.size(); i++) {
uint c = str[i];
if (c >= _glyphs.size())
continue;
const GlyphData2 &g = _glyphs[c];
rect.top = MIN(rect.top, (int16)-g._yOff);
rect.bottom = MAX(rect.bottom, (int16)(-g._yOff + g._ySz));
rect.right += g._xAdvance;
}
return rect;
}
float TeFont2::height(uint pxSize) {
return _maxHeight;
}
Graphics::Font *TeFont2::getAtSize(uint size) {
return this;
}
} // end namespace Tetraedge

View File

@ -0,0 +1,106 @@
/* 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 TETRAEDGE_TE_TE_FONT2_H
#define TETRAEDGE_TE_TE_FONT2_H
#include "common/str.h"
#include "common/file.h"
#include "common/hashmap.h"
#include "graphics/font.h"
#include "tetraedge/te/te_resource.h"
#include "tetraedge/te/te_vector2s32.h"
#include "tetraedge/te/te_vector3f32.h"
#include "tetraedge/te/te_3d_texture.h"
#include "tetraedge/te/te_intrusive_ptr.h"
#include "tetraedge/te/te_i_font.h"
namespace Tetraedge {
struct KernChars {
uint32 _c1;
uint32 _c2;
};
bool operator==(const KernChars &l, const KernChars &r);
}
namespace Common {
template<> struct Hash<Tetraedge::KernChars> : public UnaryFunction<Tetraedge::KernChars, uint> {
uint operator()(Tetraedge::KernChars val) const { return val._c1 * 7333 + val._c2; }
};
}
namespace Tetraedge {
/**
* A pre-rendered font format with positioning data used in Amerzone
* ('tef' format)
*/
class TeFont2 : public TeIFont, public Graphics::Font {
public:
struct GlyphData2 {
float _xSz;
float _ySz;
float _xOff; // from nominal location
float _yOff; // top location, from baseline
float _xAdvance;
float _floats[3];
TeVector3f32 _vec; // location in texture - offset from bottom left
};
TeFont2();
virtual ~TeFont2();
bool load(const Common::String &path);
bool load(const Common::FSNode &node);
void unload();
Graphics::Font *getAtSize(uint size) override;
virtual int getFontHeight() const override;
virtual int getMaxCharWidth() const override;
virtual int getCharWidth(uint32 chr) const override;
virtual void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
virtual int getKerningOffset(uint32 left, uint32 right) const override;
virtual Common::Rect getBoundingBox(const Common::String &str, int fontSize) override;
virtual TeVector3f32 kerning(uint pxSize, uint isocode1, uint isocode2) override;
virtual float height(uint pxSize) override;
private:
Common::String _loadedPath;
uint32 _numChars;
TeVector2s32 _somePt;
TeVector3f32 _someVec;
bool _hasKernData;
float _maxHeight;
// Records a map of character pairs to kerning offsets
Common::HashMap<KernChars, TeVector3f32> _kernData;
Common::Array<uint32> _uintArray;
Common::Array<GlyphData2> _glyphs;
TeImage _texture;
};
} // end namespace Tetraedge
#endif // TETRAEDGE_TE_TE_FONT2_H

View File

@ -32,44 +32,7 @@
namespace Tetraedge {
static uint getUnicodeFromISO(uint chr)
{
uint retval;
TeCore *core = g_engine->getCore();
bool isrus = (core->fileFlagSystemFlag("language") == "ru");
if (!isrus) {
uint uVar1 = 0x152;
if (chr != 0xbc) {
uVar1 = chr;
}
retval = 0x153;
if (uVar1 != 0xbd) {
retval = uVar1;
}
} else {
retval = 0xad;
if (chr != 0xad) {
if (chr == 0xf0) {
retval = 0x2116;
}
else if (chr == 0xfd) {
retval = 0xa7;
} else {
retval = chr + 0x360;
if (0x5e < chr - 0xa1) {
retval = chr;
}
}
}
}
return retval;
}
TeFont3::TeFont3() {
init();
}
TeFont3::~TeFont3() {
@ -95,77 +58,6 @@ Graphics::Font *TeFont3::getAtSize(uint size) {
return newFont;
}
TeFont3::GlyphData TeFont3::glyph(uint pxSize, uint charcode) {
Graphics::Font *font = getAtSize(pxSize);
Common::Rect bbox = font->getBoundingBox(charcode);
TeImage *img = new TeImage();
Common::SharedPtr<TePalette> nullpal;
img->createImg(bbox.width(), bbox.height(), nullpal, TeImage::RGBA8);
font->drawChar(img, charcode, 0, 0, 0xffffffff);
GlyphData retval;
retval._charcode = charcode;
retval._bitmapSize = bbox;
retval._img = img;
return retval;
}
Common::CodePage TeFont3::codePage() const {
Common::String lang = g_engine->getCore()->language();
if (lang == "he")
return Common::kWindows1255;
if (lang == "ru")
return Common::kISO8859_5;
return Common::kLatin1;
}
int TeFont3::wordWrapText(const Common::String &str, int fontSize, int maxWidth, Common::Array<Common::String> &lines) {
Graphics::Font *font = getAtSize(fontSize);
Common::Array<Common::U32String> u32lines;
int retval = font->wordWrapText(str.decode(_codePage), maxWidth, u32lines);
for (auto &line: u32lines) {
lines.push_back(line.encode(_codePage));
}
return retval;
}
Common::Rect TeFont3::getBoundingBox(const Common::String &str, int fontSize) {
Graphics::Font *font = getAtSize(fontSize);
return font->getBoundingBox(str.decode(_codePage));
}
int TeFont3::getHeight(int fontSize) {
Graphics::Font *font = getAtSize(fontSize);
return font->getFontHeight();
}
void TeFont3::draw(TeImage &destImage, const Common::String &str, int fontSize, int yoff, const TeColor &col, TeFont3::AlignStyle align) {
Graphics::Font *font = getAtSize(fontSize);
Graphics::TextAlign talign;
switch (align) {
case AlignLeft:
talign = Graphics::kTextAlignLeft;
break;
case AlignRight:
talign = Graphics::kTextAlignRight;
break;
// Note: we don't support justify.. just center. (justify is not used anyway)
case AlignJustify:
case AlignCenter:
default:
talign = Graphics::kTextAlignCenter;
break;
}
const Graphics::PixelFormat &fmt = destImage.format;
uint32 uintcol = ((uint32)col.a() << fmt.aShift) | ((uint32)(col.r()) << fmt.rShift)
| ((uint32)(col.g()) << fmt.gShift) | ((uint32)(col.b()) << fmt.bShift);
Common::U32String line = str.decode(_codePage);
if (g_engine->getCore()->language() == "he")
line = Common::convertBiDiU32String(line).visual;
font->drawString(&destImage, line, 0, yoff, destImage.w, uintcol, talign);
}
bool TeFont3::load(const Common::String &path) {
if (_loadedPath == path && _fontFile.isOpen())
return true; // already open
@ -183,8 +75,8 @@ bool TeFont3::load(const Common::FSNode &node) {
setAccessName(path);
_loadedPath = path;
if (!node.exists()) {
warning("TeFont3::load: File %s doesn't exist", path.c_str());
if (!node.isReadable()) {
warning("TeFont3::load: Can't read from %s", path.c_str());
return false;
}
@ -206,32 +98,4 @@ void TeFont3::unload() {
_fontFile.close();
}
void TeFont3::init() {
_codePage = codePage();
}
float TeFont3::ascender(uint pxSize) {
Graphics::Font *font = getAtSize(pxSize);
return font->getFontAscent();
}
float TeFont3::descender(uint pxSize) {
error("TODO: Implement TeFont3::descender");
}
float TeFont3::height(uint pxSize) {
Graphics::Font *font = getAtSize(pxSize);
return font->getFontHeight();
}
TeVector3f32 TeFont3::kerning(uint pxSize, uint isocode1, uint isocode2) {
uint32 uni1 = getUnicodeFromISO(isocode1);
uint32 uni2 = getUnicodeFromISO(isocode2);
Graphics::Font *font = getAtSize(pxSize);
int offset = font->getKerningOffset(uni1, uni2);
// note: not perfect because we have no Y, but it's ok..
return TeVector3f32(offset, 0.0f, 0.0f);
}
} // end namespace Tetraedge

View File

@ -34,6 +34,7 @@
#include "tetraedge/te/te_image.h"
#include "tetraedge/te/te_intrusive_ptr.h"
#include "tetraedge/te/te_3d_texture.h"
#include "tetraedge/te/te_i_font.h"
struct FT_FaceRec_;
struct FT_LibraryRec_;
@ -44,51 +45,26 @@ class Font;
namespace Tetraedge {
class TeFont3 : public TeResource {
/**
* TeFont3 is a minimal wrapper on Graphics::Font for TTF files, supporting
* multiple sizes and matching the original TeFont api a bit closer.
*/
class TeFont3 : public TeIFont {
public:
TeFont3();
~TeFont3();
enum AlignStyle {
AlignLeft,
AlignRight,
AlignJustify,
AlignCenter
};
struct GlyphData {
uint32 _charcode;
Common::Rect _bitmapSize;
TeIntrusivePtr<TeImage> _img;
};
virtual ~TeFont3();
bool load(const Common::String &path);
bool load(const Common::FSNode &node);
void unload();
GlyphData glyph(uint size, uint charcode);
private:
float ascender(uint pxSize);
float descender(uint pxSize);
float height(uint pxSize);
TeVector3f32 kerning(uint pxSize, uint isocode1, uint isocode2);
TeIntrusivePtr<Te3DTexture> getFontSizeData(int size) const {
return _fontSizeData[size];
}
Common::Rect getBoundingBox(const Common::String &str, int fontSize);
int getHeight(int fontSize);
void draw(TeImage &destImage, const Common::String &str, int fontSize, int yoff, const TeColor &col, AlignStyle alignMode);
int wordWrapText(const Common::String &str, int fontSize, int maxWidth, Common::Array<Common::String> &lines);
private:
void init();
Graphics::Font *getAtSize(uint size);
Common::CodePage codePage() const;
Common::CodePage _codePage;
Graphics::Font *getAtSize(uint size) override;
Common::File _fontFile;
Common::HashMap<uint, Graphics::Font *> _fonts;
Common::String _loadedPath;

View File

@ -0,0 +1,133 @@
/* 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/>.
*
*/
// Since FreeType2 includes files, which contain forbidden symbols, we need to
// allow all symbols here.
#define FORBIDDEN_SYMBOL_ALLOW_ALL
#include "tetraedge/tetraedge.h"
#include "tetraedge/te/te_font3.h"
#include "tetraedge/te/te_core.h"
#include "graphics/font.h"
#include "graphics/fonts/ttf.h"
#include "common/unicode-bidi.h"
namespace Tetraedge {
TeIFont::TeIFont() {
_codePage = codePage();
}
TeIFont::~TeIFont() {
}
TeIFont::GlyphData TeIFont::glyph(uint pxSize, uint charcode) {
Graphics::Font *font = getAtSize(pxSize);
Common::Rect bbox = font->getBoundingBox(charcode);
TeImage *img = new TeImage();
Common::SharedPtr<TePalette> nullpal;
img->createImg(bbox.width(), bbox.height(), nullpal, TeImage::RGBA8);
font->drawChar(img, charcode, 0, 0, 0xffffffff);
GlyphData retval;
retval._charcode = charcode;
retval._bitmapSize = bbox;
retval._img = img;
return retval;
}
Common::CodePage TeIFont::codePage() const {
Common::String lang = g_engine->getCore()->language();
if (lang == "he")
return Common::kWindows1255;
if (lang == "ru")
return Common::kISO8859_5;
return Common::kLatin1;
}
int TeIFont::wordWrapText(const Common::String &str, int fontSize, int maxWidth, Common::Array<Common::String> &lines) {
Graphics::Font *font = getAtSize(fontSize);
Common::Array<Common::U32String> u32lines;
int retval = font->wordWrapText(str.decode(_codePage), maxWidth, u32lines);
for (auto &line: u32lines) {
lines.push_back(line.encode(_codePage));
}
return retval;
}
Common::Rect TeIFont::getBoundingBox(const Common::String &str, int fontSize) {
Graphics::Font *font = getAtSize(fontSize);
return font->getBoundingBox(str.decode(_codePage));
}
int TeIFont::getHeight(int fontSize) {
Graphics::Font *font = getAtSize(fontSize);
return font->getFontHeight();
}
void TeIFont::draw(TeImage &destImage, const Common::String &str, int fontSize, int yoff, const TeColor &col, TeIFont::AlignStyle align) {
Graphics::Font *font = getAtSize(fontSize);
Graphics::TextAlign talign;
switch (align) {
case AlignLeft:
talign = Graphics::kTextAlignLeft;
break;
case AlignRight:
talign = Graphics::kTextAlignRight;
break;
// Note: we don't support justify.. just center. (justify is not used anyway)
case AlignJustify:
case AlignCenter:
default:
talign = Graphics::kTextAlignCenter;
break;
}
const Graphics::PixelFormat &fmt = destImage.format;
uint32 uintcol = ((uint32)col.a() << fmt.aShift) | ((uint32)(col.r()) << fmt.rShift)
| ((uint32)(col.g()) << fmt.gShift) | ((uint32)(col.b()) << fmt.bShift);
Common::U32String line = str.decode(_codePage);
if (g_engine->getCore()->language() == "he")
line = Common::convertBiDiU32String(line).visual;
font->drawString(&destImage, line, 0, yoff, destImage.w, uintcol, talign);
}
float TeIFont::ascender(uint pxSize) {
Graphics::Font *font = getAtSize(pxSize);
return font->getFontAscent();
}
float TeIFont::descender(uint pxSize) {
error("TODO: Implement TeFont3::descender");
}
float TeIFont::height(uint pxSize) {
Graphics::Font *font = getAtSize(pxSize);
return font->getFontHeight();
}
TeVector3f32 TeIFont::kerning(uint pxSize, uint charcode1, uint charcode2) {
Graphics::Font *font = getAtSize(pxSize);
int offset = font->getKerningOffset(charcode1, charcode2);
// note: not perfect because we have no Y, but it's ok..
return TeVector3f32(offset, 0.0f, 0.0f);
}
} // end namespace Tetraedge

View File

@ -0,0 +1,78 @@
/* 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 TETRAEDGE_TE_TE_I_FONT_H
#define TETRAEDGE_TE_TE_I_FONT_H
#include "common/str.h"
#include "graphics/font.h"
#include "tetraedge/te/te_color.h"
#include "tetraedge/te/te_image.h"
#include "tetraedge/te/te_resource.h"
#include "tetraedge/te/te_vector3f32.h"
namespace Tetraedge {
/**
* A wrapper to provide a TeFont-like interface using ScummVM'S font class.
*/
class TeIFont : public TeResource {
public:
enum AlignStyle {
AlignLeft,
AlignRight,
AlignJustify,
AlignCenter
};
struct GlyphData {
uint32 _charcode;
Common::Rect _bitmapSize;
TeIntrusivePtr<TeImage> _img;
};
TeIFont();
virtual ~TeIFont();
virtual Graphics::Font *getAtSize(uint size) = 0;
virtual float ascender(uint pxSize);
virtual float descender(uint pxSize);
virtual float height(uint pxSize);
virtual TeVector3f32 kerning(uint pxSize, uint isocode1, uint isocode2);
virtual void draw(TeImage &destImage, const Common::String &str, int fontSize, int yoff, const TeColor &col, AlignStyle alignMode);
virtual Common::Rect getBoundingBox(const Common::String &str, int fontSize);
virtual int getHeight(int fontSize);
virtual int wordWrapText(const Common::String &str, int fontSize, int maxWidth, Common::Array<Common::String> &lines);
virtual TeIFont::GlyphData glyph(uint pxSize, uint charcode);
protected:
Common::CodePage _codePage;
private:
Common::CodePage codePage() const;
};
} // end namespace Tetraedge
#endif // TETRAEDGE_TE_TE_I_FONT_H

View File

@ -27,7 +27,7 @@
namespace Tetraedge {
TePng::TePng(const Common::String &extn) {
TePng::TePng(const Common::String &extn) : _height(0) {
if (extn == "png#anim") {
_nbFrames = 8;
_frameRate = 8.0f;
@ -63,6 +63,9 @@ bool TePng::load(Common::SeekableReadStream &stream) {
return false;
_loadedSurface = png.getSurface()->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 0, 8, 16, 24));
_height = _loadedSurface->h;
return true;
}

View File

@ -30,7 +30,7 @@
namespace Tetraedge {
TeTextBase2::TeTextBase2() : _drawRect(0, 0), _size(0, 0),
_alignStyle(TeFont3::AlignLeft), _interLine(0.0f), _globalColor(0xff, 0xff, 0xff, 0xff),
_alignStyle(TeIFont::AlignLeft), _interLine(0.0f), _globalColor(0xff, 0xff, 0xff, 0xff),
_wrapMode(WrapModeFixed), _strikethrough(false), _fontSize(10), _valueWasSet(true) {
_mesh = TeMesh::makeInstance();
_mesh->setglTexEnvBlend();
@ -49,7 +49,7 @@ void TeTextBase2::build() {
if (!_text.size() || !_fontSize)
return;
TeIntrusivePtr<TeFont3> font = _fonts[0];
TeIntrusivePtr<TeIFont> font = _fonts[0];
if (!font.get()) {
warning("[TeTextBase2::build()] Warning : font missing");
return;
@ -78,7 +78,7 @@ void TeTextBase2::build() {
float lineHeight = font->getHeight(_fontSize);
float height = 0;
for (const Common::String &line : _wrappedLines) {
if (_alignStyle == TeFont3::AlignJustify) {
if (_alignStyle == TeIFont::AlignJustify) {
warning("TODO: Implement TeTextBase2::computeNbSpaces for Justify");
//computeNbSpaces(&line, offset, line.endOffset);
}
@ -185,11 +185,11 @@ TeColor TeTextBase2::currentColor(uint offset) const {
return result;
}
TeIntrusivePtr<TeFont3> TeTextBase2::currentFont(uint offset) {
TeIntrusivePtr<TeIFont> TeTextBase2::currentFont(uint offset) {
if (_fonts.size() == 0)
return TeIntrusivePtr<TeFont3>();
return TeIntrusivePtr<TeIFont>();
int closest_off = -1;
TeIntrusivePtr<TeFont3> result;
TeIntrusivePtr<TeIFont> result;
// Find closest without going over.
for (auto &pair : _fonts) {
if ((int)pair._key > closest_off && pair._key <= offset) {
@ -198,7 +198,7 @@ TeIntrusivePtr<TeFont3> TeTextBase2::currentFont(uint offset) {
}
}
if (closest_off == -1)
return TeIntrusivePtr<TeFont3>();
return TeIntrusivePtr<TeIFont>();
return result;
}
@ -220,7 +220,7 @@ void TeTextBase2::drawEmptyChar(uint offset) {
}
void TeTextBase2::drawLine(TeImage &img, const Common::String &str, int yoffset) {
TeIntrusivePtr<TeFont3> font = _fonts[0];
TeIntrusivePtr<TeIFont> font = _fonts[0];
// Note: We draw this with black because the global color will be applied on
// the mesh.
@ -257,7 +257,7 @@ int TeTextBase2::nextNonSpaceChar(uint offset) {
return offset; // TODO: or offset - 1?
}
void TeTextBase2::setAlignStyle(TeFont3::AlignStyle style) {
void TeTextBase2::setAlignStyle(TeIFont::AlignStyle style) {
_alignStyle = style;
_valueWasSet = true;
}
@ -267,7 +267,7 @@ void TeTextBase2::setColor(uint offset, const TeColor &color) {
_valueWasSet = true;
}
void TeTextBase2::setFont(uint offset, const TeIntrusivePtr<TeFont3> &newfont) {
void TeTextBase2::setFont(uint offset, const TeIntrusivePtr<TeIFont> &newfont) {
_fonts.setVal(offset, newfont);
_valueWasSet = true;
}

View File

@ -26,8 +26,8 @@
#include "common/hashmap.h"
#include "tetraedge/te/te_color.h"
#include "tetraedge/te/te_font3.h"
#include "tetraedge/te/te_intrusive_ptr.h"
#include "tetraedge/te/te_i_font.h"
#include "tetraedge/te/te_mesh.h"
#include "tetraedge/te/te_vector2s32.h"
@ -56,16 +56,16 @@ public:
void clearText();
TeColor currentColor(uint offset) const;
TeIntrusivePtr<TeFont3> currentFont(uint offset);
TeIntrusivePtr<TeIFont> currentFont(uint offset);
void draw();
uint endOfWord(uint i) const;
void insertNewLine(uint offset);
bool isASpace(uint offset) const;
int newLines(uint offset) const;
int nextNonSpaceChar(uint start);
void setAlignStyle(TeFont3::AlignStyle style);
void setAlignStyle(TeIFont::AlignStyle style);
void setColor(uint offset, const TeColor &color);
void setFont(uint offset, const TeIntrusivePtr<TeFont3> &newfont);
void setFont(uint offset, const TeIntrusivePtr<TeIFont> &newfont);
void setFontSize(int fontSz);
void setGlobalColor(const TeColor &color);
void setInterLine(float val);
@ -84,7 +84,7 @@ private:
void drawEmptyChar(uint offset);
void drawLine(TeImage &img, const Common::String &str, int yoffset);
TeFont3::AlignStyle _alignStyle;
TeIFont::AlignStyle _alignStyle;
WrapMode _wrapMode;
int _fontSize;
bool _valueWasSet;
@ -101,7 +101,7 @@ private:
Common::Array<uint32> _lineBreaks;
Common::HashMap<uint, TeColor> _colors;
Common::HashMap<uint, TeIntrusivePtr<TeFont3>> _fonts;
Common::HashMap<uint, TeIntrusivePtr<TeIFont>> _fonts;
};
} // end namespace Tetraedge

View File

@ -26,6 +26,8 @@
#include "tetraedge/te/te_renderer.h"
#include "tetraedge/te/te_text_layout.h"
#include "tetraedge/te/te_text_layout_xml_parser.h"
#include "tetraedge/te/te_font3.h"
#include "tetraedge/te/te_font2.h"
namespace Tetraedge {
@ -55,17 +57,17 @@ void TeTextLayout::draw() {
}
static TeFont3::AlignStyle _alignNameToEnum(const Common::String &name) {
static TeIFont::AlignStyle _alignNameToEnum(const Common::String &name) {
if (name == "left")
return TeFont3::AlignLeft;
return TeIFont::AlignLeft;
else if (name == "right")
return TeFont3::AlignRight;
return TeIFont::AlignRight;
else if (name == "justify")
return TeFont3::AlignJustify;
return TeIFont::AlignJustify;
else if (name =="center")
return TeFont3::AlignCenter;
return TeIFont::AlignCenter;
warning("Unknown text align style: %s", name.c_str());
return TeFont3::AlignLeft;
return TeIFont::AlignLeft;
}
void TeTextLayout::setText(const Common::String &val) {
@ -116,10 +118,14 @@ void TeTextLayout::setText(const Common::String &val) {
if (parser.fontSize())
_baseFontSize = parser.fontSize();
if (parser.fontFile().size()) {
if (!parser.fontFile().empty()) {
Common::Path fontPath(parser.fontFile());
Common::FSNode fontNode = g_engine->getCore()->findFile(fontPath);
TeIntrusivePtr<TeFont3> font = g_engine->getResourceManager()->getResource<TeFont3>(fontNode);
TeIntrusivePtr<TeIFont> font;
if (parser.fontFile().hasSuffixIgnoreCase(".ttf"))
font = g_engine->getResourceManager()->getResource<TeFont3>(fontNode).get();
else
font = g_engine->getResourceManager()->getResource<TeFont2>(fontNode).get();
//font->load(fontPath); // lazy load this later.
_base.setFont(0, font);
}

View File

@ -34,7 +34,12 @@ bool TeTextLayoutXmlParser::parserCallback_color(ParserNode *node) {
bool TeTextLayoutXmlParser::parserCallback_font(ParserNode *node) {
_fontFile = node->values["file"];
_fontSize = node->values["size"].asUint64();
if (node->values.contains("size"))
_fontSize = node->values["size"].asUint64();
else {
warning("default font size to 16");
_fontSize = 16;
}
return true;
}

View File

@ -46,7 +46,7 @@ public:
KEY_END()
XML_KEY(font)
XML_PROP(file, true)
XML_PROP(size, true)
XML_PROP(size, false)
KEY_END()
XML_KEY(br)
KEY_END()

View File

@ -612,6 +612,8 @@ void TeWarp::takeObject(const Common::String &name) {
}
void TeWarp::unload() {
// Not done in original but can happen if user clicks really fast.
g_engine->getInputMgr()->_mouseLDownSignal.remove(this, &TeWarp::onMouseLeftDown);
unloadTextures();
_xCount = 0;
_yCount = 0;