diff options
Diffstat (limited to 'libraries/irrlicht-1.8/source/Irrlicht/CGUIFont.cpp')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CGUIFont.cpp | 1178 |
1 files changed, 589 insertions, 589 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CGUIFont.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CGUIFont.cpp index 8c7f85f..b2db857 100644 --- a/libraries/irrlicht-1.8/source/Irrlicht/CGUIFont.cpp +++ b/libraries/irrlicht-1.8/source/Irrlicht/CGUIFont.cpp | |||
@@ -1,589 +1,589 @@ | |||
1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt | 1 | // Copyright (C) 2002-2012 Nikolaus Gebhardt |
2 | // This file is part of the "Irrlicht Engine". | 2 | // This file is part of the "Irrlicht Engine". |
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | 3 | // For conditions of distribution and use, see copyright notice in irrlicht.h |
4 | 4 | ||
5 | #include "CGUIFont.h" | 5 | #include "CGUIFont.h" |
6 | #ifdef _IRR_COMPILE_WITH_GUI_ | 6 | #ifdef _IRR_COMPILE_WITH_GUI_ |
7 | 7 | ||
8 | #include "os.h" | 8 | #include "os.h" |
9 | #include "IGUIEnvironment.h" | 9 | #include "IGUIEnvironment.h" |
10 | #include "IXMLReader.h" | 10 | #include "IXMLReader.h" |
11 | #include "IReadFile.h" | 11 | #include "IReadFile.h" |
12 | #include "IVideoDriver.h" | 12 | #include "IVideoDriver.h" |
13 | #include "IGUISpriteBank.h" | 13 | #include "IGUISpriteBank.h" |
14 | 14 | ||
15 | namespace irr | 15 | namespace irr |
16 | { | 16 | { |
17 | namespace gui | 17 | namespace gui |
18 | { | 18 | { |
19 | 19 | ||
20 | //! constructor | 20 | //! constructor |
21 | CGUIFont::CGUIFont(IGUIEnvironment *env, const io::path& filename) | 21 | CGUIFont::CGUIFont(IGUIEnvironment *env, const io::path& filename) |
22 | : Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0), | 22 | : Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0), |
23 | MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0) | 23 | MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0) |
24 | { | 24 | { |
25 | #ifdef _DEBUG | 25 | #ifdef _DEBUG |
26 | setDebugName("CGUIFont"); | 26 | setDebugName("CGUIFont"); |
27 | #endif | 27 | #endif |
28 | 28 | ||
29 | if (Environment) | 29 | if (Environment) |
30 | { | 30 | { |
31 | // don't grab environment, to avoid circular references | 31 | // don't grab environment, to avoid circular references |
32 | Driver = Environment->getVideoDriver(); | 32 | Driver = Environment->getVideoDriver(); |
33 | 33 | ||
34 | SpriteBank = Environment->getSpriteBank(filename); | 34 | SpriteBank = Environment->getSpriteBank(filename); |
35 | if (!SpriteBank) // could be default-font which has no file | 35 | if (!SpriteBank) // could be default-font which has no file |
36 | SpriteBank = Environment->addEmptySpriteBank(filename); | 36 | SpriteBank = Environment->addEmptySpriteBank(filename); |
37 | if (SpriteBank) | 37 | if (SpriteBank) |
38 | SpriteBank->grab(); | 38 | SpriteBank->grab(); |
39 | } | 39 | } |
40 | 40 | ||
41 | if (Driver) | 41 | if (Driver) |
42 | Driver->grab(); | 42 | Driver->grab(); |
43 | 43 | ||
44 | setInvisibleCharacters ( L" " ); | 44 | setInvisibleCharacters ( L" " ); |
45 | } | 45 | } |
46 | 46 | ||
47 | 47 | ||
48 | //! destructor | 48 | //! destructor |
49 | CGUIFont::~CGUIFont() | 49 | CGUIFont::~CGUIFont() |
50 | { | 50 | { |
51 | if (Driver) | 51 | if (Driver) |
52 | Driver->drop(); | 52 | Driver->drop(); |
53 | 53 | ||
54 | if (SpriteBank) | 54 | if (SpriteBank) |
55 | { | 55 | { |
56 | SpriteBank->drop(); | 56 | SpriteBank->drop(); |
57 | // TODO: spritebank still exists in gui-environment and should be removed here when it's | 57 | // TODO: spritebank still exists in gui-environment and should be removed here when it's |
58 | // reference-count is 1. Just can't do that from here at the moment. | 58 | // reference-count is 1. Just can't do that from here at the moment. |
59 | // But spritebank would not be able to drop textures anyway because those are in texture-cache | 59 | // But spritebank would not be able to drop textures anyway because those are in texture-cache |
60 | // where they can't be removed unless materials start reference-couting 'em. | 60 | // where they can't be removed unless materials start reference-couting 'em. |
61 | } | 61 | } |
62 | } | 62 | } |
63 | 63 | ||
64 | 64 | ||
65 | //! loads a font file from xml | 65 | //! loads a font file from xml |
66 | bool CGUIFont::load(io::IXMLReader* xml) | 66 | bool CGUIFont::load(io::IXMLReader* xml) |
67 | { | 67 | { |
68 | if (!SpriteBank) | 68 | if (!SpriteBank) |
69 | return false; | 69 | return false; |
70 | 70 | ||
71 | SpriteBank->clear(); | 71 | SpriteBank->clear(); |
72 | 72 | ||
73 | while (xml->read()) | 73 | while (xml->read()) |
74 | { | 74 | { |
75 | if (io::EXN_ELEMENT == xml->getNodeType()) | 75 | if (io::EXN_ELEMENT == xml->getNodeType()) |
76 | { | 76 | { |
77 | if (core::stringw(L"Texture") == xml->getNodeName()) | 77 | if (core::stringw(L"Texture") == xml->getNodeName()) |
78 | { | 78 | { |
79 | // add a texture | 79 | // add a texture |
80 | core::stringc fn = xml->getAttributeValue(L"filename"); | 80 | core::stringc fn = xml->getAttributeValue(L"filename"); |
81 | u32 i = (u32)xml->getAttributeValueAsInt(L"index"); | 81 | u32 i = (u32)xml->getAttributeValueAsInt(L"index"); |
82 | core::stringw alpha = xml->getAttributeValue(L"hasAlpha"); | 82 | core::stringw alpha = xml->getAttributeValue(L"hasAlpha"); |
83 | 83 | ||
84 | while (i+1 > SpriteBank->getTextureCount()) | 84 | while (i+1 > SpriteBank->getTextureCount()) |
85 | SpriteBank->addTexture(0); | 85 | SpriteBank->addTexture(0); |
86 | 86 | ||
87 | // disable mipmaps+filtering | 87 | // disable mipmaps+filtering |
88 | bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); | 88 | bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); |
89 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); | 89 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); |
90 | 90 | ||
91 | // load texture | 91 | // load texture |
92 | SpriteBank->setTexture(i, Driver->getTexture(fn)); | 92 | SpriteBank->setTexture(i, Driver->getTexture(fn)); |
93 | 93 | ||
94 | // set previous mip-map+filter state | 94 | // set previous mip-map+filter state |
95 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap); | 95 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap); |
96 | 96 | ||
97 | // couldn't load texture, abort. | 97 | // couldn't load texture, abort. |
98 | if (!SpriteBank->getTexture(i)) | 98 | if (!SpriteBank->getTexture(i)) |
99 | { | 99 | { |
100 | os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR); | 100 | os::Printer::log("Unable to load all textures in the font, aborting", ELL_ERROR); |
101 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; | 101 | _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; |
102 | return false; | 102 | return false; |
103 | } | 103 | } |
104 | else | 104 | else |
105 | { | 105 | { |
106 | // colorkey texture rather than alpha channel? | 106 | // colorkey texture rather than alpha channel? |
107 | if (alpha == core::stringw("false")) | 107 | if (alpha == core::stringw("false")) |
108 | Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0)); | 108 | Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0)); |
109 | } | 109 | } |
110 | } | 110 | } |
111 | else if (core::stringw(L"c") == xml->getNodeName()) | 111 | else if (core::stringw(L"c") == xml->getNodeName()) |
112 | { | 112 | { |
113 | // adding a character to this font | 113 | // adding a character to this font |
114 | SFontArea a; | 114 | SFontArea a; |
115 | SGUISpriteFrame f; | 115 | SGUISpriteFrame f; |
116 | SGUISprite s; | 116 | SGUISprite s; |
117 | core::rect<s32> rectangle; | 117 | core::rect<s32> rectangle; |
118 | 118 | ||
119 | a.underhang = xml->getAttributeValueAsInt(L"u"); | 119 | a.underhang = xml->getAttributeValueAsInt(L"u"); |
120 | a.overhang = xml->getAttributeValueAsInt(L"o"); | 120 | a.overhang = xml->getAttributeValueAsInt(L"o"); |
121 | a.spriteno = SpriteBank->getSprites().size(); | 121 | a.spriteno = SpriteBank->getSprites().size(); |
122 | s32 texno = xml->getAttributeValueAsInt(L"i"); | 122 | s32 texno = xml->getAttributeValueAsInt(L"i"); |
123 | 123 | ||
124 | // parse rectangle | 124 | // parse rectangle |
125 | core::stringc rectstr = xml->getAttributeValue(L"r"); | 125 | core::stringc rectstr = xml->getAttributeValue(L"r"); |
126 | wchar_t ch = xml->getAttributeValue(L"c")[0]; | 126 | wchar_t ch = xml->getAttributeValue(L"c")[0]; |
127 | 127 | ||
128 | const c8 *c = rectstr.c_str(); | 128 | const c8 *c = rectstr.c_str(); |
129 | s32 val; | 129 | s32 val; |
130 | val = 0; | 130 | val = 0; |
131 | while (*c >= '0' && *c <= '9') | 131 | while (*c >= '0' && *c <= '9') |
132 | { | 132 | { |
133 | val *= 10; | 133 | val *= 10; |
134 | val += *c - '0'; | 134 | val += *c - '0'; |
135 | c++; | 135 | c++; |
136 | } | 136 | } |
137 | rectangle.UpperLeftCorner.X = val; | 137 | rectangle.UpperLeftCorner.X = val; |
138 | while (*c == L' ' || *c == L',') c++; | 138 | while (*c == L' ' || *c == L',') c++; |
139 | 139 | ||
140 | val = 0; | 140 | val = 0; |
141 | while (*c >= '0' && *c <= '9') | 141 | while (*c >= '0' && *c <= '9') |
142 | { | 142 | { |
143 | val *= 10; | 143 | val *= 10; |
144 | val += *c - '0'; | 144 | val += *c - '0'; |
145 | c++; | 145 | c++; |
146 | } | 146 | } |
147 | rectangle.UpperLeftCorner.Y = val; | 147 | rectangle.UpperLeftCorner.Y = val; |
148 | while (*c == L' ' || *c == L',') c++; | 148 | while (*c == L' ' || *c == L',') c++; |
149 | 149 | ||
150 | val = 0; | 150 | val = 0; |
151 | while (*c >= '0' && *c <= '9') | 151 | while (*c >= '0' && *c <= '9') |
152 | { | 152 | { |
153 | val *= 10; | 153 | val *= 10; |
154 | val += *c - '0'; | 154 | val += *c - '0'; |
155 | c++; | 155 | c++; |
156 | } | 156 | } |
157 | rectangle.LowerRightCorner.X = val; | 157 | rectangle.LowerRightCorner.X = val; |
158 | while (*c == L' ' || *c == L',') c++; | 158 | while (*c == L' ' || *c == L',') c++; |
159 | 159 | ||
160 | val = 0; | 160 | val = 0; |
161 | while (*c >= '0' && *c <= '9') | 161 | while (*c >= '0' && *c <= '9') |
162 | { | 162 | { |
163 | val *= 10; | 163 | val *= 10; |
164 | val += *c - '0'; | 164 | val += *c - '0'; |
165 | c++; | 165 | c++; |
166 | } | 166 | } |
167 | rectangle.LowerRightCorner.Y = val; | 167 | rectangle.LowerRightCorner.Y = val; |
168 | 168 | ||
169 | CharacterMap.insert(ch,Areas.size()); | 169 | CharacterMap.insert(ch,Areas.size()); |
170 | 170 | ||
171 | // make frame | 171 | // make frame |
172 | f.rectNumber = SpriteBank->getPositions().size(); | 172 | f.rectNumber = SpriteBank->getPositions().size(); |
173 | f.textureNumber = texno; | 173 | f.textureNumber = texno; |
174 | 174 | ||
175 | // add frame to sprite | 175 | // add frame to sprite |
176 | s.Frames.push_back(f); | 176 | s.Frames.push_back(f); |
177 | s.frameTime = 0; | 177 | s.frameTime = 0; |
178 | 178 | ||
179 | // add rectangle to sprite bank | 179 | // add rectangle to sprite bank |
180 | SpriteBank->getPositions().push_back(rectangle); | 180 | SpriteBank->getPositions().push_back(rectangle); |
181 | a.width = rectangle.getWidth(); | 181 | a.width = rectangle.getWidth(); |
182 | 182 | ||
183 | // add sprite to sprite bank | 183 | // add sprite to sprite bank |
184 | SpriteBank->getSprites().push_back(s); | 184 | SpriteBank->getSprites().push_back(s); |
185 | 185 | ||
186 | // add character to font | 186 | // add character to font |
187 | Areas.push_back(a); | 187 | Areas.push_back(a); |
188 | } | 188 | } |
189 | } | 189 | } |
190 | } | 190 | } |
191 | 191 | ||
192 | // set bad character | 192 | // set bad character |
193 | WrongCharacter = getAreaFromCharacter(L' '); | 193 | WrongCharacter = getAreaFromCharacter(L' '); |
194 | 194 | ||
195 | setMaxHeight(); | 195 | setMaxHeight(); |
196 | 196 | ||
197 | return true; | 197 | return true; |
198 | } | 198 | } |
199 | 199 | ||
200 | 200 | ||
201 | void CGUIFont::setMaxHeight() | 201 | void CGUIFont::setMaxHeight() |
202 | { | 202 | { |
203 | if ( !SpriteBank ) | 203 | if ( !SpriteBank ) |
204 | return; | 204 | return; |
205 | 205 | ||
206 | MaxHeight = 0; | 206 | MaxHeight = 0; |
207 | s32 t; | 207 | s32 t; |
208 | 208 | ||
209 | core::array< core::rect<s32> >& p = SpriteBank->getPositions(); | 209 | core::array< core::rect<s32> >& p = SpriteBank->getPositions(); |
210 | 210 | ||
211 | for (u32 i=0; i<p.size(); ++i) | 211 | for (u32 i=0; i<p.size(); ++i) |
212 | { | 212 | { |
213 | t = p[i].getHeight(); | 213 | t = p[i].getHeight(); |
214 | if (t>MaxHeight) | 214 | if (t>MaxHeight) |
215 | MaxHeight = t; | 215 | MaxHeight = t; |
216 | } | 216 | } |
217 | 217 | ||
218 | } | 218 | } |
219 | 219 | ||
220 | 220 | ||
221 | //! loads a font file, native file needed, for texture parsing | 221 | //! loads a font file, native file needed, for texture parsing |
222 | bool CGUIFont::load(io::IReadFile* file) | 222 | bool CGUIFont::load(io::IReadFile* file) |
223 | { | 223 | { |
224 | if (!Driver) | 224 | if (!Driver) |
225 | return false; | 225 | return false; |
226 | 226 | ||
227 | return loadTexture(Driver->createImageFromFile(file), | 227 | return loadTexture(Driver->createImageFromFile(file), |
228 | file->getFileName()); | 228 | file->getFileName()); |
229 | } | 229 | } |
230 | 230 | ||
231 | 231 | ||
232 | //! loads a font file, native file needed, for texture parsing | 232 | //! loads a font file, native file needed, for texture parsing |
233 | bool CGUIFont::load(const io::path& filename) | 233 | bool CGUIFont::load(const io::path& filename) |
234 | { | 234 | { |
235 | if (!Driver) | 235 | if (!Driver) |
236 | return false; | 236 | return false; |
237 | 237 | ||
238 | return loadTexture(Driver->createImageFromFile( filename ), | 238 | return loadTexture(Driver->createImageFromFile( filename ), |
239 | filename); | 239 | filename); |
240 | } | 240 | } |
241 | 241 | ||
242 | 242 | ||
243 | //! load & prepare font from ITexture | 243 | //! load & prepare font from ITexture |
244 | bool CGUIFont::loadTexture(video::IImage* image, const io::path& name) | 244 | bool CGUIFont::loadTexture(video::IImage* image, const io::path& name) |
245 | { | 245 | { |
246 | if (!image || !SpriteBank) | 246 | if (!image || !SpriteBank) |
247 | return false; | 247 | return false; |
248 | 248 | ||
249 | s32 lowerRightPositions = 0; | 249 | s32 lowerRightPositions = 0; |
250 | 250 | ||
251 | video::IImage* tmpImage=image; | 251 | video::IImage* tmpImage=image; |
252 | bool deleteTmpImage=false; | 252 | bool deleteTmpImage=false; |
253 | switch(image->getColorFormat()) | 253 | switch(image->getColorFormat()) |
254 | { | 254 | { |
255 | case video::ECF_R5G6B5: | 255 | case video::ECF_R5G6B5: |
256 | tmpImage = Driver->createImage(video::ECF_A1R5G5B5,image->getDimension()); | 256 | tmpImage = Driver->createImage(video::ECF_A1R5G5B5,image->getDimension()); |
257 | image->copyTo(tmpImage); | 257 | image->copyTo(tmpImage); |
258 | deleteTmpImage=true; | 258 | deleteTmpImage=true; |
259 | break; | 259 | break; |
260 | case video::ECF_A1R5G5B5: | 260 | case video::ECF_A1R5G5B5: |
261 | case video::ECF_A8R8G8B8: | 261 | case video::ECF_A8R8G8B8: |
262 | break; | 262 | break; |
263 | case video::ECF_R8G8B8: | 263 | case video::ECF_R8G8B8: |
264 | tmpImage = Driver->createImage(video::ECF_A8R8G8B8,image->getDimension()); | 264 | tmpImage = Driver->createImage(video::ECF_A8R8G8B8,image->getDimension()); |
265 | image->copyTo(tmpImage); | 265 | image->copyTo(tmpImage); |
266 | deleteTmpImage=true; | 266 | deleteTmpImage=true; |
267 | break; | 267 | break; |
268 | default: | 268 | default: |
269 | os::Printer::log("Unknown texture format provided for CGUIFont::loadTexture", ELL_ERROR); | 269 | os::Printer::log("Unknown texture format provided for CGUIFont::loadTexture", ELL_ERROR); |
270 | return false; | 270 | return false; |
271 | } | 271 | } |
272 | readPositions(tmpImage, lowerRightPositions); | 272 | readPositions(tmpImage, lowerRightPositions); |
273 | 273 | ||
274 | WrongCharacter = getAreaFromCharacter(L' '); | 274 | WrongCharacter = getAreaFromCharacter(L' '); |
275 | 275 | ||
276 | // output warnings | 276 | // output warnings |
277 | if (!lowerRightPositions || !SpriteBank->getSprites().size()) | 277 | if (!lowerRightPositions || !SpriteBank->getSprites().size()) |
278 | os::Printer::log("Either no upper or lower corner pixels in the font file. If this font was made using the new font tool, please load the XML file instead. If not, the font may be corrupted.", ELL_ERROR); | 278 | os::Printer::log("Either no upper or lower corner pixels in the font file. If this font was made using the new font tool, please load the XML file instead. If not, the font may be corrupted.", ELL_ERROR); |
279 | else | 279 | else |
280 | if (lowerRightPositions != (s32)SpriteBank->getPositions().size()) | 280 | if (lowerRightPositions != (s32)SpriteBank->getPositions().size()) |
281 | os::Printer::log("The amount of upper corner pixels and the lower corner pixels is not equal, font file may be corrupted.", ELL_ERROR); | 281 | os::Printer::log("The amount of upper corner pixels and the lower corner pixels is not equal, font file may be corrupted.", ELL_ERROR); |
282 | 282 | ||
283 | bool ret = ( !SpriteBank->getSprites().empty() && lowerRightPositions ); | 283 | bool ret = ( !SpriteBank->getSprites().empty() && lowerRightPositions ); |
284 | 284 | ||
285 | if ( ret ) | 285 | if ( ret ) |
286 | { | 286 | { |
287 | bool flag[2]; | 287 | bool flag[2]; |
288 | flag[0] = Driver->getTextureCreationFlag ( video::ETCF_ALLOW_NON_POWER_2 ); | 288 | flag[0] = Driver->getTextureCreationFlag ( video::ETCF_ALLOW_NON_POWER_2 ); |
289 | flag[1] = Driver->getTextureCreationFlag ( video::ETCF_CREATE_MIP_MAPS ); | 289 | flag[1] = Driver->getTextureCreationFlag ( video::ETCF_CREATE_MIP_MAPS ); |
290 | 290 | ||
291 | Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, true); | 291 | Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, true); |
292 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false ); | 292 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false ); |
293 | 293 | ||
294 | SpriteBank->addTexture(Driver->addTexture(name, tmpImage)); | 294 | SpriteBank->addTexture(Driver->addTexture(name, tmpImage)); |
295 | 295 | ||
296 | Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, flag[0] ); | 296 | Driver->setTextureCreationFlag(video::ETCF_ALLOW_NON_POWER_2, flag[0] ); |
297 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, flag[1] ); | 297 | Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, flag[1] ); |
298 | } | 298 | } |
299 | if (deleteTmpImage) | 299 | if (deleteTmpImage) |
300 | tmpImage->drop(); | 300 | tmpImage->drop(); |
301 | image->drop(); | 301 | image->drop(); |
302 | 302 | ||
303 | setMaxHeight(); | 303 | setMaxHeight(); |
304 | 304 | ||
305 | return ret; | 305 | return ret; |
306 | } | 306 | } |
307 | 307 | ||
308 | 308 | ||
309 | void CGUIFont::readPositions(video::IImage* image, s32& lowerRightPositions) | 309 | void CGUIFont::readPositions(video::IImage* image, s32& lowerRightPositions) |
310 | { | 310 | { |
311 | if (!SpriteBank ) | 311 | if (!SpriteBank ) |
312 | return; | 312 | return; |
313 | 313 | ||
314 | const core::dimension2d<u32> size = image->getDimension(); | 314 | const core::dimension2d<u32> size = image->getDimension(); |
315 | 315 | ||
316 | video::SColor colorTopLeft = image->getPixel(0,0); | 316 | video::SColor colorTopLeft = image->getPixel(0,0); |
317 | colorTopLeft.setAlpha(255); | 317 | colorTopLeft.setAlpha(255); |
318 | image->setPixel(0,0,colorTopLeft); | 318 | image->setPixel(0,0,colorTopLeft); |
319 | video::SColor colorLowerRight = image->getPixel(1,0); | 319 | video::SColor colorLowerRight = image->getPixel(1,0); |
320 | video::SColor colorBackGround = image->getPixel(2,0); | 320 | video::SColor colorBackGround = image->getPixel(2,0); |
321 | video::SColor colorBackGroundTransparent = 0; | 321 | video::SColor colorBackGroundTransparent = 0; |
322 | 322 | ||
323 | image->setPixel(1,0,colorBackGround); | 323 | image->setPixel(1,0,colorBackGround); |
324 | 324 | ||
325 | // start parsing | 325 | // start parsing |
326 | 326 | ||
327 | core::position2d<s32> pos(0,0); | 327 | core::position2d<s32> pos(0,0); |
328 | for (pos.Y=0; pos.Y<(s32)size.Height; ++pos.Y) | 328 | for (pos.Y=0; pos.Y<(s32)size.Height; ++pos.Y) |
329 | { | 329 | { |
330 | for (pos.X=0; pos.X<(s32)size.Width; ++pos.X) | 330 | for (pos.X=0; pos.X<(s32)size.Width; ++pos.X) |
331 | { | 331 | { |
332 | const video::SColor c = image->getPixel(pos.X, pos.Y); | 332 | const video::SColor c = image->getPixel(pos.X, pos.Y); |
333 | if (c == colorTopLeft) | 333 | if (c == colorTopLeft) |
334 | { | 334 | { |
335 | image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); | 335 | image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); |
336 | SpriteBank->getPositions().push_back(core::rect<s32>(pos, pos)); | 336 | SpriteBank->getPositions().push_back(core::rect<s32>(pos, pos)); |
337 | } | 337 | } |
338 | else | 338 | else |
339 | if (c == colorLowerRight) | 339 | if (c == colorLowerRight) |
340 | { | 340 | { |
341 | // too many lower right points | 341 | // too many lower right points |
342 | if (SpriteBank->getPositions().size()<=(u32)lowerRightPositions) | 342 | if (SpriteBank->getPositions().size()<=(u32)lowerRightPositions) |
343 | { | 343 | { |
344 | lowerRightPositions = 0; | 344 | lowerRightPositions = 0; |
345 | return; | 345 | return; |
346 | } | 346 | } |
347 | 347 | ||
348 | image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); | 348 | image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); |
349 | SpriteBank->getPositions()[lowerRightPositions].LowerRightCorner = pos; | 349 | SpriteBank->getPositions()[lowerRightPositions].LowerRightCorner = pos; |
350 | // add frame to sprite bank | 350 | // add frame to sprite bank |
351 | SGUISpriteFrame f; | 351 | SGUISpriteFrame f; |
352 | f.rectNumber = lowerRightPositions; | 352 | f.rectNumber = lowerRightPositions; |
353 | f.textureNumber = 0; | 353 | f.textureNumber = 0; |
354 | SGUISprite s; | 354 | SGUISprite s; |
355 | s.Frames.push_back(f); | 355 | s.Frames.push_back(f); |
356 | s.frameTime = 0; | 356 | s.frameTime = 0; |
357 | SpriteBank->getSprites().push_back(s); | 357 | SpriteBank->getSprites().push_back(s); |
358 | // add character to font | 358 | // add character to font |
359 | SFontArea a; | 359 | SFontArea a; |
360 | a.overhang = 0; | 360 | a.overhang = 0; |
361 | a.underhang = 0; | 361 | a.underhang = 0; |
362 | a.spriteno = lowerRightPositions; | 362 | a.spriteno = lowerRightPositions; |
363 | a.width = SpriteBank->getPositions()[lowerRightPositions].getWidth(); | 363 | a.width = SpriteBank->getPositions()[lowerRightPositions].getWidth(); |
364 | Areas.push_back(a); | 364 | Areas.push_back(a); |
365 | // map letter to character | 365 | // map letter to character |
366 | wchar_t ch = (wchar_t)(lowerRightPositions + 32); | 366 | wchar_t ch = (wchar_t)(lowerRightPositions + 32); |
367 | CharacterMap.set(ch, lowerRightPositions); | 367 | CharacterMap.set(ch, lowerRightPositions); |
368 | 368 | ||
369 | ++lowerRightPositions; | 369 | ++lowerRightPositions; |
370 | } | 370 | } |
371 | else | 371 | else |
372 | if (c == colorBackGround) | 372 | if (c == colorBackGround) |
373 | image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); | 373 | image->setPixel(pos.X, pos.Y, colorBackGroundTransparent); |
374 | } | 374 | } |
375 | } | 375 | } |
376 | } | 376 | } |
377 | 377 | ||
378 | 378 | ||
379 | //! set an Pixel Offset on Drawing ( scale position on width ) | 379 | //! set an Pixel Offset on Drawing ( scale position on width ) |
380 | void CGUIFont::setKerningWidth(s32 kerning) | 380 | void CGUIFont::setKerningWidth(s32 kerning) |
381 | { | 381 | { |
382 | GlobalKerningWidth = kerning; | 382 | GlobalKerningWidth = kerning; |
383 | } | 383 | } |
384 | 384 | ||
385 | 385 | ||
386 | //! set an Pixel Offset on Drawing ( scale position on width ) | 386 | //! set an Pixel Offset on Drawing ( scale position on width ) |
387 | s32 CGUIFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const | 387 | s32 CGUIFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previousLetter) const |
388 | { | 388 | { |
389 | s32 ret = GlobalKerningWidth; | 389 | s32 ret = GlobalKerningWidth; |
390 | 390 | ||
391 | if (thisLetter) | 391 | if (thisLetter) |
392 | { | 392 | { |
393 | ret += Areas[getAreaFromCharacter(*thisLetter)].overhang; | 393 | ret += Areas[getAreaFromCharacter(*thisLetter)].overhang; |
394 | 394 | ||
395 | if (previousLetter) | 395 | if (previousLetter) |
396 | { | 396 | { |
397 | ret += Areas[getAreaFromCharacter(*previousLetter)].underhang; | 397 | ret += Areas[getAreaFromCharacter(*previousLetter)].underhang; |
398 | } | 398 | } |
399 | } | 399 | } |
400 | 400 | ||
401 | return ret; | 401 | return ret; |
402 | } | 402 | } |
403 | 403 | ||
404 | 404 | ||
405 | //! set an Pixel Offset on Drawing ( scale position on height ) | 405 | //! set an Pixel Offset on Drawing ( scale position on height ) |
406 | void CGUIFont::setKerningHeight(s32 kerning) | 406 | void CGUIFont::setKerningHeight(s32 kerning) |
407 | { | 407 | { |
408 | GlobalKerningHeight = kerning; | 408 | GlobalKerningHeight = kerning; |
409 | } | 409 | } |
410 | 410 | ||
411 | 411 | ||
412 | //! set an Pixel Offset on Drawing ( scale position on height ) | 412 | //! set an Pixel Offset on Drawing ( scale position on height ) |
413 | s32 CGUIFont::getKerningHeight () const | 413 | s32 CGUIFont::getKerningHeight () const |
414 | { | 414 | { |
415 | return GlobalKerningHeight; | 415 | return GlobalKerningHeight; |
416 | } | 416 | } |
417 | 417 | ||
418 | 418 | ||
419 | //! returns the sprite number from a given character | 419 | //! returns the sprite number from a given character |
420 | u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const | 420 | u32 CGUIFont::getSpriteNoFromChar(const wchar_t *c) const |
421 | { | 421 | { |
422 | return Areas[getAreaFromCharacter(*c)].spriteno; | 422 | return Areas[getAreaFromCharacter(*c)].spriteno; |
423 | } | 423 | } |
424 | 424 | ||
425 | 425 | ||
426 | s32 CGUIFont::getAreaFromCharacter(const wchar_t c) const | 426 | s32 CGUIFont::getAreaFromCharacter(const wchar_t c) const |
427 | { | 427 | { |
428 | core::map<wchar_t, s32>::Node* n = CharacterMap.find(c); | 428 | core::map<wchar_t, s32>::Node* n = CharacterMap.find(c); |
429 | if (n) | 429 | if (n) |
430 | return n->getValue(); | 430 | return n->getValue(); |
431 | else | 431 | else |
432 | return WrongCharacter; | 432 | return WrongCharacter; |
433 | } | 433 | } |
434 | 434 | ||
435 | void CGUIFont::setInvisibleCharacters( const wchar_t *s ) | 435 | void CGUIFont::setInvisibleCharacters( const wchar_t *s ) |
436 | { | 436 | { |
437 | Invisible = s; | 437 | Invisible = s; |
438 | } | 438 | } |
439 | 439 | ||
440 | 440 | ||
441 | //! returns the dimension of text | 441 | //! returns the dimension of text |
442 | core::dimension2d<u32> CGUIFont::getDimension(const wchar_t* text) const | 442 | core::dimension2d<u32> CGUIFont::getDimension(const wchar_t* text) const |
443 | { | 443 | { |
444 | core::dimension2d<u32> dim(0, 0); | 444 | core::dimension2d<u32> dim(0, 0); |
445 | core::dimension2d<u32> thisLine(0, MaxHeight); | 445 | core::dimension2d<u32> thisLine(0, MaxHeight); |
446 | 446 | ||
447 | for (const wchar_t* p = text; *p; ++p) | 447 | for (const wchar_t* p = text; *p; ++p) |
448 | { | 448 | { |
449 | bool lineBreak=false; | 449 | bool lineBreak=false; |
450 | if (*p == L'\r') // Mac or Windows breaks | 450 | if (*p == L'\r') // Mac or Windows breaks |
451 | { | 451 | { |
452 | lineBreak = true; | 452 | lineBreak = true; |
453 | if (p[1] == L'\n') // Windows breaks | 453 | if (p[1] == L'\n') // Windows breaks |
454 | ++p; | 454 | ++p; |
455 | } | 455 | } |
456 | else if (*p == L'\n') // Unix breaks | 456 | else if (*p == L'\n') // Unix breaks |
457 | { | 457 | { |
458 | lineBreak = true; | 458 | lineBreak = true; |
459 | } | 459 | } |
460 | if (lineBreak) | 460 | if (lineBreak) |
461 | { | 461 | { |
462 | dim.Height += thisLine.Height; | 462 | dim.Height += thisLine.Height; |
463 | if (dim.Width < thisLine.Width) | 463 | if (dim.Width < thisLine.Width) |
464 | dim.Width = thisLine.Width; | 464 | dim.Width = thisLine.Width; |
465 | thisLine.Width = 0; | 465 | thisLine.Width = 0; |
466 | continue; | 466 | continue; |
467 | } | 467 | } |
468 | 468 | ||
469 | const SFontArea &area = Areas[getAreaFromCharacter(*p)]; | 469 | const SFontArea &area = Areas[getAreaFromCharacter(*p)]; |
470 | 470 | ||
471 | thisLine.Width += area.underhang; | 471 | thisLine.Width += area.underhang; |
472 | thisLine.Width += area.width + area.overhang + GlobalKerningWidth; | 472 | thisLine.Width += area.width + area.overhang + GlobalKerningWidth; |
473 | } | 473 | } |
474 | 474 | ||
475 | dim.Height += thisLine.Height; | 475 | dim.Height += thisLine.Height; |
476 | if (dim.Width < thisLine.Width) | 476 | if (dim.Width < thisLine.Width) |
477 | dim.Width = thisLine.Width; | 477 | dim.Width = thisLine.Width; |
478 | 478 | ||
479 | return dim; | 479 | return dim; |
480 | } | 480 | } |
481 | 481 | ||
482 | //! draws some text and clips it to the specified rectangle if wanted | 482 | //! draws some text and clips it to the specified rectangle if wanted |
483 | void CGUIFont::draw(const core::stringw& text, const core::rect<s32>& position, | 483 | void CGUIFont::draw(const core::stringw& text, const core::rect<s32>& position, |
484 | video::SColor color, | 484 | video::SColor color, |
485 | bool hcenter, bool vcenter, const core::rect<s32>* clip | 485 | bool hcenter, bool vcenter, const core::rect<s32>* clip |
486 | ) | 486 | ) |
487 | { | 487 | { |
488 | if (!Driver || !SpriteBank) | 488 | if (!Driver || !SpriteBank) |
489 | return; | 489 | return; |
490 | 490 | ||
491 | core::dimension2d<s32> textDimension; // NOTE: don't make this u32 or the >> later on can fail when the dimension width is < position width | 491 | core::dimension2d<s32> textDimension; // NOTE: don't make this u32 or the >> later on can fail when the dimension width is < position width |
492 | core::position2d<s32> offset = position.UpperLeftCorner; | 492 | core::position2d<s32> offset = position.UpperLeftCorner; |
493 | 493 | ||
494 | if (hcenter || vcenter || clip) | 494 | if (hcenter || vcenter || clip) |
495 | textDimension = getDimension(text.c_str()); | 495 | textDimension = getDimension(text.c_str()); |
496 | 496 | ||
497 | if (hcenter) | 497 | if (hcenter) |
498 | offset.X += (position.getWidth() - textDimension.Width) >> 1; | 498 | offset.X += (position.getWidth() - textDimension.Width) >> 1; |
499 | 499 | ||
500 | if (vcenter) | 500 | if (vcenter) |
501 | offset.Y += (position.getHeight() - textDimension.Height) >> 1; | 501 | offset.Y += (position.getHeight() - textDimension.Height) >> 1; |
502 | 502 | ||
503 | if (clip) | 503 | if (clip) |
504 | { | 504 | { |
505 | core::rect<s32> clippedRect(offset, textDimension); | 505 | core::rect<s32> clippedRect(offset, textDimension); |
506 | clippedRect.clipAgainst(*clip); | 506 | clippedRect.clipAgainst(*clip); |
507 | if (!clippedRect.isValid()) | 507 | if (!clippedRect.isValid()) |
508 | return; | 508 | return; |
509 | } | 509 | } |
510 | 510 | ||
511 | core::array<u32> indices(text.size()); | 511 | core::array<u32> indices(text.size()); |
512 | core::array<core::position2di> offsets(text.size()); | 512 | core::array<core::position2di> offsets(text.size()); |
513 | 513 | ||
514 | for(u32 i = 0;i < text.size();i++) | 514 | for(u32 i = 0;i < text.size();i++) |
515 | { | 515 | { |
516 | wchar_t c = text[i]; | 516 | wchar_t c = text[i]; |
517 | 517 | ||
518 | bool lineBreak=false; | 518 | bool lineBreak=false; |
519 | if ( c == L'\r') // Mac or Windows breaks | 519 | if ( c == L'\r') // Mac or Windows breaks |
520 | { | 520 | { |
521 | lineBreak = true; | 521 | lineBreak = true; |
522 | if ( text[i + 1] == L'\n') // Windows breaks | 522 | if ( text[i + 1] == L'\n') // Windows breaks |
523 | c = text[++i]; | 523 | c = text[++i]; |
524 | } | 524 | } |
525 | else if ( c == L'\n') // Unix breaks | 525 | else if ( c == L'\n') // Unix breaks |
526 | { | 526 | { |
527 | lineBreak = true; | 527 | lineBreak = true; |
528 | } | 528 | } |
529 | 529 | ||
530 | if (lineBreak) | 530 | if (lineBreak) |
531 | { | 531 | { |
532 | offset.Y += MaxHeight; | 532 | offset.Y += MaxHeight; |
533 | offset.X = position.UpperLeftCorner.X; | 533 | offset.X = position.UpperLeftCorner.X; |
534 | 534 | ||
535 | if ( hcenter ) | 535 | if ( hcenter ) |
536 | { | 536 | { |
537 | offset.X += (position.getWidth() - textDimension.Width) >> 1; | 537 | offset.X += (position.getWidth() - textDimension.Width) >> 1; |
538 | } | 538 | } |
539 | continue; | 539 | continue; |
540 | } | 540 | } |
541 | 541 | ||
542 | SFontArea& area = Areas[getAreaFromCharacter(c)]; | 542 | SFontArea& area = Areas[getAreaFromCharacter(c)]; |
543 | 543 | ||
544 | offset.X += area.underhang; | 544 | offset.X += area.underhang; |
545 | if ( Invisible.findFirst ( c ) < 0 ) | 545 | if ( Invisible.findFirst ( c ) < 0 ) |
546 | { | 546 | { |
547 | indices.push_back(area.spriteno); | 547 | indices.push_back(area.spriteno); |
548 | offsets.push_back(offset); | 548 | offsets.push_back(offset); |
549 | } | 549 | } |
550 | 550 | ||
551 | offset.X += area.width + area.overhang + GlobalKerningWidth; | 551 | offset.X += area.width + area.overhang + GlobalKerningWidth; |
552 | } | 552 | } |
553 | 553 | ||
554 | SpriteBank->draw2DSpriteBatch(indices, offsets, clip, color); | 554 | SpriteBank->draw2DSpriteBatch(indices, offsets, clip, color); |
555 | } | 555 | } |
556 | 556 | ||
557 | 557 | ||
558 | //! Calculates the index of the character in the text which is on a specific position. | 558 | //! Calculates the index of the character in the text which is on a specific position. |
559 | s32 CGUIFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const | 559 | s32 CGUIFont::getCharacterFromPos(const wchar_t* text, s32 pixel_x) const |
560 | { | 560 | { |
561 | s32 x = 0; | 561 | s32 x = 0; |
562 | s32 idx = 0; | 562 | s32 idx = 0; |
563 | 563 | ||
564 | while (text[idx]) | 564 | while (text[idx]) |
565 | { | 565 | { |
566 | const SFontArea& a = Areas[getAreaFromCharacter(text[idx])]; | 566 | const SFontArea& a = Areas[getAreaFromCharacter(text[idx])]; |
567 | 567 | ||
568 | x += a.width + a.overhang + a.underhang + GlobalKerningWidth; | 568 | x += a.width + a.overhang + a.underhang + GlobalKerningWidth; |
569 | 569 | ||
570 | if (x >= pixel_x) | 570 | if (x >= pixel_x) |
571 | return idx; | 571 | return idx; |
572 | 572 | ||
573 | ++idx; | 573 | ++idx; |
574 | } | 574 | } |
575 | 575 | ||
576 | return -1; | 576 | return -1; |
577 | } | 577 | } |
578 | 578 | ||
579 | 579 | ||
580 | IGUISpriteBank* CGUIFont::getSpriteBank() const | 580 | IGUISpriteBank* CGUIFont::getSpriteBank() const |
581 | { | 581 | { |
582 | return SpriteBank; | 582 | return SpriteBank; |
583 | } | 583 | } |
584 | 584 | ||
585 | } // end namespace gui | 585 | } // end namespace gui |
586 | } // end namespace irr | 586 | } // end namespace irr |
587 | 587 | ||
588 | #endif // _IRR_COMPILE_WITH_GUI_ | 588 | #endif // _IRR_COMPILE_WITH_GUI_ |
589 | 589 | ||