~baltix/+junk/irrlicht-test

« back to all changes in this revision

Viewing changes to tools/IrrFontTool/newFontTool/CVectorFontTool.h

  • 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
/*
 
2
        Vector font tool - Gaz Davidson December 2006-2011
 
3
 
 
4
        I noticed bitmap fonts were taking massive amounts of video memory at reasonable sizes,
 
5
        so I decided to make a vector font. I always wanted to try converting pixels to triangles...
 
6
 
 
7
        And I failed! This is a collection of the ugliest, bloated, most inneficient algorithms
 
8
        i've ever written, but its kinda working so I'm not changing it.
 
9
*/
 
10
 
 
11
#ifndef __VECTOR_FONT_TOOL_INCLUDED__
 
12
#define __VECTOR_FONT_TOOL_INCLUDED__
 
13
 
 
14
#include "irrlicht.h"
 
15
#include "CFontTool.h"
 
16
#include <assert.h>
 
17
 
 
18
using namespace irr;
 
19
using namespace video;
 
20
 
 
21
struct STriangleList
 
22
{
 
23
        core::array<core::vector2df>    positions;
 
24
        core::array<u16>                indexes;
 
25
 
 
26
        // for adding one triangle list to another,
 
27
        // these triangles share positions, but dont share triangles
 
28
        STriangleList& operator+=(STriangleList &other)
 
29
        {
 
30
                core::matrix4 m;
 
31
                core::array<s32> map;
 
32
                map.set_used(other.positions.size());
 
33
 
 
34
                for (u32 i=0; i<map.size(); ++i)
 
35
                        map[i]=-1;
 
36
 
 
37
                for (u32 i=0; i<positions.size(); ++i)
 
38
                        for (u32 j=0; j<map.size(); ++j)
 
39
                                if ( positions[i] == other.positions[j] )
 
40
                                        map[j] = i;
 
41
 
 
42
                for (u32 i=0; i<map.size(); ++i)
 
43
                        if (map[i] == -1)
 
44
                        {
 
45
                                positions.push_back(other.positions[i]);
 
46
                                map[i] = positions.size()-1;
 
47
                        }
 
48
 
 
49
                // add triangles
 
50
                for (u32 i=0; i<other.indexes.size(); ++i)
 
51
                        indexes.push_back((u32)map[other.indexes[i]]);
 
52
 
 
53
                return *this;
 
54
        }
 
55
 
 
56
        // functions for building triangles for shapes,
 
57
        // each shape can't have duplicate triangles
 
58
        bool hasTriangle(core::vector2df a, core::vector2df b, core::vector2df c)
 
59
        {
 
60
                // make sure the triangle is wound correctly
 
61
                if (core::line2df(a,b).getPointOrientation(c) < 0)
 
62
                        { core::vector2df tmp=a; a=b; b=tmp; }
 
63
 
 
64
                u32 ia=0xffffffff, ib=0xffffffff, ic=0xffffffff;
 
65
                // Find each vertex
 
66
                for (u32 i=0; i < positions.size() && (ia==(u32)-1||ib==(u32)-1||ic==(u32)-1) ; ++i)
 
67
                {
 
68
                        if (positions[i] == a)
 
69
                                ia = i;
 
70
                        if (positions[i] == b)
 
71
                                ib = i;
 
72
                        if (positions[i] == c)
 
73
                                ic = i;
 
74
                }
 
75
 
 
76
                if (ia==0xffffffff)
 
77
                {
 
78
                        return false;
 
79
                }
 
80
                if (ib==0xffffffff)
 
81
                {
 
82
                        return false;
 
83
                }
 
84
                if (ic==0xffffffff)
 
85
                {
 
86
                        return false;
 
87
                }
 
88
 
 
89
                for (u32 i=0; i<indexes.size(); i+=3)
 
90
                        if ( (indexes[i] == ia && indexes[i+1] == ib && indexes[i+2] == ic) ||
 
91
                                (indexes[i] == ic && indexes[i+1] == ia && indexes[i+2] == ib) ||
 
92
                                (indexes[i] == ib && indexes[i+1] == ic && indexes[i+2] == ia) )
 
93
                                        return true;
 
94
 
 
95
                return false;
 
96
        }
 
97
 
 
98
        void add(core::vector2df a, core::vector2df b, core::vector2df c)
 
99
        {
 
100
 
 
101
                // make sure the triangle is wound correctly
 
102
                if (core::line2df(a,b).getPointOrientation(c) < 0)
 
103
                {
 
104
                        core::vector2df tmp=a; a=b; b=tmp;
 
105
                }
 
106
 
 
107
                u32 ia=0xffffffff, ib=0xffffffff, ic=0xffffffff;
 
108
                // no duplicate vertex positions allowed...
 
109
                for (u32 i=0; i < positions.size() && (ia==-1||ib==-1||ic==-1) ; ++i)
 
110
                {
 
111
                        if (positions[i] == a)
 
112
                                ia = i;
 
113
                        if (positions[i] == b)
 
114
                                ib = i;
 
115
                        if (positions[i] == c)
 
116
                                ic = i;
 
117
                }
 
118
                bool found=true;
 
119
                if (ia==0xffffffff)
 
120
                {
 
121
                        ia = positions.size();
 
122
                        positions.push_back(a);
 
123
                        found=false;
 
124
                }
 
125
                if (ib==0xffffffff)
 
126
                {
 
127
                        ib = positions.size();
 
128
                        positions.push_back(b);
 
129
                        found=false;
 
130
                }
 
131
                if (ic==0xffffffff)
 
132
                {
 
133
                        ic = positions.size();
 
134
                        positions.push_back(c);
 
135
                        found=false;
 
136
                }
 
137
 
 
138
                // no duplicate triangles allowed
 
139
                if (found)
 
140
                {
 
141
                        found=false;
 
142
                        for (u32 i=0; i<indexes.size(); i+=3)
 
143
                        {
 
144
                                if ( (indexes[i] == ia && indexes[i+1] == ib && indexes[i+2] == ic) ||
 
145
                                        (indexes[i] == ic && indexes[i+1] == ia && indexes[i+2] == ib) ||
 
146
                                        (indexes[i] == ib && indexes[i+1] == ic && indexes[i+2] == ia) )
 
147
                                {
 
148
                                        found=true;
 
149
                                        break;
 
150
                                }
 
151
                        }
 
152
                }
 
153
 
 
154
                if (!found)
 
155
                {
 
156
                        indexes.push_back(ia);
 
157
                        indexes.push_back(ib);
 
158
                        indexes.push_back(ic);
 
159
                }
 
160
        }
 
161
};
 
162
 
 
163
// finds groups of pixels and triangulates them
 
164
class CGroupFinder
 
165
{
 
166
public:
 
167
        CGroupFinder(bool *memory, s32 w, s32 h, IrrlichtDevice *dev):
 
168
                width(w), height(h), mem(memory), Device(dev)
 
169
        {
 
170
                refbuffer.set_used(w*h);
 
171
                for (u32 i=0; i<refbuffer.size(); ++i)
 
172
                        refbuffer[i]=0;
 
173
                // find groups of pixels
 
174
                findGroups();
 
175
                removeGroups();
 
176
 
 
177
                // triangulate
 
178
                for (u32 i=0; i<groups.size(); ++i)
 
179
                {
 
180
                        groups[i].triangulate();
 
181
                }
 
182
        }
 
183
 
 
184
        // contains a clockwise edge line
 
185
        struct SEdge
 
186
        {
 
187
                SEdge() : positions() { }
 
188
 
 
189
                core::array<core::position2di> positions;
 
190
 
 
191
                bool isMember(s32 x, s32 y)
 
192
                {
 
193
                        for (u32 i=0; i<positions.size(); ++i)
 
194
                                if (positions[i].X == x && positions[i].Y == y)
 
195
                                        return true;
 
196
                        return false;
 
197
                }
 
198
 
 
199
                // reduces the number of points in the edge
 
200
                void reduce(s32 level=0)
 
201
                {
 
202
                        // level 0- remove points on the same line
 
203
                        for (u32 i=1; i < positions.size()-1; ++i)
 
204
                        {
 
205
                                // same point as the last one?! shouldnt happen, dunno why it does :|
 
206
                                if (positions[i-1] == positions[i])
 
207
                                {
 
208
                                        positions.erase(i--);
 
209
                                        continue;
 
210
                                }
 
211
 
 
212
                                // get headings
 
213
                                core::vector2d<f32>     h1((f32)(positions[i-1].X - positions[i].X),(f32)(positions[i-1].Y - positions[i].Y)),
 
214
                                                        h2((f32)(positions[i].X - positions[i+1].X),(f32)(positions[i].Y - positions[i+1].Y));
 
215
                                h1.normalize();
 
216
                                h2.normalize();
 
217
 
 
218
                                if (h1==h2) // erase the current point
 
219
                                        positions.erase(i--);
 
220
                        }
 
221
 
 
222
                        // level 1- if point1 points at point3, we can skip point2
 
223
                        // level 2+ allow a deviation of level-1
 
224
 
 
225
                }
 
226
 
 
227
        };
 
228
 
 
229
        // contains an array of lines for triangulation
 
230
        struct SLineList
 
231
        {
 
232
                core::array<core::line2df>      lines;
 
233
                SLineList() : lines() { }
 
234
                void addEdge(const SEdge &edge)
 
235
                {
 
236
                        // adds lines to the buffer
 
237
                        for (u32 i=1; i<edge.positions.size(); ++i)
 
238
                                addLine(core::line2df((f32)edge.positions[i-1].X,       (f32)edge.positions[i-1].Y,
 
239
                                                (f32)edge.positions[i].X,       (f32)edge.positions[i].Y ));
 
240
                }
 
241
                void addLine( const core::line2df &line )
 
242
                {
 
243
                        // no dupes!
 
244
                        if (!hasLine(line))
 
245
                                lines.push_back(line);
 
246
                }
 
247
                bool hasLine( const core::line2df &line )
 
248
                {
 
249
                        for (u32 i=0; i<lines.size(); ++i)
 
250
                                if (line == lines[i] || (line.start == lines[i].end && line.end == lines[i].start) )
 
251
                                        return true;
 
252
                        return false;
 
253
                }
 
254
 
 
255
                bool crossesWith( core::line2df l, core::vector2df p)
 
256
                {
 
257
                        // inside checks only work with clockwise triangles
 
258
                        if (l.getPointOrientation(p) < 0)
 
259
                                { core::vector2df tmp=l.start; l.start=l.end; l.end=tmp; }
 
260
 
 
261
                        // make the 3 triangle edges
 
262
                        core::line2df &la=l, lb(l.end,p), lc(p,l.start);
 
263
 
 
264
                        // test every line in the list
 
265
                        for (u32 i=0; i<lines.size(); ++i)
 
266
                        {
 
267
                                core::line2df &l2 = lines[i];
 
268
 
 
269
                                // the triangle isn't allowed to enclose any points
 
270
                                // triangles are clockwise, so if to the right of all 3 lines, it's enclosed
 
271
                                if (la.getPointOrientation(l2.start) > 0 &&
 
272
                                        lb.getPointOrientation(l2.start) > 0 &&
 
273
                                        lc.getPointOrientation(l2.start) > 0)
 
274
                                        return true;
 
275
                                //if (la.getPointOrientation(l2.start) < 0 &&
 
276
                                //      lb.getPointOrientation(l2.start) < 0 &&
 
277
                                //      lc.getPointOrientation(l2.start) < 0)
 
278
                                //      return true;
 
279
 
 
280
                                core::vector2df out;
 
281
                                //if (la.intersectWith(l2,out))
 
282
                                //      if (out != la.start && out != la.end &&
 
283
                                //              out != l2.start && out != l2.end)
 
284
                                //              return true;
 
285
                                if (lb.intersectWith(l2,out))
 
286
                                        if (!out.equals(lb.start) && !out.equals(lb.end) &&
 
287
                                                !out.equals(l2.start) && !out.equals(l2.end))
 
288
                                                return true;
 
289
                                if (lc.intersectWith(l2,out))
 
290
                                        if (!out.equals(lc.start) && !out.equals(lc.end) &&
 
291
                                                !out.equals(l2.start) && !out.equals(l2.end))
 
292
                                                return true;
 
293
 
 
294
                                // my shit intersection code only works with lines in certain directions :(
 
295
                                if (l2.intersectWith(lb,out))
 
296
                                        if (!out.equals(lb.start) && !out.equals(lb.end) &&
 
297
                                                !out.equals(l2.start) && !out.equals(l2.end))
 
298
                                                return true;
 
299
                                if (l2.intersectWith(lc,out))
 
300
                                        if (!out.equals(lc.start) && !out.equals(lc.end) &&
 
301
                                                !out.equals(l2.start) && !out.equals(l2.end))
 
302
                                                return true;
 
303
 
 
304
 
 
305
                                if (lb.isPointOnLine(l2.start) && l2.start != lb.start && l2.start != lb.end)
 
306
                                        return true;
 
307
                                if (lc.isPointOnLine(l2.start) && l2.start != lc.start && l2.start != lc.end)
 
308
                                        return true;
 
309
 
 
310
                        }
 
311
                        return false;
 
312
                }
 
313
        };
 
314
 
 
315
        // an area of adjacent pixels
 
316
        struct SPixelGroup
 
317
        {
 
318
                SPixelGroup(IrrlichtDevice *device) : triangles(), pixelWidth(0), pixelHeight(0),
 
319
                        Device(device) {}
 
320
 
 
321
                core::array<core::position2di>  pixels;
 
322
                core::array<SEdge>              edges;
 
323
                STriangleList           triangles;
 
324
                core::array<SLineList>  ll;
 
325
                core::array<bool>               isMemberCache;
 
326
                s32                     pixelWidth;
 
327
                s32                     pixelHeight;
 
328
                IrrlichtDevice          *Device;
 
329
 
 
330
                void triangulate()
 
331
                {
 
332
 
 
333
                        // find edges in this group
 
334
                        makeEdges();
 
335
 
 
336
                        // triangulate the group
 
337
                        makeTriangles();
 
338
 
 
339
                }
 
340
 
 
341
                void drawTriangle( core::line2df line, core::vector2df point)
 
342
                {
 
343
                        //const u32 endt = Device->getTimer()->getTime() + t;
 
344
                        f32 scale = 5;
 
345
 
 
346
 
 
347
                        //while(Device->getTimer()->getTime() < endt )
 
348
                        //{
 
349
                                Device->run();
 
350
                                Device->getVideoDriver()->beginScene(true,true,video::SColor(0,0,0,0));
 
351
                                for (u32 v=0;v<ll.size(); ++v)
 
352
                                for (u32 h=0;h<ll[v].lines.size(); ++h)
 
353
                                {
 
354
                                        core::line2df &currentline = ll[v].lines[h];
 
355
                                        core::position2di st = core::position2di((s32)(currentline.start.X*scale)+50, (s32)(currentline.start.Y*scale)+50);
 
356
                                        core::position2di en = core::position2di((s32)(currentline.end.X*scale)+50, (s32)(currentline.end.Y*scale)+50);
 
357
 
 
358
                                        Device->getVideoDriver()->draw2DLine(st,en, SColor(255,255,255,255));
 
359
                                }
 
360
                                // draw this triangle
 
361
                                const core::position2di st((s32)(line.start.X*scale)+50, (s32)(line.start.Y*scale)+50);
 
362
                                const core::position2di en((s32)(line.end.X*scale)+50, (s32)(line.end.Y*scale)+50);
 
363
                                const core::position2di p((s32)(point.X*scale)+50, (s32)(point.Y*scale)+50);
 
364
                                Device->getVideoDriver()->draw2DLine(st,en, SColor(255,255,0,0));
 
365
                                Device->getVideoDriver()->draw2DLine(en,p, SColor(255,0,255,0));
 
366
                                Device->getVideoDriver()->draw2DLine(p,st, SColor(255,0,0,255));
 
367
 
 
368
                                Device->getVideoDriver()->endScene();
 
369
                        //}
 
370
                }
 
371
 
 
372
                void makeTriangles()
 
373
                {
 
374
                        // make lines from edges, because they're easier to deal with
 
375
                        ll.clear();
 
376
                        for (u32 i=0; i < edges.size(); ++i)
 
377
                        {
 
378
                                SLineList l;
 
379
                                l.addEdge(edges[i]);
 
380
                                ll.push_back(l);
 
381
                        }
 
382
                        // add an extra one for inside edges
 
383
                        SLineList innerlines;
 
384
                        ll.push_back(innerlines);
 
385
 
 
386
                        // loop through each edge and make triangles
 
387
                        for (u32 i=0; i<ll.size(); ++i)
 
388
                        {
 
389
                                // loop through each line in the edge
 
390
                                for (u32 cl=0; cl<ll[i].lines.size(); ++cl)
 
391
                                {
 
392
 
 
393
                                        core::line2df &currentLine = ll[i].lines[cl];
 
394
                                        f32 bestScore = -10.0f;
 
395
                                        s32 bestEdge = -1;
 
396
                                        s32 bestPoint = -1;
 
397
                                        // find the best scoring point to join to this line
 
398
                                        for (u32 k=0; k<ll.size(); ++k)
 
399
                                                for (u32 j=0; j< ll[k].lines.size(); ++j)
 
400
                                                {
 
401
                                                        f32 score = 0.0f;
 
402
                                                        core::vector2df point(ll[k].lines[j].start.X,
 
403
                                                                                        ll[k].lines[j].start.Y);
 
404
                                                        core::line2df line1(point,currentLine.start);
 
405
                                                        core::line2df line2(currentLine.end,point);
 
406
 
 
407
                                                        // can't be part of the current line
 
408
                                                        if (point == currentLine.start || point == currentLine.end)
 
409
                                                                continue;
 
410
 
 
411
                                                        // must be to the right hand side (triangles are wound clockwise)
 
412
                                                        // unless its part of the inside...
 
413
                                                        f32 side1 = currentLine.getPointOrientation(point);
 
414
                                                        f32 side2 = core::line2df(point,currentLine.start).getPointOrientation(currentLine.end);
 
415
                                                        f32 side3 = core::line2df(currentLine.end,point).getPointOrientation(currentLine.start);
 
416
                                                        if (i<ll.size()-1)
 
417
                                                                if (side1 <= 0 || side2 <= 0 || side3 <=0)
 
418
                                                                        continue;
 
419
 
 
420
                                                        // can't already have this triangle
 
421
                                                        if (triangles.hasTriangle(currentLine.start,currentLine.end,point))
 
422
                                                                continue;
 
423
 
 
424
                                                        // must not cross any other lines or enclose any points
 
425
                                                        bool itCrossed = false;
 
426
                                                        for (u32 v=0; v<ll.size(); ++v)
 
427
                                                                if (ll[v].crossesWith(currentLine, point))
 
428
                                                                {
 
429
                                                                        itCrossed = true;
 
430
                                                                        break;
 
431
                                                                }
 
432
                                                        if (itCrossed)
 
433
                                                                continue;
 
434
 
 
435
 
 
436
                                                        // so, we like this triangle, but how much?
 
437
                                                        // is it better than all the others?
 
438
 
 
439
                                                        // we prefer points from other edges, unless its on the inside
 
440
                                                        if (k==i && i != ll.size()-1)
 
441
                                                                score = 1;
 
442
                                                        else
 
443
                                                                score = 2;
 
444
 
 
445
                                                        // we prefer evenly shaped triangles
 
446
 
 
447
                                                        // we prefer triangles with a large area
 
448
 
 
449
                                                        // do we like this one more than the others?
 
450
                                                        if (score>bestScore)
 
451
                                                        {
 
452
                                                                bestScore = score;
 
453
                                                                bestEdge = k;
 
454
                                                                bestPoint = j;
 
455
                                                        }
 
456
                                                }
 
457
                                        // hopefully we found one
 
458
                                        if (bestEdge >= 0 && bestPoint >= 0 && bestScore >= 0.0f)
 
459
                                        {
 
460
                                                //assert(bestEdge >= 0 && bestPoint >= 0);
 
461
                                                //assert(bestScore >= 0.0f);
 
462
 
 
463
                                                core::vector2df point(ll[bestEdge].lines[bestPoint].start.X, ll[bestEdge].lines[bestPoint].start.Y);
 
464
 
 
465
                                                // add it to the triangles list
 
466
                                                triangles.add(currentLine.start, currentLine.end, point);
 
467
 
 
468
                                                // add inner lines to the line buffer, but only if they arent in others
 
469
 
 
470
                                                core::line2df la(point,currentLine.start);
 
471
                                                core::line2df lb(currentLine.end,point);
 
472
 
 
473
                                                bool found = false;
 
474
                                                for (u32 lineno=0;lineno<ll.size()-1; ++lineno)
 
475
                                                        if (ll[lineno].hasLine(la))
 
476
                                                                { found=true; break; }
 
477
                                                if (!found)
 
478
                                                        ll[ll.size()-1].addLine(la);
 
479
 
 
480
                                                for (u32 lineno=0;lineno<ll.size()-1; ++lineno)
 
481
                                                        if (ll[lineno].hasLine(lb))
 
482
                                                                { found=true; break; }
 
483
                                                if (!found)
 
484
                                                        ll[ll.size()-1].addLine(lb);
 
485
 
 
486
                                                //drawTriangle(currentLine, point);
 
487
 
 
488
                                        }
 
489
 
 
490
                                }
 
491
                        }
 
492
                }
 
493
 
 
494
                // finds the edges
 
495
                void makeEdges()
 
496
                {
 
497
 
 
498
                        // speed it up
 
499
                        refreshIsMemberCache();
 
500
 
 
501
                        // clear the edges
 
502
                        edges.clear();
 
503
 
 
504
                        // loop through each pixel
 
505
                        for (u32 i=0; i < pixels.size(); ++i)
 
506
                        {
 
507
                                core::position2di &p = pixels[i];
 
508
                                s32 &x=p.X, &y=p.Y;
 
509
                                bool ul = isMember(p.X-1,p.Y-1);
 
510
                                bool u = isMember(p.X,p.Y-1);
 
511
                                bool ur = isMember(p.X+1,p.Y-1);
 
512
                                bool l = isMember(p.X-1,p.Y);
 
513
                                bool r = isMember(p.X+1,p.Y);
 
514
                                bool bl = isMember(p.X-1,p.Y+1);
 
515
                                bool b = isMember(p.X,p.Y+1);
 
516
                                bool br = isMember(p.X+1,p.Y+1);
 
517
 
 
518
                                // walls already added?
 
519
                                bool top=u, bottom=b, left=l, right=r;
 
520
 
 
521
                                if (!(ul | u | ur | l | r | bl | b | br))
 
522
                                {
 
523
                                        // lone square
 
524
                                        SEdge a;
 
525
                                        a.positions.push_back( core::position2di(x,y));
 
526
                                        a.positions.push_back( core::position2di(x+1,y));
 
527
                                        a.positions.push_back( core::position2di(x+1,y+1));
 
528
                                        a.positions.push_back( core::position2di(x,y+1));
 
529
                                        a.positions.push_back( core::position2di(x,y));
 
530
                                        edges.push_back(a);
 
531
                                        top=bottom=left=right=true;
 
532
                                }
 
533
                                else
 
534
                                {
 
535
                                        if (!(ul|u|l) && (b&r) )
 
536
                                        {
 
537
                                                // upper outer diagonal "/"
 
538
                                                addToEdges(x,y+1,x+1,y);
 
539
                                                top=left=true;
 
540
                                        } else if ( !(u|ur|r) && (b&l) )
 
541
                                        {
 
542
                                                // upper outer diagonal "\"
 
543
                                                addToEdges(x,y,x+1,y+1);
 
544
                                                top=right=true;
 
545
                                        } else if ( !(l|bl|b) && (r&u) )
 
546
                                        {
 
547
                                                // lower outer diagonal "\"
 
548
                                                addToEdges(x+1,y+1,x,y);
 
549
                                                left=bottom=true;
 
550
                                        } else if ( !(r|br|b) && (l&u) )
 
551
                                        {
 
552
                                                // lower outer diagonal "/"
 
553
                                                addToEdges(x+1,y,x,y+1);
 
554
                                                right=bottom=true;
 
555
                                        }/* else if (!(b) && (l&bl) )
 
556
                                        {
 
557
                                                // upper inner diagonal "/"
 
558
                                                addToEdges(x+1,y+1,x,y+2);
 
559
                                                //bottom=true;
 
560
                                        } else if ( !(b) && (r&br) )
 
561
                                        {
 
562
                                                // upper inner diagonal "\"
 
563
                                                addToEdges(x+1,y+2,x,y+1);
 
564
                                                //bottom=true;
 
565
                                        } else if ( !(r) && (b&br) )
 
566
                                        {
 
567
                                                // lower inner diagonal "\"
 
568
                                                addToEdges(x+1,y,x+2,y+1);
 
569
                                                //right=true;
 
570
                                        } else if ( !(l) && (b&bl) )
 
571
                                        {
 
572
                                                // lower inner diagonal "/"
 
573
                                                addToEdges(x-1,y+1,x,y);
 
574
                                                //left=true;
 
575
                                        }*/
 
576
 
 
577
                                        // add flat edges
 
578
                                        if (!left       /*&& !( (u&ul) || (b&bl)) */)   addToEdges(x,y+1,x,y);
 
579
                                        if (!top        /*&& !( (l&ul) || (r&ur)) */)   addToEdges(x,y,x+1,y);
 
580
                                        if (!right      /*&& !( (u&ur) || (b&br)) */)   addToEdges(x+1,y,x+1,y+1);
 
581
                                        if (!bottom /*&& !( (l&bl) || (r&br)) */)       addToEdges(x+1,y+1,x,y+1);
 
582
                                } // lone square
 
583
                        } // for
 
584
 
 
585
                        // reduce the number of points in each edge
 
586
                        for (u32 i=0; i<edges.size(); ++i)
 
587
                        {
 
588
                                edges[i].reduce(1);
 
589
 
 
590
                                // all edges should have at least 3 points
 
591
                                assert(edges[i].positions.size() >= 3);
 
592
 
 
593
                                // all edges should be closed
 
594
                                assert(edges[i].positions[0] == edges[i].positions[edges[i].positions.size()-1] );
 
595
                        }
 
596
                }
 
597
 
 
598
                // adds a line to the edges arrays
 
599
                void addToEdges(s32 x1, s32 y1, s32 x2, s32 y2)
 
600
                {
 
601
                        bool found=false;
 
602
                        // loop through each edge
 
603
                        for (u32 i=0; i<edges.size(); ++i)
 
604
                        {
 
605
                                // if this line starts at the end of an edge
 
606
                                if ( edges[i].positions[edges[i].positions.size()-1] == core::position2di(x1,y1))
 
607
                                {
 
608
                                        // add it to the end
 
609
                                        edges[i].positions.push_back(core::position2di(x2,y2));
 
610
                                        found=true;
 
611
                                        break;
 
612
                                }
 
613
                                // if the line ends at the start of the edge
 
614
                                if ( edges[i].positions[0]== core::position2di(x2,y2))
 
615
                                {
 
616
                                        // add it to the front
 
617
                                        edges[i].positions.push_front(core::position2di(x1,y1));
 
618
                                        found=true;
 
619
                                        break;
 
620
                                }
 
621
                        }
 
622
                        if (!found)
 
623
                        {
 
624
                                // we make a new edge
 
625
                                SEdge n;
 
626
                                n.positions.push_back(core::position2di(x1,y1));
 
627
                                n.positions.push_back(core::position2di(x2,y2));
 
628
                                edges.push_back(n);
 
629
                        }
 
630
 
 
631
                        joinEdges();
 
632
                }
 
633
 
 
634
                void joinEdges()
 
635
                {
 
636
                        // touching edges are joined
 
637
 
 
638
                        for (u32 i=0; i < edges.size(); ++i)
 
639
                                for (u32 j=0; j < edges.size(); ++j)
 
640
                        {
 
641
                                if (i != j && edges[j].positions.size() && edges[i].positions.size())
 
642
                                {
 
643
                                        if (edges[j].positions[0] == edges[i].positions[edges[i].positions.size()-1])
 
644
                                        {
 
645
                                                for (u32 k=0; k < edges[j].positions.size(); ++k)
 
646
                                                        edges[i].positions.push_back(edges[j].positions[k]);
 
647
                                                edges[j].positions.clear();
 
648
                                        }
 
649
                                }
 
650
                        }
 
651
 
 
652
                        // remove empty edges
 
653
                        for (u32 i=0; i<edges.size(); ++i)
 
654
                                if (edges[i].positions.size() == 0)
 
655
                                        edges.erase(i--);
 
656
                }
 
657
 
 
658
                // tells if this x,y position is a member of this group
 
659
                bool isMember(s32 x, s32 y)
 
660
                {
 
661
                        //for (u32 i=0; i<pixels.size(); ++i)
 
662
                        //      if (pixels[i].X == x && pixels[i].Y == y)
 
663
                        //      return true;
 
664
                        if (x>pixelWidth || y>pixelHeight || x<0 || y<0)
 
665
                                return false;
 
666
                        else
 
667
                                return isMemberCache[pixelWidth*y + x];
 
668
                }
 
669
 
 
670
                void refreshIsMemberCache()
 
671
                {
 
672
                        isMemberCache.clear();
 
673
                        pixelWidth=0; pixelHeight=0;
 
674
                        for (u32 i=0; i<pixels.size(); ++i)
 
675
                        {
 
676
                                if (pixels[i].X>pixelWidth) pixelWidth=pixels[i].X;
 
677
                                if (pixels[i].Y>pixelHeight) pixelHeight=pixels[i].Y;
 
678
                        }
 
679
                        pixelWidth+=2; pixelHeight+=2;
 
680
                        isMemberCache.set_used(pixelWidth*pixelHeight+1);
 
681
                        for (u32 i=0; i<isMemberCache.size(); ++i)
 
682
                                isMemberCache[i] = false;
 
683
                        for (u32 i=0; i<pixels.size(); ++i)
 
684
                                isMemberCache[pixelWidth*pixels[i].Y + pixels[i].X] = true;
 
685
                }
 
686
        };
 
687
 
 
688
 
 
689
        void drawEdges(IrrlichtDevice *device, u32 t, s32 scale)
 
690
        {
 
691
                const u32 stt = device->getTimer()->getTime();
 
692
                const u32 endt = stt + t;
 
693
 
 
694
                while(device->getTimer()->getTime() < endt )
 
695
                {
 
696
                        const f32 phase = f32((device->getTimer()->getTime()-stt) % 500) / 500.0f;
 
697
 
 
698
                        device->run();
 
699
                        device->getVideoDriver()->beginScene(true,true,video::SColor(0,0,0,0));
 
700
                        for (u32 g=0;g<groups.size(); ++g)
 
701
                        for (u32 v=0;v<groups[g].edges.size(); ++v)
 
702
                        for (u32 p=1;p<groups[g].edges[v].positions.size(); ++p)
 
703
                        {
 
704
                                core::position2di st = core::position2di(groups[g].edges[v].positions[p-1].X*scale+50, groups[g].edges[v].positions[p-1].Y*scale+50) ;
 
705
                                core::position2di en = core::position2di(groups[g].edges[v].positions[p].X*scale+50, groups[g].edges[v].positions[p].Y*scale+50) ;
 
706
                                core::position2di ep = en-st;
 
707
                                ep = st + core::position2di((s32)(ep.X*phase), (s32)(ep.Y*phase));
 
708
                                device->getVideoDriver()->draw2DLine(st,en);
 
709
                                device->getVideoDriver()->draw2DLine(st,ep,video::SColor(255,255,0,0) );
 
710
                        }
 
711
                        device->getVideoDriver()->endScene();
 
712
                }
 
713
        }
 
714
 
 
715
        void drawTriangles(IrrlichtDevice *device, u32 t, s32 scale)
 
716
        {
 
717
                const u32 stt = device->getTimer()->getTime();
 
718
                const u32 endt = stt + t;
 
719
 
 
720
                while(device->getTimer()->getTime() < endt )
 
721
                {
 
722
                        const f32 phase = f32((device->getTimer()->getTime()-stt) % 500) / 500.0f;
 
723
 
 
724
                        device->run();
 
725
                        device->getVideoDriver()->beginScene(true,true,video::SColor(0,0,0,0));
 
726
                        for (u32 g=0;g<groups.size(); ++g)
 
727
                        for (u32 v=0;v<groups[g].triangles.indexes.size()*phase; v+=3)
 
728
                        {
 
729
                                STriangleList &t = groups[g].triangles;
 
730
                                core::position2di st((s32)(t.positions[t.indexes[v+0]].X*scale)+50,(s32)(t.positions[t.indexes[v+0]].Y*scale)+50);
 
731
                                core::position2di en((s32)(t.positions[t.indexes[v+1]].X*scale)+50,(s32)(t.positions[t.indexes[v+1]].Y*scale)+50);
 
732
                                device->getVideoDriver()->draw2DLine(st,en, SColor(255,255,0,0));
 
733
                                st = core::position2di((s32)(t.positions[t.indexes[v+1]].X*scale)+50,(s32)(t.positions[t.indexes[v+1]].Y*scale)+50);
 
734
                                en = core::position2di((s32)(t.positions[t.indexes[v+2]].X*scale)+50,(s32)(t.positions[t.indexes[v+2]].Y*scale)+50);
 
735
                                device->getVideoDriver()->draw2DLine(st,en, SColor(255,0,255,0));
 
736
                                st = core::position2di((s32)(t.positions[t.indexes[v+2]].X*scale)+50,(s32)(t.positions[t.indexes[v+2]].Y*scale)+50);
 
737
                                en = core::position2di((s32)(t.positions[t.indexes[v+0]].X*scale)+50,(s32)(t.positions[t.indexes[v+0]].Y*scale)+50);
 
738
                                device->getVideoDriver()->draw2DLine(st,en, SColor(255,0,0,255));
 
739
                        }
 
740
                        device->getVideoDriver()->endScene();
 
741
                }
 
742
        }
 
743
 
 
744
        void drawTriLines(IrrlichtDevice *device, u32 t, s32 scale)
 
745
        {
 
746
                const u32 endt = device->getTimer()->getTime() + t;
 
747
 
 
748
                while(device->getTimer()->getTime() < endt )
 
749
                {
 
750
                        device->run();
 
751
                        device->getVideoDriver()->beginScene(true,true,video::SColor(0,0,0,0));
 
752
                        for (u32 g=0;g<groups.size(); ++g)
 
753
                        for (u32 v=0;v<groups[g].ll.size()-1; ++v)
 
754
                        for (u32 h=0;h<groups[g].ll[v].lines.size(); ++h)
 
755
                        {
 
756
                                core::line2df &currentline = groups[g].ll[v].lines[h];
 
757
                                const core::position2di st((s32)(currentline.start.X*scale)+50, (s32)(currentline.start.Y*scale)+50);
 
758
                                const core::position2di en((s32)(currentline.end.X*scale)+50, (s32)(currentline.end.Y*scale)+50);
 
759
                                device->getVideoDriver()->draw2DLine(st,en, SColor(255,255,0,0));
 
760
                        }
 
761
 
 
762
                        device->getVideoDriver()->endScene();
 
763
                }
 
764
        }
 
765
        void drawTri3D(IrrlichtDevice *device, u32 t)
 
766
        {
 
767
                for (u32 g=0;g<groups.size(); ++g)
 
768
                {
 
769
                        STriangleList &t = groups[g].triangles;
 
770
                        core::array<S3DVertex> verts;
 
771
                        verts.clear();
 
772
                        for(u32 v=0; v< t.positions.size(); ++v)
 
773
                        {
 
774
                                verts.push_back(S3DVertex(
 
775
                                                        -t.positions[v].X, -t.positions[v].Y, -100,
 
776
                                                        0,0,1,SColor(255,255,255,255),0,0));
 
777
                        }
 
778
 
 
779
                        device->getVideoDriver()->drawIndexedTriangleList(verts.pointer(),verts.size(),t.indexes.pointer(), t.indexes.size()/3 );
 
780
                }
 
781
        }
 
782
 
 
783
 
 
784
        // process all pixels
 
785
        void findGroups()
 
786
        {
 
787
                for (int y=0; y<height; ++y)
 
788
                        for (int x=0; x<width; ++x)
 
789
                                processPixel(x,y);
 
790
 
 
791
        }
 
792
 
 
793
        // remove groups with no pixels
 
794
        void removeGroups()
 
795
        {
 
796
                for (u32 i=0; i<groups.size(); ++i)
 
797
                        if (groups[i].pixels.size() == 0)
 
798
                                groups.erase(i--);
 
799
 
 
800
                /*for (s32 y=0; y <height; ++y)
 
801
                {
 
802
                        printf("\n");
 
803
                        for (s32 x=0; x <width; ++x)
 
804
                        {
 
805
                                s32 i;
 
806
                                for (i=0; i<groups.size(); ++i)
 
807
                                {
 
808
                                        bool k = groups[i].isMember(x,y);
 
809
                                        if (k)
 
810
                                                break;
 
811
                                }
 
812
                                printf("%d",i);
 
813
                        }
 
814
                }*/
 
815
 
 
816
 
 
817
        }
 
818
 
 
819
        // adds a pixel to its area, merging touching areas
 
820
        void processPixel(s32 x, s32 y)
 
821
        {
 
822
                // solid?
 
823
                if (getPixel(x,y))
 
824
                {
 
825
                        s32 g=0, grp=0;
 
826
 
 
827
                        bool found=false;
 
828
                        if (x>0) // look one behind
 
829
                        {
 
830
                                grp = getRef(x-1,y);
 
831
                                if (grp) found=true;
 
832
                        }
 
833
                        if (y>0) // look above
 
834
                        {
 
835
                                if (x>0) // top left
 
836
                                {
 
837
                                        g = getRef(x-1,y-1);
 
838
 
 
839
                                        if (g)
 
840
                                        {
 
841
                                                if (found)
 
842
                                                {
 
843
                                                        mergeGroups(grp, g);
 
844
                                                }
 
845
                                                else
 
846
                                                {
 
847
                                                        grp = g;
 
848
                                                        found = true;
 
849
                                                }
 
850
                                        }
 
851
                                }
 
852
 
 
853
                                if (x<width-1) // top right
 
854
                                {
 
855
                                        g = getRef(x+1,y-1);
 
856
 
 
857
                                        if (g)
 
858
                                        {
 
859
                                                if (found)
 
860
                                                {
 
861
                                                        mergeGroups(grp, g);
 
862
                                                }
 
863
                                                else
 
864
                                                {
 
865
                                                        grp = g;
 
866
                                                        found = true;
 
867
                                                }
 
868
                                        }
 
869
                                }
 
870
 
 
871
                                // top
 
872
 
 
873
                                g = getRef(x,y-1);
 
874
 
 
875
                                if (g)
 
876
                                {
 
877
                                        if (found)
 
878
                                        {
 
879
                                                mergeGroups(grp, g);
 
880
                                        }
 
881
                                        else
 
882
                                        {
 
883
                                                grp = g;
 
884
                                                found = true;
 
885
                                        }
 
886
                                }
 
887
 
 
888
                        }
 
889
 
 
890
                        // didn't find a group for this pixel, so we add one
 
891
                        if (!found)
 
892
                        {
 
893
                                SPixelGroup p(Device);
 
894
                                p.pixels.push_back(core::position2di(x,y));
 
895
                                groups.push_back(p);
 
896
                                groupRefs.push_back(groups.size());
 
897
                                grp=groups.size();
 
898
                        }
 
899
                        else
 
900
                        {
 
901
                                groups[groupRefs[grp-1]-1].pixels.push_back(core::position2di(x,y));
 
902
                        }
 
903
                        setRef(x,y,groupRefs[grp-1]);
 
904
                }
 
905
        }
 
906
 
 
907
        bool& getPixel(s32 x, s32 y) { return mem[y*width +x]; }
 
908
        s32& getRef(s32 x, s32 y) { return refbuffer[y*width +x]; }
 
909
        void setRef(s32 x, s32 y, s32 g) { refbuffer[y*width +x] = g; }
 
910
 
 
911
        void mergeGroups(s32 g1, s32 g2)
 
912
        {
 
913
                if (g1==g2)
 
914
                        return;
 
915
                // joins two groups together
 
916
                for (u32 i=0; i<groups[g2-1].pixels.size(); ++i)
 
917
                        groups[g1-1].pixels.push_back(groups[g2-1].pixels[i]);
 
918
                groups[g2-1].pixels.clear();
 
919
                groupRefs[g2-1] = g1;
 
920
        }
 
921
 
 
922
        s32 width, height;
 
923
        core::array<SPixelGroup> groups;
 
924
        core::array<s32> groupRefs;
 
925
        core::array<s32> refbuffer;
 
926
        bool *mem;
 
927
        IrrlichtDevice *Device;
 
928
};
 
929
 
 
930
// creates a simple vector font from a bitmap from the font tool
 
931
class CVectorFontTool
 
932
{
 
933
public:
 
934
        CVectorFontTool(CFontTool *fonttool) :
 
935
                triangulator(0), FontTool(fonttool), 
 
936
                letterHeight(0), letterWidth(0), triangles()
 
937
        {
 
938
                core::map<wchar_t, u32>::Iterator it = FontTool->CharMap.getIterator();
 
939
 
 
940
                while(!it.atEnd())
 
941
                {
 
942
                        CFontTool::SFontArea &fa = FontTool->Areas[(*it).getValue()];
 
943
 
 
944
                        if (fa.rectangle.getWidth() > letterWidth)
 
945
                                letterWidth = fa.rectangle.getWidth();
 
946
                        if (fa.rectangle.getHeight() > letterHeight)
 
947
                                letterHeight = fa.rectangle.getHeight();
 
948
 
 
949
                        it++;
 
950
                }
 
951
 
 
952
                // number of verts is one more than number of pixels because it's a grid of squares
 
953
                letterWidth++;
 
954
                letterHeight++;
 
955
 
 
956
                // create image memory
 
957
                imagedata.set_used(letterWidth*letterHeight);
 
958
 
 
959
                // create vertex list, set position etc
 
960
                verts.set_used(letterWidth*letterHeight);
 
961
                for (s32 y=0; y<letterHeight; ++y)
 
962
                {
 
963
                        for (s32 x=0; x<letterWidth; ++x)
 
964
                        {
 
965
                                S3DVertex &v = getVert(x,y);
 
966
                                v.Pos = core::vector3df((f32)x,(f32)y,0.0f);
 
967
                                v.TCoords.X = (f32)letterWidth / (f32)x;
 
968
                                v.TCoords.Y = (f32)letterHeight / (f32)y;
 
969
                                v.Normal = core::vector3df(0,0,-1);
 
970
                                v.Color = SColor(255,255,255,255);
 
971
                        }
 
972
                }
 
973
                // clear index list
 
974
                inds.clear();
 
975
 
 
976
                // create each char in the font...
 
977
                it = FontTool->CharMap.getIterator();
 
978
                while(!it.atEnd())
 
979
                {
 
980
                        addChar((*it).getKey());
 
981
                        it++;
 
982
                }
 
983
        }
 
984
 
 
985
        ~CVectorFontTool()
 
986
        {
 
987
                if (triangulator)
 
988
                        delete triangulator;
 
989
        }
 
990
 
 
991
        void addChar(wchar_t thischar)
 
992
        {
 
993
                const s32 area = FontTool->CharMap[thischar];
 
994
                const CFontTool::SFontArea &fa = FontTool->Areas[area];
 
995
 
 
996
                const s32 img = fa.sourceimage;
 
997
                const core::rect<s32>& r = fa.rectangle;
 
998
 
 
999
                // init image memory
 
1000
                IImage *image = FontTool->currentImages[img];
 
1001
                for (u32 i=0; i < imagedata.size(); ++i)
 
1002
                        imagedata[i] = false;
 
1003
                for (s32 y=r.UpperLeftCorner.Y; y < r.LowerRightCorner.Y; ++y)
 
1004
                {
 
1005
                        for (s32 x=r.UpperLeftCorner.X; x < r.LowerRightCorner.X ; ++x)
 
1006
                                if (image->getPixel(x,y).getBlue() > 0)
 
1007
                                {
 
1008
                                        imagedata[letterWidth*(y-r.UpperLeftCorner.Y) +(x-r.UpperLeftCorner.X)] = true;
 
1009
                                }
 
1010
                }
 
1011
 
 
1012
                // get shape areas
 
1013
                triangulator = new CGroupFinder(imagedata.pointer(), letterWidth, letterHeight, FontTool->Device );
 
1014
 
 
1015
                wprintf(L"Created character '%c' in texture %d\n", thischar, img );
 
1016
 
 
1017
                //floodfill->drawEdges(FontTool->Device, 500, 3);
 
1018
                //floodfill->drawTriangles(FontTool->Device, 500,30);
 
1019
                //floodfill->drawTriLines(FontTool->Device, 200,3);
 
1020
 
 
1021
                /*
 
1022
                if (area==32 && map == 0)
 
1023
                {
 
1024
                        scene::ISceneManager *smgr = FontTool->Device->getSceneManager();
 
1025
                        smgr->addCameraSceneNodeFPS();
 
1026
                        while(FontTool->Device->run())
 
1027
                        {
 
1028
                                //floodfill->drawEdges(FontTool->Device, 100, 30);
 
1029
                                FontTool->Device->getVideoDriver()->beginScene(true, true, video::SColor(0,200,200,200));
 
1030
                                smgr->drawAll();
 
1031
                                floodfill->drawTri3D(FontTool->Device, 100);
 
1032
                                FontTool->Device->getVideoDriver()->endScene();
 
1033
                        }
 
1034
                }*/
 
1035
 
 
1036
                u32 lastind = triangles.indexes.size();
 
1037
 
 
1038
                // loop through each shape and add it to the current character...
 
1039
                for (u32 i=0; i < triangulator->groups.size(); ++i)
 
1040
                        triangles += triangulator->groups[i].triangles;
 
1041
 
 
1042
                // add character details
 
1043
                charstarts.push_back(lastind);
 
1044
                charlengths.push_back(triangles.indexes.size() - lastind);
 
1045
                chars.push_back(thischar);
 
1046
        }
 
1047
 
 
1048
        bool saveVectorFont(const c8 *filename, const c8 *formatname)
 
1049
        {
 
1050
                IrrlichtDevice *Device = FontTool->Device;
 
1051
 
 
1052
                if (triangles.indexes.size() == 0)
 
1053
                {
 
1054
                        Device->getLogger()->log("No vector data to write, aborting.");
 
1055
                        return false;
 
1056
                }
 
1057
 
 
1058
                core::stringc fn = filename;
 
1059
 
 
1060
                if (core::stringc(formatname) == core::stringc("xml"))
 
1061
                {
 
1062
                        fn += ".xml";
 
1063
                        io::IXMLWriter *writer = FontTool->Device->getFileSystem()->createXMLWriter(fn.c_str());
 
1064
 
 
1065
                        // header and line breaks
 
1066
                        writer->writeXMLHeader();
 
1067
                        writer->writeLineBreak();
 
1068
 
 
1069
                        // write info header
 
1070
                        writer->writeElement(L"font", false, L"type", L"vector");
 
1071
                        writer->writeLineBreak();
 
1072
                        writer->writeLineBreak();
 
1073
 
 
1074
                        // write each letter
 
1075
 
 
1076
                        for (u32 n=0; n<chars.size(); ++n)
 
1077
                        {
 
1078
                                u32 i = FontTool->CharMap[chars[n]];
 
1079
                                CFontTool::SFontArea &fa = FontTool->Areas[i];
 
1080
                                wchar_t c[2];
 
1081
                                c[0] = chars[n];
 
1082
                                c[1] = L'\0';
 
1083
                                core::stringw area, under, over;
 
1084
                                area = core::stringw(fa.rectangle.LowerRightCorner.X-
 
1085
                                                fa.rectangle.UpperLeftCorner.X);
 
1086
                                area += L", ";
 
1087
                                area += fa.rectangle.LowerRightCorner.Y-
 
1088
                                                fa.rectangle.UpperLeftCorner.Y;
 
1089
 
 
1090
 
 
1091
                                core::array<core::stringw> names;
 
1092
                                core::array<core::stringw> values;
 
1093
                                names.clear();
 
1094
                                values.clear();
 
1095
                                // char
 
1096
                                names.push_back(core::stringw(L"c"));
 
1097
                                values.push_back(core::stringw(c));
 
1098
 
 
1099
                                // width+height
 
1100
                                names.push_back(core::stringw(L"wh"));
 
1101
                                values.push_back(area);
 
1102
 
 
1103
                                // start
 
1104
                                names.push_back(core::stringw(L"st"));
 
1105
                                values.push_back(core::stringw(charstarts[n]));
 
1106
                                // length
 
1107
                                names.push_back(core::stringw(L"len"));
 
1108
                                values.push_back(core::stringw(charlengths[n]));
 
1109
 
 
1110
                                if (fa.underhang != 0)
 
1111
                                {
 
1112
                                        under = core::stringw(fa.underhang);
 
1113
                                        names.push_back(core::stringw(L"u"));
 
1114
                                        values.push_back(under);
 
1115
                                }
 
1116
                                if (fa.overhang != 0)
 
1117
                                {
 
1118
                                        over = core::stringw(fa.overhang);
 
1119
                                        names.push_back(core::stringw(L"o"));
 
1120
                                        values.push_back(over);
 
1121
                                }
 
1122
                                writer->writeElement(L"c", true, names, values);
 
1123
 
 
1124
                                writer->writeLineBreak();
 
1125
                        }
 
1126
 
 
1127
                        // write vertex data
 
1128
                        core::stringw data, count;
 
1129
                        data = L"";
 
1130
                        count = core::stringw(triangles.positions.size());
 
1131
                        for (u32 i=0; i<triangles.positions.size(); ++i)
 
1132
                        {
 
1133
                                if (i!=0)
 
1134
                                        data += L", ";
 
1135
                                data += (s32)triangles.positions[i].X;
 
1136
                                data += L",";
 
1137
                                data += (s32)triangles.positions[i].Y;
 
1138
                        }
 
1139
                        writer->writeElement(L"Vertices", true, L"count", count.c_str(), L"data", data.c_str());
 
1140
                        writer->writeLineBreak();
 
1141
 
 
1142
                        // write index list
 
1143
                        data = L"";
 
1144
                        count = core::stringw(triangles.indexes.size());
 
1145
                        for (u32 i=0; i<triangles.indexes.size(); i+=3)
 
1146
                        {
 
1147
                                if (i!=0)
 
1148
                                        data += L", ";
 
1149
                                data += triangles.indexes[i+0];
 
1150
                                data += L",";
 
1151
                                data += triangles.indexes[i+1],
 
1152
                                data += L",";
 
1153
                                data += triangles.indexes[i+2];
 
1154
                        }
 
1155
 
 
1156
                        writer->writeElement(L"Indices", true, L"count", count.c_str(), L"data", data.c_str());
 
1157
                        writer->writeLineBreak();
 
1158
 
 
1159
                        writer->writeClosingTag(L"font");
 
1160
 
 
1161
                        writer->drop();
 
1162
 
 
1163
                        Device->getLogger()->log("Font saved.");
 
1164
                        return true;
 
1165
 
 
1166
                }
 
1167
                else if (core::stringc(formatname) == core::stringc("bin"))
 
1168
                {
 
1169
                        FontTool->Device->getLogger()->log("binary fonts not supported yet, sorry");
 
1170
                        return false;
 
1171
                }
 
1172
                else
 
1173
                {
 
1174
                        FontTool->Device->getLogger()->log("unsupported file format, unable to save vector font");
 
1175
                        return false;
 
1176
                }
 
1177
        }
 
1178
 
 
1179
        S3DVertex& getVert(s32 x, s32 y) { return verts[letterWidth*y +x]; }
 
1180
 
 
1181
        core::array<S3DVertex>  verts;
 
1182
        core::array<u16>                inds;
 
1183
        core::array<bool>               imagedata;
 
1184
 
 
1185
        core::array<s32>                charstarts;     // start position of each char
 
1186
        core::array<s32>                charlengths;    // index count
 
1187
        core::array<wchar_t>            chars;          // letters
 
1188
 
 
1189
        CGroupFinder*           triangulator;
 
1190
        CFontTool*              FontTool;
 
1191
 
 
1192
        s32                     letterHeight;
 
1193
        s32                     letterWidth;
 
1194
 
 
1195
        STriangleList           triangles;
 
1196
};
 
1197
 
 
1198
#endif // __VECTOR_FONT_TOOL_INCLUDED__
 
1199