lazarus/components/aggpas/src/agg_span_gouraud_gray.pas
mattias 36a2b1ea07 added aggpas
git-svn-id: trunk@21942 -
2009-10-01 12:24:32 +00:00

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.