1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "mutationofjb/font.h"
24 #include "mutationofjb/encryptedfile.h"
25 #include "mutationofjb/util.h"
26 #include "common/debug.h"
27
28 namespace MutationOfJB {
29
Font(const Common::String & fileName,int horizSpacing,int lineHeight)30 Font::Font(const Common::String &fileName, int horizSpacing, int lineHeight) :
31 _horizSpacing(horizSpacing),
32 _lineHeight(lineHeight),
33 _maxCharWidth(0) {
34
35 load(fileName);
36 }
37
load(const Common::String & fileName)38 bool Font::load(const Common::String &fileName) {
39 EncryptedFile file;
40 file.open(fileName);
41 if (!file.isOpen()) {
42 reportFileMissingError(fileName.c_str());
43 return false;
44 }
45
46 file.seek(0x02D6, SEEK_SET); // Skip header + unknown data (unused palette?).
47
48 uint16 noGlyphs = 0;
49 noGlyphs = file.readUint16LE();
50
51 file.seek(7, SEEK_CUR); // Skip unknown data (0s).
52
53 uint8 maxHeight = 0;
54
55 while (noGlyphs--) {
56 const uint8 character = file.readByte();
57 const uint8 width = file.readByte();
58 const uint8 height = file.readByte();
59
60 Graphics::ManagedSurface &surf = _glyphs[character];
61 surf.create(width, height);
62 for (int h = 0; h < height; ++h) {
63 file.read(surf.getBasePtr(0, h), width);
64 }
65
66 if (width > _maxCharWidth) {
67 _maxCharWidth = width;
68 }
69
70 if (height > maxHeight) {
71 maxHeight = height;
72 }
73 }
74
75 if (_lineHeight == -1) {
76 _lineHeight = maxHeight;
77 }
78
79 return true;
80 }
81
getFontHeight() const82 int Font::getFontHeight() const {
83 return _lineHeight;
84 }
85
getMaxCharWidth() const86 int Font::getMaxCharWidth() const {
87 return _maxCharWidth;
88 }
89
getCharWidth(uint32 chr) const90 int Font::getCharWidth(uint32 chr) const {
91 GlyphMap::iterator it = _glyphs.find(chr);
92 if (it == _glyphs.end()) {
93 return 0;
94 }
95 return it->_value.w;
96 }
97
getKerningOffset(uint32 left,uint32 right) const98 int Font::getKerningOffset(uint32 left, uint32 right) const {
99 if (left == 0) {
100 // Do not displace the first character.
101 return 0;
102 }
103
104 if (_glyphs.find(left) == _glyphs.end()) {
105 // Missing glyphs must not create extra displacement.
106 // FIXME: This way is not completely correct, as if the last character is
107 // missing a glyph, it will still create extra displacement. This should
108 // not affect the visuals but it might affect getStringWidth() / getBoundingBox().
109 return 0;
110 }
111
112 return _horizSpacing;
113 }
114
115 class FontBlitOperation {
116 public:
FontBlitOperation(const Font & font,const byte baseColor)117 FontBlitOperation(const Font &font, const byte baseColor)
118 : _font(font),
119 _baseColor(baseColor) {}
120
operator ()(const byte srcColor,const byte destColor)121 byte operator()(const byte srcColor, const byte destColor) {
122 if (srcColor == 0) {
123 // Transparency - keep destination color.
124 return destColor;
125 }
126
127 // Replace destination with transformed source color.
128 return _font.transformColor(_baseColor, srcColor);
129 }
130
131 private:
132 const Font &_font;
133 const byte _baseColor;
134 };
135
drawChar(Graphics::Surface * dst,uint32 chr,int x,int y,uint32 color) const136 void Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
137 GlyphMap::iterator it = _glyphs.find(chr);
138 if (it == _glyphs.end()) {
139 // Missing glyph is a common situation in the game and it's okay to ignore it.
140 return;
141 }
142
143 Graphics::ManagedSurface &glyphSurface = it->_value;
144 blit_if(glyphSurface, *dst, Common::Point(x, y), FontBlitOperation(*this, color));
145 }
146
transformColor(uint8 baseColor,uint8 glyphColor) const147 uint8 Font::transformColor(uint8 baseColor, uint8 glyphColor) const {
148 return baseColor + glyphColor - 0x10;
149 }
150
SystemFont()151 SystemFont::SystemFont() : Font("sysfnt.aft", 1, 7) {}
152
SpeechFont()153 SpeechFont::SpeechFont() : Font("font1.aft", -1, -1) {}
154
transformColor(uint8 baseColor,uint8 glyphColor) const155 uint8 SpeechFont::transformColor(uint8 baseColor, uint8 glyphColor) const {
156 // Hack in original game.
157 if (glyphColor == 0x11) {
158 return 0xC0;
159 }
160
161 return Font::transformColor(baseColor, glyphColor);
162 }
163
164 }
165