📄 ftgrays.c
字号:
p = fx1 * ( y2 - y1 ); first = 0; incr = -1; dx = -dx; } delta = p / dx; mod = p % dx; if ( mod < 0 ) { delta--; mod += dx; } ras.area += ( fx1 + first ) * delta; ras.cover += delta; ex1 += incr; if ( set_cell( RAS_VAR_ ex1, ey ) ) goto Error; y1 += delta; if ( ex1 != ex2 ) { p = ONE_PIXEL * ( y2 - y1 ); lift = p / dx; rem = p % dx; if ( rem < 0 ) { lift--; rem += dx; } mod -= dx; while ( ex1 != ex2 ) { delta = lift; mod += rem; if ( mod >= 0 ) { mod -= dx; delta++; } ras.area += ONE_PIXEL * delta; ras.cover += delta; y1 += delta; ex1 += incr; if ( set_cell( RAS_VAR_ ex1, ey ) ) goto Error; } } delta = y2 - y1; ras.area += ( fx2 + ONE_PIXEL - first ) * delta; ras.cover += delta; return 0; Error: return 1; } /*************************************************************************/ /* */ /* Render a given line as a series of scanlines. */ /* */ static int render_line( RAS_ARG_ TPos to_x, TPos to_y ) { TScan ey1, ey2, fy1, fy2; TPos dx, dy, x, x2; int p, rem, mod, lift, delta, first, incr; ey1 = TRUNC( ras.last_ey ); ey2 = TRUNC( to_y ); /* if (ey2 >= ras.max_ey) ey2 = ras.max_ey-1; */ fy1 = ras.y - ras.last_ey; fy2 = to_y - SUBPIXELS( ey2 ); dx = to_x - ras.x; dy = to_y - ras.y; /* XXX: we should do something about the trivial case where dx == 0, */ /* as it happens very often! */ /* perform vertical clipping */ { TScan min, max; min = ey1; max = ey2; if ( ey1 > ey2 ) { min = ey2; max = ey1; } if ( min >= ras.max_ey || max < ras.min_ey ) goto End; } /* everything is on a single scanline */ if ( ey1 == ey2 ) { if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, to_x, fy2 ) ) goto Error; goto End; } /* ok, we have to render several scanlines */ p = ( ONE_PIXEL - fy1 ) * dx; first = ONE_PIXEL; incr = 1; if ( dy < 0 ) { p = fy1 * dx; first = 0; incr = -1; dy = -dy; } delta = p / dy; mod = p % dy; if ( mod < 0 ) { delta--; mod += dy; } x = ras.x + delta; if ( render_scanline( RAS_VAR_ ey1, ras.x, fy1, x, first ) ) goto Error; ey1 += incr; if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) ) goto Error; if ( ey1 != ey2 ) { p = ONE_PIXEL * dx; lift = p / dy; rem = p % dy; if ( rem < 0 ) { lift--; rem += dy; } mod -= dy; while ( ey1 != ey2 ) { delta = lift; mod += rem; if ( mod >= 0 ) { mod -= dy; delta++; } x2 = x + delta; if ( render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, x2, first ) ) goto Error; x = x2; ey1 += incr; if ( set_cell( RAS_VAR_ TRUNC( x ), ey1 ) ) goto Error; } } if ( render_scanline( RAS_VAR_ ey1, x, ONE_PIXEL - first, to_x, fy2 ) ) goto Error; End: ras.x = to_x; ras.y = to_y; ras.last_ey = SUBPIXELS( ey2 ); return 0; Error: return 1; } static void split_conic( FT_Vector* base ) { TPos a, b; base[4].x = base[2].x; b = base[1].x; a = base[3].x = ( base[2].x + b ) / 2; b = base[1].x = ( base[0].x + b ) / 2; base[2].x = ( a + b ) / 2; base[4].y = base[2].y; b = base[1].y; a = base[3].y = ( base[2].y + b ) / 2; b = base[1].y = ( base[0].y + b ) / 2; base[2].y = ( a + b ) / 2; } static int render_conic( RAS_ARG_ FT_Vector* control, FT_Vector* to ) { TPos dx, dy; int top, level; int* levels; FT_Vector* arc; dx = DOWNSCALE( ras.x ) + to->x - ( control->x << 1 ); if ( dx < 0 ) dx = -dx; dy = DOWNSCALE( ras.y ) + to->y - ( control->y << 1 ); if ( dy < 0 ) dy = -dy; if ( dx < dy ) dx = dy; level = 1; dx = dx / ras.conic_level; while ( dx > 0 ) { dx >>= 2; level++; } /* a shortcut to speed things up */ if ( level <= 1 ) { /* we compute the mid-point directly in order to avoid */ /* calling split_conic() */ TPos to_x, to_y, mid_x, mid_y; to_x = UPSCALE( to->x ); to_y = UPSCALE( to->y ); mid_x = ( ras.x + to_x + 2 * UPSCALE( control->x ) ) / 4; mid_y = ( ras.y + to_y + 2 * UPSCALE( control->y ) ) / 4; return render_line( RAS_VAR_ mid_x, mid_y ) || render_line( RAS_VAR_ to_x, to_y ); } arc = ras.bez_stack; levels = ras.lev_stack; top = 0; levels[0] = level; arc[0].x = UPSCALE( to->x ); arc[0].y = UPSCALE( to->y ); arc[1].x = UPSCALE( control->x ); arc[1].y = UPSCALE( control->y ); arc[2].x = ras.x; arc[2].y = ras.y; while ( top >= 0 ) { level = levels[top]; if ( level > 1 ) { /* check that the arc crosses the current band */ TPos min, max, y; min = max = arc[0].y; y = arc[1].y; if ( y < min ) min = y; if ( y > max ) max = y; y = arc[2].y; if ( y < min ) min = y; if ( y > max ) max = y; if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) goto Draw; split_conic( arc ); arc += 2; top++; levels[top] = levels[top - 1] = level - 1; continue; } Draw: { TPos to_x, to_y, mid_x, mid_y; to_x = arc[0].x; to_y = arc[0].y; mid_x = ( ras.x + to_x + 2 * arc[1].x ) / 4; mid_y = ( ras.y + to_y + 2 * arc[1].y ) / 4; if ( render_line( RAS_VAR_ mid_x, mid_y ) || render_line( RAS_VAR_ to_x, to_y ) ) return 1; top--; arc -= 2; } } return 0; } static void split_cubic( FT_Vector* base ) { TPos a, b, c, d; base[6].x = base[3].x; c = base[1].x; d = base[2].x; base[1].x = a = ( base[0].x + c ) / 2; base[5].x = b = ( base[3].x + d ) / 2; c = ( c + d ) / 2; base[2].x = a = ( a + c ) / 2; base[4].x = b = ( b + c ) / 2; base[3].x = ( a + b ) / 2; base[6].y = base[3].y; c = base[1].y; d = base[2].y; base[1].y = a = ( base[0].y + c ) / 2; base[5].y = b = ( base[3].y + d ) / 2; c = ( c + d ) / 2; base[2].y = a = ( a + c ) / 2; base[4].y = b = ( b + c ) / 2; base[3].y = ( a + b ) / 2; } static int render_cubic( RAS_ARG_ FT_Vector* control1, FT_Vector* control2, FT_Vector* to ) { TPos dx, dy, da, db; int top, level; int* levels; FT_Vector* arc; dx = DOWNSCALE( ras.x ) + to->x - ( control1->x << 1 ); if ( dx < 0 ) dx = -dx; dy = DOWNSCALE( ras.y ) + to->y - ( control1->y << 1 ); if ( dy < 0 ) dy = -dy; if ( dx < dy ) dx = dy; da = dx; dx = DOWNSCALE( ras.x ) + to->x - 3 * ( control1->x + control2->x ); if ( dx < 0 ) dx = -dx; dy = DOWNSCALE( ras.y ) + to->y - 3 * ( control1->x + control2->y ); if ( dy < 0 ) dy = -dy; if ( dx < dy ) dx = dy; db = dx; level = 1; da = da / ras.cubic_level; db = db / ras.conic_level; while ( da > 0 || db > 0 ) { da >>= 2; db >>= 3; level++; } if ( level <= 1 ) { TPos to_x, to_y, mid_x, mid_y; to_x = UPSCALE( to->x ); to_y = UPSCALE( to->y ); mid_x = ( ras.x + to_x + 3 * UPSCALE( control1->x + control2->x ) ) / 8; mid_y = ( ras.y + to_y + 3 * UPSCALE( control1->y + control2->y ) ) / 8; return render_line( RAS_VAR_ mid_x, mid_y ) || render_line( RAS_VAR_ to_x, to_y ); } arc = ras.bez_stack; arc[0].x = UPSCALE( to->x ); arc[0].y = UPSCALE( to->y ); arc[1].x = UPSCALE( control2->x ); arc[1].y = UPSCALE( control2->y ); arc[2].x = UPSCALE( control1->x ); arc[2].y = UPSCALE( control1->y ); arc[3].x = ras.x; arc[3].y = ras.y; levels = ras.lev_stack; top = 0; levels[0] = level; while ( top >= 0 ) { level = levels[top]; if ( level > 1 ) { /* check that the arc crosses the current band */ TPos min, max, y; min = max = arc[0].y; y = arc[1].y; if ( y < min ) min = y; if ( y > max ) max = y; y = arc[2].y; if ( y < min ) min = y; if ( y > max ) max = y; y = arc[3].y; if ( y < min ) min = y; if ( y > max ) max = y; if ( TRUNC( min ) >= ras.max_ey || TRUNC( max ) < 0 ) goto Draw; split_cubic( arc ); arc += 3; top ++; levels[top] = levels[top - 1] = level - 1; continue; } Draw: { TPos to_x, to_y, mid_x, mid_y; to_x = arc[0].x; to_y = arc[0].y; mid_x = ( ras.x + to_x + 3 * ( arc[1].x + arc[2].x ) ) / 8; mid_y = ( ras.y + to_y + 3 * ( arc[1].y + arc[2].y ) ) / 8; if ( render_line( RAS_VAR_ mid_x, mid_y ) || render_line( RAS_VAR_ to_x, to_y ) ) return 1; top --; arc -= 3; } } return 0; } /* a macro comparing two cell pointers. Returns true if a <= b. */#if 1#define PACK( a ) ( ( (long)(a)->y << 16 ) + (a)->x )#define LESS_THAN( a, b ) ( PACK( a ) < PACK( b ) )#else /* 1 */#define LESS_THAN( a, b ) ( (a)->y < (b)->y || \ ( (a)->y == (b)->y && (a)->x < (b)->x ) )#endif /* 1 */#define SWAP_CELLS( a, b, temp ) do \ { \ temp = *(a); \ *(a) = *(b); \ *(b) = temp; \ } while ( 0 )#define DEBUG_SORT#define QUICK_SORT#ifdef SHELL_SORT /* a simple shell sort algorithm that works directly on our */ /* cells table */ static void shell_sort ( PCell cells,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -