#include <font.hpp>
Public Types | |
enum | GlyphWidth { FIXED, VARIABLE } |
Public Member Functions | |
Font (GlyphWidth glyph_width, const std::string &fontfile, int shadowsize=2) | |
Construct a fixed-width font. | |
~Font () | |
float | get_text_width (const std::string &text) const |
returns the width of a given text. | |
float | get_text_height (const std::string &text) const |
returns the height of a given text. | |
float | get_height () const |
returns the height of the font. | |
std::string | wrap_to_width (const std::string &text, float width, std::string *overflow) |
returns the given string, truncated (preferably at whitespace) to be at most "width" pixels wide | |
void | draw (Renderer *renderer, const std::string &text, const Vector &pos, FontAlignment alignment=ALIGN_LEFT, DrawingEffect drawing_effect=NO_EFFECT, Color color=Color(1.0, 1.0, 1.0), float alpha=1.0f) const |
Draws the given text to the screen. | |
Static Public Member Functions | |
static std::string | wrap_to_chars (const std::string &text, int max_chars, std::string *overflow) |
returns the given string, truncated (preferably at whitespace) to be at most max_chars characters long | |
Private Member Functions | |
void | draw_text (Renderer *renderer, const std::string &text, const Vector &pos, DrawingEffect drawing_effect=NO_EFFECT, Color color=Color(1.0, 1.0, 1.0), float alpha=1.0f) const |
void | draw_chars (Renderer *renderer, bool nonshadow, const std::string &text, const Vector &position, DrawingEffect drawing_effect, Color color, float alpha) const |
void | loadFontFile (const std::string &filename) |
void | loadFontSurface (const std::string &glyphimage, const std::string &shadowimage, const std::vector< std::string > &chars, GlyphWidth glyph_width, int char_width) |
Private Attributes | |
GlyphWidth | glyph_width |
std::vector< SurfacePtr > | glyph_surfaces |
std::vector< SurfacePtr > | shadow_surfaces |
int | char_height |
int | shadowsize |
std::vector< Glyph > | glyphs |
65536 of glyphs | |
Friends | |
class | DrawingContext |
Classes | |
struct | Glyph |
Definition at line 38 of file font.hpp.
enum Font::GlyphWidth |
Font::Font | ( | GlyphWidth | glyph_width, | |
const std::string & | fontfile, | |||
int | shadowsize = 2 | |||
) |
Construct a fixed-width font.
glyph_width | VARIABLE for proportional fonts, VARIABLE for monospace ones | |
fontfile | file in format supertux-font | |
sgadowsize | offset of shadow |
Definition at line 57 of file font.cpp.
References FileSystem::basename(), FileSystem::dirname(), glyphs, and loadFontFile().
00059 : 00060 glyph_width(glyph_width_), 00061 glyph_surfaces(), 00062 shadow_surfaces(), 00063 char_height(), 00064 shadowsize(shadowsize_), 00065 glyphs(65536) 00066 { 00067 for(unsigned int i=0; i<65536;i++) glyphs[i].surface_idx = -1; 00068 00069 const std::string fontdir = FileSystem::dirname(filename); 00070 const std::string fontname = FileSystem::basename(filename); 00071 00072 // scan for prefix-filename in addons search path 00073 char **rc = PHYSFS_enumerateFiles(fontdir.c_str()); 00074 for (char **i = rc; *i != NULL; i++) { 00075 std::string filename(*i); 00076 if( filename.rfind(fontname) != std::string::npos ) { 00077 loadFontFile(fontdir + filename); 00078 } 00079 } 00080 PHYSFS_freeList(rc); 00081 }
float Font::get_text_width | ( | const std::string & | text | ) | const |
returns the width of a given text.
(Note that I won't add a normal get_width function here, as we might switch to variable width fonts in the future.) Supports breaklines.
Definition at line 249 of file font.cpp.
References glyphs.
Referenced by draw(), and wrap_to_width().
00250 { 00251 float curr_width = 0; 00252 float last_width = 0; 00253 00254 for(UTF8Iterator it(text); !it.done(); ++it) 00255 { 00256 if (*it == '\n') 00257 { 00258 last_width = std::max(last_width, curr_width); 00259 curr_width = 0; 00260 } 00261 else 00262 { 00263 if( glyphs.at(*it).surface_idx != -1 ) 00264 curr_width += glyphs[*it].advance; 00265 else 00266 curr_width += glyphs[0x20].advance; 00267 } 00268 } 00269 00270 return std::max(curr_width, last_width); 00271 }
float Font::get_text_height | ( | const std::string & | text | ) | const |
returns the height of a given text.
This function supports breaklines. In case, you are positive that your text doesn't use break lines, you can just use get_height().
Definition at line 274 of file font.cpp.
References char_height.
00275 { 00276 std::string::size_type text_height = char_height; 00277 00278 for(std::string::const_iterator it = text.begin(); it != text.end(); ++it) 00279 { // since UTF8 multibyte characters are decoded with values 00280 // outside the ASCII range there is no risk of overlapping and 00281 // thus we don't need to decode the utf-8 string 00282 if (*it == '\n') 00283 text_height += char_height + 2; 00284 } 00285 00286 return text_height; 00287 }
float Font::get_height | ( | ) | const |
returns the height of the font.
Definition at line 290 of file font.cpp.
References char_height.
00291 { 00292 return char_height; 00293 }
std::string Font::wrap_to_chars | ( | const std::string & | text, | |
int | max_chars, | |||
std::string * | overflow | |||
) | [static] |
returns the given string, truncated (preferably at whitespace) to be at most max_chars characters long
Definition at line 296 of file font.cpp.
Referenced by Console::addLine().
00297 { 00298 // if text is already smaller, return full text 00299 if ((int)s.length() <= line_length) { 00300 if (overflow) *overflow = ""; 00301 return s; 00302 } 00303 00304 // if we can find a whitespace character to break at, return text up to this character 00305 int i = line_length; 00306 while ((i > 0) && (s[i] != ' ')) i--; 00307 if (i > 0) { 00308 if (overflow) *overflow = s.substr(i+1); 00309 return s.substr(0, i); 00310 } 00311 00312 // FIXME: wrap at line_length, taking care of multibyte characters 00313 if (overflow) *overflow = ""; 00314 return s; 00315 }
std::string Font::wrap_to_width | ( | const std::string & | text, | |
float | width, | |||
std::string * | overflow | |||
) |
returns the given string, truncated (preferably at whitespace) to be at most "width" pixels wide
Definition at line 318 of file font.cpp.
References get_text_width().
00319 { 00320 std::string s = s_; 00321 00322 // if text is already smaller, return full text 00323 if (get_text_width(s) <= width) { 00324 if (overflow) *overflow = ""; 00325 return s; 00326 } 00327 00328 // if we can find a whitespace character to break at, return text up to this character 00329 for (int i = s.length()-1; i >= 0; i--) { 00330 std::string s2 = s.substr(0,i); 00331 if (s[i] != ' ') continue; 00332 if (get_text_width(s2) <= width) { 00333 if (overflow) *overflow = s.substr(i+1); 00334 return s.substr(0, i); 00335 } 00336 } 00337 00338 // FIXME: hard-wrap at width, taking care of multibyte characters 00339 if (overflow) *overflow = ""; 00340 return s; 00341 }
void Font::draw | ( | Renderer * | renderer, | |
const std::string & | text, | |||
const Vector & | pos, | |||
FontAlignment | alignment = ALIGN_LEFT , |
|||
DrawingEffect | drawing_effect = NO_EFFECT , |
|||
Color | color = Color(1.0, 1.0, 1.0) , |
|||
float | alpha = 1.0f | |||
) | const |
Draws the given text to the screen.
Also needs the position. Type of alignment, drawing effect and alpha are optional.
Definition at line 344 of file font.cpp.
References ALIGN_CENTER, ALIGN_RIGHT, char_height, draw_text(), get_text_width(), Vector::x, and Vector::y.
Referenced by DrawingContext::handle_drawing_requests().
00347 { 00348 float x = pos_.x; 00349 float y = pos_.y; 00350 00351 std::string::size_type last = 0; 00352 for(std::string::size_type i = 0;; ++i) 00353 { 00354 if (text[i] == '\n' || i == text.size()) 00355 { 00356 std::string temp = text.substr(last, i - last); 00357 00358 // calculate X positions based on the alignment type 00359 Vector pos = Vector(x, y); 00360 00361 if(alignment == ALIGN_CENTER) 00362 pos.x -= get_text_width(temp) / 2; 00363 else if(alignment == ALIGN_RIGHT) 00364 pos.x -= get_text_width(temp); 00365 00366 // Cast font position to integer to get a clean drawing result and 00367 // no blurring as we would get with subpixel positions 00368 pos.x = static_cast<int>(pos.x); 00369 00370 draw_text(renderer, temp, pos, drawing_effect, color, alpha); 00371 00372 if (i == text.size()) 00373 break; 00374 00375 y += char_height + 2; 00376 last = i + 1; 00377 } 00378 } 00379 }
void Font::draw_text | ( | Renderer * | renderer, | |
const std::string & | text, | |||
const Vector & | pos, | |||
DrawingEffect | drawing_effect = NO_EFFECT , |
|||
Color | color = Color(1.0, 1.0, 1.0) , |
|||
float | alpha = 1.0f | |||
) | const [private] |
Definition at line 382 of file font.cpp.
References draw_chars(), and shadowsize.
Referenced by draw().
00384 { 00385 if(shadowsize > 0) 00386 draw_chars(renderer, false, text, 00387 pos + Vector(shadowsize, shadowsize), drawing_effect, Color(1,1,1), alpha); 00388 00389 draw_chars(renderer, true, text, pos, drawing_effect, color, alpha); 00390 }
void Font::draw_chars | ( | Renderer * | renderer, | |
bool | nonshadow, | |||
const std::string & | text, | |||
const Vector & | position, | |||
DrawingEffect | drawing_effect, | |||
Color | color, | |||
float | alpha | |||
) | const [private] |
Definition at line 393 of file font.cpp.
References Font::Glyph::advance, DrawingRequest::alpha, char_height, DrawingRequest::color, Renderer::draw_surface_part(), DrawingRequest::drawing_effect, glyph_surfaces, glyphs, Font::Glyph::offset, Rectf::p1, Rectf::p2, DrawingRequest::pos, Font::Glyph::rect, DrawingRequest::request_data, shadow_surfaces, SurfacePartRequest::size, SurfacePartRequest::source, SurfacePartRequest::surface, Font::Glyph::surface_idx, Vector::x, and Vector::y.
Referenced by draw_text().
00396 { 00397 Vector p = pos; 00398 00399 for(UTF8Iterator it(text); !it.done(); ++it) 00400 { 00401 if(*it == '\n') 00402 { 00403 p.x = pos.x; 00404 p.y += char_height + 2; 00405 } 00406 else if(*it == ' ') 00407 { 00408 p.x += glyphs[0x20].advance; 00409 } 00410 else 00411 { 00412 Glyph glyph; 00413 if( glyphs.at(*it).surface_idx != -1 ) 00414 glyph = glyphs[*it]; 00415 else 00416 glyph = glyphs[0x20]; 00417 00418 DrawingRequest request; 00419 00420 request.pos = p + glyph.offset; 00421 request.drawing_effect = drawing_effect; 00422 request.color = color; 00423 request.alpha = alpha; 00424 00425 SurfacePartRequest surfacepartrequest; 00426 surfacepartrequest.size = glyph.rect.p2 - glyph.rect.p1; 00427 surfacepartrequest.source = glyph.rect.p1; 00428 surfacepartrequest.surface = notshadow ? glyph_surfaces[glyph.surface_idx].get() : shadow_surfaces[glyph.surface_idx].get(); 00429 00430 request.request_data = &surfacepartrequest; 00431 renderer->draw_surface_part(request); 00432 00433 p.x += glyph.advance; 00434 } 00435 } 00436 }
void Font::loadFontFile | ( | const std::string & | filename | ) | [private] |
Definition at line 84 of file font.cpp.
References char_height, FIXED, lisp::Lisp::get(), lisp::Lisp::get_lisp(), glyph_width, loadFontSurface(), log_debug, log_warning, lisp::Parser::parse(), and VARIABLE.
Referenced by Font().
00085 { 00086 lisp::Parser parser; 00087 log_debug << "Loading font: " << filename << std::endl; 00088 const lisp::Lisp* root = parser.parse(filename); 00089 const lisp::Lisp* config_l = root->get_lisp("supertux-font"); 00090 00091 if(!config_l) { 00092 std::ostringstream msg; 00093 msg << "Font file:" << filename << ": is not a supertux-font file"; 00094 throw std::runtime_error(msg.str()); 00095 } 00096 00097 int def_char_width=0; 00098 00099 if( !config_l->get("glyph-width",def_char_width) ) { 00100 log_warning << "Font:"<< filename << ": misses default glyph-width" << std::endl; 00101 } 00102 00103 if( !config_l->get("glyph-height",char_height) ) { 00104 std::ostringstream msg; 00105 msg << "Font:" << filename << ": misses glyph-height"; 00106 throw std::runtime_error(msg.str()); 00107 } 00108 00109 lisp::ListIterator iter(config_l); 00110 while(iter.next()) { 00111 const std::string& token = iter.item(); 00112 if( token == "surface" ) { 00113 const lisp::Lisp * glyphs_val = iter.lisp(); 00114 int local_char_width; 00115 bool monospaced; 00116 GlyphWidth local_glyph_width; 00117 std::string glyph_image; 00118 std::string shadow_image; 00119 std::vector<std::string> chars; 00120 if( ! glyphs_val->get("glyph-width", local_char_width) ) { 00121 local_char_width = def_char_width; 00122 } 00123 if( ! glyphs_val->get("monospace", monospaced ) ) { 00124 local_glyph_width = glyph_width; 00125 } 00126 else { 00127 if( monospaced ) local_glyph_width = FIXED; 00128 else local_glyph_width = VARIABLE; 00129 } 00130 if( ! glyphs_val->get("glyphs", glyph_image) ) { 00131 std::ostringstream msg; 00132 msg << "Font:" << filename << ": missing glyphs image"; 00133 throw std::runtime_error(msg.str()); 00134 } 00135 if( ! glyphs_val->get("shadows", shadow_image) ) { 00136 std::ostringstream msg; 00137 msg << "Font:" << filename << ": missing shadows image"; 00138 throw std::runtime_error(msg.str()); 00139 } 00140 if( ! glyphs_val->get("chars", chars) || chars.size() == 0) { 00141 std::ostringstream msg; 00142 msg << "Font:" << filename << ": missing chars definition"; 00143 throw std::runtime_error(msg.str()); 00144 } 00145 00146 if( local_char_width==0 ) { 00147 std::ostringstream msg; 00148 msg << "Font:" << filename << ": misses glyph-width for some surface"; 00149 throw std::runtime_error(msg.str()); 00150 } 00151 00152 loadFontSurface(glyph_image, shadow_image, chars, 00153 local_glyph_width, local_char_width); 00154 } 00155 } 00156 }
void Font::loadFontSurface | ( | const std::string & | glyphimage, | |
const std::string & | shadowimage, | |||
const std::vector< std::string > & | chars, | |||
GlyphWidth | glyph_width, | |||
int | char_width | |||
) | [private] |
Definition at line 159 of file font.cpp.
References Font::Glyph::advance, char_height, Surface::create(), FIXED, get_physfs_SDLRWops(), glyph_surfaces, glyphs, Font::Glyph::offset, Font::Glyph::rect, shadow_surfaces, Font::Glyph::surface_idx, VARIABLE, and vline_empty().
Referenced by loadFontFile().
00166 { 00167 SurfacePtr glyph_surface = Surface::create("images/engine/fonts/" + glyphimage); 00168 SurfacePtr shadow_surface = Surface::create("images/engine/fonts/" + shadowimage); 00169 00170 int surface_idx = glyph_surfaces.size(); 00171 glyph_surfaces.push_back(glyph_surface); 00172 shadow_surfaces.push_back(shadow_surface); 00173 00174 int row=0, col=0; 00175 int wrap = glyph_surface->get_width() / char_width; 00176 00177 SDL_Surface *surface = NULL; 00178 00179 if( glyph_width == VARIABLE ) { 00180 //this does not work: 00181 // surface = ((SDL::Texture *)glyph_surface.get_texture())->get_texture(); 00182 surface = IMG_Load_RW(get_physfs_SDLRWops("images/engine/fonts/"+glyphimage), 1); 00183 if(surface == NULL) { 00184 std::ostringstream msg; 00185 msg << "Couldn't load image '" << glyphimage << "' :" << SDL_GetError(); 00186 throw std::runtime_error(msg.str()); 00187 } 00188 SDL_LockSurface(surface); 00189 } 00190 00191 for( unsigned int i = 0; i < chars.size(); i++) { 00192 for(UTF8Iterator chr(chars[i]); !chr.done(); ++chr) { 00193 int y = row * char_height; 00194 int x = col * char_width; 00195 if( ++col == wrap ) { col=0; row++; } 00196 if( *chr == 0x0020 && glyphs[0x20].surface_idx != -1) continue; 00197 00198 Glyph glyph; 00199 glyph.surface_idx = surface_idx; 00200 00201 if( glyph_width == FIXED ) 00202 { 00203 glyph.rect = Rectf(x, y, x + char_width, y + char_height); 00204 glyph.offset = Vector(0, 0); 00205 glyph.advance = char_width; 00206 } 00207 else 00208 { 00209 int left = x; 00210 while (left < x + char_width && vline_empty(surface, left, y, y + char_height, 64)) 00211 left += 1; 00212 int right = x + char_width - 1; 00213 while (right > left && vline_empty(surface, right, y, y + char_height, 64)) 00214 right -= 1; 00215 00216 if (left <= right) 00217 { 00218 glyph.offset = Vector(x-left, 0); 00219 glyph.advance = right - left + 1 + 1; // FIXME: might be useful to make spacing configurable 00220 } 00221 else 00222 { // glyph is completly transparent 00223 glyph.offset = Vector(0, 0); 00224 glyph.advance = char_width + 1; // FIXME: might be useful to make spacing configurable 00225 } 00226 00227 glyph.rect = Rectf(x, y, x + char_width, y + char_height); 00228 } 00229 00230 glyphs[*chr] = glyph; 00231 } 00232 if( col>0 && col <= wrap ) { 00233 col = 0; 00234 row++; 00235 } 00236 } 00237 00238 if( surface != NULL ) { 00239 SDL_UnlockSurface(surface); 00240 SDL_FreeSurface(surface); 00241 } 00242 }
friend class DrawingContext [friend] |
GlyphWidth Font::glyph_width [private] |
std::vector<SurfacePtr> Font::glyph_surfaces [private] |
std::vector<SurfacePtr> Font::shadow_surfaces [private] |
int Font::char_height [private] |
Definition at line 138 of file font.hpp.
Referenced by draw(), draw_chars(), get_height(), get_text_height(), loadFontFile(), and loadFontSurface().
int Font::shadowsize [private] |
std::vector<Glyph> Font::glyphs [private] |
65536 of glyphs
Definition at line 142 of file font.hpp.
Referenced by draw_chars(), Font(), get_text_width(), and loadFontSurface().