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