1 |
5 |
maiden |
#include "ttfpoint.h"
|
2 |
|
|
|
3 |
|
|
FT_Library TTFPoint::mLibrary;
|
4 |
|
|
FT_Error TTFPoint::mError;
|
5 |
|
|
|
6 |
|
|
TTFPoint::TTFPoint()
|
7 |
|
|
{
|
8 |
|
|
}
|
9 |
|
|
|
10 |
|
|
void TTFPoint::InitFreeType()
|
11 |
|
|
{
|
12 |
|
|
// intit freetype
|
13 |
|
|
mError = FT_Init_FreeType( &mLibrary );
|
14 |
|
|
if(mError)
|
15 |
|
|
{
|
16 |
|
|
cout << "Error loading freetype" << endl;
|
17 |
|
|
throw mError;
|
18 |
|
|
}
|
19 |
|
|
}
|
20 |
|
|
|
21 |
|
|
void TTFPoint::LoadFont(string filename)
|
22 |
|
|
{
|
23 |
|
|
// open font
|
24 |
|
|
mError = FT_New_Face( mLibrary,filename.c_str(),0,&mFace );
|
25 |
|
|
if(mError)
|
26 |
|
|
{
|
27 |
|
|
cout << "Error loading font" << endl;
|
28 |
|
|
throw mError;
|
29 |
|
|
}
|
30 |
|
|
|
31 |
|
|
|
32 |
|
|
// set the fontSize
|
33 |
|
|
FT_F26Dot6 font_size = 100;
|
34 |
|
|
mError = FT_Set_Char_Size( mFace, font_size, font_size, 72, 72 );
|
35 |
|
|
if(mError)
|
36 |
|
|
{
|
37 |
|
|
cout << "error setting char size" << endl;
|
38 |
|
|
throw mError;
|
39 |
|
|
}
|
40 |
|
|
|
41 |
|
|
cout << "Font: " << filename << " Loaded with " << mFace->num_glyphs << " Glyphs " << endl;
|
42 |
|
|
}
|
43 |
|
|
|
44 |
|
|
int BezierWrite::FixArea()
|
45 |
|
|
{
|
46 |
|
|
//float area = (p1.x - p0.x)*(p2.y-p0.y) - (p2.x-p0.x)*(p1.y-p0.y);
|
47 |
|
|
float area = (control.x - start.x)*(end.y-start.y) - (end.x-start.x)*(control.y-start.y);
|
48 |
|
|
if(area < 0)
|
49 |
|
|
{
|
50 |
|
|
// outside
|
51 |
|
|
fillInside = 0;
|
52 |
|
|
swap(start, end);
|
53 |
|
|
return 1;
|
54 |
|
|
}
|
55 |
|
|
else
|
56 |
|
|
{
|
57 |
|
|
// inside
|
58 |
|
|
fillInside = 1;
|
59 |
|
|
return 0;
|
60 |
|
|
}
|
61 |
|
|
}
|
62 |
|
|
|
63 |
|
|
FT_Outline TTFPoint::LoadGlyphOutline(int character, FT_Matrix &matrix, FT_Vector &pen)
|
64 |
|
|
{
|
65 |
|
|
FT_UInt glyph_index = FT_Get_Char_Index( mFace, character );
|
66 |
|
|
cout << "<Get glyph " << character << " with glyph_index " << glyph_index;
|
67 |
|
|
|
68 |
|
|
FT_Set_Transform( mFace, &matrix, &pen );
|
69 |
|
|
// load glyph
|
70 |
|
|
mError = FT_Load_Glyph(mFace,glyph_index,FT_LOAD_NO_SCALE);
|
71 |
|
|
if(mError)
|
72 |
|
|
{
|
73 |
|
|
cout << "Failed to load glyph!" << endl;
|
74 |
|
|
throw mError;
|
75 |
|
|
}
|
76 |
|
|
|
77 |
|
|
FT_GlyphSlot slot = mFace->glyph;
|
78 |
|
|
FT_Outline outline = slot->outline;
|
79 |
|
|
cout << " and " << outline.n_contours << " outlines and " << outline.n_points << " points. ";
|
80 |
|
|
|
81 |
|
|
return outline;
|
82 |
|
|
}
|
83 |
|
|
|
84 |
|
|
Glyph TTFPoint::BuildGlyph(deque<BPoint> &untangledPointList, int character)
|
85 |
|
|
{
|
86 |
|
|
Glyph current_glyph;
|
87 |
|
|
current_glyph.index = character;
|
88 |
|
|
current_glyph.advance_x = mFace->glyph->advance.x;
|
89 |
|
|
|
90 |
|
|
int firstObject = 0;
|
91 |
|
|
for(unsigned int j=0; j<untangledPointList.size(); j++)
|
92 |
|
|
{
|
93 |
|
|
int end_first=0, end_second=0, end_third=0;
|
94 |
|
|
int line_first=0, line_second=0, line_third=0;
|
95 |
|
|
|
96 |
|
|
// generate write
|
97 |
|
|
if( j+2 < untangledPointList.size()) // if we got more then three left in list
|
98 |
|
|
{
|
99 |
|
|
if(untangledPointList[j].endOfContour)
|
100 |
|
|
end_first = 1;
|
101 |
|
|
if(untangledPointList[j+1].endOfContour)
|
102 |
|
|
end_second = 1;
|
103 |
|
|
if(untangledPointList[j+2].endOfContour)
|
104 |
|
|
end_third = 1;
|
105 |
|
|
|
106 |
|
|
if(untangledPointList[j].onLine)
|
107 |
|
|
line_first = 1;
|
108 |
|
|
if(untangledPointList[j+1].onLine)
|
109 |
|
|
line_second = 1;
|
110 |
|
|
if(untangledPointList[j+2].onLine)
|
111 |
|
|
line_third = 1;
|
112 |
|
|
|
113 |
|
|
if(!end_first && !end_second && !end_third) // if no point is the end of the shape.
|
114 |
|
|
{
|
115 |
|
|
if(line_first && !line_second && line_third) // if first and last are points and middle is control point
|
116 |
|
|
{
|
117 |
|
|
BezierWrite write(untangledPointList[j],
|
118 |
|
|
untangledPointList[j+1],
|
119 |
|
|
untangledPointList[j+2]);
|
120 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
121 |
|
|
current_glyph.writes.push_back(write);
|
122 |
|
|
j++; // skip check of control point. go directly to end point.
|
123 |
|
|
}
|
124 |
|
|
else if(line_first && line_second) // if booth lines is online.
|
125 |
|
|
{
|
126 |
|
|
continue; // do nothing
|
127 |
|
|
}
|
128 |
|
|
}
|
129 |
|
|
if(end_first) // if first point is a endpoint
|
130 |
|
|
{
|
131 |
|
|
untangledPointList[j].internalControlPoint = 1; // mark end of shape for triangulation
|
132 |
|
|
if(line_first) // if point is online
|
133 |
|
|
{
|
134 |
|
|
// cout << "End of shape, first & online ";
|
135 |
|
|
if(untangledPointList[firstObject].onLine) // if two on in row, continue.
|
136 |
|
|
continue;
|
137 |
|
|
if(untangledPointList[firstObject+1].onLine) // if on, off, on, do write
|
138 |
|
|
{
|
139 |
|
|
BezierWrite write(untangledPointList[j],
|
140 |
|
|
untangledPointList[firstObject],
|
141 |
|
|
untangledPointList[firstObject+1]);
|
142 |
|
|
|
143 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
144 |
|
|
current_glyph.writes.push_back(write);
|
145 |
|
|
firstObject = j+2; // new first object in new shape.
|
146 |
|
|
// cout << "Done" << endl;
|
147 |
|
|
}
|
148 |
|
|
// else
|
149 |
|
|
// cout << "Not Done" << endl;
|
150 |
|
|
}
|
151 |
|
|
else // end of shape is a control point!
|
152 |
|
|
{
|
153 |
|
|
// cout << "End of shape, first & offline: ";
|
154 |
|
|
if(untangledPointList[firstObject].onLine) // if two on in row, continue.
|
155 |
|
|
{
|
156 |
|
|
BezierWrite write(untangledPointList[j],
|
157 |
|
|
untangledPointList[j+1],
|
158 |
|
|
untangledPointList[firstObject]);
|
159 |
|
|
|
160 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
161 |
|
|
current_glyph.writes.push_back(write);
|
162 |
|
|
firstObject = j+2; // new first object in new shape.
|
163 |
|
|
// cout << "Done" << endl;
|
164 |
|
|
}
|
165 |
|
|
// else
|
166 |
|
|
// cout << "Not done" << endl;
|
167 |
|
|
}
|
168 |
|
|
}
|
169 |
|
|
if(end_second) // if second point is a endpoint
|
170 |
|
|
{
|
171 |
|
|
untangledPointList[j+1].internalControlPoint = 1; // mark end of shape for triangulation
|
172 |
|
|
|
173 |
|
|
if(line_second) // if point is online
|
174 |
|
|
{
|
175 |
|
|
// cout << "End of shape, second & online ";
|
176 |
|
|
if(untangledPointList[firstObject].onLine) // if two on in row, continue.
|
177 |
|
|
continue;
|
178 |
|
|
if(untangledPointList[firstObject+1].onLine) // if on, off, on, do write
|
179 |
|
|
{
|
180 |
|
|
BezierWrite write(untangledPointList[j+1],
|
181 |
|
|
untangledPointList[firstObject],
|
182 |
|
|
untangledPointList[firstObject+1]);
|
183 |
|
|
|
184 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
185 |
|
|
current_glyph.writes.push_back(write);
|
186 |
|
|
firstObject = j+2; // new first object in new shape.
|
187 |
|
|
// cout << "Done" << endl;
|
188 |
|
|
}
|
189 |
|
|
// cout << "Not Done" << endl;
|
190 |
|
|
}
|
191 |
|
|
else // end of shape is a control point!
|
192 |
|
|
{
|
193 |
|
|
// will this happen?
|
194 |
|
|
// cout << "End of shape, second & offline ";
|
195 |
|
|
if(untangledPointList[firstObject].onLine)
|
196 |
|
|
{
|
197 |
|
|
BezierWrite write(untangledPointList[j],
|
198 |
|
|
untangledPointList[j+1],
|
199 |
|
|
untangledPointList[firstObject]);
|
200 |
|
|
|
201 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
202 |
|
|
current_glyph.writes.push_back(write);
|
203 |
|
|
firstObject = j+2; // new first object in new shape.
|
204 |
|
|
j++;
|
205 |
|
|
// cout << "Done" << endl;
|
206 |
|
|
}
|
207 |
|
|
// else
|
208 |
|
|
// cout << "Not Done" << endl;
|
209 |
|
|
}
|
210 |
|
|
|
211 |
|
|
}
|
212 |
|
|
if(end_third) // if third point is a endpoint
|
213 |
|
|
{
|
214 |
|
|
untangledPointList[j+2].internalControlPoint = 1; // mark end of shape for triangulation
|
215 |
|
|
if(line_third) // if point is online
|
216 |
|
|
{
|
217 |
|
|
// do nothing, itterate two steps and try again!
|
218 |
|
|
// cout << "End of shape, third & online" << endl;
|
219 |
|
|
}
|
220 |
|
|
else // end of shape is a control point!
|
221 |
|
|
{
|
222 |
|
|
// will this happen?
|
223 |
|
|
// cout << "End of shape, third & offline" << endl;
|
224 |
|
|
}
|
225 |
|
|
}
|
226 |
|
|
}
|
227 |
|
|
else if( j+2 == untangledPointList.size()) // if we got two points left
|
228 |
|
|
{
|
229 |
|
|
if(untangledPointList[j].endOfContour)
|
230 |
|
|
end_first = 1;
|
231 |
|
|
if(untangledPointList[j+1].endOfContour)
|
232 |
|
|
end_second = 1;
|
233 |
|
|
|
234 |
|
|
if(untangledPointList[j].onLine)
|
235 |
|
|
line_first = 1;
|
236 |
|
|
if(untangledPointList[j+1].onLine)
|
237 |
|
|
line_second = 1;
|
238 |
|
|
|
239 |
|
|
if(end_first)
|
240 |
|
|
{
|
241 |
|
|
untangledPointList[j].internalControlPoint = 1; // mark end of shape for triangulation
|
242 |
|
|
if(line_first)
|
243 |
|
|
{
|
244 |
|
|
// cout << "small End of shape, first & online ";
|
245 |
|
|
if(untangledPointList[firstObject].onLine) // if two on in row, continue.
|
246 |
|
|
continue;
|
247 |
|
|
if(untangledPointList[firstObject+1].onLine) // if on, off, on, do write
|
248 |
|
|
{
|
249 |
|
|
BezierWrite write(untangledPointList[j],
|
250 |
|
|
untangledPointList[firstObject],
|
251 |
|
|
untangledPointList[firstObject+1]);
|
252 |
|
|
|
253 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
254 |
|
|
current_glyph.writes.push_back(write);
|
255 |
|
|
firstObject = j+1; // new first object in new shape.
|
256 |
|
|
// cout << "Done" << endl;
|
257 |
|
|
}
|
258 |
|
|
// else
|
259 |
|
|
// cout << "Not Done" << endl;
|
260 |
|
|
}
|
261 |
|
|
else
|
262 |
|
|
{
|
263 |
|
|
// cout << "small End of shape, first & offline: ";
|
264 |
|
|
if(untangledPointList[firstObject].onLine) // if two on in row, continue.
|
265 |
|
|
{
|
266 |
|
|
BezierWrite write(untangledPointList[j],
|
267 |
|
|
untangledPointList[j+1],
|
268 |
|
|
untangledPointList[firstObject]);
|
269 |
|
|
|
270 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
271 |
|
|
current_glyph.writes.push_back(write);
|
272 |
|
|
firstObject = j+1; // new first object in new shape.
|
273 |
|
|
// cout << "Done" << endl;
|
274 |
|
|
}
|
275 |
|
|
//else
|
276 |
|
|
// cout << "Not done" << endl;
|
277 |
|
|
}
|
278 |
|
|
|
279 |
|
|
}
|
280 |
|
|
else if(end_second)
|
281 |
|
|
{
|
282 |
|
|
untangledPointList[j+1].internalControlPoint = 1; // mark end of shape for triangulation
|
283 |
|
|
if(line_second)
|
284 |
|
|
{
|
285 |
|
|
//cout << "small End of shape, second & online ";
|
286 |
|
|
if(untangledPointList[firstObject].onLine) // if two on in row, continue.
|
287 |
|
|
continue;
|
288 |
|
|
if(untangledPointList[firstObject+1].onLine) // if on, off, on, do write
|
289 |
|
|
{
|
290 |
|
|
BezierWrite write(untangledPointList[j+1],
|
291 |
|
|
untangledPointList[firstObject],
|
292 |
|
|
untangledPointList[firstObject+1]);
|
293 |
|
|
|
294 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
295 |
|
|
current_glyph.writes.push_back(write);
|
296 |
|
|
firstObject = 0; // new first object in new shape.
|
297 |
|
|
// cout << "Done" << endl;
|
298 |
|
|
}
|
299 |
|
|
//cout << "Not Done" << endl;
|
300 |
|
|
}
|
301 |
|
|
else
|
302 |
|
|
{
|
303 |
|
|
// cout << "small End of shape, second & offline ";
|
304 |
|
|
if(untangledPointList[firstObject].onLine)
|
305 |
|
|
{
|
306 |
|
|
BezierWrite write(untangledPointList[j],
|
307 |
|
|
untangledPointList[j+1],
|
308 |
|
|
untangledPointList[firstObject]);
|
309 |
|
|
|
310 |
|
|
untangledPointList[j+1].internalControlPoint = write.FixArea();
|
311 |
|
|
current_glyph.writes.push_back(write);
|
312 |
|
|
firstObject = 0; // new first object in new shape.
|
313 |
|
|
j++;
|
314 |
|
|
// cout << "Done" << endl;
|
315 |
|
|
}
|
316 |
|
|
//else
|
317 |
|
|
// cout << "Not Done" << endl;
|
318 |
|
|
}
|
319 |
|
|
}
|
320 |
|
|
|
321 |
|
|
}
|
322 |
|
|
else if( j+1 == untangledPointList.size()) // if we got one point left
|
323 |
|
|
{
|
324 |
|
|
if(untangledPointList[j].endOfContour)
|
325 |
|
|
end_first = 1;
|
326 |
|
|
|
327 |
|
|
if(untangledPointList[j].onLine)
|
328 |
|
|
line_first = 1;
|
329 |
|
|
}
|
330 |
|
|
}
|
331 |
|
|
|
332 |
|
|
// triangulate and assign to current_glyph.
|
333 |
|
|
current_glyph.triangles = Triangulate(untangledPointList);
|
334 |
|
|
|
335 |
|
|
return current_glyph;
|
336 |
|
|
}
|
337 |
|
|
|
338 |
|
|
void TTFPoint::GenerateWrites(bool all, wstring charmap)
|
339 |
|
|
{
|
340 |
|
|
if(all)
|
341 |
|
|
{
|
342 |
|
|
//save complete font
|
343 |
|
|
cout << "<COPY ALL NOT IMPLEMENTED YET!>" << endl;
|
344 |
|
|
throw 1;
|
345 |
|
|
}
|
346 |
|
|
|
347 |
|
|
FT_Matrix matrix; // transformation matrix
|
348 |
|
|
FT_Vector pen; // untransformed origin
|
349 |
|
|
|
350 |
|
|
// set up matrix
|
351 |
|
|
matrix.xx = (FT_Fixed)(1 * 0x10000L );
|
352 |
|
|
matrix.xy = (FT_Fixed)(0 * 0x10000L );
|
353 |
|
|
matrix.yx = (FT_Fixed)(0 * 0x10000L );
|
354 |
|
|
matrix.yy = (FT_Fixed)(-1 * 0x10000L );
|
355 |
|
|
|
356 |
|
|
// the pen position in 26.6 cartesian space coordinates;
|
357 |
|
|
// start at (300,200) relative to the upper left corner
|
358 |
|
|
pen.x = 0;
|
359 |
|
|
pen.y = 0;
|
360 |
|
|
|
361 |
|
|
//save selected characters
|
362 |
|
|
for(unsigned int i=0; i<charmap.size(); i++)
|
363 |
|
|
{
|
364 |
|
|
// Get the outline
|
365 |
|
|
FT_Outline outline = LoadGlyphOutline(charmap[i], matrix, pen);
|
366 |
|
|
|
367 |
|
|
deque<BPoint> untangledPointList = UntangleGlyphPoints(outline);
|
368 |
|
|
|
369 |
|
|
cout << " Untangled: " << untangledPointList.size() << " from " << outline.n_points << " points>" << endl;
|
370 |
|
|
|
371 |
|
|
mGlyphs.push_back(BuildGlyph(untangledPointList, charmap[i]));
|
372 |
|
|
}
|
373 |
|
|
}
|
374 |
|
|
|
375 |
|
|
deque<BPoint> TTFPoint::UntangleGlyphPoints(FT_Outline outline)
|
376 |
|
|
{
|
377 |
|
|
deque<BPoint> untangledPointList;
|
378 |
|
|
bool last_off = false;
|
379 |
|
|
|
380 |
|
|
BPoint lastPoint(-60000, -60000);
|
381 |
|
|
|
382 |
|
|
for(int i=0; i<outline.n_points; i++)
|
383 |
|
|
{
|
384 |
|
|
if(outline.points[i].x == lastPoint.x && outline.points[i].y == lastPoint.y)
|
385 |
|
|
continue;
|
386 |
|
|
lastPoint.x = outline.points[i].x;
|
387 |
|
|
lastPoint.y = outline.points[i].y;
|
388 |
|
|
|
389 |
|
|
if(outline.tags[i] == 0x001) // on line
|
390 |
|
|
{
|
391 |
|
|
untangledPointList.push_back(BPoint(outline.points[i].x,
|
392 |
|
|
outline.points[i].y,
|
393 |
|
|
1));
|
394 |
|
|
|
395 |
|
|
// last point was on line
|
396 |
|
|
last_off = false;
|
397 |
|
|
}
|
398 |
|
|
else // off point
|
399 |
|
|
{
|
400 |
|
|
// if last was off and this is off, then there is a implicit point inbetween.
|
401 |
|
|
if(last_off)
|
402 |
|
|
{
|
403 |
|
|
// Applying the midpoint formula to calculate implicit midpoint
|
404 |
|
|
|
405 |
|
|
// (x0 + x1) | (y0 + y1)
|
406 |
|
|
// --------- = x | --------- = y
|
407 |
|
|
// 2 | 2
|
408 |
|
|
|
409 |
|
|
int x = (outline.points[i-1].x + outline.points[i].x) / 2;
|
410 |
|
|
int y = (outline.points[i-1].y + outline.points[i].y) / 2;
|
411 |
|
|
|
412 |
|
|
// add implicit online point to list.
|
413 |
|
|
untangledPointList.push_back(BPoint(x, y, 1));
|
414 |
|
|
|
415 |
|
|
bool endOfContour = false;
|
416 |
|
|
// check if this point is the endpoint of a shape.
|
417 |
|
|
for(int j=0; j<outline.n_contours; j++)
|
418 |
|
|
{
|
419 |
|
|
if(outline.contours[j] == i)
|
420 |
|
|
{
|
421 |
|
|
endOfContour = true;
|
422 |
|
|
break;
|
423 |
|
|
}
|
424 |
|
|
}
|
425 |
|
|
|
426 |
|
|
// add explicit offline point to list
|
427 |
|
|
untangledPointList.push_back(BPoint(outline.points[i].x,
|
428 |
|
|
outline.points[i].y,
|
429 |
|
|
0, endOfContour));
|
430 |
|
|
}
|
431 |
|
|
else // this is the first point off curve.
|
432 |
|
|
{
|
433 |
|
|
bool endOfContour = false;
|
434 |
|
|
// check if this point is the endpoint of a shape.
|
435 |
|
|
for(int j=0; j<outline.n_contours; j++)
|
436 |
|
|
{
|
437 |
|
|
if(outline.contours[j] == i)
|
438 |
|
|
{
|
439 |
|
|
endOfContour = true;
|
440 |
|
|
break;
|
441 |
|
|
}
|
442 |
|
|
}
|
443 |
|
|
|
444 |
|
|
untangledPointList.push_back(BPoint(outline.points[i].x,
|
445 |
|
|
outline.points[i].y,
|
446 |
|
|
0, endOfContour));
|
447 |
|
|
|
448 |
|
|
//last point was off
|
449 |
|
|
last_off = true;
|
450 |
|
|
}
|
451 |
|
|
}
|
452 |
|
|
}
|
453 |
|
|
|
454 |
|
|
return untangledPointList;
|
455 |
|
|
}
|
456 |
|
|
|
457 |
|
|
void TTFPoint::WriteFontFile(string fontname)
|
458 |
|
|
{
|
459 |
|
|
string filename = fontname + ".h";
|
460 |
|
|
|
461 |
|
|
ofstream output(filename.c_str(),ofstream::out);
|
462 |
|
|
if( !output )
|
463 |
|
|
{
|
464 |
|
|
cout << "Couldn't open output file!" << endl;
|
465 |
|
|
throw 2;
|
466 |
|
|
}
|
467 |
|
|
|
468 |
|
|
output << "#ifndef " << fontname << "_H" << endl;
|
469 |
|
|
output << "#define " << fontname << "_H" << endl << endl;
|
470 |
|
|
output << "#include \"orgfx_vector_font.h\"" << endl << endl;
|
471 |
|
|
|
472 |
|
|
output << "orgfx_vector_font init_" << fontname << "();" << endl << endl;
|
473 |
|
|
|
474 |
|
|
output << "Glyph* " << fontname << "_glyphindexlist[256];" << endl << endl;
|
475 |
|
|
|
476 |
|
|
// write data to file
|
477 |
|
|
for(unsigned int i=0; i < mGlyphs.size(); i++)
|
478 |
|
|
{
|
479 |
|
|
// GLYPH DATA
|
480 |
|
|
output << "//Glyph: " << mGlyphs[i].index << endl;
|
481 |
|
|
output << "int " << fontname << "_glyph_" << mGlyphs[i].index << "_index = " << mGlyphs[i].index << "; " << endl;
|
482 |
|
|
output << "int " << fontname << "_glyph_" << mGlyphs[i].index << "_advance_x = " << mGlyphs[i].advance_x << "; " << endl;
|
483 |
|
|
output << "int " << fontname << "_glyph_" << mGlyphs[i].index << "_size = " << mGlyphs[i].writes.size() << ";" << endl;
|
484 |
|
|
output << "Bezier_write " << fontname << "_glyph_" << mGlyphs[i].index << "[] = {" << endl;
|
485 |
|
|
for(unsigned int j=0; j<mGlyphs[i].writes.size(); j++)
|
486 |
|
|
{
|
487 |
|
|
output << "{{"
|
488 |
|
|
<< mGlyphs[i].writes[j].start.x << ", " << mGlyphs[i].writes[j].start.y << "}, {"
|
489 |
|
|
<< mGlyphs[i].writes[j].control.x << ", " << mGlyphs[i].writes[j].control.y << "}, {"
|
490 |
|
|
<< mGlyphs[i].writes[j].end.x << ", " << mGlyphs[i].writes[j].end.y << "},"
|
491 |
|
|
<< mGlyphs[i].writes[j].fillInside << " }";
|
492 |
|
|
output << "," << endl;
|
493 |
|
|
}
|
494 |
|
|
output << "};" << endl;
|
495 |
|
|
|
496 |
|
|
// TRIANGLE DATA
|
497 |
|
|
output << "int " << fontname << "_glyph_" << mGlyphs[i].index << "_triangle_size = " << mGlyphs[i].triangles.size() << ";" << endl;
|
498 |
|
|
output << "Triangle_write " << fontname << "_glyph_" << mGlyphs[i].index << "_triangles[] = {" << endl;
|
499 |
|
|
for(unsigned int j=0; j<mGlyphs[i].triangles.size(); j++)
|
500 |
|
|
{
|
501 |
|
|
output << "{{"
|
502 |
|
|
<< mGlyphs[i].triangles[j].a.x << ", " << mGlyphs[i].triangles[j].a.y << "}, {"
|
503 |
|
|
<< mGlyphs[i].triangles[j].b.x << ", " << mGlyphs[i].triangles[j].b.y << "}, {"
|
504 |
|
|
<< mGlyphs[i].triangles[j].c.x << ", " << mGlyphs[i].triangles[j].c.y << "}}";
|
505 |
|
|
output << "," << endl;
|
506 |
|
|
}
|
507 |
|
|
output << "};" << endl;
|
508 |
|
|
|
509 |
|
|
|
510 |
|
|
}
|
511 |
|
|
|
512 |
|
|
output << "int " << fontname << "_nGlyphs = " << mGlyphs.size() << ";" << endl << endl;
|
513 |
|
|
output << "Glyph " << fontname << "_glyphlist[" << mGlyphs.size() << "];" << endl << endl;
|
514 |
|
|
output << "void generate_" << fontname << "()" << endl;
|
515 |
|
|
output << "{" << endl;
|
516 |
|
|
output << " Glyph pGlyph;" << endl;
|
517 |
|
|
|
518 |
|
|
for(unsigned int i=0; i< mGlyphs.size(); i++)
|
519 |
|
|
{
|
520 |
|
|
output << " pGlyph.index = " << fontname << "_glyph_" << mGlyphs[i].index << "_index;" << endl;
|
521 |
|
|
output << " pGlyph.advance_x = " << fontname << "_glyph_" << mGlyphs[i].index << "_advance_x;" << endl;
|
522 |
|
|
output << " pGlyph.bezier_n_writes = " << fontname << "_glyph_" << mGlyphs[i].index << "_size;" << endl;
|
523 |
|
|
output << " pGlyph.bezier = " << fontname << "_glyph_" << mGlyphs[i].index << ";" << endl;
|
524 |
|
|
output << " pGlyph.triangle_n_writes = " << fontname << "_glyph_" << mGlyphs[i].index << "_triangle_size;" << endl;
|
525 |
|
|
output << " pGlyph.triangle = " << fontname << "_glyph_" << mGlyphs[i].index << "_triangles;" << endl;
|
526 |
|
|
output << " " << fontname << "_glyphlist[" << i << "] = pGlyph;" << endl;
|
527 |
|
|
}
|
528 |
|
|
|
529 |
|
|
output << " }" << endl << endl;
|
530 |
|
|
|
531 |
|
|
output << "orgfx_vector_font init_" << fontname << "()" << endl;
|
532 |
|
|
output << "{" << endl;
|
533 |
|
|
output << " orgfx_vector_font font = orgfx_make_vector_font(" << fontname << "_glyphlist," << endl;
|
534 |
|
|
output << " " << fontname << "_nGlyphs," << endl;
|
535 |
|
|
output << " " << fontname << "_glyphindexlist," << endl;
|
536 |
|
|
output << " 256);" << endl;
|
537 |
|
|
output << " generate_" << fontname << "();" << endl;
|
538 |
|
|
output << " orgfx_init_vector_font(font);" << endl;
|
539 |
|
|
output << " return font;" << endl;
|
540 |
|
|
output << "}" << endl << endl;
|
541 |
|
|
|
542 |
|
|
output << "#endif" << endl;
|
543 |
|
|
output.close();
|
544 |
|
|
}
|
545 |
|
|
|
546 |
|
|
vector<Point*> TTFPoint::GetShapePoints(int i, vector< vector<BPoint> > &shapes)
|
547 |
|
|
{
|
548 |
|
|
vector<Point*> polyline;
|
549 |
|
|
vector<BPoint> &shape = shapes[i];
|
550 |
|
|
for(unsigned int j = 0; j < shape.size(); j++)
|
551 |
|
|
polyline.push_back(new Point(shape[j].x, shape[j].y));
|
552 |
|
|
return polyline;
|
553 |
|
|
}
|
554 |
|
|
|
555 |
|
|
deque<TriangleWrite> TTFPoint::Triangulate(deque<BPoint> &untangledPointList)
|
556 |
|
|
{
|
557 |
|
|
vector<BPoint> polyline;
|
558 |
|
|
vector< vector<BPoint> > shapes;
|
559 |
|
|
deque<TriangleWrite> triangle_writes;
|
560 |
|
|
|
561 |
|
|
// add all points to polyline
|
562 |
|
|
bool empty = true;
|
563 |
|
|
for(unsigned int i=0; i< untangledPointList.size(); i++)
|
564 |
|
|
{
|
565 |
|
|
if(untangledPointList[i].internalControlPoint == 1 || untangledPointList[i].onLine)
|
566 |
|
|
{
|
567 |
|
|
polyline.push_back(BPoint(untangledPointList[i].x, untangledPointList[i].y));
|
568 |
|
|
empty = false;
|
569 |
|
|
}
|
570 |
|
|
if(untangledPointList[i].endOfContour == 1 && i > 0)
|
571 |
|
|
{
|
572 |
|
|
shapes.push_back(polyline);
|
573 |
|
|
polyline.clear();
|
574 |
|
|
empty = true;
|
575 |
|
|
}
|
576 |
|
|
}
|
577 |
|
|
if(empty == false)
|
578 |
|
|
{
|
579 |
|
|
shapes.push_back(polyline);
|
580 |
|
|
}
|
581 |
|
|
|
582 |
|
|
if(!shapes.size())
|
583 |
|
|
return triangle_writes;
|
584 |
|
|
|
585 |
|
|
CDT* cdt = new CDT(GetShapePoints(0, shapes));
|
586 |
|
|
cdt->Triangulate();
|
587 |
|
|
int beginningOfShape = 0;
|
588 |
|
|
|
589 |
|
|
cout << "Triangulating " << shapes.size() << " contours..." << endl;
|
590 |
|
|
|
591 |
|
|
for(unsigned int i=1; i<shapes.size(); i++)
|
592 |
|
|
{
|
593 |
|
|
vector<Triangle*> triangles = cdt->GetTriangles();
|
594 |
|
|
cout << "Triangles: " << triangles.size() << endl;
|
595 |
|
|
|
596 |
|
|
// Pick the first point in the shape
|
597 |
|
|
BPoint firstPoint = shapes[i][0];
|
598 |
|
|
float x = firstPoint.x;
|
599 |
|
|
float y = firstPoint.y;
|
600 |
|
|
|
601 |
|
|
bool isHole = false;
|
602 |
|
|
|
603 |
|
|
// Check this point against all triangles
|
604 |
|
|
for(unsigned int j=0; j<triangles.size(); j++)
|
605 |
|
|
{
|
606 |
|
|
//poly2tri point
|
607 |
|
|
Point *p0 = triangles[j]->GetPoint(0);
|
608 |
|
|
Point *p1 = triangles[j]->PointCCW(*p0); // get clockwise next point after point
|
609 |
|
|
Point *p2 = triangles[j]->PointCCW(*p1); // get clockwise next point after point
|
610 |
|
|
|
611 |
|
|
// Calculate edges
|
612 |
|
|
float e0 = -(p2->y-p1->y)*(x-p1->x)+(p2->x-p1->x)*(y-p1->y);
|
613 |
|
|
float e1 = -(p0->y-p2->y)*(x-p2->x)+(p0->x-p2->x)*(y-p2->y);
|
614 |
|
|
float e2 = -(p1->y-p0->y)*(x-p0->x)+(p1->x-p0->x)*(y-p0->y);
|
615 |
|
|
|
616 |
|
|
// If the point is inside the triangle, this must be a hole
|
617 |
|
|
|
618 |
|
|
if(e0 >= 0 && e1 >= 0 && e2 >= 0)
|
619 |
|
|
{
|
620 |
|
|
isHole = true;
|
621 |
|
|
break;
|
622 |
|
|
}
|
623 |
|
|
}
|
624 |
|
|
|
625 |
|
|
// If this is a hole, we need to add it and start over
|
626 |
|
|
if(isHole)
|
627 |
|
|
{
|
628 |
|
|
cout << "Found hole!" << endl;
|
629 |
|
|
delete cdt;
|
630 |
|
|
cdt = new CDT(GetShapePoints(beginningOfShape, shapes));
|
631 |
|
|
for(unsigned int j = beginningOfShape + 1; j <= i; j++)
|
632 |
|
|
cdt->AddHole(GetShapePoints(j, shapes));
|
633 |
|
|
cdt->Triangulate();
|
634 |
|
|
}
|
635 |
|
|
// If this isn't a hole, it is a new shape
|
636 |
|
|
// Print the old one to writes, then create a new one
|
637 |
|
|
else
|
638 |
|
|
{
|
639 |
|
|
cout << "Writing shape with " << triangles.size() << " triangles!" << endl;
|
640 |
|
|
|
641 |
|
|
for(unsigned int j=0; j<triangles.size(); j++)
|
642 |
|
|
{
|
643 |
|
|
//poly2tri point
|
644 |
|
|
Point *p0 = triangles[j]->GetPoint(0);
|
645 |
|
|
Point *p1 = triangles[j]->PointCCW(*p0); // get clockwise next point after point
|
646 |
|
|
Point *p2 = triangles[j]->PointCCW(*p1); // get clockwise next point after point
|
647 |
|
|
|
648 |
|
|
triangle_writes.push_back(TriangleWrite(BPoint(p0->x, p0->y),
|
649 |
|
|
BPoint(p1->x, p1->y),
|
650 |
|
|
BPoint(p2->x, p2->y)));
|
651 |
|
|
}
|
652 |
|
|
|
653 |
|
|
delete cdt;
|
654 |
|
|
cdt = new CDT(GetShapePoints(i, shapes));
|
655 |
|
|
cdt->Triangulate();
|
656 |
|
|
beginningOfShape = i;
|
657 |
|
|
}
|
658 |
|
|
|
659 |
|
|
}
|
660 |
|
|
|
661 |
|
|
|
662 |
|
|
vector<Triangle*> triangles = cdt->GetTriangles();
|
663 |
|
|
cout << "Writing shape with " << triangles.size() << " triangles!" << endl;
|
664 |
|
|
|
665 |
|
|
// Write the final shape
|
666 |
|
|
for(unsigned int j=0; j<triangles.size(); j++)
|
667 |
|
|
{
|
668 |
|
|
//poly2tri point
|
669 |
|
|
Point *p0 = triangles[j]->GetPoint(0);
|
670 |
|
|
Point *p1 = triangles[j]->PointCCW(*p0); // get clockwise next point after point
|
671 |
|
|
Point *p2 = triangles[j]->PointCCW(*p1); // get clockwise next point after point
|
672 |
|
|
|
673 |
|
|
triangle_writes.push_back(TriangleWrite(BPoint(p0->x, p0->y),
|
674 |
|
|
BPoint(p1->x, p1->y),
|
675 |
|
|
BPoint(p2->x, p2->y)));
|
676 |
|
|
}
|
677 |
|
|
|
678 |
|
|
|
679 |
|
|
|
680 |
|
|
/*
|
681 |
|
|
|
682 |
|
|
for(unsigned int i=1; i<shapes.size(); i++)
|
683 |
|
|
{
|
684 |
|
|
cdt->AddHole(shapes[i]);
|
685 |
|
|
}
|
686 |
|
|
|
687 |
|
|
cdt->Triangulate();
|
688 |
|
|
triangles = cdt->GetTriangles();
|
689 |
|
|
cout << "Triangles: " << triangles.size() << endl;
|
690 |
|
|
|
691 |
|
|
for(unsigned int i=0; i<triangles.size(); i++)
|
692 |
|
|
{
|
693 |
|
|
//poly2tri point
|
694 |
|
|
Point *p0 = triangles[i]->GetPoint(0);
|
695 |
|
|
Point *p1 = triangles[i]->PointCCW(*p0); // get clockwise next point after point
|
696 |
|
|
Point *p2 = triangles[i]->PointCCW(*p1); // get clockwise next point after point
|
697 |
|
|
|
698 |
|
|
triangle_writes.push_back(TriangleWrite(BPoint(p0->x, p0->y),
|
699 |
|
|
BPoint(p1->x, p1->y),
|
700 |
|
|
BPoint(p2->x, p2->y)));
|
701 |
|
|
}
|
702 |
|
|
|
703 |
|
|
*/
|
704 |
|
|
|
705 |
|
|
delete cdt;
|
706 |
|
|
return triangle_writes;
|
707 |
|
|
}
|