From: Ingo Ruhnke Date: Mon, 29 Jan 2007 08:58:24 +0000 (+0000) Subject: - some more bugs/cleanup to the font class X-Git-Url: https://git.verplant.org/?a=commitdiff_plain;h=63df5714a905ea254069804373b569584a513cd9;p=supertux.git - some more bugs/cleanup to the font class - shadows are now usable with fixed width fonts, still buggy, but looking mostly ok - fixed all fonts to variable width SVN-Revision: 4723 --- diff --git a/src/resources.cpp b/src/resources.cpp index ef251a658..b18cdad12 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -45,24 +45,22 @@ void load_shared() MouseCursor::set_current(mouse_cursor); /* Load global images: */ - gold_text = new Font(Font::FIXED, + gold_text = new Font(Font::VARIABLE, "images/engine/fonts/gold.png", "images/engine/fonts/shadow.png", 16, 18); - blue_text = new Font(Font::FIXED, + blue_text = new Font(Font::VARIABLE, "images/engine/fonts/blue.png", "images/engine/fonts/shadow.png", 16, 18, 3); - // white_text = new Font("images/engine/fonts/white.png", - // "images/engine/fonts/shadow.png", 16, 18); white_text = new Font(Font::VARIABLE, - "images/engine/fonts/white.png", 16, 18); - gray_text = new Font(Font::FIXED, + "images/engine/fonts/white.png", + "images/engine/fonts/shadow.png", 16, 18); + gray_text = new Font(Font::VARIABLE, "images/engine/fonts/gray.png", "images/engine/fonts/shadow.png", 16, 18); white_small_text = new Font(Font::VARIABLE, "images/engine/fonts/white-small.png", - 8, 9); - // "images/engine/fonts/shadow-small.png", 8, 9, 1); - white_big_text = new Font(Font::FIXED, + "images/engine/fonts/shadow-small.png", 8, 9, 1); + white_big_text = new Font(Font::VARIABLE, "images/engine/fonts/white-big.png", "images/engine/fonts/shadow-big.png", 20, 22, 3); diff --git a/src/video/font.cpp b/src/video/font.cpp index 395b6c331..92eb42a23 100644 --- a/src/video/font.cpp +++ b/src/video/font.cpp @@ -90,82 +90,88 @@ bool vline_empty(SDL_Surface* surface, int x, int start_y, int end_y, Uint8 thre } // namespace Font::Font(GlyphWidth glyph_width_, - const std::string& file, const std::string& shadowfile, - int char_width, int char_height_, int shadowsize) + const std::string& filename, + const std::string& shadowfile, + int char_width, int char_height_, + int shadowsize_) : glyph_width(glyph_width_), - glyph_surface(0), shadow_chars(0), + glyph_surface(0), shadow_glyph_surface(0), char_height(char_height_), - shadowsize(shadowsize) + shadowsize(shadowsize_) { - glyph_surface = new Surface(file); - shadow_chars = new Surface(shadowfile); + glyph_surface = new Surface(filename); + shadow_glyph_surface = new Surface(shadowfile); first_char = 32; char_count = ((int) glyph_surface->get_height() / char_height) * 16; - for(uint32_t i = 0; i < char_count; ++i) + if (glyph_width == FIXED) { - float x = (i % 16) * char_width; - float y = (i / 16) * char_height; - glyphs.push_back(Rect(x, y, - x + char_width, y + char_height)); + for(uint32_t i = 0; i < char_count; ++i) + { + float x = (i % 16) * char_width; + float y = (i / 16) * char_height; + + Glyph glyph; + glyph.advance = char_width; + glyph.offset = Vector(0, 0); + glyph.rect = Rect(x, y, x + char_width, y + char_height); + + glyphs.push_back(glyph); + shadow_glyphs.push_back(glyph); + } } -} + else // glyph_width == VARIABLE + { + // Load the surface into RAM and scan the pixel data for characters + SDL_Surface* surface = IMG_Load_RW(get_physfs_SDLRWops(filename), 1); + if(surface == NULL) { + std::ostringstream msg; + msg << "Couldn't load image '" << filename << "' :" << SDL_GetError(); + throw std::runtime_error(msg.str()); + } -Font::Font(GlyphWidth glyph_width_, const std::string& filename, int char_width, int char_height_) - : glyph_width(glyph_width_), - glyph_surface(0), shadow_chars(0), - char_height(char_height_), - shadowsize(0) -{ - glyph_surface = new Surface(filename); + SDL_LockSurface(surface); - first_char = 32; - char_count = ((int) glyph_surface->get_height() / char_height) * 16; + for(uint32_t i = 0; i < char_count; ++i) + { + int x = (i % 16) * char_width; + int y = (i / 16) * char_height; - // Load the surface into RAM and scan the pixel data for characters - SDL_Surface* surface = IMG_Load_RW(get_physfs_SDLRWops(filename), 1); - if(surface == NULL) { - std::ostringstream msg; - msg << "Couldn't load image '" << filename << "' :" << SDL_GetError(); - throw std::runtime_error(msg.str()); - } + int left = x; + while (left < x + char_width && + vline_empty(surface, left, y, y + char_height, 64)) + left += 1; - SDL_LockSurface(surface); + int right = x + char_width - 1; + while (right > left && + vline_empty(surface, right, y, y + char_height, 64)) + right -= 1; - for(uint32_t i = 0; i < char_count; ++i) - { - int x = (i % 16) * char_width; - int y = (i / 16) * char_height; - - int left = x; - while (left < x + char_width && - vline_empty(surface, left, y, y + char_height, 0)) - left += 1; - - int right = x + char_width - 1; - while (right > left && - vline_empty(surface, right, y, y + char_height, 0)) - right -= 1; - - if (left <= right) - glyphs.push_back(Rect(left, y, - right+1, y + char_height)); - else // glyph is completly transparent - glyphs.push_back(Rect(x, y, - x + char_width, y + char_height)); + Glyph glyph; + glyph.offset = Vector(0, 0); - } + if (left <= right) + glyph.rect = Rect(left, y, right+1, y + char_height); + else // glyph is completly transparent + glyph.rect = Rect(x, y, x + char_width, y + char_height); + + glyph.advance = glyph.rect.get_width(); + + glyphs.push_back(glyph); + shadow_glyphs.push_back(glyph); + } - SDL_UnlockSurface(surface); + SDL_UnlockSurface(surface); - SDL_FreeSurface(surface); + SDL_FreeSurface(surface); + } } Font::~Font() { delete glyph_surface; - delete shadow_chars; + delete shadow_glyph_surface; } float @@ -184,7 +190,7 @@ Font::get_text_width(const std::string& text) const else { int idx = chr2glyph(*it); - curr_width += glyphs[idx].get_width(); + curr_width += glyphs[idx].advance; } } @@ -257,6 +263,10 @@ Font::draw(const std::string& text, const Vector& pos_, FontAlignment alignment, else if(alignment == ALIGN_RIGHT) pos.x -= get_text_width(temp); + // Cast font position to integer to get a clean drawing result and + // no bluring as we would get with subpixel positions + pos.x = static_cast(pos.x); + draw_text(temp, pos, drawing_effect, alpha); if (i == text.size()) @@ -273,8 +283,13 @@ Font::draw_text(const std::string& text, const Vector& pos, DrawingEffect drawing_effect, float alpha) const { if(shadowsize > 0) - draw_chars(shadow_chars, text, pos + Vector(shadowsize, shadowsize), - drawing_effect, alpha); + { + // FIXME: shadow_glyph_surface and glyph_surface do currently + // share the same glyph array, this is incorrect and should be + // fixed, it is however hardly noticable + draw_chars(shadow_glyph_surface, text, pos + Vector(shadowsize, shadowsize), + drawing_effect, alpha); + } draw_chars(glyph_surface, text, pos, drawing_effect, alpha); } @@ -306,6 +321,7 @@ Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos, DrawingEffect drawing_effect, float alpha) const { Vector p = pos; + for(UTF8Iterator it(text); !it.done(); ++it) { int font_index = chr2glyph(*it); @@ -317,16 +333,18 @@ Font::draw_chars(Surface* pchars, const std::string& text, const Vector& pos, } else if(*it == ' ') { - p.x += glyphs[font_index].get_width(); + p.x += glyphs[font_index].advance; } else { - const Rect& glyph = glyphs[font_index]; - pchars->draw_part(glyph.get_left(), glyph.get_top(), - p.x, p.y, - glyph.get_width(), glyph.get_height(), + const Glyph& glyph = glyphs[font_index]; + pchars->draw_part(glyph.rect.get_left(), + glyph.rect.get_top(), + p.x + glyph.offset.y, + p.y + glyph.offset.y, + glyph.rect.get_width(), glyph.rect.get_height(), alpha, drawing_effect); - p.x += glyphs[font_index].get_width(); + p.x += glyphs[font_index].advance; } } } diff --git a/src/video/font.hpp b/src/video/font.hpp index c8973b08a..b8acf0a80 100644 --- a/src/video/font.hpp +++ b/src/video/font.hpp @@ -44,21 +44,15 @@ public: /** Construct a fixed-width font * - * @param file image file containing the characters - * @param shadowfile image file containing the characters shadows - * @param w width of a character - * @param h height of a character + * @param glyph_width VARIABLE for proportional fonts, VARIABLE for monospace ones + * @param filename image file containing the characters + * @param shadowfile image file containing the characters shadows + * @param char_width width of a character + * @param char_height height of a character */ - Font(GlyphWidth glyph_width, const std::string& file, const std::string& shadowfile, - int w, int h, int shadowsize = 2); - - /** Construct a variable-width font - * - * @param file image file containing the characters - */ - Font(GlyphWidth glyph_width, const std::string& filename, - int char_width, int char_height); - + Font(GlyphWidth glyph_width, + const std::string& filename, const std::string& shadowfile, + int char_width, int char_height, int shadowsize = 2); ~Font(); /** returns the width of a given text. (Note that I won't add a normal @@ -107,7 +101,7 @@ private: GlyphWidth glyph_width; Surface* glyph_surface; - Surface* shadow_chars; + Surface* shadow_glyph_surface; int char_height; int shadowsize; @@ -116,8 +110,21 @@ private: /// the number of the last character that is represented in the font uint32_t char_count; + struct Glyph { + /** How many pixels should the cursor advance after printing the + glyph */ + float advance; + + /** Offset that is used when drawing the glyph */ + Vector offset; + + /** Position of the glyph inside the surface */ + Rect rect; + }; + /** Location of the characters inside the surface */ - std::vector glyphs; + std::vector glyphs; + std::vector shadow_glyphs; }; #endif