
git-svn-id: https://svn.code.sf.net/p/lazarus-ccr/svn@1566 8e941d3f-bd1b-0410-a28a-d453659cc2b4
3446 lines
94 KiB
ObjectPascal
3446 lines
94 KiB
ObjectPascal
(*******************************************************************
|
||
*
|
||
* TTRaster.Pas v 1.2
|
||
*
|
||
* The FreeType glyph rasterizer.
|
||
*
|
||
* Copyright 1996 David Turner, Robert Wilhelm and Werner Lemberg
|
||
*
|
||
* This file is part of the FreeType project, and may only be used
|
||
* modified and distributed under the terms of the FreeType project
|
||
* license, LICENSE.TXT. By continuing to use, modify or distribute
|
||
* this file you indicate that you have read the license and
|
||
* understand and accept it fully.
|
||
*
|
||
* NOTES : This version supports the following :
|
||
*
|
||
* - direct grayscaling
|
||
* - sub-banding
|
||
* - drop-out modes 4 and 5
|
||
* - second pass for complete drop-out control ( bitmap only )
|
||
* - variable precision
|
||
*
|
||
* Re-entrancy is _not_ planned.
|
||
*
|
||
* Changes between 1.1 and 1.2 :
|
||
*
|
||
* - no more trace tables, now uses linked list to sort
|
||
* coordinates.
|
||
*
|
||
* - reduced code size using function dispatch within a generic
|
||
* draw_sweep function.
|
||
*
|
||
* - added variable precision for finer rendering at small ppems
|
||
*
|
||
*
|
||
* Note that its interface may change in the future.
|
||
*
|
||
******************************************************************)
|
||
|
||
Unit TTRASTER;
|
||
|
||
interface
|
||
|
||
{$I TTCONFIG.INC}
|
||
|
||
{ $DEFINE TURNS}
|
||
|
||
uses
|
||
{$IFDEF VIRTUALPASCAL}
|
||
Use32,
|
||
{$ENDIF}
|
||
FreeType,
|
||
TTTypes;
|
||
|
||
const
|
||
|
||
Err_Ras_None = 0;
|
||
Err_Ras_NotIni = -2; (* Rasterizer not Initialized *)
|
||
Err_Ras_Overflow = -3; (* Profile Table Overflow *)
|
||
Err_Ras_Neg_H = -4; (* Negative Height encountered ! *)
|
||
Err_Ras_Invalid = -5; (* Invalid value encountered ! *)
|
||
Err_Ras_Invalid_Contours = -6;
|
||
|
||
function Render_Glyph( var glyph : TT_Outline;
|
||
var target : TT_Raster_Map ) : TError;
|
||
|
||
(* Render one glyph in the target bitmap, using drop-out control *)
|
||
(* mode 'scan' *)
|
||
|
||
function Render_Gray_Glyph( var glyph : TT_Outline;
|
||
var target : TT_Raster_Map ) : TError;
|
||
|
||
(* Render one gray-level glyph in the target pixmap *)
|
||
(* palette points to an array of 5 colors used for the rendering *)
|
||
(* use nil to reuse the last palette. Default is VGA graylevels *)
|
||
|
||
{$IFDEF SMOOTH}
|
||
function Render_Smooth_Glyph( var glyph : TGlyphRecord;
|
||
target : PRasterBlock;
|
||
scan : Byte;
|
||
palette : pointer ) : boolean;
|
||
{$ENDIF}
|
||
|
||
procedure Set_High_Precision( High : boolean );
|
||
(* Set rendering precision. Should be set to TRUE for small sizes only *)
|
||
(* ( typically < 20 ppem ) *)
|
||
|
||
procedure Set_Second_Pass( Pass : boolean );
|
||
(* Set second pass flag *)
|
||
|
||
function TTRaster_Init : TError;
|
||
procedure TTRaster_Done;
|
||
|
||
implementation
|
||
|
||
uses
|
||
TTCalc, { used for MulDiv }
|
||
TTError
|
||
{$IFDEF DEBUG}
|
||
,GMain { Used to access VRAM pointer VIO during DEBUG }
|
||
{$ENDIF}
|
||
;
|
||
|
||
|
||
{$DEFINE NO_ASM}
|
||
|
||
const
|
||
Render_Pool_Size = 64000;
|
||
Gray_Lines_Size = 2048;
|
||
|
||
MaxBezier = 32; (* Maximum number of stacked B<>ziers. *)
|
||
(* Setting this constant to more than 32 *)
|
||
(* is a pure waste of space *)
|
||
|
||
Pixel_Bits = 6; (* fractional bits of input coordinates *)
|
||
|
||
Cell_Bits = 8;
|
||
|
||
type
|
||
|
||
TEtats = ( Indetermine, Ascendant, Descendant, Plat );
|
||
|
||
PProfile = ^TProfile;
|
||
TProfile = record
|
||
Flow : Int; (* ascending or descending Profile *)
|
||
Height : Int; (* Profile's height in scanlines *)
|
||
Start : Int; (* Profile's starting scanline *)
|
||
Offset : ULong; (* offset of first coordinate in *)
|
||
(* render pool *)
|
||
|
||
Link : PProfile; (* link used in several cases *)
|
||
|
||
X : Longint; (* current coordinate during sweep *)
|
||
CountL : Int; (* number of lines to step before *)
|
||
(* this Profile becomes drawable *)
|
||
|
||
next : PProfile; (* next Profile of the same contour *)
|
||
end;
|
||
|
||
TBand = record
|
||
Y_Min : Int;
|
||
Y_Max : Int;
|
||
end;
|
||
|
||
(* Simple record used to implement a stack of bands, required *)
|
||
(* by the sub-banding mechanism *)
|
||
|
||
const
|
||
AlignProfileSize = ( sizeOf(TProfile) + 3 ) div 4;
|
||
(* You may need to compute this according to your prefered alignement *)
|
||
|
||
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);
|
||
|
||
(* left and right fill bitmasks *)
|
||
|
||
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;
|
||
|
||
(* prototypes used for sweep function dispatch *)
|
||
|
||
TPoint = record x, y : long; end;
|
||
|
||
TBezierStack = array[0..32*2] of TPoint;
|
||
PBezierStack = ^TBezierStack;
|
||
|
||
{$IFNDEF CONST_PREC}
|
||
|
||
var
|
||
Precision_Bits : Int; (* Fractional bits of Raster coordinates *)
|
||
Precision : Int;
|
||
Precision_Half : Int;
|
||
Precision_Step : Int; (* Bezier subdivision minimal step *)
|
||
Precision_Shift : Int; (* Shift used to convert coordinates *)
|
||
Precision_Mask : Longint; (* integer truncatoin mask *)
|
||
Precision_Jitter : Int;
|
||
|
||
{$ELSE}
|
||
|
||
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;
|
||
|
||
{$ENDIF}
|
||
|
||
var
|
||
Scale_Shift : Int;
|
||
|
||
cProfile : PProfile; (* current Profile *)
|
||
fProfile : PProfile; (* head of Profiles linked list *)
|
||
oProfile : PProfile; (* old Profile *)
|
||
gProfile : PProfile; (* last Profile in case of impact *)
|
||
|
||
nProfs : Int; (* current number of Profiles *)
|
||
|
||
Etat : TEtats; (* State of current trace *)
|
||
|
||
Fresh : Boolean; (* Indicates a new Profile which 'Start' field *)
|
||
(* must be set *)
|
||
|
||
Joint : Boolean; (* Indicates that the last arc stopped sharp *)
|
||
(* on a scan-line. Important to get rid of *)
|
||
(* doublets *)
|
||
|
||
Buff : PStorage; (* Profiles buffer a.k.a. Render Pool *)
|
||
SizeBuff : ULong; (* current render pool's size *)
|
||
MaxBuff : ULong; (* current render pool's top *)
|
||
profCur : ULong; (* current render pool cursor *)
|
||
|
||
Cible : TT_Raster_Map; (* Description of target map *)
|
||
|
||
BWidth : integer;
|
||
BCible : PByte; (* target bitmap buffer *)
|
||
GCible : PByte; (* target pixmap buffer *)
|
||
|
||
TraceOfs : Int; (* current offset in target bitmap *)
|
||
TraceIncr : Int; (* increment to next line in target map *)
|
||
TraceG : Int; (* current offset in targer pixmap *)
|
||
|
||
gray_min_x : Int; (* current min x during gray rendering *)
|
||
gray_max_x : Int; (* current max x during gray rendering *)
|
||
|
||
(* Dispatch variables : *)
|
||
|
||
Proc_Sweep_Init : Function_Sweep_Init; (* Sweep initialisation *)
|
||
Proc_Sweep_Span : Function_Sweep_Span; (* Span drawing *)
|
||
Proc_Sweep_Drop : Function_Sweep_Span; (* Drop out control *)
|
||
Proc_Sweep_Step : Function_Sweep_Step; (* Sweep line step *)
|
||
|
||
Arcs : TBezierStack;
|
||
CurArc : Int; (* stack's top *)
|
||
|
||
Points : TT_Points;
|
||
|
||
Flags : PByte; (* current flags array *)
|
||
Outs : TT_PConStarts; (* current endpoints array *)
|
||
|
||
nPoints, (* current number of points *)
|
||
nContours : Int; (* current number of contours *)
|
||
|
||
LastX, (* Last and extrema coordinates during *)
|
||
LastY, (* rendering *)
|
||
MinY,
|
||
MaxY : LongInt;
|
||
|
||
{$IFDEF TURNS}
|
||
numTurns : Int;
|
||
{$ENDIF}
|
||
|
||
DropOutControl : Byte; (* current drop-out control mode *)
|
||
|
||
Count_Table : array[0..255] of Word;
|
||
(* Look-up table used to quickly count set bits in a gray 2x2 cell *)
|
||
|
||
Count_Table2 : array[0..255] of Word;
|
||
(* Look-up table used to quickly count set bits in a gray 2x2 cell *)
|
||
|
||
Grays : array[0..4] of Byte;
|
||
(* gray palette used during gray-levels rendering *)
|
||
(* 0 : background .. 4 : foreground *)
|
||
|
||
Gray_Lines : PByte; { 2 intermediate bitmap lines }
|
||
Gray_Width : integer; { width of the 'gray' lines in pixels }
|
||
|
||
{$IFDEF SMOOTH}
|
||
Smooth_Cols : integer;
|
||
Smooths : array[0..16] of Byte;
|
||
(* smooth palette used during smooth-levels rendering *)
|
||
(* 0 : background...16 : foreground *)
|
||
|
||
smooth_pass : integer;
|
||
{$ENDIF}
|
||
|
||
Second_Pass : boolean;
|
||
(* indicates wether an horizontal pass should be performed *)
|
||
(* to control drop-out accurately when calling Render_Glyph *)
|
||
(* Note that there is no horizontal pass during gray render *)
|
||
|
||
(* better set it off at ppem >= 18 *)
|
||
|
||
Band_Stack : array[1..16] of TBand;
|
||
Band_Top : Int;
|
||
|
||
|
||
|
||
{$IFDEF DEBUG3}
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Pset *)
|
||
(* *)
|
||
(* Description: Used only in the "DEBUG3" state. *)
|
||
(* *)
|
||
(* This procedure simply plots a point on the video screen *)
|
||
(* Note that it relies on the value of cProfile->start, *)
|
||
(* which may sometimes not be set yet when Pset is called. *)
|
||
(* This will usually result in a dot plotted on the first *)
|
||
(* screen scanline ( far away its original position ). *)
|
||
(* *)
|
||
(* This "bug" means not that the current implementation is *)
|
||
(* buggy, as the bitmap will be rendered correctly, so don't *)
|
||
(* panic if you see 'flying' dots in debugging mode *)
|
||
(* *)
|
||
(* *)
|
||
(* Input: None *)
|
||
(* *)
|
||
(* Returns: Nada *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Clear_Band *)
|
||
(* *)
|
||
(* Description: Clears a Band on screen during DEBUG3 rendering *)
|
||
(* *)
|
||
(* Input: y1, y2 top and bottom of screen-wide band *)
|
||
(* *)
|
||
(* Returns: Nada. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
procedure ClearBand( y1, y2 : Int );
|
||
var
|
||
Y : Int;
|
||
K : Word;
|
||
begin
|
||
K := y1*80;
|
||
FillChar( Vio^[k], (y2-y1+1)*80, 0 );
|
||
end;
|
||
{$ENDIF}
|
||
|
||
{$IFNDEF CONST_PREC}
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Set_High_Precision *)
|
||
(* *)
|
||
(* Description: Sets precision variables according to param flag *)
|
||
(* *)
|
||
(* Input: High set to True for high precision ( typically for *)
|
||
(* ppem < 18 ), false otherwise. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
{$ENDIF}
|
||
|
||
procedure Set_Second_Pass( Pass : boolean );
|
||
begin
|
||
second_pass := pass;
|
||
end;
|
||
|
||
|
||
function TRUNC( x : Long ) : Long; {$IFDEF INLINE} inline; {$ENDIF}
|
||
begin
|
||
Trunc := (x and -Precision) div Precision;
|
||
end;
|
||
|
||
function FRAC( x : Long ) : Int; {$IFDEF INLINE} inline; {$ENDIF}
|
||
begin
|
||
Frac := x and (Precision-1);
|
||
end;
|
||
|
||
function FLOOR( x : Long ) : Long; {$IFDEF INLINE} inline; {$ENDIF}
|
||
begin
|
||
Floor := x and -Precision;
|
||
end;
|
||
|
||
function CEILING( x : Long ) : Long; {$IFDEF INLINE} inline; {$ENDIF}
|
||
begin
|
||
Ceiling := (x + Precision-1) and -Precision;
|
||
end;
|
||
|
||
function SCALED( x : Long ) : Long; {$IFDEF INLINE} inline; {$ENDIF}
|
||
begin
|
||
SCALED := (x shl scale_shift) - precision_half;
|
||
end;
|
||
|
||
{$IFDEF USE32} (* speed things a bit on 32-bit systems *)
|
||
function MulDiv( a, b, c : Long ) : Long; {$IFDEF INLINE} inline; {$ENDIF}
|
||
begin
|
||
MulDiv := a*b div c;
|
||
end;
|
||
{$ENDIF}
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: New_Profile *)
|
||
(* *)
|
||
(* Description: Creates a new Profile in the render pool *)
|
||
(* *)
|
||
(* Input: AEtat state/orientation of the new Profile *)
|
||
(* *)
|
||
(* Returns: True on sucess *)
|
||
(* False in case of overflow or of incoherent Profile *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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
|
||
{$IFDEF DEBUG}
|
||
Writeln('ERROR : Incoherent Profile' );
|
||
Halt(30);
|
||
{$ELSE}
|
||
New_Profile := False;
|
||
Error := Err_Ras_Invalid;
|
||
exit;
|
||
{$ENDIF}
|
||
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;
|
||
|
||
{$IFDEF TURNS}
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Insert_Y_Turn *)
|
||
(* *)
|
||
(* Description: Insert a slaient into the sorted list *)
|
||
(* *)
|
||
(* Input: new y turn *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
procedure Insert_Y_Turn( y : Int );
|
||
var
|
||
y_turns : PStorage;
|
||
y2, n : Int;
|
||
begin
|
||
n := numTurns-1;
|
||
y_turns := @Buff^[SizeBuff-numTurns];
|
||
|
||
(* look for first y value that is <= *)
|
||
while (n >= 0) and (y < y_turns^[n]) do dec(n);
|
||
|
||
(* if it is <, simply insert it, ignor if we found one == *)
|
||
|
||
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;
|
||
{$ENDIF}
|
||
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: End_Profile *)
|
||
(* *)
|
||
(* Description: Finalizes the current Profile. *)
|
||
(* *)
|
||
(* Input: None *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False on overflow or incoherency. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Finalize_Profile_Table *)
|
||
(* *)
|
||
(* Description: Adjusts all links in the Profiles list *)
|
||
(* *)
|
||
(* Input: None *)
|
||
(* *)
|
||
(* Returns: Nada *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
{$IFDEF TURNS}
|
||
Insert_Y_Turn( Bottom );
|
||
Insert_Y_Turn( Top+1 );
|
||
{$ENDIF}
|
||
P := Link;
|
||
|
||
dec( n );
|
||
end;
|
||
end
|
||
else
|
||
fProfile := nil;
|
||
|
||
end;
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Split_Bezier *)
|
||
(* *)
|
||
(* Description: Subdivises one Bezier arc into two joint *)
|
||
(* sub-arcs in the Bezier stack. *)
|
||
(* *)
|
||
(* Input: None ( subdivised bezier is taken from the top of the *)
|
||
(* stack ) *)
|
||
(* *)
|
||
(* Returns: Nada *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
procedure Split_Bezier( base : PBezierStack );
|
||
var
|
||
arc : PBezierStack;
|
||
a, b : Long;
|
||
begin
|
||
{$IFNDEF NO_ASM}
|
||
asm
|
||
push esi
|
||
push ebx
|
||
push ecx
|
||
|
||
mov esi, base
|
||
|
||
mov eax, [esi+2*8] (* arc^[4].x := arc^[2].x *)
|
||
mov ebx, [esi+1*8] (* b := arc^[1].x *)
|
||
mov ecx, [esi+0*8] (* b := (arc^[0].x+b) div 2 *)
|
||
|
||
mov [esi+4*8], eax
|
||
|
||
add eax, ebx (* a := (arc^[2].x+b) div 2 *)
|
||
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 (* arc^[3].x := a *)
|
||
mov [esi+1*8], ebx
|
||
|
||
add eax, ebx (* arc[2].x := (a+b) div 2 *)
|
||
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] (* arc^[4].x := arc^[2].x *)
|
||
mov ebx, [esi+1*8] (* b := arc^[1].x *)
|
||
mov ecx, [esi+0*8] (* b := (arc^[0].x+b) div 2 *)
|
||
|
||
mov [esi+4*8], eax
|
||
|
||
add eax, ebx (* a := (arc^[2].x+b) div 2 *)
|
||
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 (* arc^[3].x := a *)
|
||
mov [esi+1*8], ebx
|
||
|
||
add eax, ebx (* arc[2].x := (a+b) div 2 *)
|
||
mov edx, eax
|
||
sar edx, 31
|
||
sub eax, edx
|
||
sar eax, 1
|
||
mov [esi+2*8], eax
|
||
|
||
pop ecx
|
||
pop ebx
|
||
pop esi
|
||
end;
|
||
{$ELSE}
|
||
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;
|
||
{$ENDIF}
|
||
end;
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Push_Bezier *)
|
||
(* *)
|
||
(* Description: Clears the Bezier stack and pushes a new Arc on top of it. *)
|
||
(* *)
|
||
(* Input: x1,y1 x2,y2 x3,y3 new Bezier arc *)
|
||
(* *)
|
||
(* Returns: nada *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Compute the x-coordinates of an ascending line segment *)
|
||
(* and stores them in the render pool. *)
|
||
(* *)
|
||
(* Input: x1,y1 x2,y2 Segment start (x1,y1) and end (x2,y2) points *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if Render Pool overflow. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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
|
||
(* x2 := x2 + MulDiv( Dx, MaxY-y2, Dy ); *)
|
||
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);
|
||
|
||
(* Indicates that the segment stopped sharp on a ScanLine *)
|
||
|
||
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;
|
||
{top := @Buff^[profCur];}
|
||
|
||
while size > 0 do
|
||
begin
|
||
Buff^[profCur] := x1;
|
||
{$IFDEF DEBUG3} Pset; {$ENDIF}
|
||
inc( profCur );
|
||
{top := @top^[1];}
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Compute the x-coordinates of a descending line segment *)
|
||
(* and stores them in the render pool. *)
|
||
(* *)
|
||
(* Input: x1,y1 x2,y2 Segment start (x1,y1) and end (x2,y2) points *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if Render Pool overflow. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Compute the x-coordinates of an ascending bezier arc *)
|
||
(* and stores them in the render pool. *)
|
||
(* *)
|
||
(* Input: None.The arc is taken from the top of the Bezier stack. *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if Render Pool overflow. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
(* ^ Ce test permet d'<27>viter les doublons *)
|
||
|
||
Buff^[profCur] := base^[2].x;
|
||
{$IFDEF DEBUG3} Pset; {$ENDIF}
|
||
inc( profCur );
|
||
inc( e, Precision );
|
||
end
|
||
end;
|
||
|
||
if Fresh then
|
||
begin
|
||
cProfile^.Start := TRUNC(e0);
|
||
Fresh := False;
|
||
end;
|
||
|
||
if e2 < e then
|
||
goto Fin;
|
||
|
||
(* overflow ? *)
|
||
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 );
|
||
|
||
{$IFDEF DEBUG3} Pset; {$ENDIF}
|
||
|
||
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;
|
||
{$IFDEF DEBUG3} Pset; {$ENDIF}
|
||
inc( profCur );
|
||
inc( e, Precision );
|
||
end;
|
||
dec( cArc, 2 );
|
||
base := @Arcs[cArc];
|
||
end
|
||
end;
|
||
|
||
Fin:
|
||
dec( curArc, 2);
|
||
exit;
|
||
end;
|
||
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Bezier_Down *)
|
||
(* *)
|
||
(* Description: Compute the x-coordinates of a descending bezier arc *)
|
||
(* and stores them in the render pool. *)
|
||
(* *)
|
||
(* Input: None. Arc is taken from the top of the Bezier stack. *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if Render Pool overflow. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Injects a new line segment and adjust Profiles list. *)
|
||
(* *)
|
||
(* Input: x, y : segment endpoint ( start point in LastX,LastY ) *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if Render Pool overflow or Incorrect Profile *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Determines the state (ascending/descending/flat/undet) *)
|
||
(* of a Bezier arc, along one given axis. *)
|
||
(* *)
|
||
(* Input: y1, y2, y3 : coordinates of the Bezier arc. *)
|
||
(* along the concerned axis. *)
|
||
(* *)
|
||
(* Returns: State, i.e. Ascending, Descending, Flat or Undetermined *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
|
||
function Bezier_State( y1, y2, y3 : TT_F26Dot6 ) : TEtats;
|
||
begin
|
||
(* determine orientation of a Bezier arc *)
|
||
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 *)
|
||
(* *)
|
||
(* Description: Injects a new bezier arc and adjust Profiles list. *)
|
||
(* *)
|
||
(* Input: x, y : arc endpoint ( start point in LastX, LastY ) *)
|
||
(* Cx, Cy : control point *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if Render Pool overflow or Incorrect Profile *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
|
||
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;
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: DecomposeCurve *)
|
||
(* *)
|
||
(* Description: This functions scans the outline arrays in order to *)
|
||
(* emit individual segments and beziers by calling the *)
|
||
(* functions Line_To and Bezier_To. It handles all weird *)
|
||
(* cases, like when the first point is off the curve, or *)
|
||
(* when there are simply no "on" points in the contour ! *)
|
||
(* *)
|
||
(* Input: xCoord, yCoord : array coordinates to use. *)
|
||
(* first, last : indexes of first and last point in *)
|
||
(* contour. *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if case of error. *)
|
||
(* *)
|
||
(* Notes: The function assumes that 'first' < 'last' *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
procedure swap( var x, y : Long ); {$IFDEF INLINE} inline; {$ENDIF}
|
||
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; (* current point *)
|
||
cx, cy : Long; (* current Bezier control point *)
|
||
mx, my : Long; (* middle point *)
|
||
|
||
x_first, y_first : Long; (* first point coordinates *)
|
||
x_last, y_last : Long; (* last point coordinates *)
|
||
|
||
on_curve : Boolean;
|
||
begin
|
||
|
||
DecomposeCurve := False;
|
||
|
||
(* the following code is miscompiled by Virtual Pascal 1.1 *)
|
||
(* although it works OK with 2.0, strange... *)
|
||
(*
|
||
with points^[first] do
|
||
begin
|
||
x_first := SCALED( x );
|
||
y_first := SCALED( y );
|
||
end;
|
||
*)
|
||
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;
|
||
|
||
(* check first point, and set origin *)
|
||
if not on_curve then
|
||
begin
|
||
(* first point is off the curve - yes, this happens !! *)
|
||
|
||
if Flags^[last] and 1 <> 0 then
|
||
begin
|
||
LastX := x_last; (* start at last point if it is *)
|
||
LastY := y_last; (* on the curve *)
|
||
end
|
||
else
|
||
begin
|
||
LastX := (LastX + x_last) div 2; (* if both first and last point *)
|
||
LastY := (LastY + y_last) div 2; (* are off the curve, start midway *)
|
||
|
||
(* record midpoint in x_last,y_last *)
|
||
x_last := LastX;
|
||
y_last := LastY;
|
||
end;
|
||
end;
|
||
|
||
(* now process each contour point *)
|
||
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
|
||
(* the previous point was on the curve *)
|
||
|
||
on_curve := Flags^[index] and 1 <> 0;
|
||
if on_curve then
|
||
begin
|
||
(* two successive on points -> emit segment *)
|
||
if not Line_To( x, y ) then exit;
|
||
end
|
||
else
|
||
begin
|
||
(* else, keep current point as control for next bezier *)
|
||
cx := x;
|
||
cy := y;
|
||
end;
|
||
end
|
||
else
|
||
begin
|
||
(* the previous point was off the curve *)
|
||
|
||
on_curve := Flags^[index] and 1 <> 0;
|
||
if on_curve then
|
||
begin
|
||
(* reaching on point -> emit Bezier *)
|
||
if not Bezier_To( x, y, cx, cy ) then exit;
|
||
end
|
||
else
|
||
begin
|
||
(* two successive off points -> create middle point *)
|
||
(* then emit Bezier *)
|
||
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;
|
||
|
||
(* end of contour, close curve cleanly *)
|
||
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 *)
|
||
(* *)
|
||
(* Description: Converts a glyph into a series of segments and arcs *)
|
||
(* and make a Profiles list with them. *)
|
||
(* *)
|
||
(* Input: _xCoord, _yCoord : coordinates tables. *)
|
||
(* *)
|
||
(* Uses the 'Flag' table too. *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if any error was encountered during render. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
{$IFDEF TURNS}
|
||
numTurns := 0;
|
||
{$ENDIF}
|
||
|
||
cProfile := PProfile( @Buff^[profCur] );
|
||
cProfile^.Offset := profCur;
|
||
nProfs := 0;
|
||
|
||
for i := 0 to nContours-1 do
|
||
begin
|
||
|
||
Etat := Indetermine;
|
||
gProfile := nil;
|
||
|
||
(* decompose a single contour into individual segments and *)
|
||
(* beziers *)
|
||
|
||
if not DecomposeCurve( j, outs^[i], flipped ) then exit;
|
||
j := outs^[i] + 1;
|
||
|
||
(* We _must_ take care of the case when the first and last arcs join *)
|
||
(* while having the same orientation *)
|
||
|
||
if ( Frac(lastY) = 0 ) and
|
||
( lastY >= MinY ) and
|
||
( lastY <= MaxY ) then
|
||
|
||
if ( gProfile <> nil ) and (* gProfile can be nil *)
|
||
( gProfile^.Flow = cProfile^.Flow ) then (* if the contour was *)
|
||
(* too small to be drawn *)
|
||
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;
|
||
|
||
|
||
(************************************************)
|
||
(* *)
|
||
(* Init_Linked *)
|
||
(* *)
|
||
(* Init an empty linked list. *)
|
||
(* *)
|
||
(************************************************)
|
||
|
||
procedure Init_Linked( var L : PProfile );
|
||
begin
|
||
L := nil;
|
||
end;
|
||
|
||
(************************************************)
|
||
(* *)
|
||
(* InsNew : *)
|
||
(* *)
|
||
(* Inserts a new Profile in a linked list. *)
|
||
(* *)
|
||
(************************************************)
|
||
|
||
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;
|
||
|
||
(************************************************)
|
||
(* *)
|
||
(* DelOld : *)
|
||
(* *)
|
||
(* Removes an old Profile from a linked list *)
|
||
(* *)
|
||
(************************************************)
|
||
|
||
|
||
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;
|
||
|
||
{$IFDEF ASSERT}
|
||
Writeln('(Raster:DelOld) Incoherent deletion');
|
||
halt(9);
|
||
{$ENDIF}
|
||
end;
|
||
|
||
|
||
{$IFDEF TURNS}
|
||
(************************************************)
|
||
(* *)
|
||
(* Update: *)
|
||
(* *)
|
||
(* Update all X offsets in a drawing list *)
|
||
(* *)
|
||
(************************************************)
|
||
|
||
procedure Update( var List : PProfile );
|
||
var
|
||
current : PProfile;
|
||
begin
|
||
(* recompute coordinates *)
|
||
current := list;
|
||
|
||
while current <> nil do with current^ do
|
||
begin
|
||
X := Buff^[offset];
|
||
inc( offset, flow );
|
||
dec( height );
|
||
current := link;
|
||
end;
|
||
end;
|
||
{$ENDIF}
|
||
|
||
(************************************************)
|
||
(* *)
|
||
(* Sort : *)
|
||
(* *)
|
||
(* Sorts 'quickly' (??) a trace list. *)
|
||
(* *)
|
||
(************************************************)
|
||
|
||
procedure Sort( var List : PProfile );
|
||
var
|
||
current, next : PProfile;
|
||
old : ^PProfile;
|
||
begin
|
||
|
||
(* First, recompute coordinates *)
|
||
|
||
current := list;
|
||
|
||
while current <> nil do with current^ do
|
||
begin
|
||
X := Buff^[offset];
|
||
inc( offset, flow );
|
||
dec( height );
|
||
current := link;
|
||
end;
|
||
|
||
(* Then, do the sort *)
|
||
|
||
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;
|
||
|
||
{$IFDEF TURNS}
|
||
|
||
(********************************************************************)
|
||
(* *)
|
||
(* Generic Sweep Drawing routine *)
|
||
(* *)
|
||
(* *)
|
||
(* *)
|
||
(********************************************************************)
|
||
|
||
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 the empty linked lists *)
|
||
|
||
Init_Linked( Wait );
|
||
|
||
Init_Linked( Draw_Left );
|
||
Init_Linked( Draw_Right );
|
||
|
||
Init_Linked( Drop_Left );
|
||
Init_Linked( Drop_Right );
|
||
|
||
(* First, compute min Y and max Y *)
|
||
|
||
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;
|
||
|
||
(* Check the y-turns *)
|
||
if (numTurns = 0) then
|
||
begin
|
||
Error := Err_Ras_Invalid;
|
||
exit;
|
||
end;
|
||
|
||
(* Now inits the sweeps *)
|
||
|
||
Proc_Sweep_Init( min_Y, max_Y );
|
||
|
||
(* Then compute the distance of each Profile to min Y *)
|
||
|
||
P := Wait;
|
||
while P <> nil do
|
||
begin
|
||
with P^ do CountL := (Start-min_Y);
|
||
P := P^.link;;
|
||
end;
|
||
|
||
(* Let's go *)
|
||
|
||
y := min_y;
|
||
y_height := 0;
|
||
|
||
if ( numTurns > 0 ) and
|
||
( Buff^[sizeBuff-numTurns] = min_y ) then
|
||
dec( numTurns );
|
||
|
||
while numTurns > 0 do
|
||
begin
|
||
(* Look in the wait list for new activations *)
|
||
|
||
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 the drawing lists *)
|
||
|
||
Sort( Draw_Left );
|
||
Sort( Draw_Right );
|
||
|
||
y_change := Buff^[sizebuff-numTurns];
|
||
dec( numTurns );
|
||
|
||
y_height := y_change - y;
|
||
|
||
while y < y_change do
|
||
begin
|
||
|
||
(* Let's trace *)
|
||
|
||
dropouts := 0;
|
||
|
||
P_Left := Draw_Left;
|
||
P_Right := Draw_Right;
|
||
|
||
while ( P_Left <> nil ) do
|
||
begin
|
||
|
||
{$IFDEF ASSERT}
|
||
if P_Right = nil then
|
||
Halt(13);
|
||
{$ENDIF}
|
||
|
||
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 );
|
||
|
||
(* mark profile for drop-out control *)
|
||
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;
|
||
|
||
{$IFDEF ASSERT}
|
||
if P_Right <> nil then
|
||
Halt(10);
|
||
{$ENDIF}
|
||
|
||
(* Now perform the dropouts only _after_ the span drawing *)
|
||
if (dropouts > 0) then
|
||
goto Scan_DropOuts;
|
||
|
||
Next_Line:
|
||
|
||
(* Step to next line *)
|
||
Proc_Sweep_Step;
|
||
|
||
inc(y);
|
||
|
||
if y < y_change then
|
||
begin
|
||
Update( Draw_Left );
|
||
Update( Draw_Right );
|
||
end
|
||
|
||
end;
|
||
|
||
(* We finalize the Profiles that need it *)
|
||
|
||
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;
|
||
|
||
|
||
{$ELSE}
|
||
|
||
(********************************************************************)
|
||
(* *)
|
||
(* Generic Sweep Drawing routine *)
|
||
(* *)
|
||
(* *)
|
||
(* *)
|
||
(********************************************************************)
|
||
|
||
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 the empty linked lists *)
|
||
|
||
Init_Linked( Wait );
|
||
|
||
Init_Linked( Draw_Left );
|
||
Init_Linked( Draw_Right );
|
||
|
||
Init_Linked( Drop_Left );
|
||
Init_Linked( Drop_Right );
|
||
|
||
(* First, compute min Y and max Y *)
|
||
|
||
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;
|
||
|
||
(* Now inits the sweeps *)
|
||
|
||
Proc_Sweep_Init( min_Y, max_Y );
|
||
|
||
(* Then compute the distance of each Profile to min Y *)
|
||
|
||
P := Wait;
|
||
while P <> nil do
|
||
begin
|
||
with P^ do CountL := (Start-min_Y);
|
||
P := P^.link;;
|
||
end;
|
||
|
||
(* Let's go *)
|
||
|
||
for y := min_Y to max_Y do
|
||
begin
|
||
|
||
(* Look in the wait list for new activations *)
|
||
|
||
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 the drawing lists *)
|
||
|
||
Sort( Draw_Left );
|
||
Sort( Draw_Right );
|
||
|
||
(* Let's trace *)
|
||
|
||
dropouts := 0;
|
||
|
||
P_Left := Draw_Left;
|
||
P_Right := Draw_Right;
|
||
|
||
while ( P_Left <> nil ) do
|
||
begin
|
||
|
||
{$IFDEF ASSERT}
|
||
if P_Right = nil then
|
||
Halt(13);
|
||
{$ENDIF}
|
||
|
||
Q_Left := P_Left^ .Link;
|
||
Q_Right := P_Right^.Link;
|
||
|
||
{$IFDEF ASSERT}
|
||
if Q_Right = nil then
|
||
Halt(11);
|
||
{$ENDIF}
|
||
|
||
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 );
|
||
|
||
(* We finalize the Profile if needed *)
|
||
|
||
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;
|
||
|
||
{$IFDEF ASSERT}
|
||
if P_Right <> nil then
|
||
Halt(10);
|
||
{$ENDIF}
|
||
|
||
(* Now perform the dropouts only _after_ the span drawing *)
|
||
|
||
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;
|
||
|
||
(* Step to next line *)
|
||
|
||
Proc_Sweep_Step;
|
||
|
||
end;
|
||
|
||
Draw_Sweep := True;
|
||
|
||
end;
|
||
|
||
{$ENDIF}
|
||
|
||
{$F+ Far calls are necessary for function pointers under BP7}
|
||
{ This flag is currently ignored by the Virtual Compiler }
|
||
|
||
(***********************************************************************)
|
||
(* *)
|
||
(* Vertical Sweep Procedure Set : *)
|
||
(* *)
|
||
(* These three routines are used during the vertical black/white *)
|
||
(* sweep phase by the generic Draw_Sweep function. *)
|
||
(* *)
|
||
(***********************************************************************)
|
||
|
||
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
|
||
{$IFNDEF NO_ASM}
|
||
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;
|
||
{$ELSE}
|
||
|
||
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;
|
||
{$ENDIF}
|
||
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
|
||
|
||
(* Drop-out control *)
|
||
|
||
e1 := ( x1+Precision-1 ) and Precision_Mask;
|
||
e2 := x2 and Precision_Mask;
|
||
|
||
(* We are guaranteed that x2-x1 <= Precision here *)
|
||
|
||
if e1 > e2 then
|
||
if e1 = e2 + Precision then
|
||
|
||
case DropOutControl of
|
||
|
||
(* Drop-out Control Rule #3 *)
|
||
1 : e1 := e2;
|
||
|
||
4 : begin
|
||
e1 := ((x1+x2+1) div 2 + Precision-1) and Precision_Mask;
|
||
e2 := e1;
|
||
end;
|
||
|
||
(* Drop-out Control Rule #4 *)
|
||
|
||
(* The spec is not very clear regarding rule #4. It *)
|
||
(* presents a method that is way too costly to implement *)
|
||
(* while the general idea seems to get rid of 'stubs'. *)
|
||
(* *)
|
||
(* Here, we only get rid of stubs recognized when : *)
|
||
(* *)
|
||
(* upper stub : *)
|
||
(* *)
|
||
(* - P_Left and P_Right are in the same contour *)
|
||
(* - P_Right is the successor of P_Left in that contour *)
|
||
(* - y is the top of P_Left and P_Right *)
|
||
(* *)
|
||
(* lower stub : *)
|
||
(* *)
|
||
(* - P_Left and P_Right are in the same contour *)
|
||
(* - P_Left is the successor of P_Right in that contour *)
|
||
(* - y is the bottom of P_Left *)
|
||
(* *)
|
||
|
||
2,5 : begin
|
||
|
||
if ( x2-x1 < Precision_Half ) then
|
||
begin
|
||
(* upper stub test *)
|
||
|
||
if ( Left^.next = Right ) and
|
||
( Left^.Height <= 0 ) then exit;
|
||
|
||
(* lower stub test *)
|
||
|
||
if ( Right^.next = Left ) and
|
||
( Left^.Start = y ) then exit;
|
||
end;
|
||
|
||
(* Check that the rightmost pixel is not already set *)
|
||
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; (* unsupported mode *)
|
||
end
|
||
|
||
else
|
||
else
|
||
e2 := e1; (* when x1 = e1, x2 = e2, e2 = e1 + 64 *)
|
||
|
||
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;
|
||
|
||
|
||
(***********************************************************************)
|
||
(* *)
|
||
(* Horizontal Sweep Procedure Set : *)
|
||
(* *)
|
||
(* These three routines are used during the horizontal black/white *)
|
||
(* sweep phase by the generic Draw_Sweep function. *)
|
||
(* *)
|
||
(***********************************************************************)
|
||
|
||
procedure Horizontal_Sweep_Init( var min, max : Int );
|
||
begin
|
||
(* Nothing, really *)
|
||
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;
|
||
|
||
{$IFDEF RIEN}
|
||
e1 := ( x1+(Precision-1) ) and Precision_Mask;
|
||
e2 := x2 and Precision_Mask;
|
||
|
||
(* We are here guaranteed that x2-x1 > Precision *)
|
||
|
||
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;
|
||
{$ENDIF}
|
||
|
||
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;
|
||
|
||
(* During the horizontal sweep, we only take care of drop-outs *)
|
||
|
||
if e1 > e2 then
|
||
if e1 = e2 + Precision then
|
||
|
||
case DropOutControl of
|
||
|
||
0 : exit;
|
||
|
||
(* Drop-out Control Rule #3 *)
|
||
1 : e1 := e2;
|
||
|
||
4 : begin
|
||
e1 := ( (x1+x2) div 2 +Precision div 2 ) and Precision_Mask;
|
||
e2 := e1;
|
||
end;
|
||
|
||
(* Drop-out Control Rule #4 *)
|
||
|
||
(* The spec is not very clear regarding rule #4. It *)
|
||
(* presents a method that is way too costly to implement *)
|
||
(* while the general idea seems to get rid of 'stubs'. *)
|
||
(* *)
|
||
|
||
2,5 : begin
|
||
|
||
(* rightmost stub test *)
|
||
|
||
if ( Left^.next = Right ) and
|
||
( Left^.Height <= 0 ) then exit;
|
||
|
||
(* leftmost stub test *)
|
||
|
||
if ( Right^.next = Left ) and
|
||
( Left^.Start = y ) then exit;
|
||
|
||
(* Check that the upmost pixel is not already set *)
|
||
|
||
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; (* Unsupported mode *)
|
||
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
|
||
(* Nothing, really *)
|
||
end;
|
||
|
||
(***********************************************************************)
|
||
(* *)
|
||
(* Vertical Gray Sweep Procedure Set : *)
|
||
(* *)
|
||
(* These two routines are used during the vertical gray-levels *)
|
||
(* sweep phase by the generic Draw_Sweep function. *)
|
||
(* *)
|
||
(* *)
|
||
(* NOTES : *)
|
||
(* *)
|
||
(* - The target pixmap's width *must* be a multiple of 4 *)
|
||
(* *)
|
||
(* - you have to use the function Vertical_Sweep_Span for *)
|
||
(* the gray span call. *)
|
||
(* *)
|
||
(***********************************************************************)
|
||
|
||
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;
|
||
|
||
(***********************************************************************)
|
||
(* *)
|
||
(* Horizontal Gray Sweep Procedure Set : *)
|
||
(* *)
|
||
(* These three routines are used during the horizontal gray-levels *)
|
||
(* sweep phase by the generic Draw_Sweep function. *)
|
||
(* *)
|
||
(***********************************************************************)
|
||
|
||
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);
|
||
(* if Cible.flow = TT_Flow_Up then *)
|
||
j := y + e1*Cible.cols;
|
||
(* else
|
||
// j := c1 + (Cible.rows-1-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);
|
||
(* if Cible.flow = TT_Flow_Up then *)
|
||
j := y + e2*Cible.cols;
|
||
(* else
|
||
// j := c1 + (Cible.rows-1-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;
|
||
|
||
(* During the horizontal sweep, we only take care of drop-outs *)
|
||
|
||
if e1 > e2 then
|
||
if e1 = e2 + Precision then
|
||
|
||
case DropOutControl of
|
||
|
||
0 : exit;
|
||
|
||
(* Drop-out Control Rule #3 *)
|
||
1 : e1 := e2;
|
||
|
||
4 : begin
|
||
e1 := ( (x1+x2) div 2 +Precision div 2 ) and Precision_Mask;
|
||
e2 := e1;
|
||
end;
|
||
|
||
(* Drop-out Control Rule #4 *)
|
||
|
||
(* The spec is not very clear regarding rule #4. It *)
|
||
(* presents a method that is way too costly to implement *)
|
||
(* while the general idea seems to get rid of 'stubs'. *)
|
||
(* *)
|
||
|
||
2,5 : begin
|
||
|
||
(* lowest stub test *)
|
||
|
||
if ( Left^.next = Right ) and
|
||
( Left^.Height <= 0 ) then exit;
|
||
|
||
(* upper stub test *)
|
||
|
||
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; (* Unsupported mode *)
|
||
end;
|
||
|
||
if (e1 >= 0) then
|
||
begin
|
||
(* A small trick to make 'average' thin line appear in *)
|
||
(* medium gray.. *)
|
||
|
||
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;
|
||
|
||
{$IFDEF SMOOTH}
|
||
|
||
(***********************************************************************)
|
||
(* *)
|
||
(* Vertical Smooth Sweep Procedure Set : *)
|
||
(* *)
|
||
(* These two routines are used during the vertical smooth-levels *)
|
||
(* sweep phase by the generic Draw_Sweep function. *)
|
||
(* *)
|
||
(* *)
|
||
(* NOTES : *)
|
||
(* *)
|
||
(* - The target pixmap's width *must* be a multiple of 2 *)
|
||
(* *)
|
||
(* - you have to use the function Vertical_Sweep_Span for *)
|
||
(* the smooth span call. *)
|
||
(* *)
|
||
(***********************************************************************)
|
||
|
||
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;
|
||
(*
|
||
for i := 0 to Smooth_Cols-1 do
|
||
GCible^[i] := 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;
|
||
|
||
{$ENDIF}
|
||
|
||
{$F- End of dispatching functions definitions }
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Render_Single_Pass *)
|
||
(* *)
|
||
(* Description: Performs one sweep with sub-banding. *)
|
||
(* *)
|
||
(* Input: _XCoord, _YCoord : x and y coordinates arrays *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if any error was encountered during render. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
(* sub-banding *)
|
||
|
||
{$IFDEF DEBUG3}
|
||
ClearBand( MinY shr Precision_Bits, MaxY shr Precision_Bits );
|
||
{$ENDIF}
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Renders a glyph in a bitmap. Sub-banding if needed *)
|
||
(* *)
|
||
(* Input: AGlyph Glyph record *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if any error was encountered during render. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
(* Vertical Sweep *)
|
||
|
||
{$IFDEF FPC}
|
||
Proc_Sweep_Init := @Vertical_Sweep_Init;
|
||
Proc_Sweep_Span := @Vertical_Sweep_Span;
|
||
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
|
||
Proc_Sweep_Step := @Vertical_Sweep_Step;
|
||
{$ELSE}
|
||
Proc_Sweep_Init := Vertical_Sweep_Init;
|
||
Proc_Sweep_Span := Vertical_Sweep_Span;
|
||
Proc_Sweep_Drop := Vertical_Sweep_Drop;
|
||
Proc_Sweep_Step := Vertical_Sweep_Step;
|
||
{$ENDIF}
|
||
|
||
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;
|
||
|
||
(* Horizontal Sweep *)
|
||
|
||
if Second_Pass then
|
||
begin
|
||
|
||
{$IFDEF FPC}
|
||
Proc_Sweep_Init := @Horizontal_Sweep_Init;
|
||
Proc_Sweep_Span := @Horizontal_Sweep_Span;
|
||
Proc_Sweep_Drop := @Horizontal_Sweep_Drop;
|
||
Proc_Sweep_Step := @Horizontal_Sweep_Step;
|
||
{$ELSE}
|
||
Proc_Sweep_Init := Horizontal_Sweep_Init;
|
||
Proc_Sweep_Span := Horizontal_Sweep_Span;
|
||
Proc_Sweep_Drop := Horizontal_Sweep_Drop;
|
||
Proc_Sweep_Step := Horizontal_Sweep_Step;
|
||
{$ENDIF}
|
||
|
||
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 *)
|
||
(* *)
|
||
(* Description: Renders a glyph with grayscaling. Sub-banding if needed *)
|
||
(* *)
|
||
(* Input: AGlyph Glyph record *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if any error was encountered during render. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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 );
|
||
|
||
{$IFDEF FPC}
|
||
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;
|
||
{$ELSE}
|
||
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;
|
||
{$ENDIF}
|
||
|
||
if not Render_Single_Pass( False ) then exit;
|
||
|
||
(* Horizontal Sweep *)
|
||
|
||
if Second_Pass then
|
||
begin
|
||
|
||
{$IFDEF FPC}
|
||
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;
|
||
{$ELSE}
|
||
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;
|
||
{$ENDIF}
|
||
|
||
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;
|
||
|
||
{$IFDEF SMOOTH}
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Render_Smooth_Glyph *)
|
||
(* *)
|
||
(* Description: Renders a glyph with grayscaling. Sub-banding if needed *)
|
||
(* *)
|
||
(* Input: AGlyph Glyph record *)
|
||
(* *)
|
||
(* Returns: True on success *)
|
||
(* False if any error was encountered during render. *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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^;
|
||
(*
|
||
if palette <> nil then
|
||
move( palette^, Grays, 5 );
|
||
*)
|
||
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 );
|
||
|
||
{$IFDEF FPK}
|
||
Proc_Sweep_Init := @Smooth_Sweep_Init;
|
||
Proc_Sweep_Span := @Vertical_Sweep_Span;
|
||
Proc_Sweep_Drop := @Vertical_Sweep_Drop;
|
||
Proc_Sweep_Step := @Smooth_Sweep_Step;
|
||
{$ELSE}
|
||
Proc_Sweep_Init := Smooth_Sweep_Init;
|
||
Proc_Sweep_Span := Vertical_Sweep_Span;
|
||
Proc_Sweep_Drop := Vertical_Sweep_Drop;
|
||
Proc_Sweep_Step := Smooth_Sweep_Step;
|
||
{$ENDIF}
|
||
|
||
if not Render_Single_Pass( Glyph.XCoord, Glyph.YCoord ) then exit;
|
||
|
||
Render_Smooth_Glyph := Success;
|
||
|
||
end;
|
||
|
||
{$ENDIF}
|
||
|
||
(****************************************************************************)
|
||
(* *)
|
||
(* Function: Init_Rasterizer *)
|
||
(* *)
|
||
(* Description: Initializes the rasterizer. *)
|
||
(* *)
|
||
(* Input: rasterBlock target bitmap/pixmap description *)
|
||
(* profBuffer pointer to the render pool *)
|
||
(* profSize size in bytes of the render pool *)
|
||
(* *)
|
||
(* Returns: 1 ( always, but we should check parameters ) *)
|
||
(* *)
|
||
(****************************************************************************)
|
||
|
||
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;
|
||
|
||
{$IFDEF SMOOTH}
|
||
Smooth_Cols := Gray_Lines_Size div 4;
|
||
{$ENDIF}
|
||
|
||
{ Initialisation of Count_Table }
|
||
|
||
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;
|
||
|
||
(* default Grays takes the gray levels of the standard VGA *)
|
||
(* 256 colors mode *)
|
||
|
||
Grays[0] := 0;
|
||
Grays[1] := 23;
|
||
Grays[2] := 27;
|
||
Grays[3] := 29;
|
||
Grays[4] := 31;
|
||
|
||
|
||
{$IFDEF SMOOTH}
|
||
|
||
{ Initialisation of Count_Table2 }
|
||
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 );
|
||
{$ENDIF}
|
||
|
||
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.
|