freetype-commit
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Git][freetype/freetype][gsoc-anurag-2022-final] 2 commits: [dense] Add


From: Anurag Thakur (@AdbhutDev)
Subject: [Git][freetype/freetype][gsoc-anurag-2022-final] 2 commits: [dense] Add rasterizer functions
Date: Sat, 19 Nov 2022 05:14:57 +0000

Anurag Thakur pushed to branch gsoc-anurag-2022-final at FreeType / FreeType

Commits:

  • f126946b
    by Anurag Thakur at 2022-11-19T10:28:46+05:30
    [dense] Add rasterizer functions
    
    * src/dense/ftdense.c: (ONE_PIXEL, TRUNC, UPSCALE, DOWNSCALE,
    FT_SWAP, FT_MIN, FT_MAX, FT_ABS): New Macros
    
    (dense_move_to, dense_line_to, dense_conic_to): Added outline
    decomposing functions
    
    (dense_raster_new, dense_raster_done, dense_raster_reset,
    dense_raster_set_mode, dense_raster_render): Added interface
    functions
    
  • f1c10659
    by Anurag Thakur at 2022-11-19T10:42:07+05:30
    [dense] Add drawing functions to rasterizer
    
    * src/dense/ftdense.c: (dense_render_line, dense_render_quadratic,
    dense_render_cubic, dense_render_glyph, dense_raster_render): New
    Functions
    

1 changed file:

Changes:

  • src/dense/ftdense.c
    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 */


  • reply via email to

    [Prev in Thread] Current Thread [Next in Thread]