1 /* _______ __ __ __ ______ __ __ _______ __ __ 2 * / _____/\ / /\ / /\ / /\ / ____/\ / /\ / /\ / ___ /\ / |\/ /\ 3 * / /\____\// / // / // / // /\___\// /_// / // /\_/ / // , |/ / / 4 * / / /__ / / // / // / // / / / ___ / // ___ / // /| ' / / 5 * / /_// /\ / /_// / // / // /_/_ / / // / // /\_/ / // / | / / 6 * /______/ //______/ //_/ //_____/\ /_/ //_/ //_/ //_/ //_/ /|_/ / 7 * \______\/ \______\/ \_\/ \_____\/ \_\/ \_\/ \_\/ \_\/ \_\/ \_\/ 8 * 9 * Copyright (c) 2004 - 2008 Olof Naess�n and Per Larsson 10 * 11 * 12 * Per Larsson a.k.a finalman 13 * Olof Naess�n a.k.a jansem/yakslem 14 * 15 * Visit: http://guichan.sourceforge.net 16 * 17 * License: (BSD) 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in 25 * the documentation and/or other materials provided with the 26 * distribution. 27 * 3. Neither the name of Guichan nor the names of its contributors may 28 * be used to endorse or promote products derived from this software 29 * without specific prior written permission. 30 * 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 36 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED 37 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 38 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 39 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 40 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 41 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 42 */ 43 44 /* 45 * For comments regarding functions please see the header file. 46 */ 47 48 #include "guichan/imagefont.hpp" 49 50 #include <sstream> 51 52 #include "guichan/color.hpp" 53 #include "guichan/exception.hpp" 54 #include "guichan/graphics.hpp" 55 #include "guichan/image.hpp" 56 57 namespace gcn 58 { ImageFont(const std::string & filename,const std::string & glyphs)59 ImageFont::ImageFont(const std::string& filename, 60 const std::string& glyphs) 61 { 62 mFilename = filename; 63 mImage = Image::load(filename, false); 64 65 Color separator = mImage->getPixel(0, 0); 66 67 int i = 0; 68 for (i = 0; 69 i < mImage->getWidth() && separator == mImage->getPixel(i, 0); 70 ++i) 71 { 72 } 73 74 if (i >= mImage->getWidth()) 75 { 76 throw GCN_EXCEPTION("Corrupt image."); 77 } 78 79 int j = 0; 80 for (j = 0; j < mImage->getHeight(); ++j) 81 { 82 if (separator == mImage->getPixel(i, j)) 83 { 84 break; 85 } 86 } 87 88 mHeight = j; 89 int x = 0, y = 0; 90 unsigned char k; 91 92 for (i = 0; i < (int)glyphs.size(); ++i) 93 { 94 k = glyphs.at(i); 95 mGlyph[k] = scanForGlyph(k, x, y, separator); 96 // Update x och y with new coordinates. 97 x = mGlyph[k].x + mGlyph[k].width; 98 y = mGlyph[k].y; 99 } 100 101 mImage->convertToDisplayFormat(); 102 103 mRowSpacing = 0; 104 mGlyphSpacing = 0; 105 } 106 ImageFont(Image * image,const std::string & glyphs)107 ImageFont::ImageFont(Image* image, 108 const std::string& glyphs) 109 { 110 mFilename = "Image*"; 111 if (image == NULL) 112 { 113 GCN_EXCEPTION("Font image is NULL"); 114 } 115 mImage = image; 116 117 Color separator = mImage->getPixel(0, 0); 118 119 int i = 0; 120 for (i = 0; 121 i < mImage->getWidth() && separator == mImage->getPixel(i, 0); 122 ++i) 123 { 124 } 125 126 if (i >= mImage->getWidth()) 127 { 128 throw GCN_EXCEPTION("Corrupt image."); 129 } 130 131 int j = 0; 132 for (j = 0; j < mImage->getHeight(); ++j) 133 { 134 if (separator == mImage->getPixel(i, j)) 135 { 136 break; 137 } 138 } 139 140 mHeight = j; 141 int x = 0, y = 0; 142 unsigned char k; 143 144 for (i = 0; i < (int)glyphs.size(); ++i) 145 { 146 k = glyphs.at(i); 147 mGlyph[k] = scanForGlyph(k, x, y, separator); 148 // Update x och y with new coordinates. 149 x = mGlyph[k].x + mGlyph[k].width; 150 y = mGlyph[k].y; 151 } 152 153 mImage->convertToDisplayFormat(); 154 155 mRowSpacing = 0; 156 mGlyphSpacing = 0; 157 } 158 ImageFont(const std::string & filename,unsigned char glyphsFrom,unsigned char glyphsTo)159 ImageFont::ImageFont(const std::string& filename, 160 unsigned char glyphsFrom, 161 unsigned char glyphsTo) 162 { 163 mFilename = filename; 164 mImage = Image::load(filename, false); 165 166 Color separator = mImage->getPixel(0, 0); 167 168 int i = 0; 169 for (i=0; separator == mImage->getPixel(i, 0) 170 && i < mImage->getWidth(); ++i) 171 { 172 } 173 174 if (i >= mImage->getWidth()) 175 { 176 throw GCN_EXCEPTION("Corrupt image."); 177 } 178 179 int j = 0; 180 for (j = 0; j < mImage->getHeight(); ++j) 181 { 182 if (separator == mImage->getPixel(i, j)) 183 { 184 break; 185 } 186 } 187 188 mHeight = j; 189 int x = 0, y = 0; 190 191 for (i = glyphsFrom; i < glyphsTo + 1; i++) 192 { 193 mGlyph[i] = scanForGlyph(i, x, y, separator); 194 // Update x och y with new coordinates. 195 x = mGlyph[i].x + mGlyph[i].width; 196 y = mGlyph[i].y; 197 } 198 199 mImage->convertToDisplayFormat(); 200 201 mRowSpacing = 0; 202 mGlyphSpacing = 0; 203 } 204 ~ImageFont()205 ImageFont::~ImageFont() 206 { 207 delete mImage; 208 } 209 getWidth(unsigned char glyph) const210 int ImageFont::getWidth(unsigned char glyph) const 211 { 212 if (mGlyph[glyph].width == 0) 213 { 214 return mGlyph[(int)(' ')].width + mGlyphSpacing; 215 } 216 217 return mGlyph[glyph].width + mGlyphSpacing; 218 } 219 getHeight() const220 int ImageFont::getHeight() const 221 { 222 return mHeight + mRowSpacing; 223 } 224 drawGlyph(Graphics * graphics,unsigned char glyph,int x,int y)225 int ImageFont::drawGlyph(Graphics* graphics, 226 unsigned char glyph, 227 int x, int y) 228 { 229 // This is needed for drawing the glyph in the middle 230 // if we have spacing. 231 int yoffset = getRowSpacing() / 2; 232 233 if (mGlyph[glyph].width == 0) 234 { 235 graphics->drawRectangle(Rectangle(x, 236 y + 1 + yoffset, 237 mGlyph[(int)(' ')].width - 1, 238 mGlyph[(int)(' ')].height - 2)); 239 240 return mGlyph[(int)(' ')].width + mGlyphSpacing; 241 } 242 243 graphics->drawImage(mImage, 244 mGlyph[glyph].x, 245 mGlyph[glyph].y, 246 x, 247 y + yoffset, 248 mGlyph[glyph].width, 249 mGlyph[glyph].height); 250 251 return mGlyph[glyph].width + mGlyphSpacing; 252 } 253 drawString(Graphics * graphics,const std::string & text,int x,int y)254 void ImageFont::drawString(Graphics* graphics, 255 const std::string& text, 256 int x, 257 int y) 258 { 259 unsigned int i; 260 261 for (i = 0; i < text.size(); ++i) 262 { 263 drawGlyph(graphics, text.at(i), x, y); 264 x += getWidth(text.at(i)); 265 } 266 } 267 setRowSpacing(int spacing)268 void ImageFont::setRowSpacing(int spacing) 269 { 270 mRowSpacing = spacing; 271 } 272 getRowSpacing()273 int ImageFont::getRowSpacing() 274 { 275 return mRowSpacing; 276 } 277 setGlyphSpacing(int spacing)278 void ImageFont::setGlyphSpacing(int spacing) 279 { 280 mGlyphSpacing = spacing; 281 } 282 getGlyphSpacing()283 int ImageFont::getGlyphSpacing() 284 { 285 return mGlyphSpacing; 286 } 287 scanForGlyph(unsigned char glyph,int x,int y,const Color & separator)288 Rectangle ImageFont::scanForGlyph(unsigned char glyph, 289 int x, 290 int y, 291 const Color& separator) 292 { 293 Color color; 294 do 295 { 296 ++x; 297 298 if (x >= mImage->getWidth()) 299 { 300 y += mHeight + 1; 301 x = 0; 302 303 if (y >= mImage->getHeight()) 304 { 305 std::string str; 306 std::ostringstream os(str); 307 os << "Image "; 308 os << mFilename; 309 os << " with font is corrupt near character '"; 310 os << glyph; 311 os << "'"; 312 throw GCN_EXCEPTION(os.str()); 313 } 314 } 315 316 color = mImage->getPixel(x, y); 317 318 } while (color == separator); 319 320 int width = 0; 321 322 do 323 { 324 ++width; 325 326 if (x + width >= mImage->getWidth()) 327 { 328 std::string str; 329 std::ostringstream os(str); 330 os << "Image "; 331 os << mFilename; 332 os << " with font is corrupt near character '"; 333 os << glyph; 334 os << "'"; 335 throw GCN_EXCEPTION(os.str()); 336 } 337 338 color = mImage->getPixel(x + width, y); 339 340 } while (color != separator); 341 342 return Rectangle(x, y, width, mHeight); 343 } 344 getWidth(const std::string & text) const345 int ImageFont::getWidth(const std::string& text) const 346 { 347 unsigned int i; 348 int size = 0; 349 350 for (i = 0; i < text.size(); ++i) 351 { 352 size += getWidth(text.at(i)); 353 } 354 355 return size - mGlyphSpacing; 356 } 357 getStringIndexAt(const std::string & text,int x) const358 int ImageFont::getStringIndexAt(const std::string& text, int x) const 359 { 360 unsigned int i; 361 int size = 0; 362 363 for (i = 0; i < text.size(); ++i) 364 { 365 size += getWidth(text.at(i)); 366 367 if (size > x) 368 { 369 return i; 370 } 371 } 372 373 return text.size(); 374 } 375 } 376