mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-07-20 08:25:59 +02:00
394 lines
9.5 KiB
ObjectPascal
394 lines
9.5 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 4 (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
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
//
|
|
// Adaptation for 32-bit screen coordinates (scanline32_u) has been sponsored by
|
|
// Liberty Technology Systems, Inc., visit http://lib-sys.com
|
|
//
|
|
// Liberty Technology Systems, Inc. is the provider of
|
|
// PostScript and PDF technology for software developers.
|
|
//
|
|
// [Pascal Port History] -----------------------------------------------------
|
|
//
|
|
// 23.06.2006-Milano: ptrcomp adjustments
|
|
// 17.01.2006-Milano: Unit port establishment
|
|
//
|
|
{ agg_scanline_u.pas }
|
|
unit
|
|
agg_scanline_u ;
|
|
|
|
INTERFACE
|
|
|
|
{$I agg_mode.inc }
|
|
|
|
uses
|
|
agg_basics ,
|
|
agg_scanline ,
|
|
agg_alpha_mask_u8 ;
|
|
|
|
{ TYPES DEFINITION }
|
|
type
|
|
//==============================================================scanline_u
|
|
//
|
|
// Unpacked scanline container class
|
|
//
|
|
// This class is used to transfer data from a scanline rasterizer
|
|
// to the rendering buffer. It's organized very simple. The class stores
|
|
// information of horizontal spans to render it into a pixel-map buffer.
|
|
// Each span has staring X, length, and an array of bytes that determine the
|
|
// cover-values for each pixel.
|
|
// Before using this class you should know the minimal and maximal pixel
|
|
// coordinates of your scanline. The protocol of using is:
|
|
// 1. reset(min_x, max_x)
|
|
// 2. add_cell() / add_span() - accumulate scanline.
|
|
// When forming one scanline the next X coordinate must be always greater
|
|
// than the last stored one, i.e. it works only with ordered coordinates.
|
|
// 3. Call finalize(y) and render the scanline.
|
|
// 3. Call reset_spans() to prepare for the new scanline.
|
|
//
|
|
// 4. Rendering:
|
|
//
|
|
// Scanline provides an iterator class that allows you to extract
|
|
// the spans and the cover values for each pixel. Be aware that clipping
|
|
// has not been done yet, so you should perform it yourself.
|
|
// Use scanline_u8::iterator to render spans:
|
|
//-------------------------------------------------------------------------
|
|
//
|
|
// int y = sl.y(); // Y-coordinate of the scanline
|
|
//
|
|
// ************************************
|
|
// ...Perform vertical clipping here...
|
|
// ************************************
|
|
//
|
|
// scanline_u8::const_iterator span = sl.begin();
|
|
//
|
|
// unsigned char* row = m_rbuf->row(y); // The the address of the beginning
|
|
// // of the current row
|
|
//
|
|
// unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that
|
|
// // num_spans is always greater than 0.
|
|
//
|
|
// do
|
|
// {
|
|
// const scanline_u8::cover_type* covers =
|
|
// span->covers; // The array of the cover values
|
|
//
|
|
// int num_pix = span->len; // Number of pixels of the span.
|
|
// // Always greater than 0, still it's
|
|
// // better to use "int" instead of
|
|
// // "unsigned" because it's more
|
|
// // convenient for clipping
|
|
// int x = span->x;
|
|
//
|
|
// **************************************
|
|
// ...Perform horizontal clipping here...
|
|
// ...you have x, covers, and pix_count..
|
|
// **************************************
|
|
//
|
|
// unsigned char* dst = row + x; // Calculate the start address of the row.
|
|
// // In this case we assume a simple
|
|
// // grayscale image 1-byte per pixel.
|
|
// do
|
|
// {
|
|
// *dst++ = *covers++; // Hypotetical rendering.
|
|
// }
|
|
// while(--num_pix);
|
|
//
|
|
// ++span;
|
|
// }
|
|
// while(--num_spans); // num_spans cannot be 0, so this loop is quite safe
|
|
//------------------------------------------------------------------------
|
|
//
|
|
// The question is: why should we accumulate the whole scanline when we
|
|
// could render just separate spans when they're ready?
|
|
// That's because using the scanline is generally faster. When is consists
|
|
// of more than one span the conditions for the processor cash system
|
|
// are better, because switching between two different areas of memory
|
|
// (that can be very large) occurs less frequently.
|
|
//------------------------------------------------------------------------
|
|
span_u8_ptr = ^span_u8;
|
|
span_u8 = record
|
|
x ,
|
|
len : int16;
|
|
|
|
covers : int8u_ptr;
|
|
|
|
end;
|
|
|
|
scanline_u8 = object(scanline )
|
|
m_min_x : int;
|
|
m_max_len : unsigned;
|
|
m_last_x ,
|
|
m_y : int;
|
|
|
|
m_covers : int8u_ptr;
|
|
m_spans ,
|
|
m_cur_span : span_u8_ptr;
|
|
|
|
constructor Construct;
|
|
destructor Destruct;
|
|
|
|
procedure reset(min_x ,max_x : int ); virtual;
|
|
procedure reset_spans; virtual;
|
|
|
|
procedure finalize (y_ : int ); virtual;
|
|
procedure add_cell (x : int; cover : unsigned ); virtual;
|
|
procedure add_cells(x : int; len : unsigned; covers : int8u_ptr ); virtual;
|
|
procedure add_span (x : int; len ,cover : unsigned ); virtual;
|
|
|
|
function y : int; virtual;
|
|
function num_spans : unsigned; virtual;
|
|
function begin_ : pointer; virtual;
|
|
|
|
function sz_of_span : unsigned; virtual;
|
|
|
|
end;
|
|
|
|
scanline_u8_am = object(scanline_u8 )
|
|
m_alpha_mask : alpha_mask_ptr;
|
|
|
|
constructor Construct; overload;
|
|
constructor Construct(am : alpha_mask_ptr ); overload;
|
|
|
|
procedure finalize(y_ : int ); virtual;
|
|
|
|
end;
|
|
|
|
{ GLOBAL PROCEDURES }
|
|
|
|
|
|
IMPLEMENTATION
|
|
{ LOCAL VARIABLES & CONSTANTS }
|
|
{ UNIT IMPLEMENTATION }
|
|
{ CONSTRUCT }
|
|
constructor scanline_u8.Construct;
|
|
begin
|
|
m_min_x :=0;
|
|
m_max_len:=0;
|
|
m_last_x :=$7FFFFFF0;
|
|
|
|
m_covers :=NIL;
|
|
m_spans :=NIL;
|
|
m_cur_span:=NIL;
|
|
|
|
end;
|
|
|
|
{ DESTRUCT }
|
|
destructor scanline_u8.Destruct;
|
|
begin
|
|
agg_freemem(pointer(m_spans ) ,m_max_len * sizeof(span_u8 ) );
|
|
agg_freemem(pointer(m_covers ) ,m_max_len * sizeof(int8u ) );
|
|
|
|
end;
|
|
|
|
{ RESET }
|
|
procedure scanline_u8.reset;
|
|
var
|
|
max_len : unsigned;
|
|
|
|
begin
|
|
max_len:=max_x - min_x + 2;
|
|
|
|
if max_len > m_max_len then
|
|
begin
|
|
agg_freemem(pointer(m_spans ) ,m_max_len * sizeof(span_u8 ) );
|
|
agg_freemem(pointer(m_covers ) ,m_max_len * sizeof(int8u ) );
|
|
|
|
agg_getmem(pointer(m_covers ) ,max_len * sizeof(int8u ) );
|
|
agg_getmem(pointer(m_spans ) ,max_len * sizeof(span_u8 ) );
|
|
|
|
m_max_len:=max_len;
|
|
|
|
end;
|
|
|
|
m_last_x :=$7FFFFFF0;
|
|
m_min_x :=min_x;
|
|
m_cur_span:=m_spans;
|
|
|
|
end;
|
|
|
|
{ RESET_SPANS }
|
|
procedure scanline_u8.reset_spans;
|
|
begin
|
|
m_last_x :=$7FFFFFF0;
|
|
m_cur_span:=m_spans;
|
|
|
|
end;
|
|
|
|
{ FINALIZE }
|
|
procedure scanline_u8.finalize;
|
|
begin
|
|
m_y:=y_;
|
|
|
|
end;
|
|
|
|
{ ADD_CELL }
|
|
procedure scanline_u8.add_cell;
|
|
begin
|
|
dec(x ,m_min_x );
|
|
|
|
int8u_ptr(ptrcomp(m_covers ) + x * sizeof(int8u ) )^:=int8u(cover );
|
|
|
|
if x = m_last_x + 1 then
|
|
inc(m_cur_span.len )
|
|
|
|
else
|
|
begin
|
|
inc(ptrcomp(m_cur_span ) ,sizeof(span_u8 ) );
|
|
|
|
m_cur_span.x :=int16(x + m_min_x );
|
|
m_cur_span.len:=1;
|
|
|
|
m_cur_span.covers:=int8u_ptr(ptrcomp(m_covers ) + x * sizeof(int8u ) );
|
|
|
|
end;
|
|
|
|
m_last_x:=x;
|
|
|
|
end;
|
|
|
|
{ ADD_CELLS }
|
|
procedure scanline_u8.add_cells;
|
|
begin
|
|
dec (x ,m_min_x );
|
|
move(
|
|
covers^ ,
|
|
int8u_ptr(ptrcomp(m_covers ) + x )^ ,
|
|
len * sizeof(int8u ) );
|
|
|
|
if x = m_last_x + 1 then
|
|
inc(m_cur_span.len ,int16(len ) )
|
|
|
|
else
|
|
begin
|
|
inc(ptrcomp(m_cur_span ) ,sizeof(span_u8 ) );
|
|
|
|
m_cur_span.x :=int16(x + m_min_x );
|
|
m_cur_span.len :=int16(len );
|
|
m_cur_span.covers:=int8u_ptr(ptrcomp(m_covers ) + x * sizeof(int8u ) );
|
|
|
|
end;
|
|
|
|
m_last_x:=x + len - 1;
|
|
|
|
end;
|
|
|
|
{ ADD_SPAN }
|
|
procedure scanline_u8.add_span;
|
|
begin
|
|
dec(x ,m_min_x );
|
|
|
|
fillchar(int8u_ptr(ptrcomp(m_covers ) + x * sizeof(int8u ) )^ ,len ,cover );
|
|
|
|
if x = m_last_x + 1 then
|
|
inc(m_cur_span.len ,int16(len ) )
|
|
|
|
else
|
|
begin
|
|
inc(ptrcomp(m_cur_span ) ,sizeof(span_u8 ) );
|
|
|
|
m_cur_span.x :=int16(x + m_min_x );
|
|
m_cur_span.len :=int16(len );
|
|
m_cur_span.covers:=int8u_ptr(ptrcomp(m_covers ) + x * sizeof(int8u ) );
|
|
|
|
end;
|
|
|
|
m_last_x:=x + len - 1;
|
|
|
|
end;
|
|
|
|
{ Y }
|
|
function scanline_u8.y;
|
|
begin
|
|
result:=m_y;
|
|
|
|
end;
|
|
|
|
{ NUM_SPANS }
|
|
function scanline_u8.num_spans;
|
|
begin
|
|
result:=(ptrcomp(m_cur_span ) - ptrcomp(m_spans ) ) div sizeof(span_u8 );
|
|
|
|
end;
|
|
|
|
{ BEGIN_ }
|
|
function scanline_u8.begin_;
|
|
begin
|
|
result:=span_u8_ptr(ptrcomp(m_spans ) + sizeof(span_u8 ) );
|
|
|
|
end;
|
|
|
|
{ SZ_OF_SPAN }
|
|
function scanline_u8.sz_of_span;
|
|
begin
|
|
result:=sizeof(span_u8 );
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor scanline_u8_am.Construct;
|
|
begin
|
|
inherited Construct;
|
|
|
|
m_alpha_mask:=NIL;
|
|
|
|
end;
|
|
|
|
{ CONSTRUCT }
|
|
constructor scanline_u8_am.Construct(am : alpha_mask_ptr );
|
|
begin
|
|
inherited Construct;
|
|
|
|
m_alpha_mask:=am;
|
|
|
|
end;
|
|
|
|
{ FINALIZE }
|
|
procedure scanline_u8_am.finalize;
|
|
var
|
|
span : span_u8_ptr;
|
|
|
|
ss ,count : unsigned;
|
|
|
|
begin
|
|
inherited finalize(y_ );
|
|
|
|
if m_alpha_mask <> NIL then
|
|
begin
|
|
span :=begin_;
|
|
ss :=sz_of_span;
|
|
count:=num_spans;
|
|
|
|
repeat
|
|
m_alpha_mask.combine_hspan(span.x ,y ,span.covers ,span.len );
|
|
|
|
inc(ptrcomp(span ) ,ss );
|
|
dec(count );
|
|
|
|
until count = 0;
|
|
|
|
end;
|
|
|
|
end;
|
|
|
|
END.
|
|
|