1
- // stb_truetype.h - v1.25 - public domain
1
+ // stb_truetype.h - v1.26 - public domain
2
2
// authored from 2009-2021 by Sean Barrett / RAD Game Tools
3
3
//
4
4
// =======================================================================
58
58
//
59
59
// VERSION HISTORY
60
60
//
61
+ // 1.26 (2021-08-28) fix broken rasterizer
61
62
// 1.25 (2021-07-11) many fixes
62
63
// 1.24 (2020-02-05) fix warning
63
64
// 1.23 (2020-02-02) query SVG data for glyphs; query whole kerning table (but only kern not GPOS)
@@ -3061,6 +3062,23 @@ static void stbtt__handle_clipped_edge(float *scanline, int x, stbtt__active_edg
3061
3062
}
3062
3063
}
3063
3064
3065
+ static float stbtt__sized_trapezoid_area (float height , float top_width , float bottom_width )
3066
+ {
3067
+ STBTT_assert (top_width >= 0 );
3068
+ STBTT_assert (bottom_width >= 0 );
3069
+ return (top_width + bottom_width ) / 2.0f * height ;
3070
+ }
3071
+
3072
+ static float stbtt__position_trapezoid_area (float height , float tx0 , float tx1 , float bx0 , float bx1 )
3073
+ {
3074
+ return stbtt__sized_trapezoid_area (height , tx1 - tx0 , bx1 - bx0 );
3075
+ }
3076
+
3077
+ static float stbtt__sized_triangle_area (float height , float width )
3078
+ {
3079
+ return height * width / 2 ;
3080
+ }
3081
+
3064
3082
static void stbtt__fill_active_edges_new (float * scanline , float * scanline_fill , int len , stbtt__active_edge * e , float y_top )
3065
3083
{
3066
3084
float y_bottom = y_top + 1 ;
@@ -3115,10 +3133,10 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
3115
3133
float height ;
3116
3134
// simple case, only spans one pixel
3117
3135
int x = (int ) x_top ;
3118
- height = sy1 - sy0 ;
3136
+ height = ( sy1 - sy0 ) * e -> direction ;
3119
3137
STBTT_assert (x >= 0 && x < len );
3120
- scanline [x ] += e -> direction * ( 1 - (( x_top - x ) + ( x_bottom - x ))/ 2 ) * height ;
3121
- scanline_fill [x ] += e -> direction * height ; // everything right of this pixel is filled
3138
+ scanline [x ] += stbtt__position_trapezoid_area ( height , x_top , x + 1.0f , x_bottom , x + 1.0f ) ;
3139
+ scanline_fill [x ] += height ; // everything right of this pixel is filled
3122
3140
} else {
3123
3141
int x ,x1 ,x2 ;
3124
3142
float y_crossing , y_final , step , sign , area ;
@@ -3134,47 +3152,89 @@ static void stbtt__fill_active_edges_new(float *scanline, float *scanline_fill,
3134
3152
dy = - dy ;
3135
3153
t = x0 , x0 = xb , xb = t ;
3136
3154
}
3137
- assert (dy >= 0 );
3138
- assert (dx >= 0 );
3155
+ STBTT_assert (dy >= 0 );
3156
+ STBTT_assert (dx >= 0 );
3139
3157
3140
3158
x1 = (int ) x_top ;
3141
3159
x2 = (int ) x_bottom ;
3142
3160
// compute intersection with y axis at x1+1
3143
- y_crossing = (x1 + 1 - x0 ) * dy + y_top ;
3161
+ y_crossing = y_top + dy * (x1 + 1 - x0 );
3162
+
3163
+ // compute intersection with y axis at x2
3164
+ y_final = y_top + dy * (x2 - x0 );
3165
+
3166
+ // x1 x_top x2 x_bottom
3167
+ // y_top +------|-----+------------+------------+--------|---+------------+
3168
+ // | | | | | |
3169
+ // | | | | | |
3170
+ // sy0 | Txxxxx|............|............|............|............|
3171
+ // y_crossing | *xxxxx.......|............|............|............|
3172
+ // | | xxxxx..|............|............|............|
3173
+ // | | /- xx*xxxx........|............|............|
3174
+ // | | dy < | xxxxxx..|............|............|
3175
+ // y_final | | \- | xx*xxx.........|............|
3176
+ // sy1 | | | | xxxxxB...|............|
3177
+ // | | | | | |
3178
+ // | | | | | |
3179
+ // y_bottom +------------+------------+------------+------------+------------+
3180
+ //
3181
+ // goal is to measure the area covered by '.' in each pixel
3182
+
3144
3183
// if x2 is right at the right edge of x1, y_crossing can blow up, github #1057
3184
+ // @TODO: maybe test against sy1 rather than y_bottom?
3145
3185
if (y_crossing > y_bottom )
3146
3186
y_crossing = y_bottom ;
3147
3187
3148
3188
sign = e -> direction ;
3149
- // area of the rectangle covered from y0..y_crossing
3189
+
3190
+ // area of the rectangle covered from sy0..y_crossing
3150
3191
area = sign * (y_crossing - sy0 );
3151
- // area of the triangle (x_top,y0), (x+1,y0), (x+1,y_crossing)
3152
- scanline [x1 ] += area * (x1 + 1 - x_top )/2 ;
3192
+
3193
+ // area of the triangle (x_top,sy0), (x1+1,sy0), (x1+1,y_crossing)
3194
+ scanline [x1 ] += stbtt__sized_triangle_area (area , x1 + 1 - x_top );
3153
3195
3154
3196
// check if final y_crossing is blown up; no test case for this
3155
- y_final = y_crossing + dy * (x2 - (x1 + 1 )); // advance y by number of steps taken below
3156
3197
if (y_final > y_bottom ) {
3157
3198
y_final = y_bottom ;
3158
3199
dy = (y_final - y_crossing ) / (x2 - (x1 + 1 )); // if denom=0, y_final = y_crossing, so y_final <= y_bottom
3159
3200
}
3160
3201
3161
- step = sign * dy * 1 ; // dy is dy/dx, change in y for every 1 change in x, which is also how much pixel area changes for each step in x
3202
+ // in second pixel, area covered by line segment found in first pixel
3203
+ // is always a rectangle 1 wide * the height of that line segment; this
3204
+ // is exactly what the variable 'area' stores. it also gets a contribution
3205
+ // from the line segment within it. the THIRD pixel will get the first
3206
+ // pixel's rectangle contribution, the second pixel's rectangle contribution,
3207
+ // and its own contribution. the 'own contribution' is the same in every pixel except
3208
+ // the leftmost and rightmost, a trapezoid that slides down in each pixel.
3209
+ // the second pixel's contribution to the third pixel will be the
3210
+ // rectangle 1 wide times the height change in the second pixel, which is dy.
3211
+
3212
+ step = sign * dy * 1 ; // dy is dy/dx, change in y for every 1 change in x,
3213
+ // which multiplied by 1-pixel-width is how much pixel area changes for each step in x
3214
+ // so the area advances by 'step' every time
3215
+
3162
3216
for (x = x1 + 1 ; x < x2 ; ++ x ) {
3163
- scanline [x ] += area + step /2 ; // area of parallelogram is step/2
3217
+ scanline [x ] += area + step /2 ; // area of trapezoid is 1* step/2
3164
3218
area += step ;
3165
3219
}
3166
3220
STBTT_assert (STBTT_fabs (area ) <= 1.01f ); // accumulated error from area += step unless we round step down
3221
+ STBTT_assert (sy1 > y_final - 0.01f );
3167
3222
3168
- // area of the triangle (x2,y_crossing), (x_bottom,y1), (x2,y1)
3169
- scanline [x2 ] += area + sign * (x_bottom - x2 )/2 * (sy1 - y_crossing );
3223
+ // area covered in the last pixel is the rectangle from all the pixels to the left,
3224
+ // plus the trapezoid filled by the line segment in this pixel all the way to the right edge
3225
+ scanline [x2 ] += area + sign * stbtt__position_trapezoid_area (sy1 - y_final , (float ) x2 , x2 + 1.0f , x_bottom , x2 + 1.0f );
3170
3226
3227
+ // the rest of the line is filled based on the total height of the line segment in this pixel
3171
3228
scanline_fill [x2 ] += sign * (sy1 - sy0 );
3172
3229
}
3173
3230
} else {
3174
3231
// if edge goes outside of box we're drawing, we require
3175
3232
// clipping logic. since this does not match the intended use
3176
3233
// of this library, we use a different, very slow brute
3177
3234
// force implementation
3235
+ // note though that this does happen some of the time because
3236
+ // x_top and x_bottom can be extrapolated at the top & bottom of
3237
+ // the shape and actually lie outside the bounding box
3178
3238
int x ;
3179
3239
for (x = 0 ; x < len ; ++ x ) {
3180
3240
// cases:
0 commit comments