Unit TTRASTER;
interface
uses
Use32,
FreeType,
TTTypes;
const
Err_Ras_None = 0;
Err_Ras_NotIni = -2;
Err_Ras_Overflow = -3;
Err_Ras_Neg_H = -4;
Err_Ras_Invalid = -5;
Err_Ras_Invalid_Contours = -6;
function Render_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError;
function Render_Gray_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError;
function Render_Smooth_Glyph( var glyph : TGlyphRecord;
target : PRasterBlock;
scan : Byte;
palette : pointer ) : boolean;
procedure Set_High_Precision( High : boolean );
procedure Set_Second_Pass( Pass : boolean );
function TTRaster_Init : TError;
procedure TTRaster_Done;
implementation
uses
TTCalc,
TTError
,GMain
;
const
Render_Pool_Size = 64000;
Gray_Lines_Size = 2048;
MaxBezier = 32;
Pixel_Bits = 6;
Cell_Bits = 8;
type
TEtats = ( Indetermine, Ascendant, Descendant, Plat );
PProfile = ^TProfile;
TProfile = record
Flow : Int;
Height : Int;
Start : Int;
Offset : ULong;
Link : PProfile;
X : Longint;
CountL : Int;
next : PProfile;
end;
TBand = record
Y_Min : Int;
Y_Max : Int;
end;
const
AlignProfileSize = ( sizeOf(TProfile) + 3 ) div 4;
LMask : array[0..7] of Byte
= ($FF,$7F,$3F,$1F,$0F,$07,$03,$01);
RMask : array[0..7] of Byte
= ($80,$C0,$E0,$F0,$F8,$FC,$FE,$FF);
type
Function_Sweep_Init = procedure( var min, max : Int );
Function_Sweep_Span = procedure( y : Int;
x1 : TT_F26dot6;
x2 : TT_F26dot6;
Left : PProfile;
Right : PProfile );
Function_Sweep_Step = procedure;
TPoint = record x, y : long; end;
TBezierStack = array[0..32*2] of TPoint;
PBezierStack = ^TBezierStack;
var
Precision_Bits : Int;
Precision : Int;
Precision_Half : Int;
Precision_Step : Int;
Precision_Shift : Int;
Precision_Mask : Longint;
Precision_Jitter : Int;
const
Precision_Bits = 6;
Precision = 1 shl Precision_Bits;
Precision_Half = Precision div 2;
Precision_Step = Precision_Half;
Precision_Shift = 0;
Precision_Mask = -Precision;
Precision_Jitter = 2;
var
Scale_Shift : Int;
cProfile : PProfile;
fProfile : PProfile;
oProfile : PProfile;
gProfile : PProfile;
nProfs : Int;
Etat : TEtats;
Fresh : Boolean;
Joint : Boolean;
Buff : PStorage;
SizeBuff : ULong;
MaxBuff : ULong;
profCur : ULong;
Cible : TT_Raster_Map;
BWidth : integer;
BCible : PByte;
GCible : PByte;
TraceOfs : Int;
TraceIncr : Int;
TraceG : Int;
gray_min_x : Int;
gray_max_x : Int;
Proc_Sweep_Init : Function_Sweep_Init;
Proc_Sweep_Span : Function_Sweep_Span;
Proc_Sweep_Drop : Function_Sweep_Span;
Proc_Sweep_Step : Function_Sweep_Step;
Arcs : TBezierStack;
CurArc : Int;
Points : TT_Points;
Flags : PByte;
Outs : TT_PConStarts;
nPoints,
nContours : Int;
LastX,
LastY,
MinY,
MaxY : LongInt;
numTurns : Int;
DropOutControl : Byte;
Count_Table : array[0..255] of Word;
Count_Table2 : array[0..255] of Word;
Grays : array[0..4] of Byte;
Gray_Lines : PByte;
Gray_Width : integer;
Smooth_Cols : integer;
Smooths : array[0..16] of Byte;
smooth_pass : integer;
Second_Pass : boolean;
Band_Stack : array[1..16] of TBand;
Band_Top : Int;
procedure PSet;
var c : byte;
o : Int;
xz : LongInt;
begin
xz := Buff^[profCur] div Precision;
with cProfile^ do
begin
case Flow of
TT_Flow_Up : o := 80 * (profCur-Offset+Start) + xz div 8;
TT_Flow_Down : o := 80 * (Start-profCur+offset) + xz div 8;
end;
if o > 0 then
begin
c := Vio^[o] or ( $80 shr ( xz and 7 ));
Vio^[o] := c;
end
end;
end;
procedure ClearBand( y1, y2 : Int );
var
Y : Int;
K : Word;
begin
K := y1*80;
FillChar( Vio^[k], (y2-y1+1)*80, 0 );
end;
procedure Set_High_Precision( High : boolean );
begin
if High then
begin
Precision_Bits := 10;
Precision_Step := 128;
Precision_Jitter := 24;
end
else
begin
Precision_Bits := 6;
Precision_Step := 32;
Precision_Jitter := 2;
end;
Precision := 1 shl Precision_Bits;
Precision_Half := Precision shr 1;
Precision_Shift := Precision_Bits - Pixel_Bits;
Precision_Mask := -Precision;
end;
procedure Set_Second_Pass( Pass : boolean );
begin
second_pass := pass;
end;
function TRUNC( x : Long ) : Long; inline;
begin
Trunc := (x and -Precision) div Precision;
end;
function FRAC( x : Long ) : Int; inline;
begin
Frac := x and (Precision-1);
end;
function FLOOR( x : Long ) : Long; inline;
begin
Floor := x and -Precision;
end;
function CEILING( x : Long ) : Long; inline;
begin
Ceiling := (x + Precision-1) and -Precision;
end;
function SCALED( x : Long ) : Long; inline;
begin
SCALED := (x shl scale_shift) - precision_half;
end;
function MulDiv( a, b, c : Long ) : Long; inline;
begin
MulDiv := a*b div c;
end;
function New_Profile( AEtat : TEtats ) : boolean;
begin
if fProfile = NIL then
begin
cProfile := PProfile( @Buff^[profCur] );
fProfile := cProfile;
inc( profCur, AlignProfileSize );
end;
if profCur >= MaxBuff then
begin
Error := Err_Ras_Overflow;
New_Profile := False;
exit;
end;
with cProfile^ do
begin
Case AEtat of
Ascendant : Flow := TT_Flow_Up;
Descendant : Flow := TT_Flow_Down;
else
Writeln('ERROR : Incoherent Profile' );
Halt(30);
New_Profile := False;
Error := Err_Ras_Invalid;
exit;
end;
Start := 0;
Height := 0;
Offset := profCur;
Link := nil;
next := nil;
end;
if gProfile = nil then gProfile := cProfile;
Etat := AEtat;
Fresh := True;
Joint := False;
New_Profile := True;
end;
procedure Insert_Y_Turn( y : Int );
var
y_turns : PStorage;
y2, n : Int;
begin
n := numTurns-1;
y_turns := @Buff^[SizeBuff-numTurns];
while (n >= 0) and (y < y_turns^[n]) do dec(n);
if (n >= 0) and (y > y_turns^[n]) then
while (n >= 0) do
begin
y2 := y_turns^[n];
y_turns^[n] := y;
y := y2;
dec( n );
end;
if (n < 0) then
begin
dec( MaxBuff );
inc( numTurns );
Buff^[SizeBuff-numTurns] := y;
end
end;
function End_Profile : boolean;
var
H : Int;
oldProfile : PProfile;
begin
H := profCur - cProfile^.Offset;
if H < 0 then
begin
End_Profile := False;
Error := Err_Ras_Neg_H;
exit;
end;
if H > 0 then
begin
oldProfile := cProfile;
cProfile^.Height := H;
cProfile := PProfile( @Buff^[profCur] );
inc( profCur, AlignProfileSize );
cProfile^.Height := 0;
cProfile^.Offset := profCur;
oldProfile^.next := cProfile;
inc( nProfs );
end;
if profCur >= MaxBuff then
begin
End_Profile := False;
Error := Err_Ras_Overflow;
exit;
end;
Joint := False;
End_Profile := True;
end;
procedure Finalize_Profile_Table;
var
n : int;
p : PProfile;
Bottom, Top : Int;
begin
n := nProfs;
if n > 1 then
begin
P := fProfile;
while n > 0 do with P^ do
begin
if n > 1 then
Link := PProfile( @Buff^[ Offset + Height ] )
else
Link := nil;
with P^ do
Case Flow of
TT_Flow_Up : begin
Bottom := Start;
Top := Start+Height-1;
end;
TT_Flow_Down : begin
Bottom := Start-Height+1;
Top := Start;
Start := Bottom;
Offset := Offset+Height-1;
end;
end;
Insert_Y_Turn( Bottom );
Insert_Y_Turn( Top+1 );
P := Link;
dec( n );
end;
end
else
fProfile := nil;
end;
procedure Split_Bezier( base : PBezierStack );
var
arc : PBezierStack;
a, b : Long;
begin
asm
push esi
push ebx
push ecx
mov esi, base
mov eax, [esi+2*8]
mov ebx, [esi+1*8]
mov ecx, [esi+0*8]
mov [esi+4*8], eax
add eax, ebx
add ebx, ecx
mov edx, eax
mov ecx, ebx
sar edx, 31
sar ecx, 31
sub eax, edx
sub ebx, ecx
sar eax, 1
sar ebx, 1
mov [esi+3*8], eax
mov [esi+1*8], ebx
add eax, ebx
mov edx, eax
sar edx, 31
sub eax, edx
sar eax, 1
mov [esi+2*8], eax
add esi, 4
mov eax, [esi+2*8]
mov ebx, [esi+1*8]
mov ecx, [esi+0*8]
mov [esi+4*8], eax
add eax, ebx
add ebx, ecx
mov edx, eax
mov ecx, ebx
sar edx, 31
sar ecx, 31
sub eax, edx
sub ebx, ecx
sar eax, 1
sar ebx, 1
mov [esi+3*8], eax
mov [esi+1*8], ebx
add eax, ebx
mov edx, eax
sar edx, 31
sub eax, edx
sar eax, 1
mov [esi+2*8], eax
pop ecx
pop ebx
pop esi
end;
arc := base;
arc^[4].x := arc^[2].x;
b := arc^[1].x;
a := (arc^[2].x + b) div 2; arc^[3].x := a;
b := (arc^[0].x + b) div 2; arc^[1].x := b;
arc^[2].x := (a+b) div 2;
arc^[4].y := arc^[2].y;
b := arc^[1].y;
a := (arc^[2].y + b) div 2; arc^[3].y := a;
b := (arc^[0].y + b) div 2; arc^[1].y := b;
arc^[2].y := (a+b) div 2;
end;
procedure PushBezier( x1, y1, x2, y2, x3, y3 : LongInt );
begin
curArc:=0;
with Arcs[CurArc+2] do begin x:=x1; y:=y1; end;
with Arcs[CurArc+1] do begin x:=x2; y:=y2; end;
with Arcs[ CurArc ] do begin x:=x3; y:=y3; end;
end;
function Line_Up( x1, y1, x2, y2, miny, maxy : LongInt ) : boolean;
var
Dx, Dy : LongInt;
e1, e2, f1, f2, size : Int;
Ix, Rx, Ax : LongInt;
top : PStorage;
begin
Line_Up := True;
Dx := x2-x1; Dy := y2-y1;
if (Dy <= 0) or (y2 < MinY) or (y1 > MaxY) then exit;
if y1 < MinY then
begin
x1 := x1 + MulDiv( Dx, MinY-y1, Dy );
e1 := Trunc(MinY);
f1 := 0;
end
else
begin
e1 := Trunc(y1);
f1 := Frac(y1);
end;
if y2 > MaxY then
begin
e2 := Trunc(MaxY);
f2 := 0;
end
else
begin
e2 := Trunc(y2);
f2 := Frac(y2);
end;
if f1 > 0 then
if e1 = e2 then exit
else
begin
inc( x1, MulDiv( Dx, precision-f1, Dy ) );
inc( e1 );
end
else
if Joint then
dec( profCur );
Joint := (f2 = 0);
if Fresh then
begin
cProfile^.Start := e1;
Fresh := False;
end;
size := ( e2-e1 )+1;
if ( profCur + size >= MaxBuff ) then
begin
Line_Up := False;
Error := Err_Ras_Overflow;
exit;
end;
if Dx > 0 then
begin
Ix := (Precision*Dx) div Dy;
Rx := (Precision*Dx) mod Dy;
Dx := 1;
end
else
begin
Ix := -((Precision*-Dx) div Dy);
Rx := (Precision*-Dx) mod Dy;
Dx := -1;
end;
Ax := -Dy;
while size > 0 do
begin
Buff^[profCur] := x1;
Pset;
inc( profCur );
inc( x1, Ix );
inc( ax, rx );
if ax >= 0 then
begin
dec( ax, dy );
inc( x1, dx );
end;
dec( size );
end;
end;
function Line_Down( x1, y1, x2, y2, miny, maxy : LongInt ): boolean;
var
_fresh : Boolean;
begin
_fresh := fresh;
Line_Down := Line_Up( x1, -y1, x2, -y2, -maxy, -miny );
if _fresh and not fresh then
cProfile^.start := -cProfile^.start;
end;
function Bezier_Up( miny, maxy : Long ) : boolean;
var
x1, y1, x2, y2, e, e2, e0 : LongInt;
carc, debArc, f1 : Int;
base : PBezierStack;
label
Fin;
begin
Bezier_Up := True;
carc := curArc;
base := @Arcs[cArc];
y1 := base^[2].y;
y2 := base^[0].y;
if ( y2 < MinY ) or ( y1 > MaxY ) then
goto Fin;
e2 := FLOOR(y2);
if e2 > MaxY then e2 := MaxY;
e0 := MinY;
if y1 < MinY then
e := MinY
else
begin
e := CEILING(y1);
f1 := FRAC(y1);
e0 := e;
if f1 = 0 then
begin
if Joint then begin dec(profCur); Joint:=False; end;
Buff^[profCur] := base^[2].x;
Pset;
inc( profCur );
inc( e, Precision );
end
end;
if Fresh then
begin
cProfile^.Start := TRUNC(e0);
Fresh := False;
end;
if e2 < e then
goto Fin;
if ( profCur + TRUNC(e2-e)+ 1 >= MaxBuff ) then
begin
Bezier_Up := False;
Error := Err_Ras_Overflow;
exit;
end;
debArc := cArc;
while ( cArc >= debArc ) and ( e <= e2 ) do
begin
Joint := False;
y2 := base^[0].y;
if y2 > e then
begin
y1 := base^[2].y;
if ( y2-y1 >= precision_step ) then
begin
Split_Bezier( base );
inc( cArc, 2 );
base := @base^[2];
end
else
begin
Buff^[profCur] := base^[2].x +
MulDiv( base^[0].x - base^[2].x,
e - y1,
y2 - y1 );
Pset;
inc( profCur );
dec( cArc, 2 );
base := @Arcs[cArc];
inc( e, Precision );
end;
end
else
begin
if y2 = e then
begin
joint := True;
Buff^[profCur] := Arcs[cArc].x;
Pset;
inc( profCur );
inc( e, Precision );
end;
dec( cArc, 2 );
base := @Arcs[cArc];
end
end;
Fin:
dec( curArc, 2);
exit;
end;
function Bezier_Down( miny, maxy : Long ) : boolean;
var
base : PBezierStack;
_fresh : Boolean;
begin
_fresh := fresh;
base := @Arcs[curArc];
base^[0].y := -base^[0].y;
base^[1].y := -base^[1].y;
base^[2].y := -base^[2].y;
Bezier_Down := Bezier_Up( -maxy, -miny );
if _fresh and not fresh then
cProfile^.start := -cProfile^.start;
base^[0].y := -base^[0].y;
end;
function Line_To( x, y : LongInt ) : boolean;
begin
Line_To := False;
case Etat of
Indetermine : if y > lastY then
if not New_Profile( Ascendant ) then exit else
else
if y < lastY then
if not New_Profile( Descendant ) then exit;
Ascendant : if y < lastY then
if not End_Profile or
not New_Profile( Descendant ) then exit;
Descendant : if y > LastY then
if not End_Profile or
not New_Profile( Ascendant ) then exit;
end;
Case Etat of
Ascendant : if not Line_Up ( LastX, LastY, X, Y, miny, maxy ) then exit;
Descendant : if not Line_Down( LastX, LastY, X, Y, miny, maxy ) then exit;
end;
LastX := x;
LastY := y;
Line_To := True;
end;
function Bezier_State( y1, y2, y3 : TT_F26Dot6 ) : TEtats;
begin
if y1 = y2 then
if y2 = y3 then Bezier_State := Plat
else
if y2 > y3 then Bezier_State := Descendant
else
Bezier_State := Ascendant
else
if y1 > y2 then
if y2 >= y3 then Bezier_State := Descendant
else
Bezier_State := Indetermine
else
if y2 <= y3 then Bezier_State := Ascendant
else
Bezier_State := Indetermine;
end;
function Bezier_To( x, y, Cx, Cy : LongInt ) : boolean;
var
y3, x3 : LongInt;
Etat_Bez : TEtats;
begin
Bezier_To := False;
PushBezier( LastX, LastY, Cx, Cy, X, Y );
while ( curArc >= 0 ) do
begin
y3 := Arcs[curArc].y;
x3 := Arcs[curArc].x;
Etat_Bez := Bezier_State( Arcs[curArc+2].y, Arcs[curArc+1].y, y3 );
case Etat_Bez of
Plat : dec( curArc, 2 );
Indetermine : begin
Split_Bezier( @Arcs[curArc] );
inc( curArc, 2 );
end;
else
if Etat <> Etat_Bez then
begin
if Etat <> Indetermine then
if not End_Profile then exit;
if not New_Profile( Etat_Bez ) then exit;
end;
case Etat of
Ascendant : if not Bezier_Up( miny, maxy ) then exit;
Descendant : if not Bezier_Down( miny, maxy ) then exit;
end;
end;
end;
LastX := x3;
LastY := y3;
Bezier_To := True;
end;
procedure swap( var x, y : Long ); inline;
var
s : Long;
begin
s := x; x := y; y := s;
end;
function DecomposeCurve( first, last : Int;
flipped : Boolean ) : boolean;
var
index : Int;
x, y : Long;
cx, cy : Long;
mx, my : Long;
x_first, y_first : Long;
x_last, y_last : Long;
on_curve : Boolean;
begin
DecomposeCurve := False;
x_first := SCALED( points^[first].x );
y_first := SCALED( points^[first].y );
if flipped then swap( x_first, y_first );
with points^[last] do
begin
x_last := SCALED( x );
y_last := SCALED( y );
end;
if flipped then swap( x_last, y_last );
LastX := x_first; cx := x_first;
LastY := y_first; cy := y_first;
index := first;
on_curve := Flags^[first] and 1 <> 0;
if not on_curve then
begin
if Flags^[last] and 1 <> 0 then
begin
LastX := x_last;
LastY := y_last;
end
else
begin
LastX := (LastX + x_last) div 2;
LastY := (LastY + y_last) div 2;
x_last := LastX;
y_last := LastY;
end;
end;
while ( index < last ) do
begin
inc( index );
x := SCALED( points^[index].x );
y := SCALED( points^[index].y );
if flipped then swap( x, y );
if on_curve then
begin
on_curve := Flags^[index] and 1 <> 0;
if on_curve then
begin
if not Line_To( x, y ) then exit;
end
else
begin
cx := x;
cy := y;
end;
end
else
begin
on_curve := Flags^[index] and 1 <> 0;
if on_curve then
begin
if not Bezier_To( x, y, cx, cy ) then exit;
end
else
begin
mx := (cx + x) div 2;
my := (cy + y) div 2;
if not Bezier_To( mx, my, cx, cy ) then exit;
cx := x;
cy := y;
end;
end;
end;
if ( Flags^[first] and 1 <> 0 ) then
if on_curve then
if not Line_To( x_first, y_first ) then exit else
else
if not Bezier_To( x_first, y_first, cx, cy ) then exit else
else
if not on_curve then
if not Bezier_To( x_last, y_last, cx, cy ) then exit;
DecomposeCurve := True;
end;
Function Convert_Glyph( flipped : Boolean ) : boolean;
var
i, j, First, Last, Start : Int;
y1, y2, y3 : LongInt;
lastProfile : PProfile;
begin
Convert_Glyph := False;
j := 0;
fProfile := NIL;
Joint := False;
Fresh := False;
MaxBuff := SizeBuff - AlignProfileSize;
numTurns := 0;
cProfile := PProfile( @Buff^[profCur] );
cProfile^.Offset := profCur;
nProfs := 0;
for i := 0 to nContours-1 do
begin
Etat := Indetermine;
gProfile := nil;
if not DecomposeCurve( j, outs^[i], flipped ) then exit;
j := outs^[i] + 1;
if ( Frac(lastY) = 0 ) and
( lastY >= MinY ) and
( lastY <= MaxY ) then
if ( gProfile <> nil ) and
( gProfile^.Flow = cProfile^.Flow ) then
dec( profCur );
lastProfile := cProfile;
if not End_Profile then exit;
if gProfile <> nil then lastProfile^.next := gProfile;
end;
Finalize_Profile_Table;
Convert_Glyph := (profCur < MaxBuff);
end;
procedure Init_Linked( var L : PProfile );
begin
L := nil;
end;
procedure InsNew( var List : PProfile;
Profile : PProfile );
var
current : PProfile;
old : ^PProfile;
x : Long;
label
Place;
begin
old := @list;
current := old^;
x := profile^.x;
while current <> nil do
begin
if x < current^.x then
goto Place;
old := @current^.link;
current := old^;
end;
Place:
profile^.link := current;
old^ := profile;
end;
procedure DelOld( var List : PProfile;
Profile : PProfile );
var
current : PProfile;
old : ^PProfile;
begin
old := @list;
current := old^;
while current <> nil do
begin
if current = profile then
begin
old^ := current^.link;
exit;
end;
old := @current^.link;
current := old^;
end;
Writeln('(Raster:DelOld) Incoherent deletion');
halt(9);
end;
procedure Update( var List : PProfile );
var
current : PProfile;
begin
current := list;
while current <> nil do with current^ do
begin
X := Buff^[offset];
inc( offset, flow );
dec( height );
current := link;
end;
end;
procedure Sort( var List : PProfile );
var
current, next : PProfile;
old : ^PProfile;
begin
current := list;
while current <> nil do with current^ do
begin
X := Buff^[offset];
inc( offset, flow );
dec( height );
current := link;
end;
old := @list;
current := old^;
if current = nil then
exit;
next := current^.link;
while next <> nil do
begin
if current^.x <= next^.x then
begin
old := @current^.link;
current := old^;
if current = nil then
exit;
end
else
begin
old^ := next;
current^.link := next^.link;
next^.link := current;
old := @list;
current := old^;
end;
next := current^.link;
end;
end;
function Draw_Sweep : boolean;
label
Scan_DropOuts,
Next_Line,
Skip_To_Next;
var
y, k,
I, J : Int;
P, Q : PProfile;
Top,
Bottom,
y_height,
y_change,
min_Y,
max_Y : Int;
x1, x2, xs, e1, e2 : LongInt;
Wait : PProfile;
Draw_Left : PProfile;
Draw_Right : PProfile;
Drop_Left : PProfile;
Drop_Right : PProfile;
P_Left, Q_Left : PProfile;
P_Right, Q_Right : PProfile;
Phase : Int;
dropouts : Int;
begin
Draw_Sweep := False;
Init_Linked( Wait );
Init_Linked( Draw_Left );
Init_Linked( Draw_Right );
Init_Linked( Drop_Left );
Init_Linked( Drop_Right );
P := fProfile;
max_Y := TRUNC(MinY);
min_Y := TRUNC(MaxY);
while P <> nil do
with P^ do
begin
Q := P^.Link;
Bottom := P^.Start;
Top := Bottom + P^.Height-1;
if min_Y > Bottom then min_Y := Bottom;
if max_Y < Top then max_Y := Top;
X := 0;
InsNew( Wait, P );
P := Q;
end;
if (numTurns = 0) then
begin
Error := Err_Ras_Invalid;
exit;
end;
Proc_Sweep_Init( min_Y, max_Y );
P := Wait;
while P <> nil do
begin
with P^ do CountL := (Start-min_Y);
P := P^.link;;
end;
y := min_y;
y_height := 0;
if ( numTurns > 0 ) and
( Buff^[sizeBuff-numTurns] = min_y ) then
dec( numTurns );
while numTurns > 0 do
begin
P := Wait;
while P <> nil do with P^ do
begin
Q := link;
dec( CountL, y_height );
if CountL = 0 then
begin
DelOld( Wait, P );
case Flow of
TT_Flow_Up : InsNew( Draw_Left, P );
TT_Flow_Down : InsNew( Draw_Right, P );
end
end;
P := Q;
end;
Sort( Draw_Left );
Sort( Draw_Right );
y_change := Buff^[sizebuff-numTurns];
dec( numTurns );
y_height := y_change - y;
while y < y_change do
begin
dropouts := 0;
P_Left := Draw_Left;
P_Right := Draw_Right;
while ( P_Left <> nil ) do
begin
if P_Right = nil then
Halt(13);
x1 := P_Left^ .X;
x2 := P_Right^.X;
if x1 > x2 then
begin
xs := x1;
x1 := x2;
x2 := xs;
end;
if ( x2-x1 <= Precision ) then
begin
e1 := ( x1+Precision-1 ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if (dropOutControl <> 0) and
((e1 > e2) or (e2 = e1 + Precision)) then
begin
P_Left ^.x := x1;
P_Right^.x := x2;
inc( dropouts );
P_Left^.CountL := 1;
goto Skip_To_Next;
end
end;
Proc_Sweep_Span( y, x1, x2, P_Left, P_Right );
Skip_To_Next:
P_Left := P_Left ^.Link;
P_Right := P_Right^.Link;
end;
if P_Right <> nil then
Halt(10);
if (dropouts > 0) then
goto Scan_DropOuts;
Next_Line:
Proc_Sweep_Step;
inc(y);
if y < y_change then
begin
Update( Draw_Left );
Update( Draw_Right );
end
end;
P := Draw_Left;
while P <> nil do
begin
Q := P^.Link;
if P^.height = 0 then
DelOld( Draw_Left, P );
P := Q;
end;
P := Draw_Right;
while P <> nil do
begin
Q := P^.Link;
if P^.height = 0 then
DelOld( Draw_Right, P );
P := Q;
end;
end;
while y <= max_y do
begin
Proc_Sweep_Step;
inc( y );
end;
Draw_Sweep := True;
exit;
Scan_DropOuts :
P_Left := Draw_Left;
P_Right := Draw_Right;
while (P_Left <> nil) do
begin
if P_Left^.countL <> 0 then
begin
P_Left^.countL := 0;
Proc_Sweep_Drop( y, P_Left^.x, P_Right^.x, P_Left, P_Right );
end;
P_Left := P_Left^.link;
P_Right := P_Right^.Link;
end;
goto Next_Line;
end;
function Draw_Sweep : boolean;
label
Skip_To_Next;
var
y, k,
I, J : Int;
P, Q : PProfile;
Top,
Bottom,
min_Y,
max_Y : Int;
x1, x2, xs, e1, e2 : LongInt;
Wait : PProfile;
Draw_Left : PProfile;
Draw_Right : PProfile;
Drop_Left : PProfile;
Drop_Right : PProfile;
P_Left, Q_Left : PProfile;
P_Right, Q_Right : PProfile;
Phase : Int;
dropouts : Int;
begin
Draw_Sweep := False;
Init_Linked( Wait );
Init_Linked( Draw_Left );
Init_Linked( Draw_Right );
Init_Linked( Drop_Left );
Init_Linked( Drop_Right );
P := fProfile;
max_Y := TRUNC(MinY);
min_Y := TRUNC(MaxY);
while P <> nil do
with P^ do
begin
Q := P^.Link;
Bottom := P^.Start;
Top := Bottom + P^.Height-1;
if min_Y > Bottom then min_Y := Bottom;
if max_Y < Top then max_Y := Top;
X := 0;
InsNew( Wait, P );
P := Q;
end;
Proc_Sweep_Init( min_Y, max_Y );
P := Wait;
while P <> nil do
begin
with P^ do CountL := (Start-min_Y);
P := P^.link;;
end;
for y := min_Y to max_Y do
begin
P := Wait;
while P <> nil do with P^ do
begin
Q := link;
if CountL = 0 then
begin
DelOld( Wait, P );
case Flow of
TT_Flow_Up : InsNew( Draw_Left, P );
TT_Flow_Down : InsNew( Draw_Right, P );
end
end
else
dec( CountL );
P := Q;
end;
Sort( Draw_Left );
Sort( Draw_Right );
dropouts := 0;
P_Left := Draw_Left;
P_Right := Draw_Right;
while ( P_Left <> nil ) do
begin
if P_Right = nil then
Halt(13);
Q_Left := P_Left^ .Link;
Q_Right := P_Right^.Link;
if Q_Right = nil then
Halt(11);
x1 := P_Left^ .X;
x2 := P_Right^.X;
if x1 > x2 then
begin
xs := x1;
x1 := x2;
x2 := xs;
end;
if ( x2-x1 <= Precision ) then
begin
e1 := ( x1+Precision-1 ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if (dropOutControl <> 0) and
((e1 > e2) or (e2 = e1 + Precision)) then
begin
P_Left^.x := x1;
P_Right^.x := x2;
inc( dropouts );
DelOld( Draw_Left, P_Left );
DelOld( Draw_Right, P_Right );
InsNew( Drop_Left, P_Left );
InsNew( Drop_Right, P_Right );
goto Skip_To_Next;
end
end;
Proc_Sweep_Span( y, x1, x2, P_Left, P_Right );
if P_Left ^.height = 0 then
DelOld( Draw_Left, P_Left );
if P_Right^.height = 0 then
DelOld( Draw_Right, P_Right );
Skip_To_Next:
P_Left := Q_Left;
P_Right := Q_Right;
end;
if P_Right <> nil then
Halt(10);
P_Left := Drop_Left;
P_Right := Drop_Right;
while ( dropouts > 0 ) do
begin
Q_Left := P_Left^. Link;
Q_Right := P_Right^.Link;
DelOld( Drop_Left, P_Left );
DelOld( Drop_Right, P_Right );
Proc_Sweep_Drop( y, P_Left^.x, P_Right^.x, P_Left, P_Right );
if P_Left^.height > 0 then
InsNew( Draw_Left, P_Left );
if P_Right^.height > 0 then
InsNew( Draw_Right, P_Right );
P_Left := Q_Left;
P_Right := Q_Right;
dec( dropouts );
end;
Proc_Sweep_Step;
end;
Draw_Sweep := True;
end;
procedure Vertical_Sweep_Init( var min, max : Int );
begin
case Cible.flow of
TT_Flow_Up : begin
traceOfs := min * Cible.cols;
traceIncr := Cible.cols;
end;
else
traceOfs := (Cible.rows - 1 - min)*Cible.cols;
traceIncr := -Cible.cols;
end;
gray_min_x := 0;
gray_max_x := 0;
end;
procedure Vertical_Sweep_Span( y : Int;
x1,
x2 : TT_F26dot6;
Left,
Right : PProfile );
var
e1, e2 : Longint;
c1, c2 : Int;
f1, f2 : Int;
base : PByte;
begin
asm
push esi
push ebx
push ecx
mov eax, X1
mov ebx, X2
mov ecx, [Precision_Bits]
sub ebx, eax
add eax, [Precision]
dec eax
sub ebx, [Precision]
cmp ebx, [Precision_Jitter]
jg @No_Jitter
@Do_Jitter:
mov ebx, eax
jmp @0
@No_Jitter:
mov ebx, X2
@0:
sar ebx, cl
js @Sortie
sar eax, cl
mov ecx, [BWidth]
cmp eax, ebx
jg @Sortie
cmp eax, ecx
jge @Sortie
test eax, eax
jns @1
xor eax, eax
@1:
cmp ebx, ecx
jl @2
lea ebx, [ecx-1]
@2:
mov edx, eax
mov ecx, ebx
and edx, 7
sar eax, 3
and ecx, 7
sar ebx, 3
cmp eax, [gray_min_X]
jge @3
mov [gray_min_X], eax
@3:
cmp ebx, [gray_max_X]
jl @4
mov [gray_max_X], ebx
@4:
mov esi, ebx
mov ebx, [BCible]
add ebx, [TraceOfs]
add ebx, eax
sub esi, eax
jz @5
mov al, [LMask + edx].byte
or [ebx], al
inc ebx
dec esi
jz @6
mov eax, -1
@7:
mov [ebx].byte, al
dec esi
lea ebx, [ebx+1]
jnz @7
@6:
mov al, [RMask + ecx].byte
or [ebx], al
jmp @8
@5:
mov al, [LMask + edx].byte
and al, [RMask + ecx].byte
or [ebx], al
@8:
@Sortie:
pop ecx
pop ebx
pop esi
end;
e1 := (( x1+Precision-1 ) and Precision_Mask) div Precision;
if ( x2-x1-Precision <= Precision_Jitter ) then
e2 := e1
else
e2 := ( x2 and Precision_Mask ) div Precision;
if (e2 >= 0) and (e1 < BWidth) then
begin
if e1 < 0 then e1 := 0;
if e2 >= BWidth then e2 := BWidth-1;
c1 := e1 shr 3;
c2 := e2 shr 3;
f1 := e1 and 7;
f2 := e2 and 7;
if gray_min_X > c1 then gray_min_X := c1;
if gray_max_X < c2 then gray_max_X := c2;
base := @BCible^[TraceOfs + c1];
if c1 = c2 then
base^[0] := base^[0] or ( LMask[f1] and Rmask[f2] )
else
begin
base^[0] := base^[0] or LMask[f1];
if c2>c1+1 then
FillChar( base^[1], c2-c1-1, $FF );
base := @base^[c2-c1];
base^[0] := base^[0] or RMask[f2];
end
end;
end;
procedure Vertical_Sweep_Drop( y : Int;
x1,
x2 : TT_F26dot6;
Left,
Right : PProfile );
var
e1, e2 : Longint;
c1, c2 : Int;
f1, f2 : Int;
j : Int;
begin
e1 := ( x1+Precision-1 ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if e1 > e2 then
if e1 = e2 + Precision then
case DropOutControl of
1 : e1 := e2;
4 : begin
e1 := ((x1+x2+1) div 2 + Precision-1) and Precision_Mask;
e2 := e1;
end;
2,5 : begin
if ( x2-x1 < Precision_Half ) then
begin
if ( Left^.next = Right ) and
( Left^.Height <= 0 ) then exit;
if ( Right^.next = Left ) and
( Left^.Start = y ) then exit;
end;
e1 := e1 div Precision;
c1 := e1 shr 3;
f1 := e1 and 7;
if ( e1 >= 0 ) and ( e1 < BWidth ) and
( BCible^[TraceOfs+c1] and ($80 shr f1) <> 0 ) then
exit;
case DropOutControl of
2 : e1 := e2;
5 : e1 := ((x1+x2+1) div 2 + Precision-1) and Precision_Mask;
end;
e2 := e1;
end;
else
exit;
end
else
else
e2 := e1;
e1 := e1 div Precision;
if (e1 >= 0) and (e1 < BWidth ) then
begin
c1 := e1 shr 3;
f1 := e1 and 7;
if gray_min_X > c1 then gray_min_X := c1;
if gray_max_X < c1 then gray_max_X := c1;
j := TraceOfs + c1;
BCible^[j] := BCible^[j] or ($80 shr f1);
end;
end;
procedure Vertical_Sweep_Step;
begin
inc( TraceOfs, traceIncr );
end;
procedure Horizontal_Sweep_Init( var min, max : Int );
begin
end;
procedure Horizontal_Sweep_Span( y : Int;
x1,
x2 : TT_F26dot6;
Left,
Right : PProfile );
var
e1, e2 : Longint;
c1, c2 : Int;
f1, f2 : Int;
j : Int;
begin
if ( x2-x1 < Precision ) then
begin
e1 := ( x1+(Precision-1) ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if e1 = e2 then
begin
c1 := y shr 3;
f1 := y and 7;
if (e1 >= 0) then
begin
e1 := e1 shr Precision_Bits;
if Cible.flow = TT_Flow_Up then
j := c1 + e1*Cible.cols
else
j := c1 + (Cible.rows-1-e1)*Cible.cols;
if e1 < Cible.Rows then
BCible^[j] := BCible^[j] or ($80 shr f1);
end;
end;
end;
e1 := ( x1+(Precision-1) ) and Precision_Mask;
e2 := x2 and Precision_Mask;
c1 := y shr 3;
f1 := y and 7;
if (e1 >= 0) then
begin
e1 := e1 shr Precision_Bits;
if Cible.flow = TT_Flow_Up then
j := c1 + e1*Cible.cols
else
j := c1 + (Cible.rows-1-e1)*Cible.cols;
if e1 < Cible.Rows then
BCible^[j] := BCible^[j] or ($80 shr f1);
end;
if (e2 >= 0) then
begin
e2 := e2 shr Precision_Bits;
if Cible.flow = TT_Flow_Up then
j := c1 + e1*Cible.cols
else
j := c1 + (Cible.rows-1-e2)*Cible.cols;
if (e2 <> e1) and (e2 < Cible.Rows) then
BCible^[j] := BCible^[j] or ($80 shr f1);
end;
end;
procedure Horizontal_Sweep_Drop( y : Int;
x1,
x2 : TT_F26dot6;
Left,
Right : PProfile );
var
e1, e2 : Longint;
c1, c2 : Int;
f1, f2 : Int;
j : Int;
begin
e1 := ( x1+(Precision-1) ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if e1 > e2 then
if e1 = e2 + Precision then
case DropOutControl of
0 : exit;
1 : e1 := e2;
4 : begin
e1 := ( (x1+x2) div 2 +Precision div 2 ) and Precision_Mask;
e2 := e1;
end;
2,5 : begin
if ( Left^.next = Right ) and
( Left^.Height <= 0 ) then exit;
if ( Right^.next = Left ) and
( Left^.Start = y ) then exit;
e1 := e1 div Precision;
c1 := y shr 3;
f1 := y and 7;
if Cible.flow = TT_Flow_Up then
j := c1 + e1*Cible.cols
else
j := c1 + (Cible.rows-1-e1)*Cible.cols;
if ( e1 >= 0 ) and ( e1 < Cible.Rows ) and
( BCible^[j] and ($80 shr f1) <> 0 ) then exit;
case DropOutControl of
2 : e1 := e2;
5 : e1 := ((x1+x2) div 2 + Precision_Half) and Precision_Mask;
end;
e2 := e1;
end;
else
exit;
end;
c1 := y shr 3;
f1 := y and 7;
if (e1 >= 0) then
begin
e1 := e1 shr Precision_Bits;
if Cible.flow = TT_Flow_Up then
j := c1 + e1*Cible.cols
else
j := c1 + (Cible.rows-1-e1)*Cible.cols;
if e1 < Cible.Rows then BCible^[j] := BCible^[j] or ($80 shr f1);
end;
end;
procedure Horizontal_Sweep_Step;
begin
end;
procedure Vertical_Gray_Sweep_Init( var min, max : Int );
begin
min := min and -2;
max := (max+3) and -2;
case Cible.flow of
TT_Flow_Up : begin
traceG := (min div 2)*Cible.cols;
traceIncr := Cible.cols;
end;
else
traceG := (Cible.rows-1- (min div 2))*Cible.cols;
traceIncr := -Cible.cols;
end;
TraceOfs := 0;
gray_min_x := Cible.Cols;
gray_max_x := -Cible.Cols;
end;
procedure Vertical_Gray_Sweep_Step;
var
j, c1, c2 : Int;
begin
inc( TraceOfs, Gray_Width );
if TraceOfs > Gray_Width then
begin
if gray_max_X >= 0 then
begin
if gray_max_x > cible.cols-1 then gray_max_x := cible.cols-1;
if gray_min_x < 0 then gray_min_x := 0;
j := TraceG + gray_min_x*4;
for c1 := gray_min_x to gray_max_x do
begin
c2 := Count_Table[ BCible^[c1 ] ] +
Count_Table[ BCible^[c1+Gray_Width] ];
if c2 <> 0 then
begin
BCible^[c1 ] := 0;
BCible^[c1+Gray_Width] := 0;
GCible^[j] := GCible^[j] or Grays[ (c2 and $F000) shr 12 ]; inc(j);
GCible^[j] := GCible^[j] or Grays[ (c2 and $0F00) shr 8 ]; inc(j);
GCible^[j] := GCible^[j] or Grays[ (c2 and $00F0) shr 4 ]; inc(j);
GCible^[j] := GCible^[j] or Grays[ (c2 and $000F) ]; inc(j);
end
else
inc( j, 4 );
end;
end;
TraceOfs := 0;
inc( TraceG, traceIncr );
gray_min_x := Cible.Cols;
gray_max_x := -Cible.Cols;
end;
end;
procedure Horizontal_Gray_Sweep_Span( y : Int;
x1,
x2 : TT_F26dot6;
Left,
Right : PProfile );
var
e1, e2 : TT_F26Dot6;
c1, f1, j : Int;
begin
exit;
y := y div 2;
e1 := ( x1+(Precision-1) ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if (e1 >= 0) then
begin
e1 := e1 shr (Precision_Bits+1);
j := y + e1*Cible.cols;
if e1 < Cible.Rows then
if GCible^[j] = Grays[0] then
GCible^[j] := Grays[1];
end;
if (e2 >= 0) then
begin
e2 := e2 shr (Precision_Bits+1);
j := y + e2*Cible.cols;
if (e2 <> e1) and (e2 < Cible.Rows) then
if GCible^[j] = Grays[0] then
GCible^[j] := Grays[1];
end;
end;
procedure Horizontal_Gray_Sweep_Drop( y : Int;
x1,
x2 : TT_F26dot6;
Left,
Right : PProfile );
var
e1, e2 : Longint;
f1, f2 : Int;
color : Byte;
j : Int;
begin
e1 := ( x1+(Precision-1) ) and Precision_Mask;
e2 := x2 and Precision_Mask;
if e1 > e2 then
if e1 = e2 + Precision then
case DropOutControl of
0 : exit;
1 : e1 := e2;
4 : begin
e1 := ( (x1+x2) div 2 +Precision div 2 ) and Precision_Mask;
e2 := e1;
end;
2,5 : begin
if ( Left^.next = Right ) and
( Left^.Height <= 0 ) then exit;
if ( Right^.next = Left ) and
( Left^.Start = y ) then exit;
case DropOutControl of
2 : e1 := e2;
5 : e1 := ((x1+x2) div 2 + Precision_Half) and Precision_Mask;
end;
e2 := e1;
end;
else
exit;
end;
if (e1 >= 0) then
begin
if ( x2-x1 >= Precision_Half ) then
color := Grays[2]
else color := Grays[1];
e1 := e1 shr (Precision_Bits+1);
if Cible.flow = TT_Flow_Up then
j := (y div 2) + e1*Cible.cols
else
j := (y div 2) + (Cible.rows-1-e1)*Cible.cols;
if e1 < Cible.Rows then
if GCible^[j] = Grays[0] then
GCible^[j] := color;
end;
end;
procedure Smooth_Sweep_Init( var min, max : Int );
var
i : integer;
begin
min := min and -4;
max := (max + 7) and -4;
TraceOfs := 0;
TraceG := Cible.Cols * ( min div 4 );
gray_min_x := Cible.Cols;
gray_max_x := -Cible.Cols;
smooth_pass := 0;
end;
procedure Smooth_Sweep_Step;
var
j, c1, c2 : Int;
begin
if gray_max_X >= 0 then
begin
if gray_max_x > cible.cols-1 then gray_max_x := cible.cols-1;
if gray_min_x < 0 then gray_min_x := 0;
j := TraceG + gray_min_x*2;
for c1 := gray_min_x to gray_max_x do
begin
c2 := Count_Table2[ BCible^[c1] ];
if c2 <> 0 then
begin
inc( GCible^[j], c2 shr 4 ); inc(j);
inc( GCible^[j], c2 and 15 ); inc(j);
BCible^[c1] := 0;
end
else
inc( j, 2 );
end;
end;
traceOfs := 0;
inc( smooth_pass );
if smooth_pass >= 4 then
begin
j := TraceG + gray_min_x*2;
for c1 := gray_min_x to gray_max_x do
begin
c2 := GCible^[j]; GCible^[j] := Smooths[c2]; inc(j);
c2 := GCible^[j]; GCible^[j] := Smooths[c2]; inc(j);
end;
smooth_pass := 0;
inc( TraceG, Cible.Cols );
gray_min_x := Cible.Cols;
gray_max_x := -Cible.Cols;
end;
end;
function Render_Single_Pass( vertical : Boolean ) : boolean;
var
i, j, k : Int;
begin
Render_Single_Pass := False;
while Band_Top > 0 do
begin
with Band_Stack[ Band_Top ] do
begin
MaxY := longint(Y_Max) * Precision;
MinY := longint(Y_Min) * Precision;
end;
profCur := 0;
Error := Err_Ras_None;
if not Convert_Glyph( vertical ) then
begin
if Error <> Err_Ras_Overflow then exit;
Error := Err_Ras_None;
ClearBand( MinY shr Precision_Bits, MaxY shr Precision_Bits );
with Band_Stack[Band_Top] do
begin
I := Y_Min;
J := Y_Max;
end;
K := ( I + J ) div 2;
if ( Band_Top >= 8 ) or ( K <= I ) then
begin
Band_Top := 0;
Error := Err_Ras_Invalid;
exit;
end
else
begin
with Band_Stack[Band_Top+1] do
begin
Y_Min := K;
Y_Max := J;
end;
Band_Stack[Band_Top].Y_Max := K-1;
inc( Band_Top );
end
end
else
begin
if ( fProfile <> nil ) then
if not Draw_Sweep then exit;
dec( Band_Top );
end;
end;
Render_Single_Pass := true;
end;
function Render_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError;
begin
Render_Glyph := Failure;
if Buff = nil then
begin
Error := Err_Ras_NotIni;
exit;
end;
if glyph.conEnds^[glyph.n_contours-1] > glyph.n_points then
begin
Error := Err_Ras_Invalid_Contours;
exit;
end;
Cible := target;
Outs := glyph.conEnds;
Flags := PByte(glyph.flags);
nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( glyph.high_precision );
scale_shift := precision_shift;
DropOutControl := glyph.dropout_mode;
second_pass := glyph.second_pass;
Error := Err_Ras_None;
Proc_Sweep_Init := @Vertical_Sweep_Init;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Sweep_Step;
Proc_Sweep_Init := Vertical_Sweep_Init;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Sweep_Step;
Band_Top := 1;
Band_Stack[1].Y_Min := 0;
Band_Stack[1].Y_Max := Cible.Rows-1;
BWidth := Cible.width;
BCible := PByte( Cible.Buffer );
if not Render_Single_Pass( False ) then exit;
if Second_Pass then
begin
Proc_Sweep_Init := @Horizontal_Sweep_Init;
Proc_Sweep_Span := @Horizontal_Sweep_Span;
Proc_Sweep_Drop := @Horizontal_Sweep_Drop;
Proc_Sweep_Step := @Horizontal_Sweep_Step;
Proc_Sweep_Init := Horizontal_Sweep_Init;
Proc_Sweep_Span := Horizontal_Sweep_Span;
Proc_Sweep_Drop := Horizontal_Sweep_Drop;
Proc_Sweep_Step := Horizontal_Sweep_Step;
Band_Top := 1;
Band_Stack[1].Y_Min := 0;
Band_Stack[1].Y_Max := Cible.Width-1;
BWidth := Cible.rows;
BCible := PByte( Cible.Buffer );
if not Render_Single_Pass( True ) then exit;
end;
Render_Glyph := Success;
end;
function Render_Gray_Glyph( var glyph : TT_Outline;
var target : TT_Raster_Map ) : TError;
begin
Render_Gray_Glyph := Failure;
cible := target;
Outs := Glyph.conEnds;
Flags := PByte(glyph.flags);
nPoints := Glyph.n_points;
nContours := Glyph.n_contours;
points := Glyph.points;
Set_High_Precision( glyph.high_precision );
scale_shift := precision_shift+1;
DropOutControl := glyph.dropout_mode;
second_pass := glyph.high_precision;
Error := Err_Ras_None;
Band_Top := 1;
Band_Stack[1].Y_Min := 0;
Band_Stack[1].Y_Max := 2*Cible.Rows - 1;
BWidth := Gray_Width;
if BWidth > Cible.cols div 4 then BWidth := Cible.cols div 4;
BWidth := BWidth*8;
BCible := PByte( Gray_Lines );
GCible := PByte( Cible.Buffer );
Proc_Sweep_Init := @Vertical_Gray_Sweep_Init;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Vertical_Gray_Sweep_Step;
Proc_Sweep_Init := Vertical_Gray_Sweep_Init;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Vertical_Gray_Sweep_Step;
if not Render_Single_Pass( False ) then exit;
if Second_Pass then
begin
Proc_Sweep_Init := @Horizontal_Sweep_Init;
Proc_Sweep_Span := @Horizontal_Gray_Sweep_Span;
Proc_Sweep_Drop := @Horizontal_Gray_Sweep_Drop;
Proc_Sweep_Step := @Horizontal_Sweep_Step;
Proc_Sweep_Init := Horizontal_Sweep_Init;
Proc_Sweep_Span := Horizontal_Gray_Sweep_Span;
Proc_Sweep_Drop := Horizontal_Gray_Sweep_Drop;
Proc_Sweep_Step := Horizontal_Sweep_Step;
Band_Top := 1;
Band_Stack[1].Y_Min := 0;
Band_Stack[1].Y_Max := Cible.Width*2-1;
BWidth := Cible.rows;
GCible := PByte( Cible.Buffer );
if not Render_Single_Pass( True ) then exit;
end;
Render_Gray_Glyph := Success;
exit;
end;
function Render_Smooth_Glyph( var glyph : TGlyphRecord;
target : PRasterBlock;
scan : Byte;
palette : pointer ) : boolean;
begin
Render_Smooth_Glyph := Failure;
if target <> nil then
cible := target^;
Outs := Glyph.endPoints;
Flags := PByte(glyph.Flag);
nPoints := Glyph.Points;
nContours := Glyph.numConts;
scale_shift := precision_shift+2;
DropOutControl := scan;
Raster_Error := Err_Ras_None;
Band_Top := 1;
Band_Stack[1].Y_Min := 0;
Band_Stack[1].Y_Max := 4*Cible.Rows - 1;
BWidth := Smooth_Cols;
if BWidth > Cible.cols then BWidth := Cible.cols;
BWidth := BWidth*8;
BCible := PByte( Gray_Lines );
GCible := PByte( Cible.Buffer );
Proc_Sweep_Init := @Smooth_Sweep_Init;
Proc_Sweep_Span := @Vertical_Sweep_Span;
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
Proc_Sweep_Step := @Smooth_Sweep_Step;
Proc_Sweep_Init := Smooth_Sweep_Init;
Proc_Sweep_Span := Vertical_Sweep_Span;
Proc_Sweep_Drop := Vertical_Sweep_Drop;
Proc_Sweep_Step := Smooth_Sweep_Step;
if not Render_Single_Pass( Glyph.XCoord, Glyph.YCoord ) then exit;
Render_Smooth_Glyph := Success;
end;
function TTRaster_Init : TError;
var
i, j, c, l : integer;
const
Default_Grays : array[0..4] of Byte
= ( 0, 23, 27, 29, 31 );
Default_Smooths : array[0..16] of Byte
= ( 0, 20, 20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31, 31, 31, 31 );
begin
GetMem( Buff, Render_Pool_Size );
SizeBuff := (Render_Pool_Size div 4);
GetMem( Gray_Lines, Gray_Lines_Size );
Gray_Width := Gray_Lines_Size div 2;
Smooth_Cols := Gray_Lines_Size div 4;
for i := 0 to 255 do
begin
l := 0;
j := i;
for c := 0 to 3 do
begin
l := l shl 4;
if ( j and $80 <> 0 ) then inc(l);
if ( j and $40 <> 0 ) then inc(l);
j := (j shl 2) and $FF;
end;
Count_table[i] := l;
end;
Grays[0] := 0;
Grays[1] := 23;
Grays[2] := 27;
Grays[3] := 29;
Grays[4] := 31;
for i := 0 to 255 do
begin
l := 0;
j := i;
for c := 0 to 1 do
begin
l := l shl 4;
if ( j and $80 <> 0 ) then inc(l);
if ( j and $40 <> 0 ) then inc(l);
if ( j and $20 <> 0 ) then inc(l);
if ( j and $10 <> 0 ) then inc(l);
j := (j shl 4) and $FF;
end;
Count_table2[i] := l;
end;
move( Default_Smooths, Smooths, 17 );
Set_High_Precision(False);
Set_Second_Pass(False);
DropOutControl := 2;
Error := Err_Ras_None;
TTRaster_Init := Success;
end;
procedure Cycle_DropOut;
begin
case DropOutControl of
0 : DropOutControl := 1;
1 : DropOutControl := 2;
2 : DropOutControl := 4;
4 : DropOutControl := 5;
else
DropOutControl := 0;
end;
end;
procedure TTRaster_Done;
begin
FreeMem( Buff, Render_Pool_Size );
FreeMem( Gray_Lines, Gray_Lines_Size );
end;
end.