~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to tests/2dmaterial.cpp

  • Committer: Mantas Kriaučiūnas
  • Date: 2011-07-18 13:06:25 UTC
  • Revision ID: mantas@akl.lt-20110718130625-c5pvifp61e7kj1ol
Included whole irrlicht SVN libraries to work around launchpad recipe issue with quilt, see https://answers.launchpad.net/launchpad/+question/165193

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#include "testUtils.h"
 
2
#include <map>
 
3
using namespace irr;
 
4
 
 
5
namespace
 
6
{
 
7
// don't use this code! It lacks many checks and is for testing
 
8
// purposes only!!!
 
9
// based on code and media from SuperTuxKart
 
10
class ScalableFont : public gui::IGUIFontBitmap
 
11
{
 
12
        float m_scale;
 
13
        struct TextureInfo
 
14
        {
 
15
                irr::core::stringc m_file_name;
 
16
                bool m_has_alpha;
 
17
                float m_scale;
 
18
                
 
19
                TextureInfo()
 
20
                {
 
21
                        m_has_alpha = false;
 
22
                        m_scale = 1.0f;
 
23
                }
 
24
        };
 
25
        
 
26
        std::map<int /* texture file ID */, TextureInfo> m_texture_files;
 
27
        
 
28
        void lazyLoadTexture(int texID)
 
29
        {
 
30
                const bool mipmap = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS);
 
31
                Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true);
 
32
                // load texture
 
33
                SpriteBank->setTexture(texID, Driver->getTexture( m_texture_files[texID].m_file_name ));
 
34
                // set previous mip-map+filter state
 
35
                Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap);
 
36
                
 
37
                // couldn't load texture, abort.
 
38
                if (!SpriteBank->getTexture(texID))
 
39
                {
 
40
                        return;
 
41
                }
 
42
                else
 
43
                {
 
44
                        // colorkey texture rather than alpha channel?
 
45
                        if (! m_texture_files[texID].m_has_alpha)
 
46
                        {
 
47
                                Driver->makeColorKeyTexture(SpriteBank->getTexture(texID), core::position2di(0,0));
 
48
                        }
 
49
                }
 
50
        }
 
51
        void doReadXmlFile(io::IXMLReader* xml)
 
52
        {
 
53
                while (xml->read())
 
54
                {
 
55
                        if (io::EXN_ELEMENT == xml->getNodeType())
 
56
                        {
 
57
                                if (core::stringw(L"include") == xml->getNodeName())
 
58
                                {
 
59
                                        core::stringc filename = xml->getAttributeValue(L"file");
 
60
                                        io::IXMLReader* included = Environment->getFileSystem()->createXMLReader(filename.c_str());
 
61
                                        if (included != NULL)
 
62
                                        {
 
63
                                                doReadXmlFile(included);
 
64
                                                included->drop();
 
65
                                        }
 
66
                                }
 
67
                                else if (core::stringw(L"Texture") == xml->getNodeName())
 
68
                                {
 
69
                                        // add a texture
 
70
                                        core::stringc filename = xml->getAttributeValue(L"filename");
 
71
                                        core::stringc fn = filename;
 
72
                                        u32 i = (u32)xml->getAttributeValueAsInt(L"index");
 
73
                                        
 
74
                                        float scale=1.0f;
 
75
                                        if (xml->getAttributeValue(L"scale"))
 
76
                                                scale = xml->getAttributeValueAsFloat(L"scale");
 
77
                                                //std::cout  << "scale = " << scale << std::endl;
 
78
                                                
 
79
                                        core::stringw alpha = xml->getAttributeValue(L"hasAlpha");
 
80
                                        
 
81
                                        //std::cout << "---- Adding font texture " << fn.c_str() << "; alpha=" << alpha.c_str() << std::endl;
 
82
                                        
 
83
                                        
 
84
                                        // make sure the sprite bank has enough textures in it
 
85
                                        while (i+1 > SpriteBank->getTextureCount())
 
86
                                        {
 
87
                                                SpriteBank->addTexture(NULL);
 
88
                                        }
 
89
                                
 
90
                                        TextureInfo info;
 
91
                                        info.m_file_name   = fn;
 
92
                                        info.m_has_alpha   = (alpha == core::stringw("true"));
 
93
                                        info.m_scale = scale;
 
94
                                        
 
95
                                        m_texture_files[i] = info;                              
 
96
                                }
 
97
                                else if (core::stringw(L"c") == xml->getNodeName())
 
98
                                {
 
99
                                        // adding a character to this font
 
100
                                        SFontArea a;
 
101
                                        gui::SGUISpriteFrame f;
 
102
                                        gui::SGUISprite s;
 
103
                                        core::rect<s32> rectangle;
 
104
                                        
 
105
                                        a.underhang = xml->getAttributeValueAsInt(L"u");
 
106
                                        a.overhang = xml->getAttributeValueAsInt(L"o");
 
107
                                        a.spriteno = SpriteBank->getSprites().size();
 
108
                                        s32 texno = xml->getAttributeValueAsInt(L"i");
 
109
                                        
 
110
                                        // parse rectangle
 
111
                                        core::stringc rectstr   = xml->getAttributeValue(L"r");
 
112
                                        wchar_t ch = xml->getAttributeValue(L"c")[0];
 
113
                                        
 
114
                                        const c8 *c = rectstr.c_str();
 
115
                                        s32 val;
 
116
                                        val = 0;
 
117
                                        while (*c >= '0' && *c <= '9')
 
118
                                        {
 
119
                                                val *= 10;
 
120
                                                val += *c - '0';
 
121
                                                c++;
 
122
                                        }
 
123
                                        rectangle.UpperLeftCorner.X = val;
 
124
                                        while (*c == L' ' || *c == L',') c++;
 
125
                                        
 
126
                                        val = 0;
 
127
                                        while (*c >= '0' && *c <= '9')
 
128
                                        {
 
129
                                                val *= 10;
 
130
                                                val += *c - '0';
 
131
                                                c++;
 
132
                                        }
 
133
                                        rectangle.UpperLeftCorner.Y = val;
 
134
                                        while (*c == L' ' || *c == L',') c++;
 
135
                                        
 
136
                                        val = 0;
 
137
                                        while (*c >= '0' && *c <= '9')
 
138
                                        {
 
139
                                                val *= 10;
 
140
                                                val += *c - '0';
 
141
                                                c++;
 
142
                                        }
 
143
                                        rectangle.LowerRightCorner.X = val;
 
144
                                        while (*c == L' ' || *c == L',') c++;
 
145
                                        
 
146
                                        val = 0;
 
147
                                        while (*c >= '0' && *c <= '9')
 
148
                                        {
 
149
                                                val *= 10;
 
150
                                                val += *c - '0';
 
151
                                                c++;
 
152
                                        }
 
153
                                        rectangle.LowerRightCorner.Y = val;
 
154
                                        
 
155
                                        CharacterMap[ch] = Areas.size();
 
156
                                        
 
157
                                        // make frame
 
158
                                        f.rectNumber = SpriteBank->getPositions().size();
 
159
                                        f.textureNumber = texno;
 
160
                                        
 
161
                                        // add frame to sprite
 
162
                                        s.Frames.push_back(f);
 
163
                                        s.frameTime = 0;
 
164
                                        
 
165
                                        // add rectangle to sprite bank
 
166
                                        SpriteBank->getPositions().push_back(rectangle);
 
167
                                        a.width = rectangle.getWidth();
 
168
                                        
 
169
                                        // add sprite to sprite bank
 
170
                                        SpriteBank->getSprites().push_back(s);
 
171
                                        
 
172
                                        // add character to font
 
173
                                        Areas.push_back(a);
 
174
                                }
 
175
                        }
 
176
                }
 
177
        }
 
178
 
 
179
public:
 
180
 
 
181
        bool m_black_border;
 
182
        
 
183
        ScalableFont* m_fallback_font;
 
184
        float m_fallback_font_scale;
 
185
        int m_fallback_kerning_width;
 
186
        
 
187
        //! constructor
 
188
        ScalableFont(gui::IGUIEnvironment *env, const io::path& filename)
 
189
        : Driver(0), SpriteBank(0), Environment(env), WrongCharacter(0),
 
190
                MaxHeight(0), GlobalKerningWidth(0), GlobalKerningHeight(0)
 
191
        {
 
192
        #ifdef _DEBUG
 
193
                setDebugName("ScalableFont");
 
194
        #endif
 
195
                
 
196
                m_fallback_font = NULL;
 
197
                m_fallback_kerning_width = 0;
 
198
                m_fallback_font_scale = 1.0f;
 
199
                m_scale = 0.37f;
 
200
                m_black_border = false;
 
201
 
 
202
                if (Environment)
 
203
                {
 
204
                        // don't grab environment, to avoid circular references
 
205
                        Driver = Environment->getVideoDriver();
 
206
 
 
207
                        SpriteBank = Environment->addEmptySpriteBank(filename);
 
208
                        if (SpriteBank)
 
209
                                SpriteBank->grab();
 
210
                }
 
211
 
 
212
                if (Driver)
 
213
                        Driver->grab();
 
214
 
 
215
                setInvisibleCharacters ( L" " );
 
216
                
 
217
                io::IXMLReader* reader = env->getFileSystem()->createXMLReader(filename.c_str());
 
218
                if (reader)
 
219
                {
 
220
                        load( reader );
 
221
                        reader->drop();
 
222
                }
 
223
                assert(Areas.size() > 0);
 
224
        }
 
225
 
 
226
        //! destructor
 
227
        virtual ~ScalableFont()
 
228
        {
 
229
                if (Driver)
 
230
                        Driver->drop();
 
231
                if (SpriteBank)
 
232
                        SpriteBank->drop();
 
233
        }
 
234
 
 
235
        //! loads a font from an XML file
 
236
        bool load(io::IXMLReader* xml)
 
237
        {
 
238
                if (!SpriteBank)
 
239
                        return false;
 
240
 
 
241
                doReadXmlFile(xml);
 
242
                
 
243
                // set bad character
 
244
                WrongCharacter = getAreaIDFromCharacter(L' ', NULL);
 
245
 
 
246
                setMaxHeight();
 
247
 
 
248
                for(wchar_t c='0'; c<='9'; c++)
 
249
                {
 
250
                        SFontArea a = getAreaFromCharacter(c, NULL);
 
251
                        if (a.overhang > m_max_digit_area.overhang ) m_max_digit_area.overhang  = a.overhang;
 
252
                        if (a.underhang > m_max_digit_area.underhang) m_max_digit_area.underhang = a.underhang;
 
253
                        if (a.width > m_max_digit_area.width) m_max_digit_area.width = a.width;
 
254
                }
 
255
                m_max_digit_area.overhang = 0;
 
256
                m_max_digit_area.underhang=0;
 
257
                return true;
 
258
        }
 
259
        //! draws an text and clips it to the specified rectangle if wanted
 
260
        virtual void draw(const core::stringw& text, const core::rect<s32>& position,
 
261
                        video::SColor color, bool hcenter=false,
 
262
                        bool vcenter=false, const core::rect<s32>* clip=0)
 
263
        {
 
264
                if (!Driver) return;
 
265
                
 
266
                core::position2d<s32> offset = position.UpperLeftCorner;
 
267
                core::dimension2d<s32> text_dimension;
 
268
 
 
269
                // When we use the "tab" hack, disable right-alignment, it messes up everything
 
270
//              bool has_tab = (text.findFirst(L'\t') != -1);
 
271
                // ---- collect character locations
 
272
                const unsigned int text_size = text.size();
 
273
                core::array<s32> indices(text_size);
 
274
                core::array<core::position2di> offsets(text_size);
 
275
                core::array<bool> fallback;
 
276
                fallback.set_used(text_size);
 
277
                
 
278
                for (u32 i = 0; i<text_size; i++)
 
279
                {
 
280
                        wchar_t c = text[i];
 
281
 
 
282
                        //hack: one tab character is supported, it moves the cursor to the middle of the area
 
283
                        if (c == L'\t')
 
284
                        {
 
285
                                offset.X = position.UpperLeftCorner.X + position.getWidth()/2;
 
286
                                continue;
 
287
                        }
 
288
                        
 
289
                        if (c == L'\r' ||       // Windows breaks
 
290
                                c == L'\n')     // Unix breaks
 
291
                        {
 
292
                                if (c==L'\r' && text[i+1]==L'\n')
 
293
                                        c = text[++i];
 
294
                                offset.Y += (int)(MaxHeight*m_scale);
 
295
                                offset.X  = position.UpperLeftCorner.X;
 
296
                                if (hcenter)
 
297
                                        offset.X += (position.getWidth() - text_dimension.Width) >> 1;
 
298
                                continue;
 
299
                        }   // if lineBreak
 
300
 
 
301
                        bool use_fallback_font = false;
 
302
                        const SFontArea &area  = getAreaFromCharacter(c, &use_fallback_font);
 
303
                        fallback[i] = use_fallback_font;
 
304
                        offset.X += area.underhang;
 
305
                        offsets.push_back(offset);
 
306
                        // Invisible character. add something to the array anyway so that 
 
307
                        // indices from the various arrays remain in sync
 
308
                        indices.push_back((Invisible.findFirst(c) < 0) ? (int)area.spriteno
 
309
                                                : -1);
 
310
                        offset.X += getCharWidth(area, fallback[i]);
 
311
                }   // for i<text_size
 
312
 
 
313
                // ---- do the actual rendering
 
314
                const int indiceAmount = indices.size();
 
315
                core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();
 
316
                core::array< core::rect<s32> >& positions = SpriteBank->getPositions(); 
 
317
                core::array< gui::SGUISprite >* fallback_sprites;
 
318
                core::array< core::rect<s32> >* fallback_positions;
 
319
                if (m_fallback_font!=NULL)
 
320
                {
 
321
                        fallback_sprites   = &m_fallback_font->SpriteBank->getSprites();
 
322
                        fallback_positions = &m_fallback_font->SpriteBank->getPositions();
 
323
                }
 
324
                else
 
325
                {
 
326
                        fallback_sprites   = NULL;
 
327
                        fallback_positions = NULL;
 
328
                }
 
329
 
 
330
                video::IVideoDriver* driver = Environment->getVideoDriver();
 
331
                const int spriteAmount = sprites.size();
 
332
                for (int n=0; n<indiceAmount; n++)
 
333
                {
 
334
                        const int spriteID = indices[n];
 
335
                        if (!fallback[n] && (spriteID < 0 || spriteID >= spriteAmount))
 
336
                                continue;
 
337
                        if (indices[n] == -1)
 
338
                                continue;
 
339
                        
 
340
                        //assert(sprites[spriteID].Frames.size() > 0);
 
341
                        
 
342
                        const int texID = (fallback[n] ?
 
343
                                        (*fallback_sprites)[spriteID].Frames[0].textureNumber :
 
344
                                        sprites[spriteID].Frames[0].textureNumber);
 
345
                        
 
346
                        core::rect<s32> source = (fallback[n] ?
 
347
                                                (*fallback_positions)[(*fallback_sprites)[spriteID].Frames[0].rectNumber] :
 
348
                                                positions[sprites[spriteID].Frames[0].rectNumber]);
 
349
                        
 
350
                        const TextureInfo& info = (fallback[n] ?
 
351
                                                (*(m_fallback_font->m_texture_files.find(texID))).second :
 
352
                                                (*(m_texture_files.find(texID))).second);
 
353
                        float char_scale = info.m_scale;
 
354
 
 
355
                        core::dimension2d<s32> size = source.getSize();
 
356
                        
 
357
                        float scale = (fallback[n] ? m_scale*m_fallback_font_scale : m_scale);
 
358
                        size.Width  = (int)(size.Width  * scale * char_scale);
 
359
                        size.Height = (int)(size.Height * scale * char_scale);
 
360
                        
 
361
                        // align vertically if character is smaller
 
362
                        int y_shift = (size.Height < MaxHeight*m_scale ? (int)((MaxHeight*m_scale - size.Height)/2.0f) : 0);
 
363
                        
 
364
                        core::rect<s32> dest(offsets[n] + core::position2di(0, y_shift), size);
 
365
                        
 
366
                        video::SColor colors[] = {color, color, color, color};
 
367
                                        
 
368
                        video::ITexture* texture = (fallback[n] ?
 
369
                                                                                m_fallback_font->SpriteBank->getTexture(texID) :
 
370
                                                                                SpriteBank->getTexture(texID) );
 
371
                        
 
372
                        if (texture == NULL)
 
373
                        {
 
374
                                // perform lazy loading
 
375
                                
 
376
                                if (fallback[n])
 
377
                                {
 
378
                                        m_fallback_font->lazyLoadTexture(texID);
 
379
                                        texture = m_fallback_font->SpriteBank->getTexture(texID);
 
380
                                }
 
381
                                else
 
382
                                {
 
383
                                        lazyLoadTexture(texID);
 
384
                                        texture = SpriteBank->getTexture(texID);
 
385
                                }
 
386
                                
 
387
                                if (texture == NULL)
 
388
                                {
 
389
                                        continue; // no such character
 
390
                                }
 
391
                        }
 
392
                        
 
393
                        if (m_black_border)
 
394
                        {
 
395
                                // draw black border
 
396
                                video::SColor black(color.getAlpha(),0,0,0);
 
397
                                video::SColor black_colors[] = {black, black, black, black};
 
398
                                
 
399
                                for (int x_delta=-2; x_delta<=2; x_delta++)
 
400
                                {
 
401
                                        for (int y_delta=-2; y_delta<=2; y_delta++)
 
402
                                        {
 
403
                                                if (x_delta == 0 || y_delta == 0) continue;
 
404
                                                driver->draw2DImage(texture,
 
405
                                                                                        dest + core::position2d<s32>(x_delta, y_delta),
 
406
                                                                                        source,
 
407
                                                                                        clip,
 
408
                                                                                        black_colors, true);
 
409
                                        }                       
 
410
                                }
 
411
                        }
 
412
                        
 
413
                        if (fallback[n])
 
414
                        {
 
415
                                // draw text over
 
416
                                static video::SColor orange(color.getAlpha(), 255, 100, 0);
 
417
                                static video::SColor yellow(color.getAlpha(), 255, 220, 15);
 
418
                                video::SColor title_colors[] = {yellow, orange, orange, yellow};
 
419
                                driver->draw2DImage(texture,
 
420
                                                                        dest,
 
421
                                                                        source,
 
422
                                                                        clip,
 
423
                                                                        title_colors, true);
 
424
                        }
 
425
                        else
 
426
                        {
 
427
                                driver->draw2DImage(texture,
 
428
                                                                        dest,
 
429
                                                                        source,
 
430
                                                                        clip,
 
431
                                                                        colors, true);
 
432
                                
 
433
                        }
 
434
                }
 
435
        }
 
436
 
 
437
        //! returns the dimension of a text
 
438
        virtual core::dimension2d<u32> getDimension(const wchar_t* text) const
 
439
        {
 
440
                assert(Areas.size() > 0);
 
441
                
 
442
                core::dimension2d<u32> dim(0, 0);
 
443
                core::dimension2d<u32> thisLine(0, (int)(MaxHeight*m_scale));
 
444
 
 
445
                for (const wchar_t* p = text; *p; ++p)
 
446
                {
 
447
                        if (*p == L'\r' || // Windows breaks
 
448
                                *p == L'\n') // Unix breaks
 
449
                        {
 
450
                                if (*p==L'\r' && p[1] == L'\n') // Windows breaks
 
451
                                        ++p;
 
452
                                dim.Height += thisLine.Height;
 
453
                                if (dim.Width < thisLine.Width)
 
454
                                        dim.Width = thisLine.Width;
 
455
                                thisLine.Width = 0;
 
456
                                continue;
 
457
                        }
 
458
 
 
459
                        bool fallback = false;
 
460
                        const SFontArea &area = getAreaFromCharacter(*p, &fallback);
 
461
                                
 
462
                        thisLine.Width += area.underhang;
 
463
                        
 
464
                        thisLine.Width += getCharWidth(area, fallback);
 
465
                }
 
466
 
 
467
                dim.Height += thisLine.Height;
 
468
                if (dim.Width < thisLine.Width) dim.Width = thisLine.Width;
 
469
 
 
470
                // std::cout << "ScalableFont::getDimension returns : " << dim.Width << ", " << dim.Height << " --> ";
 
471
 
 
472
                dim.Width  = (int)(dim.Width + 0.9f); // round up
 
473
                dim.Height = (int)(dim.Height + 0.9f);
 
474
 
 
475
                //std::cout << dim.Width << ", " << dim.Height << std::endl;
 
476
                
 
477
                return dim;
 
478
        }
 
479
        //! Calculates the index of the character in the text which is on a specific position.
 
480
        virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const
 
481
        {
 
482
                s32 x = 0;
 
483
                s32 idx = 0;
 
484
 
 
485
                while (text[idx])
 
486
                {
 
487
                        const SFontArea& a = Areas[getAreaIDFromCharacter(text[idx], NULL)];
 
488
 
 
489
                        x += a.width + a.overhang + a.underhang + GlobalKerningWidth;
 
490
 
 
491
                        if (x >= pixel_x)
 
492
                                return idx;
 
493
 
 
494
                        ++idx;
 
495
                }
 
496
 
 
497
                return -1;
 
498
        }
 
499
        //! Returns the type of this font
 
500
        virtual gui::EGUI_FONT_TYPE getType() const { return gui::EGFT_BITMAP; }
 
501
 
 
502
        //! set an Pixel Offset on Drawing ( scale position on width )
 
503
        virtual void setKerningWidth (s32 kerning)
 
504
        {
 
505
                GlobalKerningWidth = kerning;
 
506
        }
 
507
        virtual void setKerningHeight (s32 kerning)
 
508
        {
 
509
                GlobalKerningHeight = kerning;
 
510
        }
 
511
        //! set an Pixel Offset on Drawing ( scale position on width )
 
512
        virtual s32 getKerningWidth(const wchar_t* thisLetter=0, const wchar_t* previousLetter=0) const
 
513
        {
 
514
                s32 ret = GlobalKerningWidth;
 
515
 
 
516
                if (thisLetter)
 
517
                {
 
518
                        ret += Areas[getAreaIDFromCharacter(*thisLetter, NULL)].overhang;
 
519
 
 
520
                        if (previousLetter)
 
521
                        {
 
522
                                ret += Areas[getAreaIDFromCharacter(*previousLetter, NULL)].underhang;
 
523
                        }
 
524
                }
 
525
 
 
526
                return ret;
 
527
        }
 
528
        virtual s32 getKerningHeight() const
 
529
        {
 
530
                return GlobalKerningHeight;
 
531
        }
 
532
 
 
533
        //! gets the sprite bank
 
534
        virtual gui::IGUISpriteBank* getSpriteBank() const
 
535
        {
 
536
                return SpriteBank;
 
537
        }
 
538
 
 
539
        //! returns the sprite number from a given character
 
540
        virtual u32 getSpriteNoFromChar(const wchar_t *c) const
 
541
        {
 
542
                return Areas[getAreaIDFromCharacter(*c, NULL)].spriteno;
 
543
        }
 
544
 
 
545
        virtual void setInvisibleCharacters( const wchar_t *s )
 
546
        {
 
547
                Invisible = s;
 
548
        }
 
549
 
 
550
private:
 
551
 
 
552
        struct SFontArea
 
553
        {
 
554
                SFontArea() : underhang(0), overhang(0), width(0), spriteno(0) {}
 
555
                s32 underhang;
 
556
                s32 overhang;
 
557
                s32 width;
 
558
                u32 spriteno;
 
559
        };
 
560
        
 
561
        int getCharWidth(const SFontArea& area, const bool fallback) const
 
562
        {
 
563
                core::array< gui::SGUISprite >& sprites = SpriteBank->getSprites();             
 
564
                core::array< gui::SGUISprite >* fallback_sprites = (m_fallback_font != NULL ?
 
565
                                                                                                        &m_fallback_font->SpriteBank->getSprites() :
 
566
                                                                                                        NULL);
 
567
                
 
568
                const int texID = (fallback ?
 
569
                                (*fallback_sprites)[area.spriteno].Frames[0].textureNumber :
 
570
                                sprites[area.spriteno].Frames[0].textureNumber);
 
571
                
 
572
                const TextureInfo& info = (fallback ?
 
573
                                        (*(m_fallback_font->m_texture_files.find(texID))).second :
 
574
                                        (*(m_texture_files.find(texID))).second);
 
575
                const float char_scale = info.m_scale;
 
576
                
 
577
                //std::cout << "area.spriteno=" << area.spriteno << ", char_scale=" << char_scale << std::endl;
 
578
                
 
579
                if (fallback)
 
580
                        return (int)(((area.width + area.overhang)*m_fallback_font_scale + m_fallback_kerning_width) * m_scale * char_scale);
 
581
                else
 
582
                        return (int)((area.width + area.overhang + GlobalKerningWidth) * m_scale * char_scale);
 
583
        }
 
584
        s32 getAreaIDFromCharacter(const wchar_t c, bool* fallback_font) const
 
585
        {
 
586
                std::map<wchar_t, s32>::const_iterator n = CharacterMap.find(c);
 
587
                if (n != CharacterMap.end())
 
588
                {
 
589
                        if (fallback_font != NULL)
 
590
                                *fallback_font = false;
 
591
                        return (*n).second;
 
592
                }
 
593
                else if (m_fallback_font != NULL && fallback_font != NULL)
 
594
                {
 
595
                        *fallback_font = true;
 
596
                        return m_fallback_font->getAreaIDFromCharacter(c, NULL);
 
597
                }
 
598
                else
 
599
                {
 
600
                        // std::cout << "The font does not have this character : <" << (int)c << ">" << std::endl;
 
601
                        if (fallback_font != NULL)
 
602
                                *fallback_font = false;
 
603
                        return WrongCharacter;
 
604
                }
 
605
        }
 
606
        const SFontArea &getAreaFromCharacter(const wchar_t c, bool* fallback_font) const
 
607
        {
 
608
                const int area_id = getAreaIDFromCharacter(c, fallback_font);
 
609
                const bool use_fallback_font = (fallback_font && *fallback_font);
 
610
                
 
611
                // Note: fallback_font can be NULL
 
612
                return ( use_fallback_font ? m_fallback_font->Areas[area_id] : Areas[area_id]);
 
613
        }   // getAreaFromCharacter
 
614
        void setMaxHeight()
 
615
        {
 
616
                // FIXME: should consider per-texture scaling
 
617
                MaxHeight = 0;
 
618
                s32 t;
 
619
 
 
620
                core::array< core::rect<s32> >& p = SpriteBank->getPositions();
 
621
 
 
622
                for (u32 i=0; i<p.size(); ++i)
 
623
                {
 
624
                        t = p[i].getHeight();
 
625
                        if (t>MaxHeight)
 
626
                                MaxHeight = t;
 
627
                }
 
628
        }
 
629
        core::array<SFontArea>  Areas;
 
630
        /** The maximum values of all digits, used in monospace_digits. */
 
631
        mutable SFontArea       m_max_digit_area;
 
632
        std::map<wchar_t, s32>  CharacterMap;
 
633
        video::IVideoDriver*    Driver;
 
634
        gui::IGUISpriteBank*    SpriteBank;
 
635
        gui::IGUIEnvironment*   Environment;
 
636
        u32                     WrongCharacter;
 
637
        s32                     MaxHeight;
 
638
        s32                     GlobalKerningWidth, GlobalKerningHeight;
 
639
 
 
640
        core::stringw Invisible;
 
641
};
 
642
}
 
643
 
 
644
// The actual bug that was behind this issue was the combination of
 
645
// 2d rendering and mipmaps. The issue was reproduced using the special
 
646
// draw2dimage version, hence the name.
 
647
static bool draw2DImage4c(video::E_DRIVER_TYPE type)
 
648
{
 
649
        IrrlichtDevice *device = createDevice(type, core::dimension2d<u32>(240, 120));
 
650
 
 
651
        if (!device)
 
652
                return true; // could not create selected driver.
 
653
 
 
654
        video::IVideoDriver* driver = device->getVideoDriver();
 
655
 
 
656
        if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER))
 
657
        {
 
658
                device->closeDevice();
 
659
                device->run();
 
660
                device->drop();
 
661
                return true;
 
662
        }
 
663
 
 
664
        logTestString("Testing driver %ls\n", driver->getName());
 
665
 
 
666
        driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS,true);
 
667
        driver->setTextureCreationFlag(video::ETCF_OPTIMIZED_FOR_QUALITY,true);
 
668
 
 
669
        video::ITexture* images = driver->getTexture("../media/2ddemo.png");
 
670
        driver->makeColorKeyTexture(images, core::position2d<s32>(0,0));
 
671
        
 
672
        core::rect<s32> imp1(349,15,385,78);
 
673
        core::rect<s32> imp2(387,15,423,78);
 
674
 
 
675
        // font cannot handle loading from sub-dirs
 
676
        io::path cwd = device->getFileSystem()->getWorkingDirectory();
 
677
        device->getFileSystem()->changeWorkingDirectoryTo("media");
 
678
 
 
679
        ScalableFont* font = new ScalableFont(device->getGUIEnvironment(), "title_font.xml");
 
680
        font->m_fallback_font_scale = 4.0f; 
 
681
        font->m_fallback_kerning_width = 15;
 
682
        font->setKerningWidth(-18);
 
683
        font->m_black_border = true;
 
684
 
 
685
        /*
 
686
        Prepare a nicely filtering 2d render mode for special cases.
 
687
        */
 
688
        driver->getMaterial2D().UseMipMaps = true;
 
689
        driver->getMaterial2D().TextureLayer[0].BilinearFilter = true;
 
690
        
 
691
        {
 
692
                driver->beginScene(true, true, video::SColor(255,120,102,136));
 
693
                
 
694
                driver->enableMaterial2D();
 
695
 
 
696
                // draw fire & dragons background world
 
697
                driver->draw2DImage(images, core::position2di(),
 
698
                                                        core::rect<s32>(0,0,342,224), 0,
 
699
                                                        video::SColor(255,255,255,255), true);
 
700
                
 
701
                // draw flying imp
 
702
                driver->draw2DImage(images, core::position2d<s32>(114,75),
 
703
                                                        imp1, 0, video::SColor(255,255,255,255), true);
 
704
                
 
705
                // draw second flying imp
 
706
                driver->draw2DImage(images, core::position2d<s32>(220,55),
 
707
                                                        imp2, 0, video::SColor(255,255,255,255), true);
 
708
                
 
709
                driver->draw2DImage(images, core::rect<s32>(10,10,108,48),
 
710
                                                        core::rect<s32>(354,87,442,118));
 
711
 
 
712
                video::SColor colors[] = {0xff00ffff, 0xff00ffff, 0xffffff00, 0xffffff00};
 
713
                driver->draw2DImage(images, core::recti(10,50,108,88),
 
714
                        core::recti(354,87,442,118), 0, colors, true);
 
715
 
 
716
                font->draw( L"WXYZsSdDrRjJbB", core::rect<s32>(30,20,300,300),
 
717
                                video::SColor(255,255,255,255) );
 
718
                
 
719
                driver->enableMaterial2D(false);
 
720
                
 
721
                driver->draw2DImage(images, core::recti(10,90,108,128),
 
722
                        core::recti(354,87,442,118), 0, colors, true);
 
723
 
 
724
                font->draw( L"WXYZsSdDrRjJbB", core::rect<s32>(30,60,300,400),
 
725
                                video::SColor(255,255,255,255) );
 
726
                
 
727
                driver->endScene();
 
728
        }
 
729
        font->drop();
 
730
        device->getFileSystem()->changeWorkingDirectoryTo(cwd);
 
731
 
 
732
        // don't go under 99% as the difference is not very large
 
733
        bool result = takeScreenshotAndCompareAgainstReference(driver, "-draw2DImage4cFilter.png");
 
734
 
 
735
        device->closeDevice();
 
736
        device->run();
 
737
        device->drop();
 
738
        return result;
 
739
}
 
740
 
 
741
// This test renders a 3d scene and a gui on top of it. The GUI is
 
742
// filtered via 2dmaterial (blurred).
 
743
// TODO: Works only for OpenGL right now
 
744
static bool addBlend2d(video::E_DRIVER_TYPE type)
 
745
{
 
746
        SIrrlichtCreationParameters params;
 
747
        params.AntiAlias = 0;
 
748
        params.Bits = 32;
 
749
        params.WindowSize = core::dimension2d<u32>(160, 120);
 
750
        params.DriverType = type;
 
751
 
 
752
        IrrlichtDevice *device = createDeviceEx(params);
 
753
 
 
754
        if (!device)
 
755
                return true; // in case the driver type does not exist
 
756
 
 
757
        video::IVideoDriver* driver = device->getVideoDriver();
 
758
        scene::ISceneManager* smgr = device->getSceneManager();
 
759
 
 
760
        if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER))
 
761
        {
 
762
                device->closeDevice();
 
763
                device->run();
 
764
                device->drop();
 
765
                return true;
 
766
        }
 
767
 
 
768
        logTestString("Testing driver %ls\n", driver->getName());
 
769
 
 
770
        scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
 
771
        if (!mesh)
 
772
        {
 
773
                device->closeDevice();
 
774
                device->run();
 
775
                device->drop();
 
776
                return false;
 
777
        }
 
778
        scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
 
779
 
 
780
        if (node)
 
781
        {
 
782
                node->setMaterialFlag(video::EMF_LIGHTING, false);
 
783
                node->setMD2Animation(scene::EMAT_STAND);
 
784
                node->setMaterialTexture( 0, driver->getTexture("../media/sydney.bmp") );
 
785
        }
 
786
 
 
787
        smgr->addCameraSceneNode(0, core::vector3df(0,30,-40), core::vector3df(0,5,0));
 
788
 
 
789
        gui::IGUIEnvironment* env = device->getGUIEnvironment();
 
790
        {
 
791
                // create the toolbox window
 
792
                gui::IGUIWindow* wnd = env->addWindow(core::rect<s32>(0,0,800,480),
 
793
                        false, L"Toolset", 0, 100);
 
794
 
 
795
                // create tab control and tabs
 
796
                gui::IGUITabControl* tab = env->addTabControl(
 
797
                        core::rect<s32>(2,20,800-602,480-7), wnd, true, true);
 
798
 
 
799
                gui::IGUITab* t1 = tab->addTab(L"Config");
 
800
 
 
801
                // add some edit boxes and a button to tab one
 
802
                env->addImage(driver->getTexture("../media/tools.png"), core::vector2d<s32>(10,20), true, t1);
 
803
                env->addStaticText(L"X:", core::rect<s32>(22,48,40,66), false, false, t1);
 
804
                env->addEditBox(L"1.0", core::rect<s32>(40,46,130,66), true, t1, 201);
 
805
 
 
806
                // quick scale buttons
 
807
                env->addButton(core::rect<s32>(65,20,95,40), t1, 102, L"* 10");
 
808
                env->addButton(core::rect<s32>(100,20,130,40), t1, 103, L"* 0.1");
 
809
        }
 
810
 
 
811
        video::SMaterial& material2D = driver->getMaterial2D();
 
812
        for (unsigned int n=0; n<video::MATERIAL_MAX_TEXTURES; n++)
 
813
        {
 
814
                material2D.TextureLayer[n].BilinearFilter = true;
 
815
                material2D.TextureLayer[n].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
 
816
                material2D.TextureLayer[n].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
 
817
        }
 
818
        material2D.AntiAliasing=video::EAAM_FULL_BASIC;
 
819
 
 
820
        driver->beginScene(true, true, video::SColor(255,100,101,140));
 
821
        smgr->drawAll();
 
822
        driver->enableMaterial2D();
 
823
        env->drawAll();
 
824
        driver->enableMaterial2D(false);
 
825
        driver->endScene();
 
826
 
 
827
        bool result = takeScreenshotAndCompareAgainstReference(driver, "-addBlend2D.png", 98.2f);
 
828
 
 
829
        device->closeDevice();
 
830
        device->run();
 
831
        device->drop();
 
832
        return result;
 
833
 
834
 
 
835
// This test renders 4 times the same image. Two via IGUIImage, two via draw2DImage
 
836
// 3 of the 4 images are filtered via 2dmaterial and bilinear filter, only the one
 
837
// at the bottom left is not.
 
838
static bool moreFilterTests(video::E_DRIVER_TYPE type)
 
839
{
 
840
        IrrlichtDevice* device = irr::createDevice(type, core::dimension2du(160,120));
 
841
        if (!device)
 
842
                return true;
 
843
 
 
844
        video::IVideoDriver* driver = device->getVideoDriver();
 
845
        gui::IGUIEnvironment* gui = device->getGUIEnvironment();
 
846
 
 
847
        if (!driver->queryFeature(video::EVDF_BILINEAR_FILTER))
 
848
        {
 
849
                device->closeDevice();
 
850
                device->run();
 
851
                device->drop();
 
852
                return true;
 
853
        }
 
854
 
 
855
        logTestString("Testing driver %ls\n", driver->getName());
 
856
 
 
857
        driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false);
 
858
        video::ITexture* tex = driver->getTexture("../media/irrlichtlogo.jpg");
 
859
        gui::IGUIImage* image = gui->addImage(core::recti(0,0,64,64));
 
860
        image->setScaleImage(true);
 
861
        image->setImage(tex);
 
862
        image->setUseAlphaChannel(true);
 
863
        driver->getMaterial2D().TextureLayer[0].BilinearFilter=true;
 
864
        driver->getMaterial2D().TextureLayer[0].TrilinearFilter=true;
 
865
 
 
866
        {
 
867
                driver->beginScene(true, true, irr::video::SColor(255,255,255,255));
 
868
 
 
869
                // all three logos should be with filtering
 
870
                driver->enableMaterial2D();
 
871
 
 
872
                driver->getMaterial2D().setTexture(0, 0);
 
873
                driver->draw2DImage(tex, irr::core::rect<irr::s32>(64, 64, 128, 128), irr::core::rect<irr::s32>(0, 0, 88, 31));
 
874
 
 
875
                driver->getMaterial2D().setTexture(0, tex);
 
876
                driver->draw2DImage(tex, irr::core::rect<irr::s32>(64, 0, 128, 64), irr::core::rect<irr::s32>(0, 0, 88, 31));
 
877
 
 
878
                gui->drawAll();
 
879
 
 
880
                // the next gui image should be without filter
 
881
                driver->enableMaterial2D(false);
 
882
                image->setRelativePosition(core::recti(0,64,64,128));
 
883
                gui->drawAll();
 
884
 
 
885
                driver->endScene();
 
886
        }
 
887
 
 
888
        bool result = takeScreenshotAndCompareAgainstReference(driver, "-2dmatFilter.png");
 
889
 
 
890
        device->closeDevice();
 
891
        device->run();
 
892
        device->drop();
 
893
        return result;
 
894
 
895
 
 
896
bool twodmaterial()
 
897
{
 
898
        bool result = true;
 
899
        TestWithAllDrivers(addBlend2d);
 
900
        TestWithAllDrivers(moreFilterTests);
 
901
        TestWithAllDrivers(draw2DImage4c);
 
902
        return result;
 
903
}