1
|
1
|
/** The rasterizer for the 'dense' renderer */
|
2
|
2
|
|
3
|
|
-/* END */ |
|
|
\ No newline at end of file |
|
3
|
+#undef FT_COMPONENT
|
|
4
|
+#define FT_COMPONENT dense
|
|
5
|
+
|
|
6
|
+#include <freetype/ftoutln.h>
|
|
7
|
+#include <freetype/internal/ftcalc.h>
|
|
8
|
+#include <freetype/internal/ftdebug.h>
|
|
9
|
+#include <freetype/internal/ftobjs.h>
|
|
10
|
+#include <math.h>
|
|
11
|
+
|
|
12
|
+#include "ftdense.h"
|
|
13
|
+#include "ftdenseerrs.h"
|
|
14
|
+
|
|
15
|
+#define PIXEL_BITS 8
|
|
16
|
+
|
|
17
|
+#define ONE_PIXEL ( 1 << PIXEL_BITS )
|
|
18
|
+#define TRUNC( x ) (int)( ( x ) >> PIXEL_BITS )
|
|
19
|
+
|
|
20
|
+#define UPSCALE( x ) ( ( x ) * ( ONE_PIXEL >> 6 ) )
|
|
21
|
+#define DOWNSCALE( x ) ( ( x ) >> ( PIXEL_BITS - 6 ) )
|
|
22
|
+
|
|
23
|
+#define FT_SWAP(a, b) ( (a) ^= (b) ^=(a) ^= (b))
|
|
24
|
+#define FT_MIN( a, b ) ( (a) < (b) ? (a) : (b) )
|
|
25
|
+#define FT_MAX( a, b ) ( (a) > (b) ? (a) : (b) )
|
|
26
|
+#define FT_ABS( a ) ( (a) < 0 ? -(a) : (a) )
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+typedef struct dense_TRaster_
|
|
30
|
+{
|
|
31
|
+ void* memory;
|
|
32
|
+
|
|
33
|
+} dense_TRaster, *dense_PRaster;
|
|
34
|
+
|
|
35
|
+/* Linear interpolation between P0 and P1 */
|
|
36
|
+static FT_Vector
|
|
37
|
+Lerp( float T, FT_Vector P0, FT_Vector P1 )
|
|
38
|
+{
|
|
39
|
+ FT_Vector p;
|
|
40
|
+ p.x = P0.x + T * ( P1.x - P0.x );
|
|
41
|
+ p.y = P0.y + T * ( P1.y - P0.y );
|
|
42
|
+ return p;
|
|
43
|
+}
|
|
44
|
+
|
|
45
|
+static int
|
|
46
|
+dense_move_to( const FT_Vector* to, dense_worker* worker )
|
|
47
|
+{
|
|
48
|
+ FT_Pos x, y;
|
|
49
|
+
|
|
50
|
+ x = UPSCALE( to->x );
|
|
51
|
+ y = UPSCALE( to->y );
|
|
52
|
+ worker->prev_x = x;
|
|
53
|
+ worker->prev_y = y;
|
|
54
|
+ return 0;
|
|
55
|
+}
|
|
56
|
+
|
|
57
|
+static int
|
|
58
|
+dense_line_to( const FT_Vector* to, dense_worker* worker )
|
|
59
|
+{
|
|
60
|
+ dense_render_line( worker, UPSCALE( to->x ), UPSCALE( to->y ) );
|
|
61
|
+ dense_move_to( to, worker );
|
|
62
|
+ return 0;
|
|
63
|
+}
|
|
64
|
+
|
|
65
|
+void
|
|
66
|
+dense_render_line( dense_worker* worker, FT_Pos tox, FT_Pos toy )
|
|
67
|
+{
|
|
68
|
+ float from_x = worker->prev_x;
|
|
69
|
+ float from_y = worker->prev_y;
|
|
70
|
+ if ( from_y == toy )
|
|
71
|
+ return;
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+ from_x /= 256.0;
|
|
75
|
+ from_y /= 256.0;
|
|
76
|
+ float to_x = tox / 256.0;
|
|
77
|
+ float to_y = toy / 256.0;
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+ float dir;
|
|
81
|
+ if ( from_y < to_y )
|
|
82
|
+ dir = 1;
|
|
83
|
+ else
|
|
84
|
+ {
|
|
85
|
+ dir = -1;
|
|
86
|
+ FT_SWAP(from_x, to_x );
|
|
87
|
+ FT_SWAP(from_y, to_y );
|
|
88
|
+ }
|
|
89
|
+
|
|
90
|
+ // Clip to the height.
|
|
91
|
+ if ( from_y >= worker->m_h || to_y <= 0 )
|
|
92
|
+ return;
|
|
93
|
+
|
|
94
|
+ float dxdy = ( to_x - from_x ) / (float)( to_y - from_y );
|
|
95
|
+ if ( from_y < 0 )
|
|
96
|
+ {
|
|
97
|
+ from_x -= from_y * dxdy;
|
|
98
|
+ from_y = 0;
|
|
99
|
+ }
|
|
100
|
+ if ( to_y > worker->m_h )
|
|
101
|
+ {
|
|
102
|
+ to_x -= ( to_y - worker->m_h ) * dxdy;
|
|
103
|
+ to_y = (float)worker->m_h;
|
|
104
|
+ }
|
|
105
|
+
|
|
106
|
+ float x = from_x;
|
|
107
|
+ int y0 = (int)from_y;
|
|
108
|
+ int y_limit = (int)ceil( to_y );
|
|
109
|
+ float* m_a = worker->m_a;
|
|
110
|
+
|
|
111
|
+ for ( int y = y0; y < y_limit; y++ )
|
|
112
|
+ {
|
|
113
|
+ int linestart = y * worker->m_w;
|
|
114
|
+ float dy = fmin( y + 1.0f, to_y ) - fmax( (float)y, from_y );
|
|
115
|
+ float xnext = x + dxdy * dy;
|
|
116
|
+ float d = dy * dir;
|
|
117
|
+
|
|
118
|
+ float x0, x1;
|
|
119
|
+ if ( x < xnext )
|
|
120
|
+ {
|
|
121
|
+ x0 = x;
|
|
122
|
+ x1 = xnext;
|
|
123
|
+ }
|
|
124
|
+ else
|
|
125
|
+ {
|
|
126
|
+ x0 = xnext;
|
|
127
|
+ x1 = x;
|
|
128
|
+ }
|
|
129
|
+
|
|
130
|
+ /*
|
|
131
|
+ It's possible for x0 to be negative on the last scanline because of
|
|
132
|
+ floating-point inaccuracy That would cause an out-of-bounds array access at
|
|
133
|
+ index -1.
|
|
134
|
+ */
|
|
135
|
+ float x0floor = x0 <= 0.0f ? 0.0f : (float)floor( x0 );
|
|
136
|
+
|
|
137
|
+ int x0i = (int)x0floor;
|
|
138
|
+ float x1ceil = (float)ceil( x1 );
|
|
139
|
+ int x1i = (int)x1ceil;
|
|
140
|
+ if ( x1i <= x0i + 1 )
|
|
141
|
+ {
|
|
142
|
+ float xmf = 0.5f * ( x + xnext ) - x0floor;
|
|
143
|
+ m_a[linestart + x0i] += d - d * xmf;
|
|
144
|
+ m_a[linestart + ( x0i + 1 )] += d * xmf;
|
|
145
|
+ }
|
|
146
|
+ else
|
|
147
|
+ {
|
|
148
|
+ float s = 1.0f / ( x1 - x0 );
|
|
149
|
+ float x0f = x0 - x0floor;
|
|
150
|
+ float a0 = 0.5f * s * ( 1.0f - x0f ) * ( 1.0f - x0f );
|
|
151
|
+ float x1f = x1 - x1ceil + 1.0f;
|
|
152
|
+ float am = 0.5f * s * x1f * x1f;
|
|
153
|
+ m_a[linestart + x0i] += d * a0;
|
|
154
|
+ if ( x1i == x0i + 2 )
|
|
155
|
+ m_a[linestart + ( x0i + 1 )] += d * ( 1.0f - a0 - am );
|
|
156
|
+ else
|
|
157
|
+ {
|
|
158
|
+ float a1 = s * ( 1.5f - x0f );
|
|
159
|
+ m_a[linestart + ( x0i + 1 )] += d * ( a1 - a0 );
|
|
160
|
+ for ( int xi = x0i + 2; xi < x1i - 1; xi++ )
|
|
161
|
+ m_a[linestart + xi] += d * s;
|
|
162
|
+ float a2 = a1 + ( x1i - x0i - 3 ) * s;
|
|
163
|
+ m_a[linestart + ( x1i - 1 )] += d * ( 1.0f - a2 - am );
|
|
164
|
+ }
|
|
165
|
+ m_a[linestart + x1i] += d * am;
|
|
166
|
+ }
|
|
167
|
+ x = xnext;
|
|
168
|
+ }
|
|
169
|
+}
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+static int
|
|
173
|
+dense_conic_to( const FT_Vector* control,
|
|
174
|
+ const FT_Vector* to,
|
|
175
|
+ dense_worker* worker )
|
|
176
|
+{
|
|
177
|
+ dense_render_quadratic( worker, control, to );
|
|
178
|
+ return 0;
|
|
179
|
+}
|
|
180
|
+
|
|
181
|
+void
|
|
182
|
+dense_render_quadratic( dense_worker* worker,
|
|
183
|
+ FT_Vector* control,
|
|
184
|
+ FT_Vector* to )
|
|
185
|
+{
|
|
186
|
+ /*
|
|
187
|
+ Calculate devsq as the square of four times the
|
|
188
|
+ distance from the control point to the midpoint of the curve.
|
|
189
|
+ This is the place at which the curve is furthest from the
|
|
190
|
+ line joining the control points.
|
|
191
|
+
|
|
192
|
+ 4 x point on curve = p0 + 2p1 + p2
|
|
193
|
+ 4 x midpoint = 4p1
|
|
194
|
+
|
|
195
|
+ The division by four is omitted to save time.
|
|
196
|
+ */
|
|
197
|
+
|
|
198
|
+ FT_Vector aP0 = { DOWNSCALE( worker->prev_x ), DOWNSCALE( worker->prev_y ) };
|
|
199
|
+ FT_Vector aP1 = { control->x, control->y };
|
|
200
|
+ FT_Vector aP2 = { to->x, to->y };
|
|
201
|
+
|
|
202
|
+ float devx = aP0.x - aP1.x - aP1.x + aP2.x;
|
|
203
|
+ float devy = aP0.y - aP1.y - aP1.y + aP2.y;
|
|
204
|
+ float devsq = devx * devx + devy * devy;
|
|
205
|
+
|
|
206
|
+ if ( devsq < 0.333f )
|
|
207
|
+ {
|
|
208
|
+ dense_line_to( &aP2, worker );
|
|
209
|
+ return;
|
|
210
|
+ }
|
|
211
|
+
|
|
212
|
+ /*
|
|
213
|
+ According to Raph Levien, the reason for the subdivision by n (instead of
|
|
214
|
+ recursive division by the Casteljau system) is that "I expect the flatness
|
|
215
|
+ computation to be semi-expensive (it's done once rather than on each potential
|
|
216
|
+ subdivision) and also because you'll often get fewer subdivisions. Taking a
|
|
217
|
+ circular arc as a simplifying assumption, where I get n, a recursive approach
|
|
218
|
+ would get 2^ceil(lg n), which, if I haven't made any horrible mistakes, is
|
|
219
|
+ expected to be 33% more in the limit".
|
|
220
|
+ */
|
|
221
|
+
|
|
222
|
+ const float tol = 3.0f;
|
|
223
|
+ int n = (int)floor( sqrt( sqrt( tol * devsq ) ) )/8;
|
|
224
|
+ FT_Vector p = aP0;
|
|
225
|
+ float nrecip = 1.0f / ( n + 1.0f );
|
|
226
|
+ float t = 0.0f;
|
|
227
|
+ for ( int i = 0; i < n; i++ )
|
|
228
|
+ {
|
|
229
|
+ t += nrecip;
|
|
230
|
+ FT_Vector next = Lerp( t, Lerp( t, aP0, aP1 ), Lerp( t, aP1, aP2 ) );
|
|
231
|
+ dense_line_to(&next, worker );
|
|
232
|
+ p = next;
|
|
233
|
+ }
|
|
234
|
+
|
|
235
|
+ dense_line_to( &aP2, worker );
|
|
236
|
+}
|
|
237
|
+
|
|
238
|
+static int
|
|
239
|
+dense_cubic_to( const FT_Vector* control1,
|
|
240
|
+ const FT_Vector* control2,
|
|
241
|
+ const FT_Vector* to,
|
|
242
|
+ dense_worker* worker )
|
|
243
|
+{
|
|
244
|
+ dense_render_cubic( worker, control1, control2, to );
|
|
245
|
+ return 0;
|
|
246
|
+}
|
|
247
|
+
|
|
248
|
+void
|
|
249
|
+dense_render_cubic( dense_worker* worker,
|
|
250
|
+ FT_Vector* control_1,
|
|
251
|
+ FT_Vector* control_2,
|
|
252
|
+ FT_Vector* to )
|
|
253
|
+{
|
|
254
|
+ FT_Vector aP0 = { DOWNSCALE( worker->prev_x ), DOWNSCALE( worker->prev_y ) };
|
|
255
|
+ FT_Vector aP1 = { control_1->x, control_1->y };
|
|
256
|
+ FT_Vector aP2 = { control_2->x, control_2->y };
|
|
257
|
+ FT_Vector aP3 = { to->x, to->y };
|
|
258
|
+
|
|
259
|
+ float devx = aP0.x - aP1->x - aP1->x + aP2->x;
|
|
260
|
+ float devy = aP0.y - aP1->y - aP1->y + aP2->y;
|
|
261
|
+ float devsq0 = devx * devx + devy * devy;
|
|
262
|
+ devx = aP1->x - aP2->x - aP2->x + aP3->x;
|
|
263
|
+ devy = aP1->y - aP2->y - aP2->y + aP3->y;
|
|
264
|
+ float devsq1 = devx * devx + devy * devy;
|
|
265
|
+ float devsq = fmax( devsq0, devsq1 );
|
|
266
|
+
|
|
267
|
+ if ( devsq < 0.333f )
|
|
268
|
+ {
|
|
269
|
+ dense_render_line( worker, aP3->x, aP3->y );
|
|
270
|
+ return;
|
|
271
|
+ }
|
|
272
|
+
|
|
273
|
+ const float tol = 3.0f;
|
|
274
|
+ int n = (int)floor( sqrt( sqrt( tol * devsq ) ) ) / 8;
|
|
275
|
+ FT_Vector p = aP0;
|
|
276
|
+ float nrecip = 1.0f / ( n + 1.0f );
|
|
277
|
+ float t = 0.0f;
|
|
278
|
+ for ( int i = 0; i < n; i++ )
|
|
279
|
+ {
|
|
280
|
+ t += nrecip;
|
|
281
|
+ FT_Vector a = Lerp( t, Lerp( t, aP0, *aP1 ), Lerp( t, *aP1, *aP2 ) );
|
|
282
|
+ FT_Vector b = Lerp( t, Lerp( t, *aP1, *aP2 ), Lerp( t, *aP2, *aP3 ) );
|
|
283
|
+ FT_Vector next = Lerp( t, a, b );
|
|
284
|
+ dense_render_line( worker, next.x, next.y );
|
|
285
|
+ worker->prev_x = next.x;
|
|
286
|
+ worker->prev_y = next.y;
|
|
287
|
+ p = next;
|
|
288
|
+ }
|
|
289
|
+
|
|
290
|
+ dense_line_to( &aP3, worker );
|
|
291
|
+}
|
|
292
|
+
|
|
293
|
+static int
|
|
294
|
+dense_raster_new( FT_Memory memory, dense_PRaster* araster )
|
|
295
|
+{
|
|
296
|
+ FT_Error error;
|
|
297
|
+ dense_PRaster raster;
|
|
298
|
+
|
|
299
|
+ if ( !FT_NEW( raster ) )
|
|
300
|
+ raster->memory = memory;
|
|
301
|
+
|
|
302
|
+ *araster = raster;
|
|
303
|
+ return error;
|
|
304
|
+}
|
|
305
|
+
|
|
306
|
+static void
|
|
307
|
+dense_raster_done( FT_Raster raster )
|
|
308
|
+{
|
|
309
|
+ FT_Memory memory = (FT_Memory)( (dense_PRaster)raster )->memory;
|
|
310
|
+
|
|
311
|
+ FT_FREE( raster );
|
|
312
|
+}
|
|
313
|
+
|
|
314
|
+static void
|
|
315
|
+dense_raster_reset( FT_Raster raster,
|
|
316
|
+ unsigned char* pool_base,
|
|
317
|
+ unsigned long pool_size )
|
|
318
|
+{
|
|
319
|
+ FT_UNUSED( raster );
|
|
320
|
+ FT_UNUSED( pool_base );
|
|
321
|
+ FT_UNUSED( pool_size );
|
|
322
|
+}
|
|
323
|
+
|
|
324
|
+static int
|
|
325
|
+dense_raster_set_mode( FT_Raster raster, unsigned long mode, void* args )
|
|
326
|
+{
|
|
327
|
+ FT_UNUSED( raster );
|
|
328
|
+ FT_UNUSED( mode );
|
|
329
|
+ FT_UNUSED( args );
|
|
330
|
+
|
|
331
|
+ return 0; /* nothing to do */
|
|
332
|
+}
|
|
333
|
+
|
|
334
|
+FT_DEFINE_OUTLINE_FUNCS( dense_decompose_funcs,
|
|
335
|
+
|
|
336
|
+ (FT_Outline_MoveTo_Func)dense_move_to, /* move_to */
|
|
337
|
+ (FT_Outline_LineTo_Func)dense_line_to, /* line_to */
|
|
338
|
+ (FT_Outline_ConicTo_Func)dense_conic_to, /* conic_to */
|
|
339
|
+ (FT_Outline_CubicTo_Func)dense_cubic_to, /* cubic_to */
|
|
340
|
+
|
|
341
|
+ 0, /* shift */
|
|
342
|
+ 0 /* delta */
|
|
343
|
+)
|
|
344
|
+
|
|
345
|
+static int
|
|
346
|
+dense_render_glyph( dense_worker* worker, const FT_Bitmap* target )
|
|
347
|
+{
|
|
348
|
+ FT_Error error = FT_Outline_Decompose( &( worker->outline ),
|
|
349
|
+ &dense_decompose_funcs, worker );
|
|
350
|
+ // Render into bitmap
|
|
351
|
+ const float* source = worker->m_a;
|
|
352
|
+
|
|
353
|
+ unsigned char* dest = target->buffer;
|
|
354
|
+ unsigned char* dest_end = target->buffer + worker->m_w * worker->m_h;
|
|
355
|
+ float value = 0.0f;
|
|
356
|
+ while ( dest < dest_end )
|
|
357
|
+ {
|
|
358
|
+ value += *source++;
|
|
359
|
+ if ( value > 0.0f )
|
|
360
|
+ {
|
|
361
|
+ int n = (int)( fabs( value ) * 255.0f + 0.5f );
|
|
362
|
+ if ( n > 255 )
|
|
363
|
+ n = 255;
|
|
364
|
+ *dest = (unsigned char)n;
|
|
365
|
+ }
|
|
366
|
+ else
|
|
367
|
+ *dest = 0;
|
|
368
|
+ dest++;
|
|
369
|
+ }
|
|
370
|
+
|
|
371
|
+ free(worker->m_a);
|
|
372
|
+ return error;
|
|
373
|
+}
|
|
374
|
+
|
|
375
|
+static int
|
|
376
|
+dense_raster_render( FT_Raster raster, const FT_Raster_Params* params )
|
|
377
|
+{
|
|
378
|
+ const FT_Outline* outline = (const FT_Outline*)params->source;
|
|
379
|
+ FT_Bitmap* target_map = params->target;
|
|
380
|
+
|
|
381
|
+ dense_worker worker[1];
|
|
382
|
+
|
|
383
|
+ if ( !raster )
|
|
384
|
+ return FT_THROW( Invalid_Argument );
|
|
385
|
+
|
|
386
|
+ if ( !outline )
|
|
387
|
+ return FT_THROW( Invalid_Outline );
|
|
388
|
+
|
|
389
|
+ worker->outline = *outline;
|
|
390
|
+
|
|
391
|
+ if ( !target_map )
|
|
392
|
+ return FT_THROW( Invalid_Argument );
|
|
393
|
+
|
|
394
|
+ /* nothing to do */
|
|
395
|
+ if ( !target_map->width || !target_map->rows )
|
|
396
|
+ return 0;
|
|
397
|
+
|
|
398
|
+ if ( !target_map->buffer )
|
|
399
|
+ return FT_THROW( Invalid_Argument );
|
|
400
|
+
|
|
401
|
+ worker->m_origin_x = 0;
|
|
402
|
+ worker->m_origin_y = 0;
|
|
403
|
+ worker->m_w = target_map->pitch;
|
|
404
|
+ worker->m_h = target_map->rows;
|
|
405
|
+
|
|
406
|
+ int size = worker->m_w * worker->m_h + 4;
|
|
407
|
+
|
|
408
|
+ worker->m_a = malloc( sizeof( float ) * size );
|
|
409
|
+ worker->m_a_size = size;
|
|
410
|
+
|
|
411
|
+ memset( worker->m_a, 0, ( sizeof( float ) * size ) );
|
|
412
|
+ /* exit if nothing to do */
|
|
413
|
+ if ( worker->m_w <= worker->m_origin_x || worker->m_h <= worker->m_origin_y )
|
|
414
|
+ {
|
|
415
|
+ return 0;
|
|
416
|
+ }
|
|
417
|
+
|
|
418
|
+ // Invert the pitch to account for different +ve y-axis direction in dense array
|
|
419
|
+ // (maybe temporary solution)
|
|
420
|
+ target_map->pitch *= -1;
|
|
421
|
+ return dense_render_glyph( worker, target_map );
|
|
422
|
+}
|
|
423
|
+
|
|
424
|
+FT_DEFINE_RASTER_FUNCS(
|
|
425
|
+ ft_dense_raster,
|
|
426
|
+
|
|
427
|
+ FT_GLYPH_FORMAT_OUTLINE,
|
|
428
|
+
|
|
429
|
+ (FT_Raster_New_Func)dense_raster_new, /* raster_new */
|
|
430
|
+ (FT_Raster_Reset_Func)dense_raster_reset, /* raster_reset */
|
|
431
|
+ (FT_Raster_Set_Mode_Func)dense_raster_set_mode, /* raster_set_mode */
|
|
432
|
+ (FT_Raster_Render_Func)dense_raster_render, /* raster_render */
|
|
433
|
+ (FT_Raster_Done_Func)dense_raster_done /* raster_done */
|
|
434
|
+)
|
|
435
|
+
|
|
436
|
+/* END */ |