FIFE  2008.0
 All Classes Namespaces Functions Variables Enumerations Enumerator Pages
fontbase.cpp
1 /***************************************************************************
2  * Copyright (C) 2005-2008 by the FIFE team *
3  * http://www.fifengine.de *
4  * This file is part of FIFE. *
5  * *
6  * FIFE is free software; you can redistribute it and/or *
7  * modify it under the terms of the GNU Lesser General Public *
8  * License as published by the Free Software Foundation; either *
9  * version 2.1 of the License, or (at your option) any later version. *
10  * *
11  * This library is distributed in the hope that it will be useful, *
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14  * Lesser General Public License for more details. *
15  * *
16  * You should have received a copy of the GNU Lesser General Public *
17  * License along with this library; if not, write to the *
18  * Free Software Foundation, Inc., *
19  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
20  ***************************************************************************/
21 
22 // Standard C++ library includes
23 #include <vector>
24 
25 // Platform specific includes
26 
27 // 3rd party library includes
28 #include <boost/filesystem/convenience.hpp>
29 
30 // FIFE includes
31 // These includes are split up in two parts, separated by one empty line
32 // First block: files included from the FIFE root src directory
33 // Second block: files included from the same folder
34 #include "util/structures/rect.h"
35 #include "util/base/exception.h"
36 #include "util/utf8/utf8.h"
37 #include "video/image.h"
38 #include "video/renderbackend.h"
39 
40 #include "fontbase.h"
41 
42 namespace FIFE {
43 
44  FontBase::FontBase():
45  m_pool(),
46  mColor(),
47  mGlyphSpacing(0),
48  mRowSpacing(0),
49  mFilename(""),
50  m_antiAlias(true) {
51  }
52 
53  void FontBase::invalidate() {
54  m_pool.invalidateCachedText();
55  }
56 
57  void FontBase::setRowSpacing(int spacing) {
58  mRowSpacing = spacing;
59  }
60 
62  return mRowSpacing;
63  }
64 
65  void FontBase::setGlyphSpacing(int spacing) {
66  mGlyphSpacing = spacing;
67  }
68 
70  return mGlyphSpacing;
71  }
72 
73  void FontBase::setAntiAlias(bool antiAlias) {
74  m_antiAlias = antiAlias;
75  }
76 
78  return m_antiAlias;
79  }
80 
81  SDL_Color FontBase::getColor() const {
82  return mColor;
83  }
84 
85  int FontBase::getStringIndexAt(const std::string &text, int x) const {
86  assert( utf8::is_valid(text.begin(), text.end()) );
87  std::string::const_iterator cur;
88  if (text.size() == 0) return 0;
89  if (x <= 0) return 0;
90 
91  cur = text.begin();
92 
93  utf8::next(cur, text.end());
94 
95  std::string buff;
96  while(cur != text.end()) {
97  buff = std::string(text.begin(), cur);
98 
99  if (getWidth(buff) > x) {
100  return buff.size();
101  } else {
102  utf8::next(cur, text.end());
103  }
104  }
105 
106  if (x > getWidth(text)) {
107  return text.size();
108  } else {
109  return buff.size();
110  }
111  }
112 
113  Image* FontBase::getAsImage(const std::string& text) {
114  Image* image = m_pool.getRenderedText(this, text);
115  if (!image) {
116  SDL_Surface* textSurface = renderString(text);
117  image = RenderBackend::instance()->createImage(textSurface);
118  m_pool.addRenderedText( this, text, image );
119  }
120  return image;
121  }
122 
123  Image* FontBase::getAsImageMultiline(const std::string& text) {
124  const uint8_t newline_utf8 = '\n';
125  uint32_t newline;
126  utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline);
127  //std::cout << "Text:" << text << std::endl;
128  Image* image = m_pool.getRenderedText(this, text);
129  if (!image) {
130  std::vector<SDL_Surface*> lines;
131  std::string::const_iterator it = text.begin();
132  // split text as needed
133  int render_width = 0, render_height = 0;
134  do {
135  uint32_t codepoint = 0;
136  std::string line;
137  while( codepoint != newline && it != text.end() )
138  {
139  codepoint = utf8::next(it,text.end());
140  if( codepoint != newline )
141  utf8::append(codepoint, back_inserter(line));
142  }
143  //std::cout << "Line:" << line << std::endl;
144  SDL_Surface* text_surface = renderString(line);
145  if (text_surface->w > render_width) {
146  render_width = text_surface->w;
147  }
148  lines.push_back(text_surface);
149  } while (it != text.end());
150 
151  render_height = (getRowSpacing() + getHeight()) * lines.size();
152  SDL_Surface* final_surface = SDL_CreateRGBSurface(SDL_SWSURFACE,
153  render_width,render_height,32,
154  RMASK, GMASK, BMASK ,AMASK);
155  if (!final_surface) {
156  throw SDLException(std::string("CreateRGBSurface failed: ") + SDL_GetError());
157  }
158  SDL_FillRect(final_surface, 0, 0x00000000);
159  int ypos = 0;
160  for (std::vector<SDL_Surface*>::iterator i = lines.begin(); i != lines.end(); ++i) {
161  SDL_Rect dst_rect = { 0, 0, 0, 0 };
162  dst_rect.y = ypos;
163 
164  SDL_SetAlpha(*i,0,SDL_ALPHA_OPAQUE);
165  SDL_BlitSurface(*i,0,final_surface,&dst_rect);
166  ypos += getRowSpacing() + getHeight();
167  SDL_FreeSurface(*i);
168  }
169  image = RenderBackend::instance()->createImage(final_surface);
170  m_pool.addRenderedText(this, text, image);
171  }
172  return image;
173  }
174 
175  std::string FontBase::splitTextToWidth (const std::string& text, int render_width) {
176  const uint32_t whitespace = ' ';
177  const uint8_t newline_utf8 = '\n';
178  uint32_t newline;
179  utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline);
180  if (render_width <= 0 || text.empty()) {
181  return text;
182  }
183  std::string output;
184  std::string line;
185  std::string::const_iterator pos = text.begin();
186  std::list<std::pair<size_t,std::string::const_iterator> > break_pos;
187  bool firstLine = true;
188 
189  while( pos != text.end())
190  {
191  break_pos.clear();
192  if( !firstLine ) {
193  line = "\n";
194  } else {
195  firstLine = false;
196  }
197 
198  bool haveNewLine = false;
199  while( getWidth(line) < render_width && pos != text.end() )
200  {
201  uint32_t codepoint = utf8::next(pos, text.end());
202  if (codepoint == whitespace && !line.empty())
203  break_pos.push_back( std::make_pair(line.length(),pos) );
204 
205  if( codepoint != newline )
206  utf8::append(codepoint, back_inserter(line) );
207 
208  // Special case: Already newlines in string:
209  if( codepoint == newline ) {
210  output.append(line);
211  line = "";
212  haveNewLine = true;
213  break;
214  }
215  }
216  if( haveNewLine )
217  continue;
218 
219  if( pos == text.end() )
220  break;
221 
222  if( break_pos.empty() ) {
223  // No break position and line length smaller than 2
224  // means the renderwidth is really screwed. Just continue
225  // appending single character lines.
226  if( utf8::distance(line.begin(),line.end()) <= 1 && line != "\n") {
227  output.append(line);
228  continue;
229  }
230 
231  if (line == "\n") {
232  ++pos;
233  }
234 
235  // We can't do hyphenation here,
236  // so we just retreat one character :-(
237  // FIXME
238  //line = line.erase(line.length() - 1);
239  //--pos;
240  } else {
241  line = line.substr(0,break_pos.back().first);
242  pos = break_pos.back().second;
243  }
244  output.append(line);
245  }
246  if( !line.empty() ) {
247  output.append(line);
248  }
249  return output;
250  }
251 }