+ const std::string& text;
+ std::string::size_type pos;
+ uint32_t chr;
+
+ UTF8Iterator(const std::string& text_)
+ : text(text_),
+ pos(0)
+ {
+ try {
+ chr = decode_utf8(text, pos);
+ } catch (std::exception) {
+ log_debug << "Malformed utf-8 sequence beginning with " << *((uint32_t*)(text.c_str() + pos)) << " found " << std::endl;
+ chr = 0;
+ }
+ }
+
+ bool done() const
+ {
+ return pos > text.size();
+ }
+
+ UTF8Iterator& operator++() {
+ try {
+ chr = decode_utf8(text, pos);
+ } catch (std::exception) {
+ log_debug << "Malformed utf-8 sequence beginning with " << *((uint32_t*)(text.c_str() + pos)) << " found " << std::endl;
+ chr = 0;
+ ++pos;
+ }
+
+ return *this;
+ }
+
+ uint32_t operator*() const {
+ return chr;
+ }
+};
+
+bool vline_empty(SDL_Surface* surface, int x, int start_y, int end_y, Uint8 threshold)
+{
+ Uint8* pixels = (Uint8*)surface->pixels;
+
+ for(int y = start_y; y < end_y; ++y)
+ {
+ const Uint8& p = pixels[surface->pitch*y + x*surface->format->BytesPerPixel + 3];
+ if (p > threshold)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+} // namespace
+
+Font::Font(GlyphWidth glyph_width_,
+ const std::string& filename,
+ int shadowsize_)
+: glyph_width(glyph_width_),
+ shadowsize(shadowsize_),
+ glyphs(65536)
+{
+ for(unsigned int i=0; i<65536;i++) glyphs[i].surface_idx = -1;
+
+ const std::string fontdir = FileSystem::dirname(filename);
+ const std::string fontname = FileSystem::basename(filename);
+
+ // scan for prefix-filename in addons search path
+ char **rc = PHYSFS_enumerateFiles(fontdir.c_str());
+ for (char **i = rc; *i != NULL; i++) {
+ std::string filename(*i);
+ if( filename.rfind(fontname) != std::string::npos ) {
+ loadFontFile(fontdir + filename);
+ }
+ }
+ PHYSFS_freeList(rc);
+}
+
+void
+Font::loadFontFile(const std::string &filename)
+{
+ lisp::Parser parser;
+ log_debug << "Loading font: " << filename << std::endl;
+ const lisp::Lisp* root = parser.parse(filename);
+ const lisp::Lisp* config_l = root->get_lisp("supertux-font");
+
+ if(!config_l) {
+ std::ostringstream msg;
+ msg << "Font file:" << filename << ": is not a supertux-font file";
+ throw std::runtime_error(msg.str());
+ }
+
+ int def_char_width=0;
+
+ if( !config_l->get("glyph-width",def_char_width) ) {
+ log_warning << "Font:"<< filename << ": misses default glyph-width" << std::endl;
+ }
+
+ if( !config_l->get("glyph-height",char_height) ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": misses glyph-height";
+ throw std::runtime_error(msg.str());
+ }
+
+ lisp::ListIterator iter(config_l);
+ while(iter.next()) {
+ const std::string& token = iter.item();
+ if( token == "surface" ) {
+ const lisp::Lisp * glyphs_val = iter.lisp();
+ int local_char_width;
+ bool monospaced;
+ GlyphWidth local_glyph_width;
+ std::string glyph_image;
+ std::string shadow_image;
+ std::vector<std::string> chars;
+ if( ! glyphs_val->get("glyph-width", local_char_width) ) {
+ local_char_width = def_char_width;
+ }
+ if( ! glyphs_val->get("monospace", monospaced ) ) {
+ local_glyph_width = glyph_width;
+ }
+ else {
+ if( monospaced ) local_glyph_width = FIXED;
+ else local_glyph_width = VARIABLE;
+ }
+ if( ! glyphs_val->get("glyphs", glyph_image) ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": missing glyphs image";
+ throw std::runtime_error(msg.str());
+ }
+ if( ! glyphs_val->get("shadows", shadow_image) ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": missing shadows image";
+ throw std::runtime_error(msg.str());
+ }
+ if( ! glyphs_val->get("chars", chars) || chars.size() == 0) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": missing chars definition";
+ throw std::runtime_error(msg.str());
+ }
+
+ if( local_char_width==0 ) {
+ std::ostringstream msg;
+ msg << "Font:" << filename << ": misses glyph-width for some surface";
+ throw std::runtime_error(msg.str());
+ }
+
+ loadFontSurface(glyph_image, shadow_image, chars,
+ local_glyph_width, local_char_width);
+ }
+ }
+}
+
+void
+Font::loadFontSurface(
+ const std::string &glyphimage,
+ const std::string &shadowimage,
+ const std::vector<std::string> &chars,
+ GlyphWidth glyph_width,
+ int char_width
+ )
+{
+ Surface glyph_surface = Surface("images/engine/fonts/" + glyphimage);
+ Surface shadow_surface = Surface("images/engine/fonts/" + shadowimage);
+
+ int surface_idx = glyph_surfaces.size();
+ glyph_surfaces.push_back(glyph_surface);
+ shadow_surfaces.push_back(shadow_surface);
+
+ int row=0, col=0;
+ int wrap = glyph_surface.get_width() / char_width;