FIFE 2008.0
|
00001 /*************************************************************************** 00002 * Copyright (C) 2005-2008 by the FIFE team * 00003 * http://www.fifengine.de * 00004 * This file is part of FIFE. * 00005 * * 00006 * FIFE is free software; you can redistribute it and/or * 00007 * modify it under the terms of the GNU Lesser General Public * 00008 * License as published by the Free Software Foundation; either * 00009 * version 2.1 of the License, or (at your option) any later version. * 00010 * * 00011 * This library is distributed in the hope that it will be useful, * 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * 00014 * Lesser General Public License for more details. * 00015 * * 00016 * You should have received a copy of the GNU Lesser General Public * 00017 * License along with this library; if not, write to the * 00018 * Free Software Foundation, Inc., * 00019 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * 00020 ***************************************************************************/ 00021 00022 // Standard C++ library includes 00023 #include <vector> 00024 00025 // Platform specific includes 00026 00027 // 3rd party library includes 00028 #include <boost/filesystem/convenience.hpp> 00029 00030 // FIFE includes 00031 // These includes are split up in two parts, separated by one empty line 00032 // First block: files included from the FIFE root src directory 00033 // Second block: files included from the same folder 00034 #include "util/structures/rect.h" 00035 #include "util/base/exception.h" 00036 #include "util/utf8/utf8.h" 00037 #include "video/image.h" 00038 #include "video/renderbackend.h" 00039 00040 #include "fontbase.h" 00041 00042 namespace FIFE { 00043 00044 FontBase::FontBase(): 00045 m_pool(), 00046 mColor(), 00047 mGlyphSpacing(0), 00048 mRowSpacing(0), 00049 mFilename(""), 00050 m_antiAlias(true) { 00051 } 00052 00053 void FontBase::invalidate() { 00054 m_pool.invalidateCachedText(); 00055 } 00056 00057 void FontBase::setRowSpacing(int spacing) { 00058 mRowSpacing = spacing; 00059 } 00060 00061 int FontBase::getRowSpacing() const { 00062 return mRowSpacing; 00063 } 00064 00065 void FontBase::setGlyphSpacing(int spacing) { 00066 mGlyphSpacing = spacing; 00067 } 00068 00069 int FontBase::getGlyphSpacing() const { 00070 return mGlyphSpacing; 00071 } 00072 00073 void FontBase::setAntiAlias(bool antiAlias) { 00074 m_antiAlias = antiAlias; 00075 } 00076 00077 bool FontBase::isAntiAlias() { 00078 return m_antiAlias; 00079 } 00080 00081 SDL_Color FontBase::getColor() const { 00082 return mColor; 00083 } 00084 00085 int FontBase::getStringIndexAt(const std::string &text, int x) const { 00086 assert( utf8::is_valid(text.begin(), text.end()) ); 00087 std::string::const_iterator cur; 00088 if (text.size() == 0) return 0; 00089 if (x <= 0) return 0; 00090 00091 cur = text.begin(); 00092 00093 utf8::next(cur, text.end()); 00094 00095 std::string buff; 00096 while(cur != text.end()) { 00097 buff = std::string(text.begin(), cur); 00098 00099 if (getWidth(buff) > x) { 00100 return buff.size(); 00101 } else { 00102 utf8::next(cur, text.end()); 00103 } 00104 } 00105 00106 if (x > getWidth(text)) { 00107 return text.size(); 00108 } else { 00109 return buff.size(); 00110 } 00111 } 00112 00113 Image* FontBase::getAsImage(const std::string& text) { 00114 Image* image = m_pool.getRenderedText(this, text); 00115 if (!image) { 00116 SDL_Surface* textSurface = renderString(text); 00117 image = RenderBackend::instance()->createImage(textSurface); 00118 m_pool.addRenderedText( this, text, image ); 00119 } 00120 return image; 00121 } 00122 00123 Image* FontBase::getAsImageMultiline(const std::string& text) { 00124 const uint8_t newline_utf8 = '\n'; 00125 uint32_t newline; 00126 utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline); 00127 //std::cout << "Text:" << text << std::endl; 00128 Image* image = m_pool.getRenderedText(this, text); 00129 if (!image) { 00130 std::vector<SDL_Surface*> lines; 00131 std::string::const_iterator it = text.begin(); 00132 // split text as needed 00133 int render_width = 0, render_height = 0; 00134 do { 00135 uint32_t codepoint = 0; 00136 std::string line; 00137 while( codepoint != newline && it != text.end() ) 00138 { 00139 codepoint = utf8::next(it,text.end()); 00140 if( codepoint != newline ) 00141 utf8::append(codepoint, back_inserter(line)); 00142 } 00143 //std::cout << "Line:" << line << std::endl; 00144 SDL_Surface* text_surface = renderString(line); 00145 if (text_surface->w > render_width) { 00146 render_width = text_surface->w; 00147 } 00148 lines.push_back(text_surface); 00149 } while (it != text.end()); 00150 00151 render_height = (getRowSpacing() + getHeight()) * lines.size(); 00152 SDL_Surface* final_surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 00153 render_width,render_height,32, 00154 RMASK, GMASK, BMASK ,AMASK); 00155 if (!final_surface) { 00156 throw SDLException(std::string("CreateRGBSurface failed: ") + SDL_GetError()); 00157 } 00158 SDL_FillRect(final_surface, 0, 0x00000000); 00159 int ypos = 0; 00160 for (std::vector<SDL_Surface*>::iterator i = lines.begin(); i != lines.end(); ++i) { 00161 SDL_Rect dst_rect = { 0, 0, 0, 0 }; 00162 dst_rect.y = ypos; 00163 00164 SDL_SetAlpha(*i,0,SDL_ALPHA_OPAQUE); 00165 SDL_BlitSurface(*i,0,final_surface,&dst_rect); 00166 ypos += getRowSpacing() + getHeight(); 00167 SDL_FreeSurface(*i); 00168 } 00169 image = RenderBackend::instance()->createImage(final_surface); 00170 m_pool.addRenderedText(this, text, image); 00171 } 00172 return image; 00173 } 00174 00175 std::string FontBase::splitTextToWidth (const std::string& text, int render_width) { 00176 const uint32_t whitespace = ' '; 00177 const uint8_t newline_utf8 = '\n'; 00178 uint32_t newline; 00179 utf8::utf8to32(&newline_utf8,&newline_utf8 + 1,&newline); 00180 if (render_width <= 0 || text.empty()) { 00181 return text; 00182 } 00183 std::string output; 00184 std::string line; 00185 std::string::const_iterator pos = text.begin(); 00186 std::list<std::pair<size_t,std::string::const_iterator> > break_pos; 00187 bool firstLine = true; 00188 00189 while( pos != text.end()) 00190 { 00191 break_pos.clear(); 00192 if( !firstLine ) { 00193 line = "\n"; 00194 } else { 00195 firstLine = false; 00196 } 00197 00198 bool haveNewLine = false; 00199 while( getWidth(line) < render_width && pos != text.end() ) 00200 { 00201 uint32_t codepoint = utf8::next(pos, text.end()); 00202 if (codepoint == whitespace && !line.empty()) 00203 break_pos.push_back( std::make_pair(line.length(),pos) ); 00204 00205 if( codepoint != newline ) 00206 utf8::append(codepoint, back_inserter(line) ); 00207 00208 // Special case: Already newlines in string: 00209 if( codepoint == newline ) { 00210 output.append(line); 00211 line = ""; 00212 haveNewLine = true; 00213 break; 00214 } 00215 } 00216 if( haveNewLine ) 00217 continue; 00218 00219 if( pos == text.end() ) 00220 break; 00221 00222 if( break_pos.empty() ) { 00223 // No break position and line length smaller than 2 00224 // means the renderwidth is really screwed. Just continue 00225 // appending single character lines. 00226 if( utf8::distance(line.begin(),line.end()) <= 1 && line != "\n") { 00227 output.append(line); 00228 continue; 00229 } 00230 00231 if (line == "\n") { 00232 ++pos; 00233 } 00234 00235 // We can't do hyphenation here, 00236 // so we just retreat one character :-( 00237 // FIXME 00238 //line = line.erase(line.length() - 1); 00239 //--pos; 00240 } else { 00241 line = line.substr(0,break_pos.back().first); 00242 pos = break_pos.back().second; 00243 } 00244 output.append(line); 00245 } 00246 if( !line.empty() ) { 00247 output.append(line); 00248 } 00249 return output; 00250 } 00251 }