mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-20 08:25:59 +02:00
337 lines
6.6 KiB
ObjectPascal
337 lines
6.6 KiB
ObjectPascal
//----------------------------------------------------------------------------
|
|
// Anti-Grain Geometry - Version 2.4 (Public License)
|
|
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
|
//
|
|
// Anti-Grain Geometry - Version 2.4 Release Milano 3 (AggPas 2.4 RM3)
|
|
// Pascal Port By: Milan Marusinec alias Milano
|
|
// milan@marusinec.sk
|
|
// http://www.aggpas.org
|
|
// Copyright (c) 2005-2006
|
|
//
|
|
// Permission to copy, use, modify, sell and distribute this software
|
|
// is granted provided this copyright notice appears in all copies.
|
|
// This software is provided "as is" without express or implied
|
|
// warranty, and with no claim as to its suitability for any purpose.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
// Contact: mcseem@antigrain.com
|
|
// mcseemagg@yahoo.com
|
|
// http://www.antigrain.com
|
|
//
|
|
// [Pascal Port History] -----------------------------------------------------
|
|
//
|
|
// 23.06.2006-Milano: ptrcomp adjustments
|
|
// 31.01.2006-Milano: Unit port establishment
|
|
//
|
|
{ agg_span_gouraud_gray.pas }
|
|
unit
|
|
agg_span_gouraud_gray ;
|
|
|
|
INTERFACE
|
|
|
|
{$I agg_mode.inc }
|
|
|
|
uses
|
|
agg_basics ,
|
|
agg_color ,
|
|
agg_dda_line ,
|
|
agg_span_gouraud ,
|
|
agg_span_allocator ,
|
|
agg_math ;
|
|
|
|
{ TYPES DEFINITION }
|
|
const
|
|
subpixel_shift = 4;
|
|
subpixel_size = 1 shl subpixel_shift;
|
|
|
|
type
|
|
gray_calc_ptr = ^gray_calc;
|
|
gray_calc = object
|
|
m_x1 ,m_y1 ,m_dx ,m_1dy : double;
|
|
|
|
m_v1 ,m_a1 ,
|
|
m_dv ,m_da ,
|
|
m_v ,m_a ,m_x : int;
|
|
|
|
function round(v : double ) : int;
|
|
procedure init (c1 ,c2 : coord_type_ptr );
|
|
procedure calc (y : double );
|
|
|
|
end;
|
|
|
|
span_gouraud_gray = object(span_gouraud )
|
|
m_swap : boolean;
|
|
m_y2 : int;
|
|
|
|
m_c1 ,
|
|
m_c2 ,
|
|
m_c3 : gray_calc;
|
|
|
|
constructor Construct(alloc : span_allocator_ptr ); overload;
|
|
constructor Construct(
|
|
alloc : span_allocator_ptr;
|
|
c1 ,c2 ,c3 : aggclr_ptr;
|
|
x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,d : double ); overload;
|
|
|
|
procedure prepare (max_span_len : unsigned ); virtual;
|
|
function generate(x ,y : int; len : unsigned ) : aggclr_ptr; virtual;
|
|
|
|
end;
|
|
|
|
{ GLOBAL PROCEDURES }
|
|
|
|
|
|
IMPLEMENTATION
|
|
{ LOCAL VARIABLES & CONSTANTS }
|
|
{ UNIT IMPLEMENTATION }
|
|
{ ROUND }
|
|
function gray_calc.round;
|
|
begin
|
|
if v < 0.0 then
|
|
result:=trunc(v - 0.5 )
|
|
else
|
|
result:=trunc(v + 0.5 );
|
|
|
|
end;
|
|
|
|
{ INIT }
|
|
procedure gray_calc.init;
|
|
var
|
|
dy : double;
|
|
|
|
begin
|
|
m_x1:=c1.x - 0.5;
|
|
m_y1:=c1.y - 0.5;
|
|
m_dx:=c2.x - c1.x;
|
|
|
|
dy:=c2.y - c1.y;
|
|
|
|
if Abs(dy ) < 1e-10 then
|
|
m_1dy:=1e10
|
|
else
|
|
m_1dy:=1.0 / dy;
|
|
|
|
m_v1:=c1.color.v;
|
|
m_a1:=c1.color.a;
|
|
m_dv:=c2.color.v - m_v1;
|
|
m_da:=c2.color.a - m_a1;
|
|
|
|
end;
|
|
|
|
{ CALC }
|
|
procedure gray_calc.calc;
|
|
var
|
|
k : double;
|
|
|
|
begin
|
|
k:=(y - m_y1 ) * m_1dy;
|
|
|
|
if k < 0.0 then
|
|
k:=0.0;
|
|
|
|
if k > 1.0 then
|
|
k:=1.0;
|
|
|
|
m_v:=m_v1 + self.round(m_dv * k );
|
|
m_a:=m_a1 + self.round(m_da * k );
|
|
m_x:=self.round((m_x1 + m_dx * k ) * subpixel_size );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor span_gouraud_gray.Construct(alloc : span_allocator_ptr );
|
|
begin
|
|
inherited Construct(alloc );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor span_gouraud_gray.Construct(
|
|
alloc : span_allocator_ptr;
|
|
c1 ,c2 ,c3 : aggclr_ptr;
|
|
x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,d : double );
|
|
begin
|
|
inherited Construct(alloc ,c1 ,c2 ,c3 ,x1 ,y1 ,x2 ,y2 ,x3 ,y3 ,d );
|
|
|
|
end;
|
|
|
|
{ PREPARE }
|
|
procedure span_gouraud_gray.prepare;
|
|
var
|
|
coord : array[0..2 ] of coord_type;
|
|
|
|
begin
|
|
inherited prepare(max_span_len );
|
|
|
|
arrange_vertices(@coord );
|
|
|
|
m_y2:=trunc(coord[1 ].y );
|
|
|
|
m_swap:=
|
|
calc_point_location(
|
|
coord[0 ].x ,coord[0 ].y,
|
|
coord[2 ].x ,coord[2 ].y,
|
|
coord[1 ].x ,coord[1 ].y ) < 0.0;
|
|
|
|
m_c1.init(@coord[0 ] ,@coord[2 ] );
|
|
m_c2.init(@coord[0 ] ,@coord[1 ] );
|
|
m_c3.init(@coord[1 ] ,@coord[2 ] );
|
|
|
|
end;
|
|
|
|
{ GENERATE }
|
|
function span_gouraud_gray.generate;
|
|
const
|
|
lim = agg_color.base_mask;
|
|
|
|
var
|
|
pc1 ,pc2 ,t : gray_calc_ptr;
|
|
|
|
nlen ,start ,vv ,va : int;
|
|
|
|
v ,a : dda_line_interpolator;
|
|
span : aggclr_ptr;
|
|
|
|
begin
|
|
m_c1.calc(y );
|
|
|
|
pc1:=@m_c1;
|
|
pc2:=@m_c2;
|
|
|
|
if y < m_y2 then
|
|
// Bottom part of the triangle (first subtriangle)
|
|
m_c2.calc(y + m_c2.m_1dy )
|
|
else
|
|
begin
|
|
// Upper part (second subtriangle)
|
|
m_c3.calc(y - m_c3.m_1dy );
|
|
|
|
pc2:=@m_c3;
|
|
|
|
end;
|
|
|
|
// It means that the triangle is oriented clockwise,
|
|
// so that we need to swap the controlling structures
|
|
if m_swap then
|
|
begin
|
|
t :=pc2;
|
|
pc2:=pc1;
|
|
pc1:=t;
|
|
|
|
end;
|
|
|
|
// Get the horizontal length with subpixel accuracy
|
|
// and protect it from division by zero
|
|
nlen:=Abs(pc2.m_x - pc1.m_x );
|
|
|
|
if nlen <= 0 then
|
|
nlen:=1;
|
|
|
|
v.Construct(pc1.m_v ,pc2.m_v ,nlen ,14 );
|
|
a.Construct(pc1.m_a ,pc2.m_a ,nlen ,14 );
|
|
|
|
// Calculate the starting point of the gradient with subpixel
|
|
// accuracy and correct (roll back) the interpolators.
|
|
// This operation will also clip the beginning of the span
|
|
// if necessary.
|
|
start:=pc1.m_x - (x shl subpixel_shift );
|
|
|
|
v.dec_operator(start );
|
|
a.dec_operator(start );
|
|
|
|
inc(nlen ,start );
|
|
|
|
span:=_allocator.span;
|
|
|
|
// Beginning part of the span. Since we rolled back the
|
|
// interpolators, the color values may have overflow.
|
|
// So that, we render the beginning part with checking
|
|
// for overflow. It lasts until "start" is positive;
|
|
// typically it's 1-2 pixels, but may be more in some cases.
|
|
while (len <> 0 ) and
|
|
(start > 0 ) do
|
|
begin
|
|
vv:=v._y;
|
|
va:=a._y;
|
|
|
|
if vv < 0 then
|
|
vv:=0;
|
|
|
|
if vv > lim then
|
|
vv:=lim;
|
|
|
|
if va < 0 then
|
|
va:=0;
|
|
|
|
if va > lim then
|
|
va:=lim;
|
|
|
|
span.v:=int8u(vv );
|
|
span.a:=int8u(va );
|
|
|
|
v.inc_operator(subpixel_size );
|
|
a.inc_operator(subpixel_size );
|
|
|
|
dec(nlen ,subpixel_size );
|
|
dec(start ,subpixel_size );
|
|
inc(ptrcomp(span ) ,sizeof(aggclr ) );
|
|
dec(len );
|
|
|
|
end;
|
|
|
|
// Middle part, no checking for overflow.
|
|
// Actual spans can be longer than the calculated length
|
|
// because of anti-aliasing, thus, the interpolators can
|
|
// overflow. But while "nlen" is positive we are safe.
|
|
while (len <> 0 ) and
|
|
(nlen > 0 ) do
|
|
begin
|
|
span.v:=int8u(v._y );
|
|
span.a:=int8u(a._y );
|
|
|
|
v.inc_operator(subpixel_size );
|
|
a.inc_operator(subpixel_size );
|
|
|
|
dec(nlen ,subpixel_size );
|
|
inc(ptrcomp(span ) ,sizeof(aggclr ) );
|
|
dec(len );
|
|
|
|
end;
|
|
|
|
// Ending part; checking for overflow.
|
|
// Typically it's 1-2 pixels, but may be more in some cases.
|
|
while len <> 0 do
|
|
begin
|
|
vv:=v._y;
|
|
va:=a._y;
|
|
|
|
if vv < 0 then
|
|
vv:=0;
|
|
|
|
if vv > lim then
|
|
vv:=lim;
|
|
|
|
if va < 0 then
|
|
va:=0;
|
|
|
|
if va > lim then
|
|
va:=lim;
|
|
|
|
span.v:=int8u(vv );
|
|
span.a:=int8u(va );
|
|
|
|
v.inc_operator(subpixel_size );
|
|
a.inc_operator(subpixel_size );
|
|
|
|
inc(ptrcomp(span ) ,sizeof(aggclr ) );
|
|
dec(len );
|
|
|
|
end;
|
|
|
|
result:=_allocator.span;
|
|
|
|
end;
|
|
|
|
END.
|
|
|