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