xoreos  0.0.5
ttffont.cpp
Go to the documentation of this file.
1 /* xoreos - A reimplementation of BioWare's Aurora engine
2  *
3  * xoreos is the legal property of its developers, whose names
4  * can be found in the AUTHORS file distributed with this source
5  * distribution.
6  *
7  * xoreos 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 3
10  * of the License, or (at your option) any later version.
11  *
12  * xoreos 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 xoreos. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
25 #include <cassert>
26 
27 #include "src/common/util.h"
28 #include "src/common/error.h"
29 #include "src/common/ustring.h"
30 
31 #include "src/aurora/resman.h"
32 
33 #include "src/graphics/texture.h"
34 #include "src/graphics/ttf.h"
35 
37 
41 
42 static const uint32 kPageWidth = 256;
43 static const uint32 kPageHeight = 256;
44 
45 namespace Graphics {
46 
47 namespace Aurora {
48 
49 TTFFont::Page::Page() : needRebuild(false),
50  curX(0), curY(0), heightLeft(kPageHeight), widthLeft(kPageWidth) {
51 
53  surface->fill(0x00, 0x00, 0x00, 0x00);
54 
56 }
57 
59  if (!needRebuild)
60  return;
61 
62  texture.getTexture().rebuild();
63  needRebuild = false;
64 }
65 
66 
68  load(ttf, height);
69 }
70 
71 TTFFont::TTFFont(const Common::UString &name, int height) {
72  Common::SeekableReadStream *ttf = ResMan.getResource(name, ::Aurora::kFileTypeTTF);
73  if (!ttf)
74  throw Common::Exception("No such font \"%s\"", name.c_str());
75 
76  load(ttf, height);
77 }
78 
80 }
81 
82 void TTFFont::load(Common::SeekableReadStream *ttf, int height) {
84 
85  _ttf.reset(new TTFRenderer(*ttfStream, height));
86 
87  _height = _ttf->getHeight();
88  if (_height > kPageHeight)
89  throw Common::Exception("Font height too big (%d)", _height);
90 
91  // Add all ASCII characters
92  for (uint32 i = 0; i < 128; i++)
93  addChar(i);
94 
95  // Add the Unicode "replacement character" character
96  addChar(0xFFFD);
97  _missingChar = _chars.find(0xFFFD);
98 
99  // Find an appropriate width for a "missing character" character
100  if (_missingChar == _chars.end()) {
101  // This font doesn't have the Unicode "replacement character"
102 
103  // Try to find the width of an m. Alternatively, take half of a line's height.
104  std::map<uint32, Char>::const_iterator m = _chars.find('m');
105  if (m != _chars.end())
106  _missingWidth = m->second.width;
107  else
108  _missingWidth = MAX<float>(2.0f, _height / 2);
109 
110  } else
111  _missingWidth = _missingChar->second.width;
112 
113  rebuildPages();
114 }
115 
116 float TTFFont::getWidth(uint32 c) const {
117  std::map<uint32, Char>::const_iterator cC = _chars.find(c);
118  if (cC == _chars.end())
119  return _missingWidth;
120 
121  return cC->second.width;
122 }
123 
124 float TTFFont::getHeight() const {
125  return _height;
126 }
127 
128 void TTFFont::drawMissing() const {
129  TextureMan.set();
130 
131  const float width = _missingWidth - 1.0f;
132 
133  glBegin(GL_QUADS);
134  glVertex2f(0.0f , 0.0f);
135  glVertex2f(width, 0.0f);
136  glVertex2f(width, _height);
137  glVertex2f(0.0f , _height);
138  glEnd();
139 
140  glTranslatef(width + 1.0f, 0.0f, 0.0f);
141 }
142 
143 void TTFFont::draw(uint32 c) const {
144  std::map<uint32, Char>::const_iterator cC = _chars.find(c);
145  if (cC == _chars.end()) {
146  cC = _missingChar;
147 
148  if (cC == _chars.end()) {
149  drawMissing();
150  return;
151  }
152  }
153 
154  size_t page = cC->second.page;
155  assert(page < _pages.size());
156 
157  TextureMan.set(_pages[page]->texture);
158 
159  glBegin(GL_QUADS);
160  for (int i = 0; i < 4; i++) {
161  glTexCoord2f(cC->second.tX[i], cC->second.tY[i]);
162  glVertex2f (cC->second.vX[i], cC->second.vY[i]);
163  }
164  glEnd();
165 
166  glTranslatef(cC->second.width, 0.0f, 0.0f);
167 }
168 
170  for (Common::UString::iterator c = str.begin(); c != str.end(); ++c)
171  addChar(*c);
172 
173  rebuildPages();
174 }
175 
177  for (std::vector<Page *>::iterator p = _pages.begin(); p != _pages.end(); ++p)
178  (*p)->rebuild();
179 }
180 
182  std::map<uint32, Char>::iterator cC = _chars.find(c);
183  if (cC != _chars.end())
184  return;
185 
186  if (!_ttf->hasChar(c))
187  return;
188 
189  try {
190 
191  uint32 cWidth = _ttf->getCharWidth(c);
192  if (cWidth > kPageWidth)
193  return;
194 
195  if (_pages.empty()) {
196  _pages.push_back(new Page);
197  _pages.back()->heightLeft -= _height;
198  }
199 
200  if (_pages.back()->widthLeft < cWidth) {
201  // The current character doesn't fit into the current line
202 
203  if (_pages.back()->heightLeft >= _height) {
204  // Create a new line
205 
206  _pages.back()->curX = 0;
207  _pages.back()->curY += _height;
208 
209  _pages.back()->heightLeft -= _height;
210  _pages.back()->widthLeft = kPageWidth;
211 
212  } else {
213  // Create a new page
214 
215  _pages.push_back(new Page);
216  _pages.back()->heightLeft -= _height;
217  }
218 
219  }
220 
221  _ttf->drawCharacter(c, *_pages.back()->surface, _pages.back()->curX, _pages.back()->curY);
222 
223  std::pair<std::map<uint32, Char>::iterator, bool> result;
224 
225  result = _chars.insert(std::make_pair(c, Char()));
226 
227  cC = result.first;
228 
229  Char &ch = cC->second;
230  Page &page = *_pages.back();
231 
232  ch.width = cWidth;
233  ch.page = _pages.size() - 1;
234 
235  ch.vX[0] = 0.00f; ch.vY[0] = 0.00f;
236  ch.vX[1] = cWidth; ch.vY[1] = 0.00f;
237  ch.vX[2] = cWidth; ch.vY[2] = _height;
238  ch.vX[3] = 0.00f; ch.vY[3] = _height;
239 
240  const float tX = (float) page.curX / (float) kPageWidth;
241  const float tY = (float) page.curY / (float) kPageHeight;
242  const float tW = (float) cWidth / (float) kPageWidth;
243  const float tH = (float) _height / (float) kPageHeight;
244 
245  ch.tX[0] = tX; ch.tY[0] = tY + tH;
246  ch.tX[1] = tX + tW; ch.tY[1] = tY + tH;
247  ch.tX[2] = tX + tW; ch.tY[2] = tY;
248  ch.tX[3] = tX; ch.tY[3] = tY;
249 
250  _pages.back()->widthLeft -= cWidth;
251  _pages.back()->curX += cWidth;
252  _pages.back()->needRebuild = true;
253 
254  } catch (...) {
255  if (cC != _chars.end())
256  _chars.erase(cC);
257 
259  }
260 }
261 
262 } // End of namespace Aurora
263 
264 } // End of namespace Graphics
#define ResMan
Shortcut for accessing the sound manager.
Definition: resman.h:557
A texture page filled with characters.
Definition: ttffont.h:65
A class holding an UTF-8 string.
Definition: ustring.h:48
#define TextureMan
Shortcut for accessing the texture manager.
Definition: textureman.h:127
A TrueType font.
static Texture * create(const Common::UString &name, bool deswizzle=false)
Create a texture from this image resource.
Definition: texture.cpp:323
The Aurora texture manager.
void fill(byte r, byte g, byte b, byte a)
Definition: surface.cpp:69
A simple TTF renderer outputting BGRA.
Common::ScopedPtr< TTFRenderer > _ttf
Definition: ttffont.h:93
iterator begin() const
Definition: ustring.cpp:253
static const uint32 kPageWidth
Definition: ttffont.cpp:42
void buildChars(const Common::UString &str)
Build all necessary characters to display this string.
Definition: ttffont.cpp:169
Virtual base class of a texture.
float getHeight() const
Return the height of a character.
Definition: ttffont.cpp:124
void exceptionDispatcherWarning(const char *s,...)
Exception dispatcher that prints the exception as a warning, and adds another reason on top...
Definition: error.cpp:158
Basic exceptions to throw.
utf8::iterator< std::string::const_iterator > iterator
Definition: ustring.h:50
const char * c_str() const
Return the (utf8 encoded) string data.
Definition: ustring.cpp:249
Utility templates and functions.
float getWidth(uint32 c) const
Return the width of a character.
Definition: ttffont.cpp:116
void draw(uint32 c) const
Draw this character.
Definition: ttffont.cpp:143
Font, True Type.
Definition: types.h:138
StackException Exception
Definition: error.h:59
TTFFont(Common::SeekableReadStream *ttf, int height)
Definition: ttffont.cpp:67
void addChar(uint32 c)
Definition: ttffont.cpp:181
Unicode string handling.
An image surface, in BGRA format.
A texture as used in the Aurora engines.
uint32_t uint32
Definition: types.h:204
void drawMissing() const
Definition: ttffont.cpp:128
std::map< uint32, Char >::const_iterator _missingChar
Definition: ttffont.h:98
A font character.
Definition: ttffont.h:83
Common::PtrVector< Page > _pages
Definition: ttffont.h:95
iterator end() const
Definition: ustring.cpp:257
void load(Common::SeekableReadStream *ttf, int height)
Definition: ttffont.cpp:82
std::map< uint32, Char > _chars
Definition: ttffont.h:96
static const uint32 kPageHeight
Definition: ttffont.cpp:43
Interface for a seekable & readable data stream.
Definition: readstream.h:265
The global resource manager for Aurora resources.