wesnoth-cvs-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Wesnoth-cvs-commits] wesnoth/src font.cpp


From: Guillaume Melquiond
Subject: [Wesnoth-cvs-commits] wesnoth/src font.cpp
Date: Fri, 03 Sep 2004 03:24:01 -0400

CVSROOT:        /cvsroot/wesnoth
Module name:    wesnoth
Branch:         
Changes by:     Guillaume Melquiond <address@hidden>    04/09/03 07:18:48

Modified files:
        src            : font.cpp 

Log message:
        Text rendering optimization, see patch 3334 for comments

CVSWeb URLs:
http://savannah.gnu.org/cgi-bin/viewcvs/wesnoth/wesnoth/src/font.cpp.diff?tr1=1.83&tr2=1.84&r1=text&r2=text

Patches:
Index: wesnoth/src/font.cpp
diff -u wesnoth/src/font.cpp:1.83 wesnoth/src/font.cpp:1.84
--- wesnoth/src/font.cpp:1.83   Sun Aug 29 14:58:40 2004
+++ wesnoth/src/font.cpp        Fri Sep  3 07:18:48 2004
@@ -1,4 +1,4 @@
-/* $Id: font.cpp,v 1.83 2004/08/29 14:58:40 ydirson Exp $ */
+/* $Id: font.cpp,v 1.84 2004/09/03 07:18:48 silene Exp $ */
 /*
    Copyright (C) 2003 by David White <address@hidden>
    Part of the Battle for Wesnoth Project http://wesnoth.whitevine.net
@@ -21,8 +21,10 @@
 #include "tooltips.hpp"
 #include "util.hpp"
 
+#include <algorithm>
 #include <cstdio>
 #include <iostream>
+#include <list>
 #include <map>
 #include <sstream>
 #include <stack>
@@ -177,52 +179,151 @@
 
 static const size_t max_text_line_width = 4096;
 
-SDL_Rect text_size(TTF_Font* font, const std::string& str, const SDL_Color& 
colour, int style)
+class text_surface
 {
-       const font_style_setter style_setter(font,style);
-       SDL_Rect res = {0,0,0,0};
-       int w = 0, h = 0;
+public:
+       text_surface(TTF_Font *font, std::string const &str, SDL_Color color, 
int style);
+       text_surface(TTF_Font *font, SDL_Color color, int style);
+       void set_text(std::string const &str);
+       bool operator==(text_surface const &t) const { return hash_ == t.hash_ 
&& equal(t); }
+       bool operator!=(text_surface const &t) const { return hash_ != t.hash_ 
|| !equal(t); }
+       size_t width() const;
+       size_t height() const;
+       surface const &get_surface() const;
+private:
+       int hash_;
+       TTF_Font *font_; // no font should ever be closed
+       std::string str_;
+       SDL_Color color_;
+       int style_;
+       mutable int w_, h_;
+       mutable surface surf_;
+       void hash();
+       void measure() const;
+       bool equal(text_surface const &t) const;
+};
 
-       TTF_SizeUTF8(font,str.c_str(),&w,&h);
+text_surface::text_surface(TTF_Font *font, std::string const &str, SDL_Color 
color, int style)
+  : font_(font), str_(str), color_(color), style_(style), w_(-1), h_(-1)
+{
+       hash();
+}
 
-       res.w = size_t(w);
-       res.h = size_t(h);
+text_surface::text_surface(TTF_Font *font, SDL_Color color, int style)
+  : hash_(0), font_(font), color_(color), style_(style), w_(-1), h_(-1)
+{}
 
-       return res;
+void text_surface::set_text(std::string const &str)
+{
+       str_ = str;
+       hash();
+}
+
+void text_surface::hash()
+{
+       int h = 0;
+       for(std::string::const_iterator it = str_.begin(), it_end = str_.end(); 
it != it_end; ++it)
+               h = ((h << 9) | (h >> (sizeof(int) * 8 - 9))) ^ (*it);
+       hash_ = h;
+}
+
+bool text_surface::equal(text_surface const &t) const
+{
+       return font_ == t.font_
+               && color_.r == t.color_.r && color_.g == t.color_.g && color_.b 
== t.color_.b
+               && style_ == t.style_
+               && str_ == t.str_;
+}
+
+void text_surface::measure() const
+{
+       font_style_setter const style_setter(font_, style_);
+       TTF_SizeUTF8(font_, str_.c_str(), &w_, &h_);
+}
+
+size_t text_surface::width() const
+{
+       if (w_ == -1)
+               measure();
+       return w_;
 }
 
-surface render_text_internal(TTF_Font* font,const std::string& str,
-                                                const SDL_Color& colour, int 
style)
+size_t text_surface::height() const
 {
-       const font_style_setter style_setter(font,style);
+       if (h_ == -1)
+               measure();
+       return h_;
+}
+
+surface const &text_surface::get_surface() const
+{
+       if (!surf_.null())
+               return surf_;
 
        // Impose a maximal number of characters for a text line. Do now draw
        // any text longer that that, to prevent a SDL buffer overflow
-       
-       const SDL_Rect r = text_size(font, str, colour, style);
-
-       if(r.w > max_text_line_width)
-               return NULL;
+       if (width() > max_text_line_width)
+               return surf_;
 
        // Validate the UTF-8 string: workaround a SDL_TTF bug that makes it
        // crash when used with an invalid UTF-8 string
-       std::string fixed_str = wstring_to_string(string_to_wstring(str));
+       std::string fixed_str = wstring_to_string(string_to_wstring(str_));
 
-       return TTF_RenderUTF8_Blended(font,fixed_str.c_str(),colour);
+       font_style_setter const style_setter(font_, style_);
+       surf_ = surface(TTF_RenderUTF8_Blended(font_, fixed_str.c_str(), 
color_));
+       return surf_;
+}
 
+class text_cache
+{
+public:
+       static text_surface &find(text_surface const &t);
+private:
+       typedef std::list< text_surface > text_list;
+       static text_list cache_;
+};
+
+text_cache::text_list text_cache::cache_;
+
+text_surface &text_cache::find(text_surface const &t)
+{
+       static size_t lookup_ = 0, hit_ = 0;
+       text_list::iterator it_bgn = cache_.begin(), it_end = cache_.end();
+       text_list::iterator it = std::find(it_bgn, it_end, t);
+       if (it != it_end) {
+               cache_.splice(it_bgn, cache_, it);
+               ++hit_;
+       } else {
+               if (cache_.size() >= 50)
+                       cache_.pop_back();
+               cache_.push_front(t);
+       }
+       if (++lookup_ % 1000 == 0) {
+               std::cerr << "Text cache: " << lookup_ << " lookups, "
+                 "hit percentage: " << (hit_ / 10) << "%" << std::endl;
+               hit_ = 0;
+       }
+       return cache_.front();
 }
 
 surface render_text(TTF_Font* font,const std::string& text, const SDL_Color& 
colour, int style)
 {
+       if (font == NULL)
+               return surface();
+
        // XXX Changed by erl, to not strip when rendering text. Works 
everywhere?
        const std::vector<std::string> lines = config::split(text,'\n', 
config::REMOVE_EMPTY);
        std::vector<surface> surfaces;
+       surfaces.reserve(lines.size());
        size_t width = 0, height = 0;
-       for(std::vector<std::string>::const_iterator ln = lines.begin(); ln != 
lines.end(); ++ln) {
-               if(*ln != "" && font != NULL) {
-                       surface 
res(render_text_internal(font,*ln,colour,style));
+       text_surface txt_surf(font, colour, style);
+
+       for(std::vector< std::string >::const_iterator ln = lines.begin(), 
ln_end = lines.end(); ln != ln_end; ++ln) {
+               if (!ln->empty()) {
+                       txt_surf.set_text(*ln);
+                       surface const &res = 
text_cache::find(txt_surf).get_surface();
 
-                       if(res != NULL) {
+                       if (!res.null()) {
                                surfaces.push_back(res);
                                width = maximum<size_t>(res->w,width);
                                height += res->h;
@@ -230,22 +331,22 @@
                }
        }
 
-       if(surfaces.empty()) {
-               return NULL;
-       } else if(surfaces.size() == 1) {
+       if (surfaces.empty()) {
+               return surface();
+       } else if (surfaces.size() == 1) {
                return surfaces.front();
        } else {
 
                surface 
res(create_compatible_surface(surfaces.front(),width,height));
-               if(res == NULL) {
-                       return NULL;
-               }
+               if (res.null())
+                       return res;
 
                size_t ypos = 0;
-               for(std::vector<surface>::const_iterator i = surfaces.begin(); 
i != surfaces.end(); ++i) {
-                       SDL_SetAlpha(*i,0,0);
-                       SDL_Rect dstrect = {0,ypos,(*i)->w,(*i)->h};
-                       SDL_BlitSurface(*i,NULL,res,&dstrect);
+               for(std::vector< surface >::const_iterator i = surfaces.begin(),
+                   i_end = surfaces.end(); i != i_end; ++i) {
+                       SDL_SetAlpha(*i, 0, 0); // direct blit without alpha 
blending
+                       SDL_Rect dstrect = {0, ypos};
+                       SDL_BlitSurface(*i, NULL, res, &dstrect);
                        ypos += (*i)->h;
                }
 
@@ -316,11 +417,7 @@
                return NULL;
        }
 
-       surface res = render_text(font,str,colour,style);
-       if(res == NULL) {
-               return NULL;
-       }
-       return res;
+       return render_text(font, str, colour, style);
 }
 
 
@@ -338,8 +435,10 @@
 
        const std::string etext = make_text_ellipsis(text, size, area.w);
 
-       if(gui_surface == NULL) {
-               return text_size(font,etext,colour,style);
+       if (gui_surface.null()) {
+               text_surface const &u = text_cache::find(text_surface(font, 
text, colour, style));
+               SDL_Rect res = {0, 0, u.width(), u.height()};
+               return res;
        }
 
        surface surface(render_text(font,etext,colour,style));
@@ -684,45 +783,8 @@
 
 surface floating_label::create_surface()
 {
-       if(surf_ == NULL) {
-
-               const std::vector<std::string> lines = 
config::split(text_,'\n');
-               std::vector<surface> surfaces;
-               for(std::vector<std::string>::const_iterator ln = 
lines.begin(); ln != lines.end(); ++ln) {
-                       SDL_Color colour = colour_;
-                       const int size = font_size_;
-                       const int style = 0;
-                       const std::string& str = *ln;
-
-                       TTF_Font* const font = get_font(size);
-
-                       if(str != "" && font != NULL) {
-                               
surfaces.push_back(surface(font::render_text(font,str,colour,style)));
-                       }
-               }
-
-               if(surfaces.empty()) {
-                       return NULL;
-               } else if(surfaces.size() == 1) {
-                       surf_.assign(surfaces.front());
-               } else {
-                       size_t width = 0, height = 0;
-                       std::vector<surface>::const_iterator i;
-                       for(i = surfaces.begin(); i != surfaces.end(); ++i) {
-                               width = maximum<size_t>((*i)->w,width);
-                               height += (*i)->h;
-                       }
-
-                       
surf_.assign(create_compatible_surface(surfaces.front(),width,height));
-
-                       size_t ypos = 0;
-                       for(i = surfaces.begin(); i != surfaces.end(); ++i) {
-                               SDL_SetAlpha(*i,0,0);
-                               SDL_Rect dstrect = {0,ypos,(*i)->w,(*i)->h};
-                               SDL_BlitSurface(*i,NULL,surf_,&dstrect);
-                               ypos += (*i)->h;
-                       }
-               }
+       if (surf_.null()) {
+               surf_ = font::render_text(get_font(font_size_), text_, colour_, 
0);
 
                if(surf_ == NULL) {
                        return NULL;




reply via email to

[Prev in Thread] Current Thread [Next in Thread]