mirror of
https://gitee.com/zlgopen/awtk.git
synced 2024-11-29 18:48:09 +08:00
nanovg-agg backend
This commit is contained in:
parent
77dfcd5bef
commit
14ec1c997a
7
3rd/README.md
Normal file
7
3rd/README.md
Normal file
@ -0,0 +1,7 @@
|
||||
# 第三方库
|
||||
|
||||
本目录放第三方库,并遵循下列原则:
|
||||
|
||||
* PC上需要的软件包,可在本目录放完整的软件包。如SDL和gtest。
|
||||
* 嵌入式平台需要的软件包,只放需要的文件。这样在移植到新的平台时,要加哪些文件,一目了然。
|
||||
* 如果需要修改才能使用的第三方库,请将原始项目clone到zlgopen组织下进行修改,测试无误后再同步到AWTK中,同步之后请将所有平台都测试一遍。
|
9
3rd/agg/SConscript
Normal file
9
3rd/agg/SConscript
Normal file
@ -0,0 +1,9 @@
|
||||
import os
|
||||
|
||||
env = DefaultEnvironment().Clone()
|
||||
LIB_DIR = os.environ['LIB_DIR'];
|
||||
BIN_DIR = os.environ['BIN_DIR'];
|
||||
|
||||
SOURCES = Glob('src/*.cpp')
|
||||
env.Library(os.path.join(LIB_DIR, 'agg'), SOURCES);
|
||||
|
1119
3rd/agg/include/agg_array.h
Normal file
1119
3rd/agg/include/agg_array.h
Normal file
File diff suppressed because it is too large
Load Diff
560
3rd/agg/include/agg_basics.h
Normal file
560
3rd/agg/include/agg_basics.h
Normal file
@ -0,0 +1,560 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_BASICS_INCLUDED
|
||||
#define AGG_BASICS_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_config.h"
|
||||
|
||||
//---------------------------------------------------------AGG_CUSTOM_ALLOCATOR
|
||||
#ifdef AGG_CUSTOM_ALLOCATOR
|
||||
#include "agg_allocator.h"
|
||||
#else
|
||||
namespace agg
|
||||
{
|
||||
// The policy of all AGG containers and memory allocation strategy
|
||||
// in general is that no allocated data requires explicit construction.
|
||||
// It means that the allocator can be really simple; you can even
|
||||
// replace new/delete to malloc/free. The constructors and destructors
|
||||
// won't be called in this case, however everything will remain working.
|
||||
// The second argument of deallocate() is the size of the allocated
|
||||
// block. You can use this information if you wish.
|
||||
//------------------------------------------------------------pod_allocator
|
||||
template<class T> struct pod_allocator
|
||||
{
|
||||
static T* allocate(unsigned num) { return new T [num]; }
|
||||
static void deallocate(T* ptr, unsigned) { delete [] ptr; }
|
||||
};
|
||||
|
||||
// Single object allocator. It's also can be replaced with your custom
|
||||
// allocator. The difference is that it can only allocate a single
|
||||
// object and the constructor and destructor must be called.
|
||||
// In AGG there is no need to allocate an array of objects with
|
||||
// calling their constructors (only single ones). So that, if you
|
||||
// replace these new/delete to malloc/free make sure that the in-place
|
||||
// new is called and take care of calling the destructor too.
|
||||
//------------------------------------------------------------obj_allocator
|
||||
template<class T> struct obj_allocator
|
||||
{
|
||||
static T* allocate() { return new T; }
|
||||
static void deallocate(T* ptr) { delete ptr; }
|
||||
};
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//-------------------------------------------------------- Default basic types
|
||||
//
|
||||
// If the compiler has different capacity of the basic types you can redefine
|
||||
// them via the compiler command line or by generating agg_config.h that is
|
||||
// empty by default.
|
||||
//
|
||||
#ifndef AGG_INT8
|
||||
#define AGG_INT8 signed char
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT8U
|
||||
#define AGG_INT8U unsigned char
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT16
|
||||
#define AGG_INT16 short
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT16U
|
||||
#define AGG_INT16U unsigned short
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT32
|
||||
#define AGG_INT32 int
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT32U
|
||||
#define AGG_INT32U unsigned
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT64
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#define AGG_INT64 signed __int64
|
||||
#else
|
||||
#define AGG_INT64 signed long long
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef AGG_INT64U
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__)
|
||||
#define AGG_INT64U unsigned __int64
|
||||
#else
|
||||
#define AGG_INT64U unsigned long long
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//------------------------------------------------ Some fixes for MS Visual C++
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(disable:4786) // Identifier was truncated...
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define AGG_INLINE __forceinline
|
||||
#else
|
||||
#define AGG_INLINE inline
|
||||
#endif
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//-------------------------------------------------------------------------
|
||||
typedef AGG_INT8 int8; //----int8
|
||||
typedef AGG_INT8U int8u; //----int8u
|
||||
typedef AGG_INT16 int16; //----int16
|
||||
typedef AGG_INT16U int16u; //----int16u
|
||||
typedef AGG_INT32 int32; //----int32
|
||||
typedef AGG_INT32U int32u; //----int32u
|
||||
typedef AGG_INT64 int64; //----int64
|
||||
typedef AGG_INT64U int64u; //----int64u
|
||||
|
||||
#if defined(AGG_FISTP)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4035) //Disable warning "no return value"
|
||||
AGG_INLINE int iround(double v) //-------iround
|
||||
{
|
||||
int t;
|
||||
__asm fld qword ptr [v]
|
||||
__asm fistp dword ptr [t]
|
||||
__asm mov eax, dword ptr [t]
|
||||
}
|
||||
AGG_INLINE unsigned uround(double v) //-------uround
|
||||
{
|
||||
unsigned t;
|
||||
__asm fld qword ptr [v]
|
||||
__asm fistp dword ptr [t]
|
||||
__asm mov eax, dword ptr [t]
|
||||
}
|
||||
#pragma warning(pop)
|
||||
AGG_INLINE int ifloor(double v)
|
||||
{
|
||||
return int(floor(v));
|
||||
}
|
||||
AGG_INLINE unsigned ufloor(double v) //-------ufloor
|
||||
{
|
||||
return unsigned(floor(v));
|
||||
}
|
||||
AGG_INLINE int iceil(double v)
|
||||
{
|
||||
return int(ceil(v));
|
||||
}
|
||||
AGG_INLINE unsigned uceil(double v) //--------uceil
|
||||
{
|
||||
return unsigned(ceil(v));
|
||||
}
|
||||
#elif defined(AGG_QIFIST)
|
||||
AGG_INLINE int iround(double v)
|
||||
{
|
||||
return int(v);
|
||||
}
|
||||
AGG_INLINE int uround(double v)
|
||||
{
|
||||
return unsigned(v);
|
||||
}
|
||||
AGG_INLINE int ifloor(double v)
|
||||
{
|
||||
return int(floor(v));
|
||||
}
|
||||
AGG_INLINE unsigned ufloor(double v)
|
||||
{
|
||||
return unsigned(floor(v));
|
||||
}
|
||||
AGG_INLINE int iceil(double v)
|
||||
{
|
||||
return int(ceil(v));
|
||||
}
|
||||
AGG_INLINE unsigned uceil(double v)
|
||||
{
|
||||
return unsigned(ceil(v));
|
||||
}
|
||||
#else
|
||||
AGG_INLINE int iround(double v)
|
||||
{
|
||||
return int((v < 0.0) ? v - 0.5 : v + 0.5);
|
||||
}
|
||||
AGG_INLINE int uround(double v)
|
||||
{
|
||||
return unsigned(v + 0.5);
|
||||
}
|
||||
AGG_INLINE int ifloor(double v)
|
||||
{
|
||||
int i = int(v);
|
||||
return i - (i > v);
|
||||
}
|
||||
AGG_INLINE unsigned ufloor(double v)
|
||||
{
|
||||
return unsigned(v);
|
||||
}
|
||||
AGG_INLINE int iceil(double v)
|
||||
{
|
||||
return int(ceil(v));
|
||||
}
|
||||
AGG_INLINE unsigned uceil(double v)
|
||||
{
|
||||
return unsigned(ceil(v));
|
||||
}
|
||||
#endif
|
||||
|
||||
//---------------------------------------------------------------saturation
|
||||
template<int Limit> struct saturation
|
||||
{
|
||||
AGG_INLINE static int iround(double v)
|
||||
{
|
||||
if(v < double(-Limit)) return -Limit;
|
||||
if(v > double( Limit)) return Limit;
|
||||
return agg::iround(v);
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------mul_one
|
||||
template<unsigned Shift> struct mul_one
|
||||
{
|
||||
AGG_INLINE static unsigned mul(unsigned a, unsigned b)
|
||||
{
|
||||
unsigned q = a * b + (1 << (Shift-1));
|
||||
return (q + (q >> Shift)) >> Shift;
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
typedef unsigned char cover_type; //----cover_type
|
||||
enum cover_scale_e
|
||||
{
|
||||
cover_shift = 8, //----cover_shift
|
||||
cover_size = 1 << cover_shift, //----cover_size
|
||||
cover_mask = cover_size - 1, //----cover_mask
|
||||
cover_none = 0, //----cover_none
|
||||
cover_full = cover_mask //----cover_full
|
||||
};
|
||||
|
||||
//----------------------------------------------------poly_subpixel_scale_e
|
||||
// These constants determine the subpixel accuracy, to be more precise,
|
||||
// the number of bits of the fractional part of the coordinates.
|
||||
// The possible coordinate capacity in bits can be calculated by formula:
|
||||
// sizeof(int) * 8 - poly_subpixel_shift, i.e, for 32-bit integers and
|
||||
// 8-bits fractional part the capacity is 24 bits.
|
||||
enum poly_subpixel_scale_e
|
||||
{
|
||||
poly_subpixel_shift = 8, //----poly_subpixel_shift
|
||||
poly_subpixel_scale = 1<<poly_subpixel_shift, //----poly_subpixel_scale
|
||||
poly_subpixel_mask = poly_subpixel_scale-1 //----poly_subpixel_mask
|
||||
};
|
||||
|
||||
//----------------------------------------------------------filling_rule_e
|
||||
enum filling_rule_e
|
||||
{
|
||||
fill_non_zero,
|
||||
fill_even_odd
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------pi
|
||||
const double pi = 3.14159265358979323846;
|
||||
|
||||
//------------------------------------------------------------------deg2rad
|
||||
inline double deg2rad(double deg)
|
||||
{
|
||||
return deg * pi / 180.0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------rad2deg
|
||||
inline double rad2deg(double rad)
|
||||
{
|
||||
return rad * 180.0 / pi;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------rect_base
|
||||
template<class T> struct rect_base
|
||||
{
|
||||
typedef T value_type;
|
||||
typedef rect_base<T> self_type;
|
||||
T x1, y1, x2, y2;
|
||||
|
||||
rect_base() {}
|
||||
rect_base(T x1_, T y1_, T x2_, T y2_) :
|
||||
x1(x1_), y1(y1_), x2(x2_), y2(y2_) {}
|
||||
|
||||
void init(T x1_, T y1_, T x2_, T y2_)
|
||||
{
|
||||
x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_;
|
||||
}
|
||||
|
||||
const self_type& normalize()
|
||||
{
|
||||
T t;
|
||||
if(x1 > x2) { t = x1; x1 = x2; x2 = t; }
|
||||
if(y1 > y2) { t = y1; y1 = y2; y2 = t; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool clip(const self_type& r)
|
||||
{
|
||||
if(x2 > r.x2) x2 = r.x2;
|
||||
if(y2 > r.y2) y2 = r.y2;
|
||||
if(x1 < r.x1) x1 = r.x1;
|
||||
if(y1 < r.y1) y1 = r.y1;
|
||||
return x1 <= x2 && y1 <= y2;
|
||||
}
|
||||
|
||||
bool is_valid() const
|
||||
{
|
||||
return x1 <= x2 && y1 <= y2;
|
||||
}
|
||||
|
||||
bool hit_test(T x, T y) const
|
||||
{
|
||||
return (x >= x1 && x <= x2 && y >= y1 && y <= y2);
|
||||
}
|
||||
|
||||
bool overlaps(const self_type& r) const
|
||||
{
|
||||
return !(r.x1 > x2 || r.x2 < x1
|
||||
|| r.y1 > y2 || r.y2 < y1);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------intersect_rectangles
|
||||
template<class Rect>
|
||||
inline Rect intersect_rectangles(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
Rect r = r1;
|
||||
|
||||
// First process x2,y2 because the other order
|
||||
// results in Internal Compiler Error under
|
||||
// Microsoft Visual C++ .NET 2003 69462-335-0000007-18038 in
|
||||
// case of "Maximize Speed" optimization option.
|
||||
//-----------------
|
||||
if(r.x2 > r2.x2) r.x2 = r2.x2;
|
||||
if(r.y2 > r2.y2) r.y2 = r2.y2;
|
||||
if(r.x1 < r2.x1) r.x1 = r2.x1;
|
||||
if(r.y1 < r2.y1) r.y1 = r2.y1;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
//---------------------------------------------------------unite_rectangles
|
||||
template<class Rect>
|
||||
inline Rect unite_rectangles(const Rect& r1, const Rect& r2)
|
||||
{
|
||||
Rect r = r1;
|
||||
if(r.x2 < r2.x2) r.x2 = r2.x2;
|
||||
if(r.y2 < r2.y2) r.y2 = r2.y2;
|
||||
if(r.x1 > r2.x1) r.x1 = r2.x1;
|
||||
if(r.y1 > r2.y1) r.y1 = r2.y1;
|
||||
return r;
|
||||
}
|
||||
|
||||
typedef rect_base<int> rect_i; //----rect_i
|
||||
typedef rect_base<float> rect_f; //----rect_f
|
||||
typedef rect_base<double> rect_d; //----rect_d
|
||||
|
||||
//---------------------------------------------------------path_commands_e
|
||||
enum path_commands_e
|
||||
{
|
||||
path_cmd_stop = 0, //----path_cmd_stop
|
||||
path_cmd_move_to = 1, //----path_cmd_move_to
|
||||
path_cmd_line_to = 2, //----path_cmd_line_to
|
||||
path_cmd_curve3 = 3, //----path_cmd_curve3
|
||||
path_cmd_curve4 = 4, //----path_cmd_curve4
|
||||
path_cmd_curveN = 5, //----path_cmd_curveN
|
||||
path_cmd_catrom = 6, //----path_cmd_catrom
|
||||
path_cmd_ubspline = 7, //----path_cmd_ubspline
|
||||
path_cmd_end_poly = 0x0F, //----path_cmd_end_poly
|
||||
path_cmd_mask = 0x0F //----path_cmd_mask
|
||||
};
|
||||
|
||||
//------------------------------------------------------------path_flags_e
|
||||
enum path_flags_e
|
||||
{
|
||||
path_flags_none = 0, //----path_flags_none
|
||||
path_flags_ccw = 0x10, //----path_flags_ccw
|
||||
path_flags_cw = 0x20, //----path_flags_cw
|
||||
path_flags_close = 0x40, //----path_flags_close
|
||||
path_flags_mask = 0xF0 //----path_flags_mask
|
||||
};
|
||||
|
||||
//---------------------------------------------------------------is_vertex
|
||||
inline bool is_vertex(unsigned c)
|
||||
{
|
||||
return c >= path_cmd_move_to && c < path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_drawing
|
||||
inline bool is_drawing(unsigned c)
|
||||
{
|
||||
return c >= path_cmd_line_to && c < path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------is_stop
|
||||
inline bool is_stop(unsigned c)
|
||||
{
|
||||
return c == path_cmd_stop;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_move_to
|
||||
inline bool is_move_to(unsigned c)
|
||||
{
|
||||
return c == path_cmd_move_to;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------is_line_to
|
||||
inline bool is_line_to(unsigned c)
|
||||
{
|
||||
return c == path_cmd_line_to;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------is_curve
|
||||
inline bool is_curve(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve3 || c == path_cmd_curve4;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_curve3
|
||||
inline bool is_curve3(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve3;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_curve4
|
||||
inline bool is_curve4(unsigned c)
|
||||
{
|
||||
return c == path_cmd_curve4;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------is_end_poly
|
||||
inline bool is_end_poly(unsigned c)
|
||||
{
|
||||
return (c & path_cmd_mask) == path_cmd_end_poly;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------is_close
|
||||
inline bool is_close(unsigned c)
|
||||
{
|
||||
return (c & ~(path_flags_cw | path_flags_ccw)) ==
|
||||
(path_cmd_end_poly | path_flags_close);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------is_next_poly
|
||||
inline bool is_next_poly(unsigned c)
|
||||
{
|
||||
return is_stop(c) || is_move_to(c) || is_end_poly(c);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------is_cw
|
||||
inline bool is_cw(unsigned c)
|
||||
{
|
||||
return (c & path_flags_cw) != 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------is_ccw
|
||||
inline bool is_ccw(unsigned c)
|
||||
{
|
||||
return (c & path_flags_ccw) != 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------is_oriented
|
||||
inline bool is_oriented(unsigned c)
|
||||
{
|
||||
return (c & (path_flags_cw | path_flags_ccw)) != 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------is_closed
|
||||
inline bool is_closed(unsigned c)
|
||||
{
|
||||
return (c & path_flags_close) != 0;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------get_close_flag
|
||||
inline unsigned get_close_flag(unsigned c)
|
||||
{
|
||||
return c & path_flags_close;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------clear_orientation
|
||||
inline unsigned clear_orientation(unsigned c)
|
||||
{
|
||||
return c & ~(path_flags_cw | path_flags_ccw);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------get_orientation
|
||||
inline unsigned get_orientation(unsigned c)
|
||||
{
|
||||
return c & (path_flags_cw | path_flags_ccw);
|
||||
}
|
||||
|
||||
//---------------------------------------------------------set_orientation
|
||||
inline unsigned set_orientation(unsigned c, unsigned o)
|
||||
{
|
||||
return clear_orientation(c) | o;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------point_base
|
||||
template<class T> struct point_base
|
||||
{
|
||||
typedef T value_type;
|
||||
T x,y;
|
||||
point_base() {}
|
||||
point_base(T x_, T y_) : x(x_), y(y_) {}
|
||||
};
|
||||
typedef point_base<int> point_i; //-----point_i
|
||||
typedef point_base<float> point_f; //-----point_f
|
||||
typedef point_base<double> point_d; //-----point_d
|
||||
|
||||
//-------------------------------------------------------------vertex_base
|
||||
template<class T> struct vertex_base
|
||||
{
|
||||
typedef T value_type;
|
||||
T x,y;
|
||||
unsigned cmd;
|
||||
vertex_base() {}
|
||||
vertex_base(T x_, T y_, unsigned cmd_) : x(x_), y(y_), cmd(cmd_) {}
|
||||
};
|
||||
typedef vertex_base<int> vertex_i; //-----vertex_i
|
||||
typedef vertex_base<float> vertex_f; //-----vertex_f
|
||||
typedef vertex_base<double> vertex_d; //-----vertex_d
|
||||
|
||||
//----------------------------------------------------------------row_info
|
||||
template<class T> struct row_info
|
||||
{
|
||||
int x1, x2;
|
||||
T* ptr;
|
||||
row_info() {}
|
||||
row_info(int x1_, int x2_, T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------const_row_info
|
||||
template<class T> struct const_row_info
|
||||
{
|
||||
int x1, x2;
|
||||
const T* ptr;
|
||||
const_row_info() {}
|
||||
const_row_info(int x1_, int x2_, const T* ptr_) :
|
||||
x1(x1_), x2(x2_), ptr(ptr_) {}
|
||||
};
|
||||
|
||||
//------------------------------------------------------------is_equal_eps
|
||||
template<class T> inline bool is_equal_eps(T v1, T v2, T epsilon)
|
||||
{
|
||||
return fabs(v1 - v2) <= double(epsilon);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
333
3rd/agg/include/agg_clip_liang_barsky.h
Normal file
333
3rd/agg/include/agg_clip_liang_barsky.h
Normal file
@ -0,0 +1,333 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Liang-Barsky clipping
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED
|
||||
#define AGG_CLIP_LIANG_BARSKY_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum clipping_flags_e
|
||||
{
|
||||
clipping_flags_x1_clipped = 4,
|
||||
clipping_flags_x2_clipped = 1,
|
||||
clipping_flags_y1_clipped = 8,
|
||||
clipping_flags_y2_clipped = 2,
|
||||
clipping_flags_x_clipped = clipping_flags_x1_clipped | clipping_flags_x2_clipped,
|
||||
clipping_flags_y_clipped = clipping_flags_y1_clipped | clipping_flags_y2_clipped
|
||||
};
|
||||
|
||||
//----------------------------------------------------------clipping_flags
|
||||
// Determine the clipping code of the vertex according to the
|
||||
// Cyrus-Beck line clipping algorithm
|
||||
//
|
||||
// | |
|
||||
// 0110 | 0010 | 0011
|
||||
// | |
|
||||
// -------+--------+-------- clip_box.y2
|
||||
// | |
|
||||
// 0100 | 0000 | 0001
|
||||
// | |
|
||||
// -------+--------+-------- clip_box.y1
|
||||
// | |
|
||||
// 1100 | 1000 | 1001
|
||||
// | |
|
||||
// clip_box.x1 clip_box.x2
|
||||
//
|
||||
//
|
||||
template<class T>
|
||||
inline unsigned clipping_flags(T x, T y, const rect_base<T>& clip_box)
|
||||
{
|
||||
return (x > clip_box.x2) |
|
||||
((y > clip_box.y2) << 1) |
|
||||
((x < clip_box.x1) << 2) |
|
||||
((y < clip_box.y1) << 3);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------clipping_flags_x
|
||||
template<class T>
|
||||
inline unsigned clipping_flags_x(T x, const rect_base<T>& clip_box)
|
||||
{
|
||||
return (x > clip_box.x2) | ((x < clip_box.x1) << 2);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------clipping_flags_y
|
||||
template<class T>
|
||||
inline unsigned clipping_flags_y(T y, const rect_base<T>& clip_box)
|
||||
{
|
||||
return ((y > clip_box.y2) << 1) | ((y < clip_box.y1) << 3);
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------clip_liang_barsky
|
||||
template<class T>
|
||||
inline unsigned clip_liang_barsky(T x1, T y1, T x2, T y2,
|
||||
const rect_base<T>& clip_box,
|
||||
T* x, T* y)
|
||||
{
|
||||
const double nearzero = 1e-30;
|
||||
|
||||
double deltax = x2 - x1;
|
||||
double deltay = y2 - y1;
|
||||
double xin;
|
||||
double xout;
|
||||
double yin;
|
||||
double yout;
|
||||
double tinx;
|
||||
double tiny;
|
||||
double toutx;
|
||||
double touty;
|
||||
double tin1;
|
||||
double tin2;
|
||||
double tout1;
|
||||
unsigned np = 0;
|
||||
|
||||
if(deltax == 0.0)
|
||||
{
|
||||
// bump off of the vertical
|
||||
deltax = (x1 > clip_box.x1) ? -nearzero : nearzero;
|
||||
}
|
||||
|
||||
if(deltay == 0.0)
|
||||
{
|
||||
// bump off of the horizontal
|
||||
deltay = (y1 > clip_box.y1) ? -nearzero : nearzero;
|
||||
}
|
||||
|
||||
if(deltax > 0.0)
|
||||
{
|
||||
// points to right
|
||||
xin = clip_box.x1;
|
||||
xout = clip_box.x2;
|
||||
}
|
||||
else
|
||||
{
|
||||
xin = clip_box.x2;
|
||||
xout = clip_box.x1;
|
||||
}
|
||||
|
||||
if(deltay > 0.0)
|
||||
{
|
||||
// points up
|
||||
yin = clip_box.y1;
|
||||
yout = clip_box.y2;
|
||||
}
|
||||
else
|
||||
{
|
||||
yin = clip_box.y2;
|
||||
yout = clip_box.y1;
|
||||
}
|
||||
|
||||
tinx = (xin - x1) / deltax;
|
||||
tiny = (yin - y1) / deltay;
|
||||
|
||||
if (tinx < tiny)
|
||||
{
|
||||
// hits x first
|
||||
tin1 = tinx;
|
||||
tin2 = tiny;
|
||||
}
|
||||
else
|
||||
{
|
||||
// hits y first
|
||||
tin1 = tiny;
|
||||
tin2 = tinx;
|
||||
}
|
||||
|
||||
if(tin1 <= 1.0)
|
||||
{
|
||||
if(0.0 < tin1)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)yin;
|
||||
++np;
|
||||
}
|
||||
|
||||
if(tin2 <= 1.0)
|
||||
{
|
||||
toutx = (xout - x1) / deltax;
|
||||
touty = (yout - y1) / deltay;
|
||||
|
||||
tout1 = (toutx < touty) ? toutx : touty;
|
||||
|
||||
if(tin2 > 0.0 || tout1 > 0.0)
|
||||
{
|
||||
if(tin2 <= tout1)
|
||||
{
|
||||
if(tin2 > 0.0)
|
||||
{
|
||||
if(tinx > tiny)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)(y1 + tinx * deltay);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)(x1 + tiny * deltax);
|
||||
*y++ = (T)yin;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
|
||||
if(tout1 < 1.0)
|
||||
{
|
||||
if(toutx < touty)
|
||||
{
|
||||
*x++ = (T)xout;
|
||||
*y++ = (T)(y1 + toutx * deltay);
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)(x1 + touty * deltax);
|
||||
*y++ = (T)yout;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = x2;
|
||||
*y++ = y2;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tinx > tiny)
|
||||
{
|
||||
*x++ = (T)xin;
|
||||
*y++ = (T)yout;
|
||||
}
|
||||
else
|
||||
{
|
||||
*x++ = (T)xout;
|
||||
*y++ = (T)yin;
|
||||
}
|
||||
++np;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return np;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
template<class T>
|
||||
bool clip_move_point(T x1, T y1, T x2, T y2,
|
||||
const rect_base<T>& clip_box,
|
||||
T* x, T* y, unsigned flags)
|
||||
{
|
||||
T bound;
|
||||
|
||||
if(flags & clipping_flags_x_clipped)
|
||||
{
|
||||
if(x1 == x2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bound = (flags & clipping_flags_x1_clipped) ? clip_box.x1 : clip_box.x2;
|
||||
*y = (T)(double(bound - x1) * (y2 - y1) / (x2 - x1) + y1);
|
||||
*x = bound;
|
||||
}
|
||||
|
||||
flags = clipping_flags_y(*y, clip_box);
|
||||
if(flags & clipping_flags_y_clipped)
|
||||
{
|
||||
if(y1 == y2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
bound = (flags & clipping_flags_y1_clipped) ? clip_box.y1 : clip_box.y2;
|
||||
*x = (T)(double(bound - y1) * (x2 - x1) / (y2 - y1) + x1);
|
||||
*y = bound;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------clip_line_segment
|
||||
// Returns: ret >= 4 - Fully clipped
|
||||
// (ret & 1) != 0 - First point has been moved
|
||||
// (ret & 2) != 0 - Second point has been moved
|
||||
//
|
||||
template<class T>
|
||||
unsigned clip_line_segment(T* x1, T* y1, T* x2, T* y2,
|
||||
const rect_base<T>& clip_box)
|
||||
{
|
||||
unsigned f1 = clipping_flags(*x1, *y1, clip_box);
|
||||
unsigned f2 = clipping_flags(*x2, *y2, clip_box);
|
||||
unsigned ret = 0;
|
||||
|
||||
if((f2 | f1) == 0)
|
||||
{
|
||||
// Fully visible
|
||||
return 0;
|
||||
}
|
||||
|
||||
if((f1 & clipping_flags_x_clipped) != 0 &&
|
||||
(f1 & clipping_flags_x_clipped) == (f2 & clipping_flags_x_clipped))
|
||||
{
|
||||
// Fully clipped
|
||||
return 4;
|
||||
}
|
||||
|
||||
if((f1 & clipping_flags_y_clipped) != 0 &&
|
||||
(f1 & clipping_flags_y_clipped) == (f2 & clipping_flags_y_clipped))
|
||||
{
|
||||
// Fully clipped
|
||||
return 4;
|
||||
}
|
||||
|
||||
T tx1 = *x1;
|
||||
T ty1 = *y1;
|
||||
T tx2 = *x2;
|
||||
T ty2 = *y2;
|
||||
if(f1)
|
||||
{
|
||||
if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x1, y1, f1))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if(*x1 == *x2 && *y1 == *y2)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
ret |= 1;
|
||||
}
|
||||
if(f2)
|
||||
{
|
||||
if(!clip_move_point(tx1, ty1, tx2, ty2, clip_box, x2, y2, f2))
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
if(*x1 == *x2 && *y1 == *y2)
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
ret |= 2;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
1047
3rd/agg/include/agg_color_gray.h
Normal file
1047
3rd/agg/include/agg_color_gray.h
Normal file
File diff suppressed because it is too large
Load Diff
1353
3rd/agg/include/agg_color_rgba.h
Normal file
1353
3rd/agg/include/agg_color_rgba.h
Normal file
File diff suppressed because it is too large
Load Diff
44
3rd/agg/include/agg_config.h
Normal file
44
3rd/agg/include/agg_config.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef AGG_CONFIG_INCLUDED
|
||||
#define AGG_CONFIG_INCLUDED
|
||||
|
||||
// This file can be used to redefine certain data types.
|
||||
|
||||
//---------------------------------------
|
||||
// 1. Default basic types such as:
|
||||
//
|
||||
// AGG_INT8
|
||||
// AGG_INT8U
|
||||
// AGG_INT16
|
||||
// AGG_INT16U
|
||||
// AGG_INT32
|
||||
// AGG_INT32U
|
||||
// AGG_INT64
|
||||
// AGG_INT64U
|
||||
//
|
||||
// Just replace this file with new defines if necessary.
|
||||
// For example, if your compiler doesn't have a 64 bit integer type
|
||||
// you can still use AGG if you define the follows:
|
||||
//
|
||||
// #define AGG_INT64 int
|
||||
// #define AGG_INT64U unsigned
|
||||
//
|
||||
// It will result in overflow in 16 bit-per-component image/pattern resampling
|
||||
// but it won't result any crash and the rest of the library will remain
|
||||
// fully functional.
|
||||
|
||||
|
||||
//---------------------------------------
|
||||
// 2. Default rendering_buffer type. Can be:
|
||||
//
|
||||
// Provides faster access for massive pixel operations,
|
||||
// such as blur, image filtering:
|
||||
// #define AGG_RENDERING_BUFFER row_ptr_cache<int8u>
|
||||
//
|
||||
// Provides cheaper creation and destruction (no mem allocs):
|
||||
// #define AGG_RENDERING_BUFFER row_accessor<int8u>
|
||||
//
|
||||
// You can still use both of them simultaneously in your applications
|
||||
// This #define is used only for default rendering_buffer type,
|
||||
// in short hand typedefs like pixfmt_rgba32.
|
||||
|
||||
#endif
|
157
3rd/agg/include/agg_conv_adaptor_vcgen.h
Normal file
157
3rd/agg/include/agg_conv_adaptor_vcgen.h
Normal file
@ -0,0 +1,157 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_CONV_ADAPTOR_VCGEN_INCLUDED
|
||||
#define AGG_CONV_ADAPTOR_VCGEN_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//------------------------------------------------------------null_markers
|
||||
struct null_markers
|
||||
{
|
||||
void remove_all() {}
|
||||
void add_vertex(double, double, unsigned) {}
|
||||
void prepare_src() {}
|
||||
|
||||
void rewind(unsigned) {}
|
||||
unsigned vertex(double*, double*) { return path_cmd_stop; }
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------conv_adaptor_vcgen
|
||||
template<class VertexSource,
|
||||
class Generator,
|
||||
class Markers=null_markers> class conv_adaptor_vcgen
|
||||
{
|
||||
enum status
|
||||
{
|
||||
initial,
|
||||
accumulate,
|
||||
generate
|
||||
};
|
||||
|
||||
public:
|
||||
explicit conv_adaptor_vcgen(VertexSource& source) :
|
||||
m_source(&source),
|
||||
m_status(initial)
|
||||
{}
|
||||
void attach(VertexSource& source) { m_source = &source; }
|
||||
|
||||
Generator& generator() { return m_generator; }
|
||||
const Generator& generator() const { return m_generator; }
|
||||
|
||||
Markers& markers() { return m_markers; }
|
||||
const Markers& markers() const { return m_markers; }
|
||||
|
||||
void rewind(unsigned path_id)
|
||||
{
|
||||
m_source->rewind(path_id);
|
||||
m_status = initial;
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
// Prohibit copying
|
||||
conv_adaptor_vcgen(const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
|
||||
const conv_adaptor_vcgen<VertexSource, Generator, Markers>&
|
||||
operator = (const conv_adaptor_vcgen<VertexSource, Generator, Markers>&);
|
||||
|
||||
VertexSource* m_source;
|
||||
Generator m_generator;
|
||||
Markers m_markers;
|
||||
status m_status;
|
||||
unsigned m_last_cmd;
|
||||
double m_start_x;
|
||||
double m_start_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class VertexSource, class Generator, class Markers>
|
||||
unsigned conv_adaptor_vcgen<VertexSource, Generator, Markers>::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_stop;
|
||||
bool done = false;
|
||||
while(!done)
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
m_markers.remove_all();
|
||||
m_last_cmd = m_source->vertex(&m_start_x, &m_start_y);
|
||||
m_status = accumulate;
|
||||
|
||||
case accumulate:
|
||||
if(is_stop(m_last_cmd)) return path_cmd_stop;
|
||||
|
||||
m_generator.remove_all();
|
||||
m_generator.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
|
||||
m_markers.add_vertex(m_start_x, m_start_y, path_cmd_move_to);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
cmd = m_source->vertex(x, y);
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_last_cmd = cmd;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_start_x = *x;
|
||||
m_start_y = *y;
|
||||
break;
|
||||
}
|
||||
m_generator.add_vertex(*x, *y, cmd);
|
||||
m_markers.add_vertex(*x, *y, path_cmd_line_to);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
m_last_cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
if(is_end_poly(cmd))
|
||||
{
|
||||
m_generator.add_vertex(*x, *y, cmd);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_generator.rewind(0);
|
||||
m_status = generate;
|
||||
|
||||
case generate:
|
||||
cmd = m_generator.vertex(x, y);
|
||||
if(is_stop(cmd))
|
||||
{
|
||||
m_status = accumulate;
|
||||
break;
|
||||
}
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
73
3rd/agg/include/agg_conv_stroke.h
Normal file
73
3rd/agg/include/agg_conv_stroke.h
Normal file
@ -0,0 +1,73 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// conv_stroke
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_CONV_STROKE_INCLUDED
|
||||
#define AGG_CONV_STROKE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vcgen_stroke.h"
|
||||
#include "agg_conv_adaptor_vcgen.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-------------------------------------------------------------conv_stroke
|
||||
template<class VertexSource, class Markers=null_markers>
|
||||
struct conv_stroke :
|
||||
public conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>
|
||||
{
|
||||
typedef Markers marker_type;
|
||||
typedef conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers> base_type;
|
||||
|
||||
conv_stroke(VertexSource& vs) :
|
||||
conv_adaptor_vcgen<VertexSource, vcgen_stroke, Markers>(vs)
|
||||
{
|
||||
}
|
||||
|
||||
void line_cap(line_cap_e lc) { base_type::generator().line_cap(lc); }
|
||||
void line_join(line_join_e lj) { base_type::generator().line_join(lj); }
|
||||
void inner_join(inner_join_e ij) { base_type::generator().inner_join(ij); }
|
||||
|
||||
line_cap_e line_cap() const { return base_type::generator().line_cap(); }
|
||||
line_join_e line_join() const { return base_type::generator().line_join(); }
|
||||
inner_join_e inner_join() const { return base_type::generator().inner_join(); }
|
||||
|
||||
void width(double w) { base_type::generator().width(w); }
|
||||
void miter_limit(double ml) { base_type::generator().miter_limit(ml); }
|
||||
void miter_limit_theta(double t) { base_type::generator().miter_limit_theta(t); }
|
||||
void inner_miter_limit(double ml) { base_type::generator().inner_miter_limit(ml); }
|
||||
void approximation_scale(double as) { base_type::generator().approximation_scale(as); }
|
||||
|
||||
double width() const { return base_type::generator().width(); }
|
||||
double miter_limit() const { return base_type::generator().miter_limit(); }
|
||||
double inner_miter_limit() const { return base_type::generator().inner_miter_limit(); }
|
||||
double approximation_scale() const { return base_type::generator().approximation_scale(); }
|
||||
|
||||
void shorten(double s) { base_type::generator().shorten(s); }
|
||||
double shorten() const { return base_type::generator().shorten(); }
|
||||
|
||||
private:
|
||||
conv_stroke(const conv_stroke<VertexSource, Markers>&);
|
||||
const conv_stroke<VertexSource, Markers>&
|
||||
operator = (const conv_stroke<VertexSource, Markers>&);
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
290
3rd/agg/include/agg_dda_line.h
Normal file
290
3rd/agg/include/agg_dda_line.h
Normal file
@ -0,0 +1,290 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// classes dda_line_interpolator, dda2_line_interpolator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_DDA_LINE_INCLUDED
|
||||
#define AGG_DDA_LINE_INCLUDED
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===================================================dda_line_interpolator
|
||||
template<int FractionShift, int YShift=0> class dda_line_interpolator
|
||||
{
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
dda_line_interpolator() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
dda_line_interpolator(int y1, int y2, unsigned count) :
|
||||
m_y(y1),
|
||||
m_inc(((y2 - y1) << FractionShift) / int(count)),
|
||||
m_dy(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator ++ ()
|
||||
{
|
||||
m_dy += m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator -- ()
|
||||
{
|
||||
m_dy -= m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator += (unsigned n)
|
||||
{
|
||||
m_dy += m_inc * n;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator -= (unsigned n)
|
||||
{
|
||||
m_dy -= m_inc * n;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y + (m_dy >> (FractionShift-YShift)); }
|
||||
int dy() const { return m_dy; }
|
||||
|
||||
|
||||
private:
|
||||
int m_y;
|
||||
int m_inc;
|
||||
int m_dy;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=================================================dda2_line_interpolator
|
||||
class dda2_line_interpolator
|
||||
{
|
||||
public:
|
||||
typedef int save_data_type;
|
||||
enum save_size_e { save_size = 2 };
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
dda2_line_interpolator() {}
|
||||
|
||||
//-------------------------------------------- Forward-adjusted line
|
||||
dda2_line_interpolator(int y1, int y2, int count) :
|
||||
m_cnt(count <= 0 ? 1 : count),
|
||||
m_lft((y2 - y1) / m_cnt),
|
||||
m_rem((y2 - y1) % m_cnt),
|
||||
m_mod(m_rem),
|
||||
m_y(y1)
|
||||
{
|
||||
if(m_mod <= 0)
|
||||
{
|
||||
m_mod += count;
|
||||
m_rem += count;
|
||||
m_lft--;
|
||||
}
|
||||
m_mod -= count;
|
||||
}
|
||||
|
||||
//-------------------------------------------- Backward-adjusted line
|
||||
dda2_line_interpolator(int y1, int y2, int count, int) :
|
||||
m_cnt(count <= 0 ? 1 : count),
|
||||
m_lft((y2 - y1) / m_cnt),
|
||||
m_rem((y2 - y1) % m_cnt),
|
||||
m_mod(m_rem),
|
||||
m_y(y1)
|
||||
{
|
||||
if(m_mod <= 0)
|
||||
{
|
||||
m_mod += count;
|
||||
m_rem += count;
|
||||
m_lft--;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------- Backward-adjusted line
|
||||
dda2_line_interpolator(int y, int count) :
|
||||
m_cnt(count <= 0 ? 1 : count),
|
||||
m_lft(y / m_cnt),
|
||||
m_rem(y % m_cnt),
|
||||
m_mod(m_rem),
|
||||
m_y(0)
|
||||
{
|
||||
if(m_mod <= 0)
|
||||
{
|
||||
m_mod += count;
|
||||
m_rem += count;
|
||||
m_lft--;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void save(save_data_type* data) const
|
||||
{
|
||||
data[0] = m_mod;
|
||||
data[1] = m_y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void load(const save_data_type* data)
|
||||
{
|
||||
m_mod = data[0];
|
||||
m_y = data[1];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator++()
|
||||
{
|
||||
m_mod += m_rem;
|
||||
m_y += m_lft;
|
||||
if(m_mod > 0)
|
||||
{
|
||||
m_mod -= m_cnt;
|
||||
m_y++;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void operator--()
|
||||
{
|
||||
if(m_mod <= m_rem)
|
||||
{
|
||||
m_mod += m_cnt;
|
||||
m_y--;
|
||||
}
|
||||
m_mod -= m_rem;
|
||||
m_y -= m_lft;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void adjust_forward()
|
||||
{
|
||||
m_mod -= m_cnt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void adjust_backward()
|
||||
{
|
||||
m_mod += m_cnt;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int mod() const { return m_mod; }
|
||||
int rem() const { return m_rem; }
|
||||
int lft() const { return m_lft; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
|
||||
private:
|
||||
int m_cnt;
|
||||
int m_lft;
|
||||
int m_rem;
|
||||
int m_mod;
|
||||
int m_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------line_bresenham_interpolator
|
||||
class line_bresenham_interpolator
|
||||
{
|
||||
public:
|
||||
enum subpixel_scale_e
|
||||
{
|
||||
subpixel_shift = 8,
|
||||
subpixel_scale = 1 << subpixel_shift,
|
||||
subpixel_mask = subpixel_scale - 1
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static int line_lr(int v) { return v >> subpixel_shift; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
line_bresenham_interpolator(int x1, int y1, int x2, int y2) :
|
||||
m_x1_lr(line_lr(x1)),
|
||||
m_y1_lr(line_lr(y1)),
|
||||
m_x2_lr(line_lr(x2)),
|
||||
m_y2_lr(line_lr(y2)),
|
||||
m_ver(abs(m_x2_lr - m_x1_lr) < abs(m_y2_lr - m_y1_lr)),
|
||||
m_len(m_ver ? abs(m_y2_lr - m_y1_lr) :
|
||||
abs(m_x2_lr - m_x1_lr)),
|
||||
m_inc(m_ver ? ((y2 > y1) ? 1 : -1) : ((x2 > x1) ? 1 : -1)),
|
||||
m_interpolator(m_ver ? x1 : y1,
|
||||
m_ver ? x2 : y2,
|
||||
m_len)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool is_ver() const { return m_ver; }
|
||||
unsigned len() const { return m_len; }
|
||||
int inc() const { return m_inc; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void hstep()
|
||||
{
|
||||
++m_interpolator;
|
||||
m_x1_lr += m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void vstep()
|
||||
{
|
||||
++m_interpolator;
|
||||
m_y1_lr += m_inc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int x1() const { return m_x1_lr; }
|
||||
int y1() const { return m_y1_lr; }
|
||||
int x2() const { return line_lr(m_interpolator.y()); }
|
||||
int y2() const { return line_lr(m_interpolator.y()); }
|
||||
int x2_hr() const { return m_interpolator.y(); }
|
||||
int y2_hr() const { return m_interpolator.y(); }
|
||||
|
||||
private:
|
||||
int m_x1_lr;
|
||||
int m_y1_lr;
|
||||
int m_x2_lr;
|
||||
int m_y2_lr;
|
||||
bool m_ver;
|
||||
unsigned m_len;
|
||||
int m_inc;
|
||||
dda2_line_interpolator m_interpolator;
|
||||
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
132
3rd/agg/include/agg_gamma_functions.h
Normal file
132
3rd/agg/include/agg_gamma_functions.h
Normal file
@ -0,0 +1,132 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_GAMMA_FUNCTIONS_INCLUDED
|
||||
#define AGG_GAMMA_FUNCTIONS_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//===============================================================gamma_none
|
||||
struct gamma_none
|
||||
{
|
||||
double operator()(double x) const { return x; }
|
||||
};
|
||||
|
||||
|
||||
//==============================================================gamma_power
|
||||
class gamma_power
|
||||
{
|
||||
public:
|
||||
gamma_power() : m_gamma(1.0) {}
|
||||
gamma_power(double g) : m_gamma(g) {}
|
||||
|
||||
void gamma(double g) { m_gamma = g; }
|
||||
double gamma() const { return m_gamma; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
return pow(x, m_gamma);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_gamma;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================gamma_threshold
|
||||
class gamma_threshold
|
||||
{
|
||||
public:
|
||||
gamma_threshold() : m_threshold(0.5) {}
|
||||
gamma_threshold(double t) : m_threshold(t) {}
|
||||
|
||||
void threshold(double t) { m_threshold = t; }
|
||||
double threshold() const { return m_threshold; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
return (x < m_threshold) ? 0.0 : 1.0;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_threshold;
|
||||
};
|
||||
|
||||
|
||||
//============================================================gamma_linear
|
||||
class gamma_linear
|
||||
{
|
||||
public:
|
||||
gamma_linear() : m_start(0.0), m_end(1.0) {}
|
||||
gamma_linear(double s, double e) : m_start(s), m_end(e) {}
|
||||
|
||||
void set(double s, double e) { m_start = s; m_end = e; }
|
||||
void start(double s) { m_start = s; }
|
||||
void end(double e) { m_end = e; }
|
||||
double start() const { return m_start; }
|
||||
double end() const { return m_end; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
if(x < m_start) return 0.0;
|
||||
if(x > m_end) return 1.0;
|
||||
return (x - m_start) / (m_end - m_start);
|
||||
}
|
||||
|
||||
private:
|
||||
double m_start;
|
||||
double m_end;
|
||||
};
|
||||
|
||||
|
||||
//==========================================================gamma_multiply
|
||||
class gamma_multiply
|
||||
{
|
||||
public:
|
||||
gamma_multiply() : m_mul(1.0) {}
|
||||
gamma_multiply(double v) : m_mul(v) {}
|
||||
|
||||
void value(double v) { m_mul = v; }
|
||||
double value() const { return m_mul; }
|
||||
|
||||
double operator() (double x) const
|
||||
{
|
||||
double y = x * m_mul;
|
||||
if(y > 1.0) y = 1.0;
|
||||
return y;
|
||||
}
|
||||
|
||||
private:
|
||||
double m_mul;
|
||||
};
|
||||
|
||||
inline double sRGB_to_linear(double x)
|
||||
{
|
||||
return (x <= 0.04045) ? (x / 12.92) : pow((x + 0.055) / (1.055), 2.4);
|
||||
}
|
||||
|
||||
inline double linear_to_sRGB(double x)
|
||||
{
|
||||
return (x <= 0.0031308) ? (x * 12.92) : (1.055 * pow(x, 1 / 2.4) - 0.055);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
300
3rd/agg/include/agg_gamma_lut.h
Normal file
300
3rd/agg/include/agg_gamma_lut.h
Normal file
@ -0,0 +1,300 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_GAMMA_LUT_INCLUDED
|
||||
#define AGG_GAMMA_LUT_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
#include "agg_gamma_functions.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
template<class LoResT=int8u,
|
||||
class HiResT=int8u,
|
||||
unsigned GammaShift=8,
|
||||
unsigned HiResShift=8> class gamma_lut
|
||||
{
|
||||
public:
|
||||
typedef gamma_lut<LoResT, HiResT, GammaShift, HiResShift> self_type;
|
||||
|
||||
enum gamma_scale_e
|
||||
{
|
||||
gamma_shift = GammaShift,
|
||||
gamma_size = 1 << gamma_shift,
|
||||
gamma_mask = gamma_size - 1
|
||||
};
|
||||
|
||||
enum hi_res_scale_e
|
||||
{
|
||||
hi_res_shift = HiResShift,
|
||||
hi_res_size = 1 << hi_res_shift,
|
||||
hi_res_mask = hi_res_size - 1
|
||||
};
|
||||
|
||||
~gamma_lut()
|
||||
{
|
||||
pod_allocator<LoResT>::deallocate(m_inv_gamma, hi_res_size);
|
||||
pod_allocator<HiResT>::deallocate(m_dir_gamma, gamma_size);
|
||||
}
|
||||
|
||||
gamma_lut() :
|
||||
m_gamma(1.0),
|
||||
m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
|
||||
m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
|
||||
{
|
||||
unsigned i;
|
||||
for(i = 0; i < gamma_size; i++)
|
||||
{
|
||||
m_dir_gamma[i] = HiResT(i << (hi_res_shift - gamma_shift));
|
||||
}
|
||||
|
||||
for(i = 0; i < hi_res_size; i++)
|
||||
{
|
||||
m_inv_gamma[i] = LoResT(i >> (hi_res_shift - gamma_shift));
|
||||
}
|
||||
}
|
||||
|
||||
gamma_lut(double g) :
|
||||
m_gamma(1.0),
|
||||
m_dir_gamma(pod_allocator<HiResT>::allocate(gamma_size)),
|
||||
m_inv_gamma(pod_allocator<LoResT>::allocate(hi_res_size))
|
||||
{
|
||||
gamma(g);
|
||||
}
|
||||
|
||||
void gamma(double g)
|
||||
{
|
||||
m_gamma = g;
|
||||
|
||||
unsigned i;
|
||||
for(i = 0; i < gamma_size; i++)
|
||||
{
|
||||
m_dir_gamma[i] = (HiResT)
|
||||
uround(pow(i / double(gamma_mask), m_gamma) * double(hi_res_mask));
|
||||
}
|
||||
|
||||
double inv_g = 1.0 / g;
|
||||
for(i = 0; i < hi_res_size; i++)
|
||||
{
|
||||
m_inv_gamma[i] = (LoResT)
|
||||
uround(pow(i / double(hi_res_mask), inv_g) * double(gamma_mask));
|
||||
}
|
||||
}
|
||||
|
||||
double gamma() const
|
||||
{
|
||||
return m_gamma;
|
||||
}
|
||||
|
||||
HiResT dir(LoResT v) const
|
||||
{
|
||||
return m_dir_gamma[unsigned(v)];
|
||||
}
|
||||
|
||||
LoResT inv(HiResT v) const
|
||||
{
|
||||
return m_inv_gamma[unsigned(v)];
|
||||
}
|
||||
|
||||
private:
|
||||
gamma_lut(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
double m_gamma;
|
||||
HiResT* m_dir_gamma;
|
||||
LoResT* m_inv_gamma;
|
||||
};
|
||||
|
||||
//
|
||||
// sRGB support classes
|
||||
//
|
||||
|
||||
// sRGB_lut - implements sRGB conversion for the various types.
|
||||
// Base template is undefined, specializations are provided below.
|
||||
template<class LinearType>
|
||||
class sRGB_lut;
|
||||
|
||||
template<>
|
||||
class sRGB_lut<float>
|
||||
{
|
||||
public:
|
||||
sRGB_lut()
|
||||
{
|
||||
// Generate lookup tables.
|
||||
for (int i = 0; i <= 255; ++i)
|
||||
{
|
||||
m_dir_table[i] = float(sRGB_to_linear(i / 255.0));
|
||||
}
|
||||
for (int i = 0; i <= 65535; ++i)
|
||||
{
|
||||
m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 65535.0));
|
||||
}
|
||||
}
|
||||
|
||||
float dir(int8u v) const
|
||||
{
|
||||
return m_dir_table[v];
|
||||
}
|
||||
|
||||
int8u inv(float v) const
|
||||
{
|
||||
return m_inv_table[int16u(0.5 + v * 65535)];
|
||||
}
|
||||
|
||||
private:
|
||||
float m_dir_table[256];
|
||||
int8u m_inv_table[65536];
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_lut<int16u>
|
||||
{
|
||||
public:
|
||||
sRGB_lut()
|
||||
{
|
||||
// Generate lookup tables.
|
||||
for (int i = 0; i <= 255; ++i)
|
||||
{
|
||||
m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0));
|
||||
}
|
||||
for (int i = 0; i <= 65535; ++i)
|
||||
{
|
||||
m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 65535.0));
|
||||
}
|
||||
}
|
||||
|
||||
int16u dir(int8u v) const
|
||||
{
|
||||
return m_dir_table[v];
|
||||
}
|
||||
|
||||
int8u inv(int16u v) const
|
||||
{
|
||||
return m_inv_table[v];
|
||||
}
|
||||
|
||||
private:
|
||||
int16u m_dir_table[256];
|
||||
int8u m_inv_table[65536];
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_lut<int8u>
|
||||
{
|
||||
public:
|
||||
sRGB_lut()
|
||||
{
|
||||
// Generate lookup tables.
|
||||
for (int i = 0; i <= 255; ++i)
|
||||
{
|
||||
m_dir_table[i] = uround(255.0 * sRGB_to_linear(i / 255.0));
|
||||
m_inv_table[i] = uround(255.0 * linear_to_sRGB(i / 255.0));
|
||||
}
|
||||
}
|
||||
|
||||
int8u dir(int8u v) const
|
||||
{
|
||||
return m_dir_table[v];
|
||||
}
|
||||
|
||||
int8u inv(int8u v) const
|
||||
{
|
||||
return m_inv_table[v];
|
||||
}
|
||||
|
||||
private:
|
||||
int8u m_dir_table[256];
|
||||
int8u m_inv_table[256];
|
||||
};
|
||||
|
||||
// Common base class for sRGB_conv objects. Defines an internal
|
||||
// sRGB_lut object so that users don't have to.
|
||||
template<class T>
|
||||
class sRGB_conv_base
|
||||
{
|
||||
public:
|
||||
static T rgb_from_sRGB(int8u x)
|
||||
{
|
||||
return lut.dir(x);
|
||||
}
|
||||
|
||||
static int8u rgb_to_sRGB(T x)
|
||||
{
|
||||
return lut.inv(x);
|
||||
}
|
||||
|
||||
private:
|
||||
static sRGB_lut<T> lut;
|
||||
};
|
||||
|
||||
// Definition of sRGB_conv_base::lut. Due to the fact that this a template,
|
||||
// we don't need to place the definition in a cpp file. Hurrah.
|
||||
template<class T>
|
||||
sRGB_lut<T> sRGB_conv_base<T>::lut;
|
||||
|
||||
// Wrapper for sRGB-linear conversion.
|
||||
// Base template is undefined, specializations are provided below.
|
||||
template<class T>
|
||||
class sRGB_conv;
|
||||
|
||||
template<>
|
||||
class sRGB_conv<float> : public sRGB_conv_base<float>
|
||||
{
|
||||
public:
|
||||
static float alpha_from_sRGB(int8u x)
|
||||
{
|
||||
static const double y = 1 / 255.0;
|
||||
return float(x * y);
|
||||
}
|
||||
|
||||
static int8u alpha_to_sRGB(float x)
|
||||
{
|
||||
return int8u(0.5 + x * 255);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_conv<int16u> : public sRGB_conv_base<int16u>
|
||||
{
|
||||
public:
|
||||
static int16u alpha_from_sRGB(int8u x)
|
||||
{
|
||||
return (x << 8) | x;
|
||||
}
|
||||
|
||||
static int8u alpha_to_sRGB(int16u x)
|
||||
{
|
||||
return x >> 8;
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class sRGB_conv<int8u> : public sRGB_conv_base<int8u>
|
||||
{
|
||||
public:
|
||||
static int8u alpha_from_sRGB(int8u x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
|
||||
static int8u alpha_to_sRGB(int8u x)
|
||||
{
|
||||
return x;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
481
3rd/agg/include/agg_image_accessors.h
Normal file
481
3rd/agg/include/agg_image_accessors.h
Normal file
@ -0,0 +1,481 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_IMAGE_ACCESSORS_INCLUDED
|
||||
#define AGG_IMAGE_ACCESSORS_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------image_accessor_clip
|
||||
template<class PixFmt> class image_accessor_clip
|
||||
{
|
||||
public:
|
||||
typedef PixFmt pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
typedef typename pixfmt_type::order_type order_type;
|
||||
typedef typename pixfmt_type::value_type value_type;
|
||||
enum pix_width_e { pix_width = pixfmt_type::pix_width };
|
||||
|
||||
image_accessor_clip() {}
|
||||
explicit image_accessor_clip(pixfmt_type& pixf,
|
||||
const color_type& bk) :
|
||||
m_pixf(&pixf)
|
||||
{
|
||||
pixfmt_type::make_pix(m_bk_buf, bk);
|
||||
}
|
||||
|
||||
void attach(pixfmt_type& pixf)
|
||||
{
|
||||
m_pixf = &pixf;
|
||||
}
|
||||
|
||||
void background_color(const color_type& bk)
|
||||
{
|
||||
pixfmt_type::make_pix(m_bk_buf, bk);
|
||||
}
|
||||
|
||||
private:
|
||||
AGG_INLINE const int8u* pixel() const
|
||||
{
|
||||
if(m_y >= 0 && m_y < (int)m_pixf->height() &&
|
||||
m_x >= 0 && m_x < (int)m_pixf->width())
|
||||
{
|
||||
return m_pixf->pix_ptr(m_x, m_y);
|
||||
}
|
||||
return m_bk_buf;
|
||||
}
|
||||
|
||||
public:
|
||||
AGG_INLINE const int8u* span(int x, int y, unsigned len)
|
||||
{
|
||||
m_x = m_x0 = x;
|
||||
m_y = y;
|
||||
if(y >= 0 && y < (int)m_pixf->height() &&
|
||||
x >= 0 && x+(int)len <= (int)m_pixf->width())
|
||||
{
|
||||
return m_pix_ptr = m_pixf->pix_ptr(x, y);
|
||||
}
|
||||
m_pix_ptr = 0;
|
||||
return pixel();
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_x()
|
||||
{
|
||||
if(m_pix_ptr) return m_pix_ptr += pix_width;
|
||||
++m_x;
|
||||
return pixel();
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_y()
|
||||
{
|
||||
++m_y;
|
||||
m_x = m_x0;
|
||||
if(m_pix_ptr &&
|
||||
m_y >= 0 && m_y < (int)m_pixf->height())
|
||||
{
|
||||
return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y);
|
||||
}
|
||||
m_pix_ptr = 0;
|
||||
return pixel();
|
||||
}
|
||||
|
||||
private:
|
||||
const pixfmt_type* m_pixf;
|
||||
int8u m_bk_buf[pix_width];
|
||||
int m_x, m_x0, m_y;
|
||||
const int8u* m_pix_ptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------image_accessor_no_clip
|
||||
template<class PixFmt> class image_accessor_no_clip
|
||||
{
|
||||
public:
|
||||
typedef PixFmt pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
typedef typename pixfmt_type::order_type order_type;
|
||||
typedef typename pixfmt_type::value_type value_type;
|
||||
enum pix_width_e { pix_width = pixfmt_type::pix_width };
|
||||
|
||||
image_accessor_no_clip() {}
|
||||
explicit image_accessor_no_clip(pixfmt_type& pixf) :
|
||||
m_pixf(&pixf)
|
||||
{}
|
||||
|
||||
void attach(pixfmt_type& pixf)
|
||||
{
|
||||
m_pixf = &pixf;
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* span(int x, int y, unsigned)
|
||||
{
|
||||
m_x = x;
|
||||
m_y = y;
|
||||
return m_pix_ptr = m_pixf->pix_ptr(x, y);
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_x()
|
||||
{
|
||||
return m_pix_ptr += pix_width;
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_y()
|
||||
{
|
||||
++m_y;
|
||||
return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y);
|
||||
}
|
||||
|
||||
private:
|
||||
const pixfmt_type* m_pixf;
|
||||
int m_x, m_y;
|
||||
const int8u* m_pix_ptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//----------------------------------------------------image_accessor_clone
|
||||
template<class PixFmt> class image_accessor_clone
|
||||
{
|
||||
public:
|
||||
typedef PixFmt pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
typedef typename pixfmt_type::order_type order_type;
|
||||
typedef typename pixfmt_type::value_type value_type;
|
||||
enum pix_width_e { pix_width = pixfmt_type::pix_width };
|
||||
|
||||
image_accessor_clone() {}
|
||||
explicit image_accessor_clone(pixfmt_type& pixf) :
|
||||
m_pixf(&pixf)
|
||||
{}
|
||||
|
||||
void attach(pixfmt_type& pixf)
|
||||
{
|
||||
m_pixf = &pixf;
|
||||
}
|
||||
|
||||
private:
|
||||
AGG_INLINE const int8u* pixel() const
|
||||
{
|
||||
int x = m_x;
|
||||
int y = m_y;
|
||||
if(x < 0) x = 0;
|
||||
if(y < 0) y = 0;
|
||||
if(x >= (int)m_pixf->width()) x = m_pixf->width() - 1;
|
||||
if(y >= (int)m_pixf->height()) y = m_pixf->height() - 1;
|
||||
return m_pixf->pix_ptr(x, y);
|
||||
}
|
||||
|
||||
public:
|
||||
AGG_INLINE const int8u* span(int x, int y, unsigned len)
|
||||
{
|
||||
m_x = m_x0 = x;
|
||||
m_y = y;
|
||||
if(y >= 0 && y < (int)m_pixf->height() &&
|
||||
x >= 0 && x+len <= (int)m_pixf->width())
|
||||
{
|
||||
return m_pix_ptr = m_pixf->pix_ptr(x, y);
|
||||
}
|
||||
m_pix_ptr = 0;
|
||||
return pixel();
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_x()
|
||||
{
|
||||
if(m_pix_ptr) return m_pix_ptr += pix_width;
|
||||
++m_x;
|
||||
return pixel();
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_y()
|
||||
{
|
||||
++m_y;
|
||||
m_x = m_x0;
|
||||
if(m_pix_ptr &&
|
||||
m_y >= 0 && m_y < (int)m_pixf->height())
|
||||
{
|
||||
return m_pix_ptr = m_pixf->pix_ptr(m_x, m_y);
|
||||
}
|
||||
m_pix_ptr = 0;
|
||||
return pixel();
|
||||
}
|
||||
|
||||
private:
|
||||
const pixfmt_type* m_pixf;
|
||||
int m_x, m_x0, m_y;
|
||||
const int8u* m_pix_ptr;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------image_accessor_wrap
|
||||
template<class PixFmt, class WrapX, class WrapY> class image_accessor_wrap
|
||||
{
|
||||
public:
|
||||
typedef PixFmt pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
typedef typename pixfmt_type::order_type order_type;
|
||||
typedef typename pixfmt_type::value_type value_type;
|
||||
enum pix_width_e { pix_width = pixfmt_type::pix_width };
|
||||
|
||||
image_accessor_wrap() {}
|
||||
explicit image_accessor_wrap(pixfmt_type& pixf) :
|
||||
m_pixf(&pixf),
|
||||
m_wrap_x(pixf.width()),
|
||||
m_wrap_y(pixf.height())
|
||||
{}
|
||||
|
||||
void attach(pixfmt_type& pixf)
|
||||
{
|
||||
m_pixf = &pixf;
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* span(int x, int y, unsigned)
|
||||
{
|
||||
m_x = x;
|
||||
m_row_ptr = m_pixf->pix_ptr(0, m_wrap_y(y));
|
||||
return m_row_ptr + m_wrap_x(x) * pix_width;
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_x()
|
||||
{
|
||||
int x = ++m_wrap_x;
|
||||
return m_row_ptr + x * pix_width;
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* next_y()
|
||||
{
|
||||
m_row_ptr = m_pixf->pix_ptr(0, ++m_wrap_y);
|
||||
return m_row_ptr + m_wrap_x(m_x) * pix_width;
|
||||
}
|
||||
|
||||
private:
|
||||
const pixfmt_type* m_pixf;
|
||||
const int8u* m_row_ptr;
|
||||
int m_x;
|
||||
WrapX m_wrap_x;
|
||||
WrapY m_wrap_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------wrap_mode_repeat
|
||||
class wrap_mode_repeat
|
||||
{
|
||||
public:
|
||||
wrap_mode_repeat() {}
|
||||
wrap_mode_repeat(unsigned size) :
|
||||
m_size(size),
|
||||
m_add(size * (0x3FFFFFFF / size)),
|
||||
m_value(0)
|
||||
{}
|
||||
|
||||
AGG_INLINE unsigned operator() (int v)
|
||||
{
|
||||
return m_value = (unsigned(v) + m_add) % m_size;
|
||||
}
|
||||
|
||||
AGG_INLINE unsigned operator++ ()
|
||||
{
|
||||
++m_value;
|
||||
if(m_value >= m_size) m_value = 0;
|
||||
return m_value;
|
||||
}
|
||||
private:
|
||||
unsigned m_size;
|
||||
unsigned m_add;
|
||||
unsigned m_value;
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------------wrap_mode_repeat_pow2
|
||||
class wrap_mode_repeat_pow2
|
||||
{
|
||||
public:
|
||||
wrap_mode_repeat_pow2() {}
|
||||
wrap_mode_repeat_pow2(unsigned size) : m_value(0)
|
||||
{
|
||||
m_mask = 1;
|
||||
while(m_mask < size) m_mask = (m_mask << 1) | 1;
|
||||
m_mask >>= 1;
|
||||
}
|
||||
AGG_INLINE unsigned operator() (int v)
|
||||
{
|
||||
return m_value = unsigned(v) & m_mask;
|
||||
}
|
||||
AGG_INLINE unsigned operator++ ()
|
||||
{
|
||||
++m_value;
|
||||
if(m_value > m_mask) m_value = 0;
|
||||
return m_value;
|
||||
}
|
||||
private:
|
||||
unsigned m_mask;
|
||||
unsigned m_value;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------wrap_mode_repeat_auto_pow2
|
||||
class wrap_mode_repeat_auto_pow2
|
||||
{
|
||||
public:
|
||||
wrap_mode_repeat_auto_pow2() {}
|
||||
wrap_mode_repeat_auto_pow2(unsigned size) :
|
||||
m_size(size),
|
||||
m_add(size * (0x3FFFFFFF / size)),
|
||||
m_mask((m_size & (m_size-1)) ? 0 : m_size-1),
|
||||
m_value(0)
|
||||
{}
|
||||
|
||||
AGG_INLINE unsigned operator() (int v)
|
||||
{
|
||||
if(m_mask) return m_value = unsigned(v) & m_mask;
|
||||
return m_value = (unsigned(v) + m_add) % m_size;
|
||||
}
|
||||
AGG_INLINE unsigned operator++ ()
|
||||
{
|
||||
++m_value;
|
||||
if(m_value >= m_size) m_value = 0;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned m_size;
|
||||
unsigned m_add;
|
||||
unsigned m_mask;
|
||||
unsigned m_value;
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------------wrap_mode_reflect
|
||||
class wrap_mode_reflect
|
||||
{
|
||||
public:
|
||||
wrap_mode_reflect() {}
|
||||
wrap_mode_reflect(unsigned size) :
|
||||
m_size(size),
|
||||
m_size2(size * 2),
|
||||
m_add(m_size2 * (0x3FFFFFFF / m_size2)),
|
||||
m_value(0)
|
||||
{}
|
||||
|
||||
AGG_INLINE unsigned operator() (int v)
|
||||
{
|
||||
m_value = (unsigned(v) + m_add) % m_size2;
|
||||
if(m_value >= m_size) return m_size2 - m_value - 1;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
AGG_INLINE unsigned operator++ ()
|
||||
{
|
||||
++m_value;
|
||||
if(m_value >= m_size2) m_value = 0;
|
||||
if(m_value >= m_size) return m_size2 - m_value - 1;
|
||||
return m_value;
|
||||
}
|
||||
private:
|
||||
unsigned m_size;
|
||||
unsigned m_size2;
|
||||
unsigned m_add;
|
||||
unsigned m_value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------wrap_mode_reflect_pow2
|
||||
class wrap_mode_reflect_pow2
|
||||
{
|
||||
public:
|
||||
wrap_mode_reflect_pow2() {}
|
||||
wrap_mode_reflect_pow2(unsigned size) : m_value(0)
|
||||
{
|
||||
m_mask = 1;
|
||||
m_size = 1;
|
||||
while(m_mask < size)
|
||||
{
|
||||
m_mask = (m_mask << 1) | 1;
|
||||
m_size <<= 1;
|
||||
}
|
||||
}
|
||||
AGG_INLINE unsigned operator() (int v)
|
||||
{
|
||||
m_value = unsigned(v) & m_mask;
|
||||
if(m_value >= m_size) return m_mask - m_value;
|
||||
return m_value;
|
||||
}
|
||||
AGG_INLINE unsigned operator++ ()
|
||||
{
|
||||
++m_value;
|
||||
m_value &= m_mask;
|
||||
if(m_value >= m_size) return m_mask - m_value;
|
||||
return m_value;
|
||||
}
|
||||
private:
|
||||
unsigned m_size;
|
||||
unsigned m_mask;
|
||||
unsigned m_value;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------wrap_mode_reflect_auto_pow2
|
||||
class wrap_mode_reflect_auto_pow2
|
||||
{
|
||||
public:
|
||||
wrap_mode_reflect_auto_pow2() {}
|
||||
wrap_mode_reflect_auto_pow2(unsigned size) :
|
||||
m_size(size),
|
||||
m_size2(size * 2),
|
||||
m_add(m_size2 * (0x3FFFFFFF / m_size2)),
|
||||
m_mask((m_size2 & (m_size2-1)) ? 0 : m_size2-1),
|
||||
m_value(0)
|
||||
{}
|
||||
|
||||
AGG_INLINE unsigned operator() (int v)
|
||||
{
|
||||
m_value = m_mask ? unsigned(v) & m_mask :
|
||||
(unsigned(v) + m_add) % m_size2;
|
||||
if(m_value >= m_size) return m_size2 - m_value - 1;
|
||||
return m_value;
|
||||
}
|
||||
AGG_INLINE unsigned operator++ ()
|
||||
{
|
||||
++m_value;
|
||||
if(m_value >= m_size2) m_value = 0;
|
||||
if(m_value >= m_size) return m_size2 - m_value - 1;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned m_size;
|
||||
unsigned m_size2;
|
||||
unsigned m_add;
|
||||
unsigned m_mask;
|
||||
unsigned m_value;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
448
3rd/agg/include/agg_image_filters.h
Normal file
448
3rd/agg/include/agg_image_filters.h
Normal file
@ -0,0 +1,448 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Image transformation filters,
|
||||
// Filtering classes (image_filter_lut, image_filter),
|
||||
// Basic filter shape classes
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_IMAGE_FILTERS_INCLUDED
|
||||
#define AGG_IMAGE_FILTERS_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
#include "agg_math.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
// See Implementation agg_image_filters.cpp
|
||||
|
||||
enum image_filter_scale_e
|
||||
{
|
||||
image_filter_shift = 14, //----image_filter_shift
|
||||
image_filter_scale = 1 << image_filter_shift, //----image_filter_scale
|
||||
image_filter_mask = image_filter_scale - 1 //----image_filter_mask
|
||||
};
|
||||
|
||||
enum image_subpixel_scale_e
|
||||
{
|
||||
image_subpixel_shift = 8, //----image_subpixel_shift
|
||||
image_subpixel_scale = 1 << image_subpixel_shift, //----image_subpixel_scale
|
||||
image_subpixel_mask = image_subpixel_scale - 1 //----image_subpixel_mask
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------image_filter_lut
|
||||
class image_filter_lut
|
||||
{
|
||||
public:
|
||||
template<class FilterF> void calculate(const FilterF& filter,
|
||||
bool normalization=true)
|
||||
{
|
||||
double r = filter.radius();
|
||||
realloc_lut(r);
|
||||
unsigned i;
|
||||
unsigned pivot = diameter() << (image_subpixel_shift - 1);
|
||||
for(i = 0; i < pivot; i++)
|
||||
{
|
||||
double x = double(i) / double(image_subpixel_scale);
|
||||
double y = filter.calc_weight(x);
|
||||
m_weight_array[pivot + i] =
|
||||
m_weight_array[pivot - i] = (int16)iround(y * image_filter_scale);
|
||||
}
|
||||
unsigned end = (diameter() << image_subpixel_shift) - 1;
|
||||
m_weight_array[0] = m_weight_array[end];
|
||||
if(normalization)
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
}
|
||||
|
||||
image_filter_lut() : m_radius(0), m_diameter(0), m_start(0) {}
|
||||
|
||||
template<class FilterF> image_filter_lut(const FilterF& filter,
|
||||
bool normalization=true)
|
||||
{
|
||||
calculate(filter, normalization);
|
||||
}
|
||||
|
||||
double radius() const { return m_radius; }
|
||||
unsigned diameter() const { return m_diameter; }
|
||||
int start() const { return m_start; }
|
||||
const int16* weight_array() const { return &m_weight_array[0]; }
|
||||
void normalize();
|
||||
|
||||
private:
|
||||
void realloc_lut(double radius);
|
||||
image_filter_lut(const image_filter_lut&);
|
||||
const image_filter_lut& operator = (const image_filter_lut&);
|
||||
|
||||
double m_radius;
|
||||
unsigned m_diameter;
|
||||
int m_start;
|
||||
pod_array<int16> m_weight_array;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------image_filter
|
||||
template<class FilterF> class image_filter : public image_filter_lut
|
||||
{
|
||||
public:
|
||||
image_filter()
|
||||
{
|
||||
calculate(m_filter_function);
|
||||
}
|
||||
private:
|
||||
FilterF m_filter_function;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------image_filter_bilinear
|
||||
struct image_filter_bilinear
|
||||
{
|
||||
static double radius() { return 1.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return 1.0 - x;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------image_filter_hanning
|
||||
struct image_filter_hanning
|
||||
{
|
||||
static double radius() { return 1.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return 0.5 + 0.5 * cos(pi * x);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------image_filter_hamming
|
||||
struct image_filter_hamming
|
||||
{
|
||||
static double radius() { return 1.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return 0.54 + 0.46 * cos(pi * x);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------image_filter_hermite
|
||||
struct image_filter_hermite
|
||||
{
|
||||
static double radius() { return 1.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return (2.0 * x - 3.0) * x * x + 1.0;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------image_filter_quadric
|
||||
struct image_filter_quadric
|
||||
{
|
||||
static double radius() { return 1.5; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
double t;
|
||||
if(x < 0.5) return 0.75 - x * x;
|
||||
if(x < 1.5) {t = x - 1.5; return 0.5 * t * t;}
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
//------------------------------------------------image_filter_bicubic
|
||||
class image_filter_bicubic
|
||||
{
|
||||
static double pow3(double x)
|
||||
{
|
||||
return (x <= 0.0) ? 0.0 : x * x * x;
|
||||
}
|
||||
|
||||
public:
|
||||
static double radius() { return 2.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return
|
||||
(1.0/6.0) *
|
||||
(pow3(x + 2) - 4 * pow3(x + 1) + 6 * pow3(x) - 4 * pow3(x - 1));
|
||||
}
|
||||
};
|
||||
|
||||
//-------------------------------------------------image_filter_kaiser
|
||||
class image_filter_kaiser
|
||||
{
|
||||
double a;
|
||||
double i0a;
|
||||
double epsilon;
|
||||
|
||||
public:
|
||||
image_filter_kaiser(double b = 6.33) :
|
||||
a(b), epsilon(1e-12)
|
||||
{
|
||||
i0a = 1.0 / bessel_i0(b);
|
||||
}
|
||||
|
||||
static double radius() { return 1.0; }
|
||||
double calc_weight(double x) const
|
||||
{
|
||||
return bessel_i0(a * sqrt(1. - x * x)) * i0a;
|
||||
}
|
||||
|
||||
private:
|
||||
double bessel_i0(double x) const
|
||||
{
|
||||
int i;
|
||||
double sum, y, t;
|
||||
|
||||
sum = 1.;
|
||||
y = x * x / 4.;
|
||||
t = y;
|
||||
|
||||
for(i = 2; t > epsilon; i++)
|
||||
{
|
||||
sum += t;
|
||||
t *= (double)y / (i * i);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------image_filter_catrom
|
||||
struct image_filter_catrom
|
||||
{
|
||||
static double radius() { return 2.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
if(x < 1.0) return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0));
|
||||
if(x < 2.0) return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x)));
|
||||
return 0.;
|
||||
}
|
||||
};
|
||||
|
||||
//---------------------------------------------image_filter_mitchell
|
||||
class image_filter_mitchell
|
||||
{
|
||||
double p0, p2, p3;
|
||||
double q0, q1, q2, q3;
|
||||
|
||||
public:
|
||||
image_filter_mitchell(double b = 1.0/3.0, double c = 1.0/3.0) :
|
||||
p0((6.0 - 2.0 * b) / 6.0),
|
||||
p2((-18.0 + 12.0 * b + 6.0 * c) / 6.0),
|
||||
p3((12.0 - 9.0 * b - 6.0 * c) / 6.0),
|
||||
q0((8.0 * b + 24.0 * c) / 6.0),
|
||||
q1((-12.0 * b - 48.0 * c) / 6.0),
|
||||
q2((6.0 * b + 30.0 * c) / 6.0),
|
||||
q3((-b - 6.0 * c) / 6.0)
|
||||
{}
|
||||
|
||||
static double radius() { return 2.0; }
|
||||
double calc_weight(double x) const
|
||||
{
|
||||
if(x < 1.0) return p0 + x * x * (p2 + x * p3);
|
||||
if(x < 2.0) return q0 + x * (q1 + x * (q2 + x * q3));
|
||||
return 0.0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------image_filter_spline16
|
||||
struct image_filter_spline16
|
||||
{
|
||||
static double radius() { return 2.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
if(x < 1.0)
|
||||
{
|
||||
return ((x - 9.0/5.0 ) * x - 1.0/5.0 ) * x + 1.0;
|
||||
}
|
||||
return ((-1.0/3.0 * (x-1) + 4.0/5.0) * (x-1) - 7.0/15.0 ) * (x-1);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//---------------------------------------------image_filter_spline36
|
||||
struct image_filter_spline36
|
||||
{
|
||||
static double radius() { return 3.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
if(x < 1.0)
|
||||
{
|
||||
return ((13.0/11.0 * x - 453.0/209.0) * x - 3.0/209.0) * x + 1.0;
|
||||
}
|
||||
if(x < 2.0)
|
||||
{
|
||||
return ((-6.0/11.0 * (x-1) + 270.0/209.0) * (x-1) - 156.0/ 209.0) * (x-1);
|
||||
}
|
||||
return ((1.0/11.0 * (x-2) - 45.0/209.0) * (x-2) + 26.0/209.0) * (x-2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------image_filter_gaussian
|
||||
struct image_filter_gaussian
|
||||
{
|
||||
static double radius() { return 2.0; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return exp(-2.0 * x * x) * sqrt(2.0 / pi);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------image_filter_bessel
|
||||
struct image_filter_bessel
|
||||
{
|
||||
static double radius() { return 3.2383; }
|
||||
static double calc_weight(double x)
|
||||
{
|
||||
return (x == 0.0) ? pi / 4.0 : besj(pi * x, 1) / (2.0 * x);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//-------------------------------------------------image_filter_sinc
|
||||
class image_filter_sinc
|
||||
{
|
||||
public:
|
||||
image_filter_sinc(double r) : m_radius(r < 2.0 ? 2.0 : r) {}
|
||||
double radius() const { return m_radius; }
|
||||
double calc_weight(double x) const
|
||||
{
|
||||
if(x == 0.0) return 1.0;
|
||||
x *= pi;
|
||||
return sin(x) / x;
|
||||
}
|
||||
private:
|
||||
double m_radius;
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------image_filter_lanczos
|
||||
class image_filter_lanczos
|
||||
{
|
||||
public:
|
||||
image_filter_lanczos(double r) : m_radius(r < 2.0 ? 2.0 : r) {}
|
||||
double radius() const { return m_radius; }
|
||||
double calc_weight(double x) const
|
||||
{
|
||||
if(x == 0.0) return 1.0;
|
||||
if(x > m_radius) return 0.0;
|
||||
x *= pi;
|
||||
double xr = x / m_radius;
|
||||
return (sin(x) / x) * (sin(xr) / xr);
|
||||
}
|
||||
private:
|
||||
double m_radius;
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------image_filter_blackman
|
||||
class image_filter_blackman
|
||||
{
|
||||
public:
|
||||
image_filter_blackman(double r) : m_radius(r < 2.0 ? 2.0 : r) {}
|
||||
double radius() const { return m_radius; }
|
||||
double calc_weight(double x) const
|
||||
{
|
||||
if(x == 0.0) return 1.0;
|
||||
if(x > m_radius) return 0.0;
|
||||
x *= pi;
|
||||
double xr = x / m_radius;
|
||||
return (sin(x) / x) * (0.42 + 0.5*cos(xr) + 0.08*cos(2*xr));
|
||||
}
|
||||
private:
|
||||
double m_radius;
|
||||
};
|
||||
|
||||
//------------------------------------------------image_filter_sinc36
|
||||
class image_filter_sinc36 : public image_filter_sinc
|
||||
{ public: image_filter_sinc36() : image_filter_sinc(3.0){} };
|
||||
|
||||
//------------------------------------------------image_filter_sinc64
|
||||
class image_filter_sinc64 : public image_filter_sinc
|
||||
{ public: image_filter_sinc64() : image_filter_sinc(4.0){} };
|
||||
|
||||
//-----------------------------------------------image_filter_sinc100
|
||||
class image_filter_sinc100 : public image_filter_sinc
|
||||
{ public: image_filter_sinc100() : image_filter_sinc(5.0){} };
|
||||
|
||||
//-----------------------------------------------image_filter_sinc144
|
||||
class image_filter_sinc144 : public image_filter_sinc
|
||||
{ public: image_filter_sinc144() : image_filter_sinc(6.0){} };
|
||||
|
||||
//-----------------------------------------------image_filter_sinc196
|
||||
class image_filter_sinc196 : public image_filter_sinc
|
||||
{ public: image_filter_sinc196() : image_filter_sinc(7.0){} };
|
||||
|
||||
//-----------------------------------------------image_filter_sinc256
|
||||
class image_filter_sinc256 : public image_filter_sinc
|
||||
{ public: image_filter_sinc256() : image_filter_sinc(8.0){} };
|
||||
|
||||
//---------------------------------------------image_filter_lanczos36
|
||||
class image_filter_lanczos36 : public image_filter_lanczos
|
||||
{ public: image_filter_lanczos36() : image_filter_lanczos(3.0){} };
|
||||
|
||||
//---------------------------------------------image_filter_lanczos64
|
||||
class image_filter_lanczos64 : public image_filter_lanczos
|
||||
{ public: image_filter_lanczos64() : image_filter_lanczos(4.0){} };
|
||||
|
||||
//--------------------------------------------image_filter_lanczos100
|
||||
class image_filter_lanczos100 : public image_filter_lanczos
|
||||
{ public: image_filter_lanczos100() : image_filter_lanczos(5.0){} };
|
||||
|
||||
//--------------------------------------------image_filter_lanczos144
|
||||
class image_filter_lanczos144 : public image_filter_lanczos
|
||||
{ public: image_filter_lanczos144() : image_filter_lanczos(6.0){} };
|
||||
|
||||
//--------------------------------------------image_filter_lanczos196
|
||||
class image_filter_lanczos196 : public image_filter_lanczos
|
||||
{ public: image_filter_lanczos196() : image_filter_lanczos(7.0){} };
|
||||
|
||||
//--------------------------------------------image_filter_lanczos256
|
||||
class image_filter_lanczos256 : public image_filter_lanczos
|
||||
{ public: image_filter_lanczos256() : image_filter_lanczos(8.0){} };
|
||||
|
||||
//--------------------------------------------image_filter_blackman36
|
||||
class image_filter_blackman36 : public image_filter_blackman
|
||||
{ public: image_filter_blackman36() : image_filter_blackman(3.0){} };
|
||||
|
||||
//--------------------------------------------image_filter_blackman64
|
||||
class image_filter_blackman64 : public image_filter_blackman
|
||||
{ public: image_filter_blackman64() : image_filter_blackman(4.0){} };
|
||||
|
||||
//-------------------------------------------image_filter_blackman100
|
||||
class image_filter_blackman100 : public image_filter_blackman
|
||||
{ public: image_filter_blackman100() : image_filter_blackman(5.0){} };
|
||||
|
||||
//-------------------------------------------image_filter_blackman144
|
||||
class image_filter_blackman144 : public image_filter_blackman
|
||||
{ public: image_filter_blackman144() : image_filter_blackman(6.0){} };
|
||||
|
||||
//-------------------------------------------image_filter_blackman196
|
||||
class image_filter_blackman196 : public image_filter_blackman
|
||||
{ public: image_filter_blackman196() : image_filter_blackman(7.0){} };
|
||||
|
||||
//-------------------------------------------image_filter_blackman256
|
||||
class image_filter_blackman256 : public image_filter_blackman
|
||||
{ public: image_filter_blackman256() : image_filter_blackman(8.0){} };
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
437
3rd/agg/include/agg_math.h
Normal file
437
3rd/agg/include/agg_math.h
Normal file
@ -0,0 +1,437 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
// Bessel function (besj) was adapted for use in AGG library by Andy Wilk
|
||||
// Contact: castor.vulgaris@gmail.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_MATH_INCLUDED
|
||||
#define AGG_MATH_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------vertex_dist_epsilon
|
||||
// Coinciding points maximal distance (Epsilon)
|
||||
const double vertex_dist_epsilon = 1e-14;
|
||||
|
||||
//-----------------------------------------------------intersection_epsilon
|
||||
// See calc_intersection
|
||||
const double intersection_epsilon = 1.0e-30;
|
||||
|
||||
//------------------------------------------------------------cross_product
|
||||
AGG_INLINE double cross_product(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------point_in_triangle
|
||||
AGG_INLINE bool point_in_triangle(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double x, double y)
|
||||
{
|
||||
bool cp1 = cross_product(x1, y1, x2, y2, x, y) < 0.0;
|
||||
bool cp2 = cross_product(x2, y2, x3, y3, x, y) < 0.0;
|
||||
bool cp3 = cross_product(x3, y3, x1, y1, x, y) < 0.0;
|
||||
return cp1 == cp2 && cp2 == cp3 && cp3 == cp1;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------calc_distance
|
||||
AGG_INLINE double calc_distance(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
return sqrt(dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------calc_sq_distance
|
||||
AGG_INLINE double calc_sq_distance(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
|
||||
//------------------------------------------------calc_line_point_distance
|
||||
AGG_INLINE double calc_line_point_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
double dx = x2-x1;
|
||||
double dy = y2-y1;
|
||||
double d = sqrt(dx * dx + dy * dy);
|
||||
if(d < vertex_dist_epsilon)
|
||||
{
|
||||
return calc_distance(x1, y1, x, y);
|
||||
}
|
||||
return ((x - x2) * dy - (y - y2) * dx) / d;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_line_point_u
|
||||
AGG_INLINE double calc_segment_point_u(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
|
||||
if(dx == 0 && dy == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
double pdx = x - x1;
|
||||
double pdy = y - y1;
|
||||
|
||||
return (pdx * dx + pdy * dy) / (dx * dx + dy * dy);
|
||||
}
|
||||
|
||||
//---------------------------------------------calc_line_point_sq_distance
|
||||
AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y,
|
||||
double u)
|
||||
{
|
||||
if(u <= 0)
|
||||
{
|
||||
return calc_sq_distance(x, y, x1, y1);
|
||||
}
|
||||
else
|
||||
if(u >= 1)
|
||||
{
|
||||
return calc_sq_distance(x, y, x2, y2);
|
||||
}
|
||||
return calc_sq_distance(x, y, x1 + u * (x2 - x1), y1 + u * (y2 - y1));
|
||||
}
|
||||
|
||||
//---------------------------------------------calc_line_point_sq_distance
|
||||
AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x, double y)
|
||||
{
|
||||
return
|
||||
calc_segment_point_sq_distance(
|
||||
x1, y1, x2, y2, x, y,
|
||||
calc_segment_point_u(x1, y1, x2, y2, x, y));
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_intersection
|
||||
AGG_INLINE bool calc_intersection(double ax, double ay, double bx, double by,
|
||||
double cx, double cy, double dx, double dy,
|
||||
double* x, double* y)
|
||||
{
|
||||
double num = (ay-cy) * (dx-cx) - (ax-cx) * (dy-cy);
|
||||
double den = (bx-ax) * (dy-cy) - (by-ay) * (dx-cx);
|
||||
if(fabs(den) < intersection_epsilon) return false;
|
||||
double r = num / den;
|
||||
*x = ax + r * (bx-ax);
|
||||
*y = ay + r * (by-ay);
|
||||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------intersection_exists
|
||||
AGG_INLINE bool intersection_exists(double x1, double y1, double x2, double y2,
|
||||
double x3, double y3, double x4, double y4)
|
||||
{
|
||||
// It's less expensive but you can't control the
|
||||
// boundary conditions: Less or LessEqual
|
||||
double dx1 = x2 - x1;
|
||||
double dy1 = y2 - y1;
|
||||
double dx2 = x4 - x3;
|
||||
double dy2 = y4 - y3;
|
||||
return ((x3 - x2) * dy1 - (y3 - y2) * dx1 < 0.0) !=
|
||||
((x4 - x2) * dy1 - (y4 - y2) * dx1 < 0.0) &&
|
||||
((x1 - x4) * dy2 - (y1 - y4) * dx2 < 0.0) !=
|
||||
((x2 - x4) * dy2 - (y2 - y4) * dx2 < 0.0);
|
||||
|
||||
// It's is more expensive but more flexible
|
||||
// in terms of boundary conditions.
|
||||
//--------------------
|
||||
//double den = (x2-x1) * (y4-y3) - (y2-y1) * (x4-x3);
|
||||
//if(fabs(den) < intersection_epsilon) return false;
|
||||
//double nom1 = (x4-x3) * (y1-y3) - (y4-y3) * (x1-x3);
|
||||
//double nom2 = (x2-x1) * (y1-y3) - (y2-y1) * (x1-x3);
|
||||
//double ua = nom1 / den;
|
||||
//double ub = nom2 / den;
|
||||
//return ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------calc_orthogonal
|
||||
AGG_INLINE void calc_orthogonal(double thickness,
|
||||
double x1, double y1,
|
||||
double x2, double y2,
|
||||
double* x, double* y)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
double d = sqrt(dx*dx + dy*dy);
|
||||
*x = thickness * dy / d;
|
||||
*y = -thickness * dx / d;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------dilate_triangle
|
||||
AGG_INLINE void dilate_triangle(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3,
|
||||
double *x, double* y,
|
||||
double d)
|
||||
{
|
||||
double dx1=0.0;
|
||||
double dy1=0.0;
|
||||
double dx2=0.0;
|
||||
double dy2=0.0;
|
||||
double dx3=0.0;
|
||||
double dy3=0.0;
|
||||
double loc = cross_product(x1, y1, x2, y2, x3, y3);
|
||||
if(fabs(loc) > intersection_epsilon)
|
||||
{
|
||||
if(cross_product(x1, y1, x2, y2, x3, y3) > 0.0)
|
||||
{
|
||||
d = -d;
|
||||
}
|
||||
calc_orthogonal(d, x1, y1, x2, y2, &dx1, &dy1);
|
||||
calc_orthogonal(d, x2, y2, x3, y3, &dx2, &dy2);
|
||||
calc_orthogonal(d, x3, y3, x1, y1, &dx3, &dy3);
|
||||
}
|
||||
*x++ = x1 + dx1; *y++ = y1 + dy1;
|
||||
*x++ = x2 + dx1; *y++ = y2 + dy1;
|
||||
*x++ = x2 + dx2; *y++ = y2 + dy2;
|
||||
*x++ = x3 + dx2; *y++ = y3 + dy2;
|
||||
*x++ = x3 + dx3; *y++ = y3 + dy3;
|
||||
*x++ = x1 + dx3; *y++ = y1 + dy3;
|
||||
}
|
||||
|
||||
//------------------------------------------------------calc_triangle_area
|
||||
AGG_INLINE double calc_triangle_area(double x1, double y1,
|
||||
double x2, double y2,
|
||||
double x3, double y3)
|
||||
{
|
||||
return (x1*y2 - x2*y1 + x2*y3 - x3*y2 + x3*y1 - x1*y3) * 0.5;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------calc_polygon_area
|
||||
template<class Storage> double calc_polygon_area(const Storage& st)
|
||||
{
|
||||
unsigned i;
|
||||
double sum = 0.0;
|
||||
double x = st[0].x;
|
||||
double y = st[0].y;
|
||||
double xs = x;
|
||||
double ys = y;
|
||||
|
||||
for(i = 1; i < st.size(); i++)
|
||||
{
|
||||
const typename Storage::value_type& v = st[i];
|
||||
sum += x * v.y - y * v.x;
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
}
|
||||
return (sum + x * ys - y * xs) * 0.5;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
// Tables for fast sqrt
|
||||
extern int16u g_sqrt_table[1024];
|
||||
extern int8 g_elder_bit_table[256];
|
||||
|
||||
|
||||
//---------------------------------------------------------------fast_sqrt
|
||||
//Fast integer Sqrt - really fast: no cycles, divisions or multiplications
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4035) //Disable warning "no return value"
|
||||
#endif
|
||||
AGG_INLINE unsigned fast_sqrt(unsigned val)
|
||||
{
|
||||
#if defined(_M_IX86) && defined(_MSC_VER) && !defined(AGG_NO_ASM)
|
||||
//For Ix86 family processors this assembler code is used.
|
||||
//The key command here is bsr - determination the number of the most
|
||||
//significant bit of the value. For other processors
|
||||
//(and maybe compilers) the pure C "#else" section is used.
|
||||
__asm
|
||||
{
|
||||
mov ebx, val
|
||||
mov edx, 11
|
||||
bsr ecx, ebx
|
||||
sub ecx, 9
|
||||
jle less_than_9_bits
|
||||
shr ecx, 1
|
||||
adc ecx, 0
|
||||
sub edx, ecx
|
||||
shl ecx, 1
|
||||
shr ebx, cl
|
||||
less_than_9_bits:
|
||||
xor eax, eax
|
||||
mov ax, g_sqrt_table[ebx*2]
|
||||
mov ecx, edx
|
||||
shr eax, cl
|
||||
}
|
||||
#else
|
||||
|
||||
//This code is actually pure C and portable to most
|
||||
//arcitectures including 64bit ones.
|
||||
unsigned t = val;
|
||||
int bit=0;
|
||||
unsigned shift = 11;
|
||||
|
||||
//The following piece of code is just an emulation of the
|
||||
//Ix86 assembler command "bsr" (see above). However on old
|
||||
//Intels (like Intel MMX 233MHz) this code is about twice
|
||||
//faster (sic!) then just one "bsr". On PIII and PIV the
|
||||
//bsr is optimized quite well.
|
||||
bit = t >> 24;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 24;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = (t >> 16) & 0xFF;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 16;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = (t >> 8) & 0xFF;
|
||||
if(bit)
|
||||
{
|
||||
bit = g_elder_bit_table[bit] + 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
bit = g_elder_bit_table[t];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This code calculates the sqrt.
|
||||
bit -= 9;
|
||||
if(bit > 0)
|
||||
{
|
||||
bit = (bit >> 1) + (bit & 1);
|
||||
shift -= bit;
|
||||
val >>= (bit << 1);
|
||||
}
|
||||
return g_sqrt_table[val] >> shift;
|
||||
#endif
|
||||
}
|
||||
#if defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------besj
|
||||
// Function BESJ calculates Bessel function of first kind of order n
|
||||
// Arguments:
|
||||
// n - an integer (>=0), the order
|
||||
// x - value at which the Bessel function is required
|
||||
//--------------------
|
||||
// C++ Mathematical Library
|
||||
// Convereted from equivalent FORTRAN library
|
||||
// Converetd by Gareth Walker for use by course 392 computational project
|
||||
// All functions tested and yield the same results as the corresponding
|
||||
// FORTRAN versions.
|
||||
//
|
||||
// If you have any problems using these functions please report them to
|
||||
// M.Muldoon@UMIST.ac.uk
|
||||
//
|
||||
// Documentation available on the web
|
||||
// http://www.ma.umist.ac.uk/mrm/Teaching/392/libs/392.html
|
||||
// Version 1.0 8/98
|
||||
// 29 October, 1999
|
||||
//--------------------
|
||||
// Adapted for use in AGG library by Andy Wilk (castor.vulgaris@gmail.com)
|
||||
//------------------------------------------------------------------------
|
||||
inline double besj(double x, int n)
|
||||
{
|
||||
if(n < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
double d = 1E-6;
|
||||
double b = 0;
|
||||
if(fabs(x) <= d)
|
||||
{
|
||||
if(n != 0) return 0;
|
||||
return 1;
|
||||
}
|
||||
double b1 = 0; // b1 is the value from the previous iteration
|
||||
// Set up a starting order for recurrence
|
||||
int m1 = (int)fabs(x) + 6;
|
||||
if(fabs(x) > 5)
|
||||
{
|
||||
m1 = (int)(fabs(1.4 * x + 60 / x));
|
||||
}
|
||||
int m2 = (int)(n + 2 + fabs(x) / 4);
|
||||
if (m1 > m2)
|
||||
{
|
||||
m2 = m1;
|
||||
}
|
||||
|
||||
// Apply recurrence down from curent max order
|
||||
for(;;)
|
||||
{
|
||||
double c3 = 0;
|
||||
double c2 = 1E-30;
|
||||
double c4 = 0;
|
||||
int m8 = 1;
|
||||
if (m2 / 2 * 2 == m2)
|
||||
{
|
||||
m8 = -1;
|
||||
}
|
||||
int imax = m2 - 2;
|
||||
for (int i = 1; i <= imax; i++)
|
||||
{
|
||||
double c6 = 2 * (m2 - i) * c2 / x - c3;
|
||||
c3 = c2;
|
||||
c2 = c6;
|
||||
if(m2 - i - 1 == n)
|
||||
{
|
||||
b = c6;
|
||||
}
|
||||
m8 = -1 * m8;
|
||||
if (m8 > 0)
|
||||
{
|
||||
c4 = c4 + 2 * c6;
|
||||
}
|
||||
}
|
||||
double c6 = 2 * c2 / x - c3;
|
||||
if(n == 0)
|
||||
{
|
||||
b = c6;
|
||||
}
|
||||
c4 += c6;
|
||||
b /= c4;
|
||||
if(fabs(b - b1) < d)
|
||||
{
|
||||
return b;
|
||||
}
|
||||
b1 = b;
|
||||
m2 += 3;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
526
3rd/agg/include/agg_math_stroke.h
Normal file
526
3rd/agg/include/agg_math_stroke.h
Normal file
@ -0,0 +1,526 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Stroke math
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_STROKE_MATH_INCLUDED
|
||||
#define AGG_STROKE_MATH_INCLUDED
|
||||
|
||||
#include "agg_math.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//-------------------------------------------------------------line_cap_e
|
||||
enum line_cap_e
|
||||
{
|
||||
butt_cap,
|
||||
square_cap,
|
||||
round_cap
|
||||
};
|
||||
|
||||
//------------------------------------------------------------line_join_e
|
||||
enum line_join_e
|
||||
{
|
||||
miter_join = 0,
|
||||
miter_join_revert = 1,
|
||||
round_join = 2,
|
||||
bevel_join = 3,
|
||||
miter_join_round = 4
|
||||
};
|
||||
|
||||
|
||||
//-----------------------------------------------------------inner_join_e
|
||||
enum inner_join_e
|
||||
{
|
||||
inner_bevel,
|
||||
inner_miter,
|
||||
inner_jag,
|
||||
inner_round
|
||||
};
|
||||
|
||||
//------------------------------------------------------------math_stroke
|
||||
template<class VertexConsumer> class math_stroke
|
||||
{
|
||||
public:
|
||||
typedef typename VertexConsumer::value_type coord_type;
|
||||
|
||||
math_stroke();
|
||||
|
||||
void line_cap(line_cap_e lc) { m_line_cap = lc; }
|
||||
void line_join(line_join_e lj) { m_line_join = lj; }
|
||||
void inner_join(inner_join_e ij) { m_inner_join = ij; }
|
||||
|
||||
line_cap_e line_cap() const { return m_line_cap; }
|
||||
line_join_e line_join() const { return m_line_join; }
|
||||
inner_join_e inner_join() const { return m_inner_join; }
|
||||
|
||||
void width(double w);
|
||||
void miter_limit(double ml) { m_miter_limit = ml; }
|
||||
void miter_limit_theta(double t);
|
||||
void inner_miter_limit(double ml) { m_inner_miter_limit = ml; }
|
||||
void approximation_scale(double as) { m_approx_scale = as; }
|
||||
|
||||
double width() const { return m_width * 2.0; }
|
||||
double miter_limit() const { return m_miter_limit; }
|
||||
double inner_miter_limit() const { return m_inner_miter_limit; }
|
||||
double approximation_scale() const { return m_approx_scale; }
|
||||
|
||||
void calc_cap(VertexConsumer& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
double len);
|
||||
|
||||
void calc_join(VertexConsumer& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double len1,
|
||||
double len2);
|
||||
|
||||
private:
|
||||
AGG_INLINE void add_vertex(VertexConsumer& vc, double x, double y)
|
||||
{
|
||||
vc.add(coord_type(x, y));
|
||||
}
|
||||
|
||||
void calc_arc(VertexConsumer& vc,
|
||||
double x, double y,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2);
|
||||
|
||||
void calc_miter(VertexConsumer& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
line_join_e lj,
|
||||
double mlimit,
|
||||
double dbevel);
|
||||
|
||||
double m_width;
|
||||
double m_width_abs;
|
||||
double m_width_eps;
|
||||
int m_width_sign;
|
||||
double m_miter_limit;
|
||||
double m_inner_miter_limit;
|
||||
double m_approx_scale;
|
||||
line_cap_e m_line_cap;
|
||||
line_join_e m_line_join;
|
||||
inner_join_e m_inner_join;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC> math_stroke<VC>::math_stroke() :
|
||||
m_width(0.5),
|
||||
m_width_abs(0.5),
|
||||
m_width_eps(0.5/1024.0),
|
||||
m_width_sign(1),
|
||||
m_miter_limit(4.0),
|
||||
m_inner_miter_limit(1.01),
|
||||
m_approx_scale(1.0),
|
||||
m_line_cap(butt_cap),
|
||||
m_line_join(miter_join),
|
||||
m_inner_join(inner_miter)
|
||||
{
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC> void math_stroke<VC>::width(double w)
|
||||
{
|
||||
m_width = w * 0.5;
|
||||
if(m_width < 0)
|
||||
{
|
||||
m_width_abs = -m_width;
|
||||
m_width_sign = -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_width_abs = m_width;
|
||||
m_width_sign = 1;
|
||||
}
|
||||
m_width_eps = m_width / 1024.0;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC> void math_stroke<VC>::miter_limit_theta(double t)
|
||||
{
|
||||
m_miter_limit = 1.0 / sin(t * 0.5) ;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_arc(VC& vc,
|
||||
double x, double y,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2)
|
||||
{
|
||||
double a1 = atan2(dy1 * m_width_sign, dx1 * m_width_sign);
|
||||
double a2 = atan2(dy2 * m_width_sign, dx2 * m_width_sign);
|
||||
double da = a1 - a2;
|
||||
int i, n;
|
||||
|
||||
da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;
|
||||
|
||||
add_vertex(vc, x + dx1, y + dy1);
|
||||
if(m_width_sign > 0)
|
||||
{
|
||||
if(a1 > a2) a2 += 2 * pi;
|
||||
n = int((a2 - a1) / da);
|
||||
da = (a2 - a1) / (n + 1);
|
||||
a1 += da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width);
|
||||
a1 += da;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(a1 < a2) a2 -= 2 * pi;
|
||||
n = int((a1 - a2) / da);
|
||||
da = (a1 - a2) / (n + 1);
|
||||
a1 -= da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width);
|
||||
a1 -= da;
|
||||
}
|
||||
}
|
||||
add_vertex(vc, x + dx2, y + dy2);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_miter(VC& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double dx1, double dy1,
|
||||
double dx2, double dy2,
|
||||
line_join_e lj,
|
||||
double mlimit,
|
||||
double dbevel)
|
||||
{
|
||||
double xi = v1.x;
|
||||
double yi = v1.y;
|
||||
double di = 1;
|
||||
double lim = m_width_abs * mlimit;
|
||||
bool miter_limit_exceeded = true; // Assume the worst
|
||||
bool intersection_failed = true; // Assume the worst
|
||||
|
||||
if(calc_intersection(v0.x + dx1, v0.y - dy1,
|
||||
v1.x + dx1, v1.y - dy1,
|
||||
v1.x + dx2, v1.y - dy2,
|
||||
v2.x + dx2, v2.y - dy2,
|
||||
&xi, &yi))
|
||||
{
|
||||
// Calculation of the intersection succeeded
|
||||
//---------------------
|
||||
di = calc_distance(v1.x, v1.y, xi, yi);
|
||||
if(di <= lim)
|
||||
{
|
||||
// Inside the miter limit
|
||||
//---------------------
|
||||
add_vertex(vc, xi, yi);
|
||||
miter_limit_exceeded = false;
|
||||
}
|
||||
intersection_failed = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Calculation of the intersection failed, most probably
|
||||
// the three points lie one straight line.
|
||||
// First check if v0 and v2 lie on the opposite sides of vector:
|
||||
// (v1.x, v1.y) -> (v1.x+dx1, v1.y-dy1), that is, the perpendicular
|
||||
// to the line determined by vertices v0 and v1.
|
||||
// This condition determines whether the next line segments continues
|
||||
// the previous one or goes back.
|
||||
//----------------
|
||||
double x2 = v1.x + dx1;
|
||||
double y2 = v1.y - dy1;
|
||||
if((cross_product(v0.x, v0.y, v1.x, v1.y, x2, y2) < 0.0) ==
|
||||
(cross_product(v1.x, v1.y, v2.x, v2.y, x2, y2) < 0.0))
|
||||
{
|
||||
// This case means that the next segment continues
|
||||
// the previous one (straight line)
|
||||
//-----------------
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
miter_limit_exceeded = false;
|
||||
}
|
||||
}
|
||||
|
||||
if(miter_limit_exceeded)
|
||||
{
|
||||
// Miter limit exceeded
|
||||
//------------------------
|
||||
switch(lj)
|
||||
{
|
||||
case miter_join_revert:
|
||||
// For the compatibility with SVG, PDF, etc,
|
||||
// we use a simple bevel join instead of
|
||||
// "smart" bevel
|
||||
//-------------------
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
break;
|
||||
|
||||
case miter_join_round:
|
||||
calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
|
||||
break;
|
||||
|
||||
default:
|
||||
// If no miter-revert, calculate new dx1, dy1, dx2, dy2
|
||||
//----------------
|
||||
if(intersection_failed)
|
||||
{
|
||||
mlimit *= m_width_sign;
|
||||
add_vertex(vc, v1.x + dx1 + dy1 * mlimit,
|
||||
v1.y - dy1 + dx1 * mlimit);
|
||||
add_vertex(vc, v1.x + dx2 - dy2 * mlimit,
|
||||
v1.y - dy2 - dx2 * mlimit);
|
||||
}
|
||||
else
|
||||
{
|
||||
double x1 = v1.x + dx1;
|
||||
double y1 = v1.y - dy1;
|
||||
double x2 = v1.x + dx2;
|
||||
double y2 = v1.y - dy2;
|
||||
di = (lim - dbevel) / (di - dbevel);
|
||||
add_vertex(vc, x1 + (xi - x1) * di,
|
||||
y1 + (yi - y1) * di);
|
||||
add_vertex(vc, x2 + (xi - x2) * di,
|
||||
y2 + (yi - y2) * di);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------stroke_calc_cap
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_cap(VC& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
double len)
|
||||
{
|
||||
vc.remove_all();
|
||||
|
||||
double dx1 = (v1.y - v0.y) / len;
|
||||
double dy1 = (v1.x - v0.x) / len;
|
||||
double dx2 = 0;
|
||||
double dy2 = 0;
|
||||
|
||||
dx1 *= m_width;
|
||||
dy1 *= m_width;
|
||||
|
||||
if(m_line_cap != round_cap)
|
||||
{
|
||||
if(m_line_cap == square_cap)
|
||||
{
|
||||
dx2 = dy1 * m_width_sign;
|
||||
dy2 = dx1 * m_width_sign;
|
||||
}
|
||||
add_vertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2);
|
||||
add_vertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2);
|
||||
}
|
||||
else
|
||||
{
|
||||
double da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2;
|
||||
double a1;
|
||||
int i;
|
||||
int n = int(pi / da);
|
||||
|
||||
da = pi / (n + 1);
|
||||
add_vertex(vc, v0.x - dx1, v0.y + dy1);
|
||||
if(m_width_sign > 0)
|
||||
{
|
||||
a1 = atan2(dy1, -dx1);
|
||||
a1 += da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, v0.x + cos(a1) * m_width,
|
||||
v0.y + sin(a1) * m_width);
|
||||
a1 += da;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
a1 = atan2(-dy1, dx1);
|
||||
a1 -= da;
|
||||
for(i = 0; i < n; i++)
|
||||
{
|
||||
add_vertex(vc, v0.x + cos(a1) * m_width,
|
||||
v0.y + sin(a1) * m_width);
|
||||
a1 -= da;
|
||||
}
|
||||
}
|
||||
add_vertex(vc, v0.x + dx1, v0.y - dy1);
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
template<class VC>
|
||||
void math_stroke<VC>::calc_join(VC& vc,
|
||||
const vertex_dist& v0,
|
||||
const vertex_dist& v1,
|
||||
const vertex_dist& v2,
|
||||
double len1,
|
||||
double len2)
|
||||
{
|
||||
double dx1 = m_width * (v1.y - v0.y) / len1;
|
||||
double dy1 = m_width * (v1.x - v0.x) / len1;
|
||||
double dx2 = m_width * (v2.y - v1.y) / len2;
|
||||
double dy2 = m_width * (v2.x - v1.x) / len2;
|
||||
|
||||
vc.remove_all();
|
||||
|
||||
double cp = cross_product(v0.x, v0.y, v1.x, v1.y, v2.x, v2.y);
|
||||
if(cp != 0 && (cp > 0) == (m_width > 0))
|
||||
{
|
||||
// Inner join
|
||||
//---------------
|
||||
double limit = ((len1 < len2) ? len1 : len2) / m_width_abs;
|
||||
if(limit < m_inner_miter_limit)
|
||||
{
|
||||
limit = m_inner_miter_limit;
|
||||
}
|
||||
|
||||
switch(m_inner_join)
|
||||
{
|
||||
default: // inner_bevel
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
break;
|
||||
|
||||
case inner_miter:
|
||||
calc_miter(vc,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
miter_join_revert,
|
||||
limit, 0);
|
||||
break;
|
||||
|
||||
case inner_jag:
|
||||
case inner_round:
|
||||
cp = (dx1-dx2) * (dx1-dx2) + (dy1-dy2) * (dy1-dy2);
|
||||
if(cp < len1 * len1 && cp < len2 * len2)
|
||||
{
|
||||
calc_miter(vc,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
miter_join_revert,
|
||||
limit, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_inner_join == inner_jag)
|
||||
{
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x, v1.y );
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x, v1.y );
|
||||
calc_arc(vc, v1.x, v1.y, dx2, -dy2, dx1, -dy1);
|
||||
add_vertex(vc, v1.x, v1.y );
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Outer join
|
||||
//---------------
|
||||
|
||||
// Calculate the distance between v1 and
|
||||
// the central point of the bevel line segment
|
||||
//---------------
|
||||
double dx = (dx1 + dx2) / 2;
|
||||
double dy = (dy1 + dy2) / 2;
|
||||
double dbevel = sqrt(dx * dx + dy * dy);
|
||||
|
||||
if(m_line_join == round_join || m_line_join == bevel_join)
|
||||
{
|
||||
// This is an optimization that reduces the number of points
|
||||
// in cases of almost collinear segments. If there's no
|
||||
// visible difference between bevel and miter joins we'd rather
|
||||
// use miter join because it adds only one point instead of two.
|
||||
//
|
||||
// Here we calculate the middle point between the bevel points
|
||||
// and then, the distance between v1 and this middle point.
|
||||
// At outer joins this distance always less than stroke width,
|
||||
// because it's actually the height of an isosceles triangle of
|
||||
// v1 and its two bevel points. If the difference between this
|
||||
// width and this value is small (no visible bevel) we can
|
||||
// add just one point.
|
||||
//
|
||||
// The constant in the expression makes the result approximately
|
||||
// the same as in round joins and caps. You can safely comment
|
||||
// out this entire "if".
|
||||
//-------------------
|
||||
if(m_approx_scale * (m_width_abs - dbevel) < m_width_eps)
|
||||
{
|
||||
if(calc_intersection(v0.x + dx1, v0.y - dy1,
|
||||
v1.x + dx1, v1.y - dy1,
|
||||
v1.x + dx2, v1.y - dy2,
|
||||
v2.x + dx2, v2.y - dy2,
|
||||
&dx, &dy))
|
||||
{
|
||||
add_vertex(vc, dx, dy);
|
||||
}
|
||||
else
|
||||
{
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
switch(m_line_join)
|
||||
{
|
||||
case miter_join:
|
||||
case miter_join_revert:
|
||||
case miter_join_round:
|
||||
calc_miter(vc,
|
||||
v0, v1, v2, dx1, dy1, dx2, dy2,
|
||||
m_line_join,
|
||||
m_miter_limit,
|
||||
dbevel);
|
||||
break;
|
||||
|
||||
case round_join:
|
||||
calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2);
|
||||
break;
|
||||
|
||||
default: // Bevel join
|
||||
add_vertex(vc, v1.x + dx1, v1.y - dy1);
|
||||
add_vertex(vc, v1.x + dx2, v1.y - dy2);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
97
3rd/agg/include/agg_pixfmt_base.h
Normal file
97
3rd/agg/include/agg_pixfmt_base.h
Normal file
@ -0,0 +1,97 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_PIXFMT_BASE_INCLUDED
|
||||
#define AGG_PIXFMT_BASE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_color_gray.h"
|
||||
#include "agg_color_rgba.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
struct pixfmt_gray_tag
|
||||
{
|
||||
};
|
||||
|
||||
struct pixfmt_rgb_tag
|
||||
{
|
||||
};
|
||||
|
||||
struct pixfmt_rgba_tag
|
||||
{
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------blender_base
|
||||
template<class ColorT, class Order = void>
|
||||
struct blender_base
|
||||
{
|
||||
typedef ColorT color_type;
|
||||
typedef Order order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
|
||||
static rgba get(value_type r, value_type g, value_type b, value_type a, cover_type cover = cover_full)
|
||||
{
|
||||
if (cover > cover_none)
|
||||
{
|
||||
rgba c(
|
||||
color_type::to_double(r),
|
||||
color_type::to_double(g),
|
||||
color_type::to_double(b),
|
||||
color_type::to_double(a));
|
||||
|
||||
if (cover < cover_full)
|
||||
{
|
||||
double x = double(cover) / cover_full;
|
||||
c.r *= x;
|
||||
c.g *= x;
|
||||
c.b *= x;
|
||||
c.a *= x;
|
||||
}
|
||||
|
||||
return c;
|
||||
}
|
||||
else return rgba::no_color();
|
||||
}
|
||||
|
||||
static rgba get(const value_type* p, cover_type cover = cover_full)
|
||||
{
|
||||
return get(
|
||||
p[order_type::R],
|
||||
p[order_type::G],
|
||||
p[order_type::B],
|
||||
p[order_type::A],
|
||||
cover);
|
||||
}
|
||||
|
||||
static void set(value_type* p, value_type r, value_type g, value_type b, value_type a)
|
||||
{
|
||||
p[order_type::R] = r;
|
||||
p[order_type::G] = g;
|
||||
p[order_type::B] = b;
|
||||
p[order_type::A] = a;
|
||||
}
|
||||
|
||||
static void set(value_type* p, const rgba& c)
|
||||
{
|
||||
p[order_type::R] = color_type::from_double(c.r);
|
||||
p[order_type::G] = color_type::from_double(c.g);
|
||||
p[order_type::B] = color_type::from_double(c.b);
|
||||
p[order_type::A] = color_type::from_double(c.a);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
995
3rd/agg/include/agg_pixfmt_rgb.h
Normal file
995
3rd/agg/include/agg_pixfmt_rgb.h
Normal file
@ -0,0 +1,995 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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 high precision colors 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_PIXFMT_RGB_INCLUDED
|
||||
#define AGG_PIXFMT_RGB_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include "agg_pixfmt_base.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//=====================================================apply_gamma_dir_rgb
|
||||
template<class ColorT, class Order, class GammaLut> class apply_gamma_dir_rgb
|
||||
{
|
||||
public:
|
||||
typedef typename ColorT::value_type value_type;
|
||||
|
||||
apply_gamma_dir_rgb(const GammaLut& gamma) : m_gamma(gamma) {}
|
||||
|
||||
AGG_INLINE void operator () (value_type* p)
|
||||
{
|
||||
p[Order::R] = m_gamma.dir(p[Order::R]);
|
||||
p[Order::G] = m_gamma.dir(p[Order::G]);
|
||||
p[Order::B] = m_gamma.dir(p[Order::B]);
|
||||
}
|
||||
|
||||
private:
|
||||
const GammaLut& m_gamma;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=====================================================apply_gamma_inv_rgb
|
||||
template<class ColorT, class Order, class GammaLut> class apply_gamma_inv_rgb
|
||||
{
|
||||
public:
|
||||
typedef typename ColorT::value_type value_type;
|
||||
|
||||
apply_gamma_inv_rgb(const GammaLut& gamma) : m_gamma(gamma) {}
|
||||
|
||||
AGG_INLINE void operator () (value_type* p)
|
||||
{
|
||||
p[Order::R] = m_gamma.inv(p[Order::R]);
|
||||
p[Order::G] = m_gamma.inv(p[Order::G]);
|
||||
p[Order::B] = m_gamma.inv(p[Order::B]);
|
||||
}
|
||||
|
||||
private:
|
||||
const GammaLut& m_gamma;
|
||||
};
|
||||
|
||||
|
||||
//=========================================================blender_rgb
|
||||
template<class ColorT, class Order>
|
||||
struct blender_rgb
|
||||
{
|
||||
typedef ColorT color_type;
|
||||
typedef Order order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
// Blend pixels using the non-premultiplied form of Alvy-Ray Smith's
|
||||
// compositing function. Since the render buffer is opaque we skip the
|
||||
// initial premultiply and final demultiply.
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
|
||||
{
|
||||
blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cr, value_type cg, value_type cb, value_type alpha)
|
||||
{
|
||||
p[Order::R] = color_type::lerp(p[Order::R], cr, alpha);
|
||||
p[Order::G] = color_type::lerp(p[Order::G], cg, alpha);
|
||||
p[Order::B] = color_type::lerp(p[Order::B], cb, alpha);
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================blender_rgb_pre
|
||||
template<class ColorT, class Order>
|
||||
struct blender_rgb_pre
|
||||
{
|
||||
typedef ColorT color_type;
|
||||
typedef Order order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
// Blend pixels using the premultiplied form of Alvy-Ray Smith's
|
||||
// compositing function.
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
|
||||
{
|
||||
blend_pix(p,
|
||||
color_type::mult_cover(cr, cover),
|
||||
color_type::mult_cover(cg, cover),
|
||||
color_type::mult_cover(cb, cover),
|
||||
color_type::mult_cover(alpha, cover));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cr, value_type cg, value_type cb, value_type alpha)
|
||||
{
|
||||
p[Order::R] = color_type::prelerp(p[Order::R], cr, alpha);
|
||||
p[Order::G] = color_type::prelerp(p[Order::G], cg, alpha);
|
||||
p[Order::B] = color_type::prelerp(p[Order::B], cb, alpha);
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================blender_rgb_gamma
|
||||
template<class ColorT, class Order, class Gamma>
|
||||
class blender_rgb_gamma : public blender_base<ColorT, Order>
|
||||
{
|
||||
public:
|
||||
typedef ColorT color_type;
|
||||
typedef Order order_type;
|
||||
typedef Gamma gamma_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
blender_rgb_gamma() : m_gamma(0) {}
|
||||
void gamma(const gamma_type& g) { m_gamma = &g; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover)
|
||||
{
|
||||
blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(value_type* p,
|
||||
value_type cr, value_type cg, value_type cb, value_type alpha)
|
||||
{
|
||||
calc_type r = m_gamma->dir(p[Order::R]);
|
||||
calc_type g = m_gamma->dir(p[Order::G]);
|
||||
calc_type b = m_gamma->dir(p[Order::B]);
|
||||
p[Order::R] = m_gamma->inv(color_type::downscale((m_gamma->dir(cr) - r) * alpha) + r);
|
||||
p[Order::G] = m_gamma->inv(color_type::downscale((m_gamma->dir(cg) - g) * alpha) + g);
|
||||
p[Order::B] = m_gamma->inv(color_type::downscale((m_gamma->dir(cb) - b) * alpha) + b);
|
||||
}
|
||||
|
||||
private:
|
||||
const gamma_type* m_gamma;
|
||||
};
|
||||
|
||||
|
||||
//==================================================pixfmt_alpha_blend_rgb
|
||||
template<class Blender, class RenBuf, unsigned Step, unsigned Offset = 0>
|
||||
class pixfmt_alpha_blend_rgb
|
||||
{
|
||||
public:
|
||||
typedef pixfmt_rgb_tag pixfmt_category;
|
||||
typedef RenBuf rbuf_type;
|
||||
typedef Blender blender_type;
|
||||
typedef typename rbuf_type::row_data row_data;
|
||||
typedef typename blender_type::color_type color_type;
|
||||
typedef typename blender_type::order_type order_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
enum
|
||||
{
|
||||
num_components = 3,
|
||||
pix_step = Step,
|
||||
pix_offset = Offset,
|
||||
pix_width = sizeof(value_type) * pix_step
|
||||
};
|
||||
struct pixel_type
|
||||
{
|
||||
value_type c[num_components];
|
||||
|
||||
void set(value_type r, value_type g, value_type b)
|
||||
{
|
||||
c[order_type::R] = r;
|
||||
c[order_type::G] = g;
|
||||
c[order_type::B] = b;
|
||||
}
|
||||
|
||||
void set(const color_type& color)
|
||||
{
|
||||
set(color.r, color.g, color.b);
|
||||
}
|
||||
|
||||
void get(value_type& r, value_type& g, value_type& b) const
|
||||
{
|
||||
r = c[order_type::R];
|
||||
g = c[order_type::G];
|
||||
b = c[order_type::B];
|
||||
}
|
||||
|
||||
color_type get() const
|
||||
{
|
||||
return color_type(
|
||||
c[order_type::R],
|
||||
c[order_type::G],
|
||||
c[order_type::B]);
|
||||
}
|
||||
|
||||
pixel_type* next()
|
||||
{
|
||||
return (pixel_type*)(c + pix_step);
|
||||
}
|
||||
|
||||
const pixel_type* next() const
|
||||
{
|
||||
return (const pixel_type*)(c + pix_step);
|
||||
}
|
||||
|
||||
pixel_type* advance(int n)
|
||||
{
|
||||
return (pixel_type*)(c + n * pix_step);
|
||||
}
|
||||
|
||||
const pixel_type* advance(int n) const
|
||||
{
|
||||
return (const pixel_type*)(c + n * pix_step);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p,
|
||||
value_type r, value_type g, value_type b, value_type a,
|
||||
unsigned cover)
|
||||
{
|
||||
m_blender.blend_pix(p->c, r, g, b, a, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p,
|
||||
value_type r, value_type g, value_type b, value_type a)
|
||||
{
|
||||
m_blender.blend_pix(p->c, r, g, b, a);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover)
|
||||
{
|
||||
m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pix(pixel_type* p, const color_type& c)
|
||||
{
|
||||
m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
if (c.is_opaque() && cover == cover_mask)
|
||||
{
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
blend_pix(p, c, cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
if (c.is_opaque())
|
||||
{
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
blend_pix(p, c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
explicit pixfmt_alpha_blend_rgb(rbuf_type& rb) :
|
||||
m_rbuf(&rb)
|
||||
{}
|
||||
void attach(rbuf_type& rb) { m_rbuf = &rb; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class PixFmt>
|
||||
bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2)
|
||||
{
|
||||
rect_i r(x1, y1, x2, y2);
|
||||
if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1)))
|
||||
{
|
||||
int stride = pixf.stride();
|
||||
m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1),
|
||||
(r.x2 - r.x1) + 1,
|
||||
(r.y2 - r.y1) + 1,
|
||||
stride);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
Blender& blender() { return m_blender; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE unsigned width() const { return m_rbuf->width(); }
|
||||
AGG_INLINE unsigned height() const { return m_rbuf->height(); }
|
||||
AGG_INLINE int stride() const { return m_rbuf->stride(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); }
|
||||
AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); }
|
||||
AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE int8u* pix_ptr(int x, int y)
|
||||
{
|
||||
return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
|
||||
}
|
||||
|
||||
AGG_INLINE const int8u* pix_ptr(int x, int y) const
|
||||
{
|
||||
return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset);
|
||||
}
|
||||
|
||||
// Return pointer to pixel value, forcing row to be allocated.
|
||||
AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len)
|
||||
{
|
||||
return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset));
|
||||
}
|
||||
|
||||
// Return pointer to pixel value, or null if row not allocated.
|
||||
AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const
|
||||
{
|
||||
int8u* p = m_rbuf->row_ptr(y);
|
||||
return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0;
|
||||
}
|
||||
|
||||
// Get pixel pointer from raw buffer pointer.
|
||||
AGG_INLINE static pixel_type* pix_value_ptr(void* p)
|
||||
{
|
||||
return (pixel_type*)((value_type*)p + pix_offset);
|
||||
}
|
||||
|
||||
// Get pixel pointer from raw buffer pointer.
|
||||
AGG_INLINE static const pixel_type* pix_value_ptr(const void* p)
|
||||
{
|
||||
return (const pixel_type*)((const value_type*)p + pix_offset);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE static void write_plain_color(void* p, color_type c)
|
||||
{
|
||||
// RGB formats are implicitly premultiplied.
|
||||
c.premultiply();
|
||||
pix_value_ptr(p)->set(c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE static color_type read_plain_color(const void* p)
|
||||
{
|
||||
return pix_value_ptr(p)->get();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE static void make_pix(int8u* p, const color_type& c)
|
||||
{
|
||||
((pixel_type*)p)->set(c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE color_type pixel(int x, int y) const
|
||||
{
|
||||
if (const pixel_type* p = pix_value_ptr(x, y))
|
||||
{
|
||||
return p->get();
|
||||
}
|
||||
return color_type::no_color();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_pixel(int x, int y, const color_type& c)
|
||||
{
|
||||
pix_value_ptr(x, y, 1)->set(c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover)
|
||||
{
|
||||
copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_hline(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c)
|
||||
{
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
do
|
||||
{
|
||||
p->set(c);
|
||||
p = p->next();
|
||||
}
|
||||
while(--len);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE void copy_vline(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c)
|
||||
{
|
||||
do
|
||||
{
|
||||
pix_value_ptr(x, y++, 1)->set(c);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_hline(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c,
|
||||
int8u cover)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
if (c.is_opaque() && cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
p->set(c);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
blend_pix(p, c, cover);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_vline(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c,
|
||||
int8u cover)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
if (c.is_opaque() && cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
pix_value_ptr(x, y++, 1)->set(c);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
blend_pix(pix_value_ptr(x, y++, 1), c, cover);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_hspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c,
|
||||
const int8u* covers)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
do
|
||||
{
|
||||
if (c.is_opaque() && *covers == cover_mask)
|
||||
{
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
blend_pix(p, c, *covers);
|
||||
}
|
||||
p = p->next();
|
||||
++covers;
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_vspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type& c,
|
||||
const int8u* covers)
|
||||
{
|
||||
if (!c.is_transparent())
|
||||
{
|
||||
do
|
||||
{
|
||||
pixel_type* p = pix_value_ptr(x, y++, 1);
|
||||
|
||||
if (c.is_opaque() && *covers == cover_mask)
|
||||
{
|
||||
p->set(c);
|
||||
}
|
||||
else
|
||||
{
|
||||
blend_pix(p, c, *covers);
|
||||
}
|
||||
++covers;
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_color_hspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type* colors)
|
||||
{
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
do
|
||||
{
|
||||
p->set(*colors++);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_color_vspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type* colors)
|
||||
{
|
||||
do
|
||||
{
|
||||
pix_value_ptr(x, y++, 1)->set(*colors++);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_hspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type* colors,
|
||||
const int8u* covers,
|
||||
int8u cover)
|
||||
{
|
||||
pixel_type* p = pix_value_ptr(x, y, len);
|
||||
|
||||
if (covers)
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(p, *colors++, *covers++);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(p, *colors++);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(p, *colors++, cover);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_vspan(int x, int y,
|
||||
unsigned len,
|
||||
const color_type* colors,
|
||||
const int8u* covers,
|
||||
int8u cover)
|
||||
{
|
||||
if (covers)
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover);
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Function> void for_each_pixel(Function f)
|
||||
{
|
||||
for (unsigned y = 0; y < height(); ++y)
|
||||
{
|
||||
row_data r = m_rbuf->row(y);
|
||||
if (r.ptr)
|
||||
{
|
||||
unsigned len = r.x2 - r.x1 + 1;
|
||||
pixel_type* p = pix_value_ptr(r.x1, y, len);
|
||||
do
|
||||
{
|
||||
f(p->c);
|
||||
p = p->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class GammaLut> void apply_gamma_dir(const GammaLut& g)
|
||||
{
|
||||
for_each_pixel(apply_gamma_dir_rgb<color_type, order_type, GammaLut>(g));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class GammaLut> void apply_gamma_inv(const GammaLut& g)
|
||||
{
|
||||
for_each_pixel(apply_gamma_inv_rgb<color_type, order_type, GammaLut>(g));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf2>
|
||||
void copy_from(const RenBuf2& from,
|
||||
int xdst, int ydst,
|
||||
int xsrc, int ysrc,
|
||||
unsigned len)
|
||||
{
|
||||
if (const int8u* p = from.row_ptr(ysrc))
|
||||
{
|
||||
memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width,
|
||||
p + xsrc * pix_width,
|
||||
len * pix_width);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Blend from an RGBA surface.
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from(const SrcPixelFormatRenderer& from,
|
||||
int xdst, int ydst,
|
||||
int xsrc, int ysrc,
|
||||
unsigned len,
|
||||
int8u cover)
|
||||
{
|
||||
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
|
||||
typedef typename SrcPixelFormatRenderer::order_type src_order;
|
||||
|
||||
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
|
||||
{
|
||||
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
|
||||
|
||||
if (cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
value_type alpha = psrc->c[src_order::A];
|
||||
if (alpha <= color_type::empty_value())
|
||||
{
|
||||
if (alpha >= color_type::full_value())
|
||||
{
|
||||
pdst->c[order_type::R] = psrc->c[src_order::R];
|
||||
pdst->c[order_type::G] = psrc->c[src_order::G];
|
||||
pdst->c[order_type::B] = psrc->c[src_order::B];
|
||||
}
|
||||
else
|
||||
{
|
||||
blend_pix(pdst,
|
||||
psrc->c[src_order::R],
|
||||
psrc->c[src_order::G],
|
||||
psrc->c[src_order::B],
|
||||
alpha);
|
||||
}
|
||||
}
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while(--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pdst, psrc->get(), cover);
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Blend from single color, using grayscale surface as alpha channel.
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_color(const SrcPixelFormatRenderer& from,
|
||||
const color_type& color,
|
||||
int xdst, int ydst,
|
||||
int xsrc, int ysrc,
|
||||
unsigned len,
|
||||
int8u cover)
|
||||
{
|
||||
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
|
||||
typedef typename SrcPixelFormatRenderer::color_type src_color_type;
|
||||
|
||||
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
|
||||
{
|
||||
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
|
||||
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0]));
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while (--len);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// Blend from color table, using grayscale surface as indexes into table.
|
||||
// Obviously, this only works for integer value types.
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_lut(const SrcPixelFormatRenderer& from,
|
||||
const color_type* color_lut,
|
||||
int xdst, int ydst,
|
||||
int xsrc, int ysrc,
|
||||
unsigned len,
|
||||
int8u cover)
|
||||
{
|
||||
typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type;
|
||||
|
||||
if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc))
|
||||
{
|
||||
pixel_type* pdst = pix_value_ptr(xdst, ydst, len);
|
||||
|
||||
if (cover == cover_mask)
|
||||
{
|
||||
do
|
||||
{
|
||||
const color_type& color = color_lut[psrc->c[0]];
|
||||
blend_pix(pdst, color);
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while(--len);
|
||||
}
|
||||
else
|
||||
{
|
||||
do
|
||||
{
|
||||
copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover);
|
||||
psrc = psrc->next();
|
||||
pdst = pdst->next();
|
||||
}
|
||||
while(--len);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
rbuf_type* m_rbuf;
|
||||
Blender m_blender;
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
typedef blender_rgb<rgba8, order_rgb> blender_rgb24;
|
||||
typedef blender_rgb<rgba8, order_bgr> blender_bgr24;
|
||||
typedef blender_rgb<srgba8, order_rgb> blender_srgb24;
|
||||
typedef blender_rgb<srgba8, order_bgr> blender_sbgr24;
|
||||
typedef blender_rgb<rgba16, order_rgb> blender_rgb48;
|
||||
typedef blender_rgb<rgba16, order_bgr> blender_bgr48;
|
||||
typedef blender_rgb<rgba32, order_rgb> blender_rgb96;
|
||||
typedef blender_rgb<rgba32, order_bgr> blender_bgr96;
|
||||
|
||||
typedef blender_rgb_pre<rgba8, order_rgb> blender_rgb24_pre;
|
||||
typedef blender_rgb_pre<rgba8, order_bgr> blender_bgr24_pre;
|
||||
typedef blender_rgb_pre<srgba8, order_rgb> blender_srgb24_pre;
|
||||
typedef blender_rgb_pre<srgba8, order_bgr> blender_sbgr24_pre;
|
||||
typedef blender_rgb_pre<rgba16, order_rgb> blender_rgb48_pre;
|
||||
typedef blender_rgb_pre<rgba16, order_bgr> blender_bgr48_pre;
|
||||
typedef blender_rgb_pre<rgba32, order_rgb> blender_rgb96_pre;
|
||||
typedef blender_rgb_pre<rgba32, order_bgr> blender_bgr96_pre;
|
||||
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb24, rendering_buffer, 3> pixfmt_rgb24;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr24, rendering_buffer, 3> pixfmt_bgr24;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_srgb24, rendering_buffer, 3> pixfmt_srgb24;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_sbgr24, rendering_buffer, 3> pixfmt_sbgr24;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb48, rendering_buffer, 3> pixfmt_rgb48;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr48, rendering_buffer, 3> pixfmt_bgr48;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb96, rendering_buffer, 3> pixfmt_rgb96;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr96, rendering_buffer, 3> pixfmt_bgr96;
|
||||
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb24_pre, rendering_buffer, 3> pixfmt_rgb24_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr24_pre, rendering_buffer, 3> pixfmt_bgr24_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_srgb24_pre, rendering_buffer, 3> pixfmt_srgb24_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_sbgr24_pre, rendering_buffer, 3> pixfmt_sbgr24_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb48_pre, rendering_buffer, 3> pixfmt_rgb48_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr48_pre, rendering_buffer, 3> pixfmt_bgr48_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb96_pre, rendering_buffer, 3> pixfmt_rgb96_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr96_pre, rendering_buffer, 3> pixfmt_bgr96_pre;
|
||||
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb24, rendering_buffer, 4, 0> pixfmt_rgbx32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb24, rendering_buffer, 4, 1> pixfmt_xrgb32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr24, rendering_buffer, 4, 1> pixfmt_xbgr32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr24, rendering_buffer, 4, 0> pixfmt_bgrx32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_srgb24, rendering_buffer, 4, 0> pixfmt_srgbx32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_srgb24, rendering_buffer, 4, 1> pixfmt_sxrgb32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_sbgr24, rendering_buffer, 4, 1> pixfmt_sxbgr32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_sbgr24, rendering_buffer, 4, 0> pixfmt_sbgrx32;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb48, rendering_buffer, 4, 0> pixfmt_rgbx64;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb48, rendering_buffer, 4, 1> pixfmt_xrgb64;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr48, rendering_buffer, 4, 1> pixfmt_xbgr64;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr48, rendering_buffer, 4, 0> pixfmt_bgrx64;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb96, rendering_buffer, 4, 0> pixfmt_rgbx128;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb96, rendering_buffer, 4, 1> pixfmt_xrgb128;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr96, rendering_buffer, 4, 1> pixfmt_xbgr128;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr96, rendering_buffer, 4, 0> pixfmt_bgrx128;
|
||||
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb24_pre, rendering_buffer, 4, 0> pixfmt_rgbx32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb24_pre, rendering_buffer, 4, 1> pixfmt_xrgb32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr24_pre, rendering_buffer, 4, 1> pixfmt_xbgr32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr24_pre, rendering_buffer, 4, 0> pixfmt_bgrx32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_srgb24_pre, rendering_buffer, 4, 0> pixfmt_srgbx32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_srgb24_pre, rendering_buffer, 4, 1> pixfmt_sxrgb32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_sbgr24_pre, rendering_buffer, 4, 1> pixfmt_sxbgr32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_sbgr24_pre, rendering_buffer, 4, 0> pixfmt_sbgrx32_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb48_pre, rendering_buffer, 4, 0> pixfmt_rgbx64_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb48_pre, rendering_buffer, 4, 1> pixfmt_xrgb64_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr48_pre, rendering_buffer, 4, 1> pixfmt_xbgr64_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr48_pre, rendering_buffer, 4, 0> pixfmt_bgrx64_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb96_pre, rendering_buffer, 4, 0> pixfmt_rgbx128_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_rgb96_pre, rendering_buffer, 4, 1> pixfmt_xrgb128_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr96_pre, rendering_buffer, 4, 1> pixfmt_xbgr128_pre;
|
||||
typedef pixfmt_alpha_blend_rgb<blender_bgr96_pre, rendering_buffer, 4, 0> pixfmt_bgrx128_pre;
|
||||
|
||||
|
||||
//-----------------------------------------------------pixfmt_rgb24_gamma
|
||||
template<class Gamma> class pixfmt_rgb24_gamma :
|
||||
public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_rgb, Gamma>, rendering_buffer, 3>
|
||||
{
|
||||
public:
|
||||
pixfmt_rgb24_gamma(rendering_buffer& rb, const Gamma& g) :
|
||||
pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_rgb, Gamma>, rendering_buffer, 3>(rb)
|
||||
{
|
||||
this->blender().gamma(g);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------pixfmt_srgb24_gamma
|
||||
template<class Gamma> class pixfmt_srgb24_gamma :
|
||||
public pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_rgb, Gamma>, rendering_buffer, 3>
|
||||
{
|
||||
public:
|
||||
pixfmt_srgb24_gamma(rendering_buffer& rb, const Gamma& g) :
|
||||
pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_rgb, Gamma>, rendering_buffer, 3>(rb)
|
||||
{
|
||||
this->blender().gamma(g);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------pixfmt_bgr24_gamma
|
||||
template<class Gamma> class pixfmt_bgr24_gamma :
|
||||
public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_bgr, Gamma>, rendering_buffer, 3>
|
||||
{
|
||||
public:
|
||||
pixfmt_bgr24_gamma(rendering_buffer& rb, const Gamma& g) :
|
||||
pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_bgr, Gamma>, rendering_buffer, 3>(rb)
|
||||
{
|
||||
this->blender().gamma(g);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------pixfmt_sbgr24_gamma
|
||||
template<class Gamma> class pixfmt_sbgr24_gamma :
|
||||
public pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_bgr, Gamma>, rendering_buffer, 3>
|
||||
{
|
||||
public:
|
||||
pixfmt_sbgr24_gamma(rendering_buffer& rb, const Gamma& g) :
|
||||
pixfmt_alpha_blend_rgb<blender_rgb_gamma<srgba8, order_bgr, Gamma>, rendering_buffer, 3>(rb)
|
||||
{
|
||||
this->blender().gamma(g);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------pixfmt_rgb48_gamma
|
||||
template<class Gamma> class pixfmt_rgb48_gamma :
|
||||
public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_rgb, Gamma>, rendering_buffer, 3>
|
||||
{
|
||||
public:
|
||||
pixfmt_rgb48_gamma(rendering_buffer& rb, const Gamma& g) :
|
||||
pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_rgb, Gamma>, rendering_buffer, 3>(rb)
|
||||
{
|
||||
this->blender().gamma(g);
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------pixfmt_bgr48_gamma
|
||||
template<class Gamma> class pixfmt_bgr48_gamma :
|
||||
public pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_bgr, Gamma>, rendering_buffer, 3>
|
||||
{
|
||||
public:
|
||||
pixfmt_bgr48_gamma(rendering_buffer& rb, const Gamma& g) :
|
||||
pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_bgr, Gamma>, rendering_buffer, 3>(rb)
|
||||
{
|
||||
this->blender().gamma(g);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1312
3rd/agg/include/agg_pixfmt_rgb_packed.h
Normal file
1312
3rd/agg/include/agg_pixfmt_rgb_packed.h
Normal file
File diff suppressed because it is too large
Load Diff
2803
3rd/agg/include/agg_pixfmt_rgba.h
Normal file
2803
3rd/agg/include/agg_pixfmt_rgba.h
Normal file
File diff suppressed because it is too large
Load Diff
148
3rd/agg/include/agg_platform_support.h
Normal file
148
3rd/agg/include/agg_platform_support.h
Normal file
@ -0,0 +1,148 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class platform_support
|
||||
//
|
||||
// It's not a part of the AGG library, it's just a helper class to create
|
||||
// interactive demo examples. Since the examples should not be too complex
|
||||
// this class is provided to support some very basic interactive graphical
|
||||
// funtionality, such as putting the rendered image to the window, simple
|
||||
// keyboard and mouse input, window resizing, setting the window title,
|
||||
// and catching the "idle" events.
|
||||
//
|
||||
// The idea is to have a single header file that does not depend on any
|
||||
// platform (I hate these endless #ifdef/#elif/#elif.../#endif) and a number
|
||||
// of different implementations depending on the concrete platform.
|
||||
// The most popular platforms are:
|
||||
//
|
||||
// Windows-32 API
|
||||
// X-Window API
|
||||
// SDL library (see http://www.libsdl.org/)
|
||||
// MacOS C/C++ API
|
||||
//
|
||||
// This file does not include any system dependent .h files such as
|
||||
// windows.h or X11.h, so, your demo applications do not depend on the
|
||||
// platform. The only file that can #include system dependend headers
|
||||
// is the implementation file agg_platform_support.cpp. Different
|
||||
// implementations are placed in different directories, such as
|
||||
// ~/agg/src/platform/win32
|
||||
// ~/agg/src/platform/sdl
|
||||
// ~/agg/src/platform/X11
|
||||
// and so on.
|
||||
//
|
||||
// All the system dependent stuff sits in the platform_specific
|
||||
// class which is forward-declared here but not defined.
|
||||
// The platform_support class has just a pointer to it and it's
|
||||
// the responsibility of the implementation to create/delete it.
|
||||
// This class being defined in the implementation file can have
|
||||
// any platform dependent stuff such as HWND, X11 Window and so on.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#ifndef AGG_PLATFORM_SUPPORT_INCLUDED
|
||||
#define AGG_PLATFORM_SUPPORT_INCLUDED
|
||||
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_trans_viewport.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------window_flag_e
|
||||
// These are flags used in method init(). Not all of them are
|
||||
// applicable on different platforms, for example the win32_api
|
||||
// cannot use a hardware buffer (window_hw_buffer).
|
||||
// The implementation should simply ignore unsupported flags.
|
||||
enum window_flag_e
|
||||
{
|
||||
window_resize = 1,
|
||||
window_hw_buffer = 2,
|
||||
window_keep_aspect_ratio = 4,
|
||||
window_process_all_keys = 8
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------pix_format_e
|
||||
// Possible formats of the rendering buffer. Initially I thought that it's
|
||||
// reasonable to create the buffer and the rendering functions in
|
||||
// accordance with the native pixel format of the system because it
|
||||
// would have no overhead for pixel format conersion.
|
||||
// But eventually I came to a conclusion that having a possibility to
|
||||
// convert pixel formats on demand is a good idea. First, it was X11 where
|
||||
// there lots of different formats and visuals and it would be great to
|
||||
// render everything in, say, RGB-24 and display it automatically without
|
||||
// any additional efforts. The second reason is to have a possibility to
|
||||
// debug renderers for different pixel formats and colorspaces having only
|
||||
// one computer and one system.
|
||||
//
|
||||
// This stuff is not included into the basic AGG functionality because the
|
||||
// number of supported pixel formats (and/or colorspaces) can be great and
|
||||
// if one needs to add new format it would be good only to add new
|
||||
// rendering files without having to modify any existing ones (a general
|
||||
// principle of incapsulation and isolation).
|
||||
//
|
||||
// Using a particular pixel format doesn't obligatory mean the necessity
|
||||
// of software conversion. For example, win32 API can natively display
|
||||
// gray8, 15-bit RGB, 24-bit BGR, and 32-bit BGRA formats.
|
||||
// This list can be (and will be!) extended in future.
|
||||
enum pix_format_e
|
||||
{
|
||||
pix_format_undefined = 0, // By default. No conversions are applied
|
||||
pix_format_bw, // 1 bit per color B/W
|
||||
pix_format_gray8, // Simple 256 level grayscale
|
||||
pix_format_sgray8, // Simple 256 level grayscale (sRGB)
|
||||
pix_format_gray16, // Simple 65535 level grayscale
|
||||
pix_format_gray32, // Grayscale, one 32-bit float per pixel
|
||||
pix_format_rgb555, // 15 bit rgb. Depends on the byte ordering!
|
||||
pix_format_rgb565, // 16 bit rgb. Depends on the byte ordering!
|
||||
pix_format_rgbAAA, // 30 bit rgb. Depends on the byte ordering!
|
||||
pix_format_rgbBBA, // 32 bit rgb. Depends on the byte ordering!
|
||||
pix_format_bgrAAA, // 30 bit bgr. Depends on the byte ordering!
|
||||
pix_format_bgrABB, // 32 bit bgr. Depends on the byte ordering!
|
||||
pix_format_rgb24, // R-G-B, one byte per color component
|
||||
pix_format_srgb24, // R-G-B, one byte per color component (sRGB)
|
||||
pix_format_bgr24, // B-G-R, one byte per color component
|
||||
pix_format_sbgr24, // B-G-R, native win32 BMP format (sRGB)
|
||||
pix_format_rgba32, // R-G-B-A, one byte per color component
|
||||
pix_format_srgba32, // R-G-B-A, one byte per color component (sRGB)
|
||||
pix_format_argb32, // A-R-G-B, native MAC format
|
||||
pix_format_sargb32, // A-R-G-B, native MAC format (sRGB)
|
||||
pix_format_abgr32, // A-B-G-R, one byte per color component
|
||||
pix_format_sabgr32, // A-B-G-R, one byte per color component (sRGB)
|
||||
pix_format_bgra32, // B-G-R-A, native win32 BMP format
|
||||
pix_format_sbgra32, // B-G-R-A, native win32 BMP format (sRGB)
|
||||
pix_format_rgb48, // R-G-B, 16 bits per color component
|
||||
pix_format_bgr48, // B-G-R, native win32 BMP format.
|
||||
pix_format_rgb96, // R-G-B, one 32-bit float per color component
|
||||
pix_format_bgr96, // B-G-R, one 32-bit float per color component
|
||||
pix_format_rgba64, // R-G-B-A, 16 bits byte per color component
|
||||
pix_format_argb64, // A-R-G-B, native MAC format
|
||||
pix_format_abgr64, // A-B-G-R, one byte per color component
|
||||
pix_format_bgra64, // B-G-R-A, native win32 BMP format
|
||||
pix_format_rgba128, // R-G-B-A, one 32-bit float per color component
|
||||
pix_format_argb128, // A-R-G-B, one 32-bit float per color component
|
||||
pix_format_abgr128, // A-B-G-R, one 32-bit float per color component
|
||||
pix_format_bgra128, // B-G-R-A, one 32-bit float per color component
|
||||
|
||||
end_of_pix_formats
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
738
3rd/agg/include/agg_rasterizer_cells_aa.h
Normal file
738
3rd/agg/include/agg_rasterizer_cells_aa.h
Normal file
@ -0,0 +1,738 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED
|
||||
#define AGG_RASTERIZER_CELLS_AA_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "agg_math.h"
|
||||
#include "agg_array.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------rasterizer_cells_aa
|
||||
// An internal class that implements the main rasterization algorithm.
|
||||
// Used in the rasterizer. Should not be used direcly.
|
||||
template<class Cell> class rasterizer_cells_aa
|
||||
{
|
||||
enum cell_block_scale_e
|
||||
{
|
||||
cell_block_shift = 12,
|
||||
cell_block_size = 1 << cell_block_shift,
|
||||
cell_block_mask = cell_block_size - 1,
|
||||
cell_block_pool = 256,
|
||||
cell_block_limit = 1024
|
||||
};
|
||||
|
||||
struct sorted_y
|
||||
{
|
||||
unsigned start;
|
||||
unsigned num;
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Cell cell_type;
|
||||
typedef rasterizer_cells_aa<Cell> self_type;
|
||||
|
||||
~rasterizer_cells_aa();
|
||||
rasterizer_cells_aa();
|
||||
|
||||
void reset();
|
||||
void style(const cell_type& style_cell);
|
||||
void line(int x1, int y1, int x2, int y2);
|
||||
|
||||
int min_x() const { return m_min_x; }
|
||||
int min_y() const { return m_min_y; }
|
||||
int max_x() const { return m_max_x; }
|
||||
int max_y() const { return m_max_y; }
|
||||
|
||||
void sort_cells();
|
||||
|
||||
unsigned total_cells() const
|
||||
{
|
||||
return m_num_cells;
|
||||
}
|
||||
|
||||
unsigned scanline_num_cells(unsigned y) const
|
||||
{
|
||||
return m_sorted_y[y - m_min_y].num;
|
||||
}
|
||||
|
||||
const cell_type* const* scanline_cells(unsigned y) const
|
||||
{
|
||||
return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start;
|
||||
}
|
||||
|
||||
bool sorted() const { return m_sorted; }
|
||||
|
||||
private:
|
||||
rasterizer_cells_aa(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
void set_curr_cell(int x, int y);
|
||||
void add_curr_cell();
|
||||
void render_hline(int ey, int x1, int y1, int x2, int y2);
|
||||
void allocate_block();
|
||||
|
||||
private:
|
||||
unsigned m_num_blocks;
|
||||
unsigned m_max_blocks;
|
||||
unsigned m_curr_block;
|
||||
unsigned m_num_cells;
|
||||
cell_type** m_cells;
|
||||
cell_type* m_curr_cell_ptr;
|
||||
pod_vector<cell_type*> m_sorted_cells;
|
||||
pod_vector<sorted_y> m_sorted_y;
|
||||
cell_type m_curr_cell;
|
||||
cell_type m_style_cell;
|
||||
int m_min_x;
|
||||
int m_min_y;
|
||||
int m_max_x;
|
||||
int m_max_y;
|
||||
bool m_sorted;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
rasterizer_cells_aa<Cell>::~rasterizer_cells_aa()
|
||||
{
|
||||
if(m_num_blocks)
|
||||
{
|
||||
cell_type** ptr = m_cells + m_num_blocks - 1;
|
||||
while(m_num_blocks--)
|
||||
{
|
||||
pod_allocator<cell_type>::deallocate(*ptr, cell_block_size);
|
||||
ptr--;
|
||||
}
|
||||
pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
rasterizer_cells_aa<Cell>::rasterizer_cells_aa() :
|
||||
m_num_blocks(0),
|
||||
m_max_blocks(0),
|
||||
m_curr_block(0),
|
||||
m_num_cells(0),
|
||||
m_cells(0),
|
||||
m_curr_cell_ptr(0),
|
||||
m_sorted_cells(),
|
||||
m_sorted_y(),
|
||||
m_min_x(0x7FFFFFFF),
|
||||
m_min_y(0x7FFFFFFF),
|
||||
m_max_x(-0x7FFFFFFF),
|
||||
m_max_y(-0x7FFFFFFF),
|
||||
m_sorted(false)
|
||||
{
|
||||
m_style_cell.initial();
|
||||
m_curr_cell.initial();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::reset()
|
||||
{
|
||||
m_num_cells = 0;
|
||||
m_curr_block = 0;
|
||||
m_curr_cell.initial();
|
||||
m_style_cell.initial();
|
||||
m_sorted = false;
|
||||
m_min_x = 0x7FFFFFFF;
|
||||
m_min_y = 0x7FFFFFFF;
|
||||
m_max_x = -0x7FFFFFFF;
|
||||
m_max_y = -0x7FFFFFFF;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::add_curr_cell()
|
||||
{
|
||||
if(m_curr_cell.area | m_curr_cell.cover)
|
||||
{
|
||||
if((m_num_cells & cell_block_mask) == 0)
|
||||
{
|
||||
if(m_num_blocks >= cell_block_limit) return;
|
||||
allocate_block();
|
||||
}
|
||||
*m_curr_cell_ptr++ = m_curr_cell;
|
||||
++m_num_cells;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::set_curr_cell(int x, int y)
|
||||
{
|
||||
if(m_curr_cell.not_equal(x, y, m_style_cell))
|
||||
{
|
||||
add_curr_cell();
|
||||
m_curr_cell.style(m_style_cell);
|
||||
m_curr_cell.x = x;
|
||||
m_curr_cell.y = y;
|
||||
m_curr_cell.cover = 0;
|
||||
m_curr_cell.area = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::render_hline(int ey,
|
||||
int x1, int y1,
|
||||
int x2, int y2)
|
||||
{
|
||||
int ex1 = x1 >> poly_subpixel_shift;
|
||||
int ex2 = x2 >> poly_subpixel_shift;
|
||||
int fx1 = x1 & poly_subpixel_mask;
|
||||
int fx2 = x2 & poly_subpixel_mask;
|
||||
|
||||
int delta, p, first, dx;
|
||||
int incr, lift, mod, rem;
|
||||
|
||||
//trivial case. Happens often
|
||||
if(y1 == y2)
|
||||
{
|
||||
set_curr_cell(ex2, ey);
|
||||
return;
|
||||
}
|
||||
|
||||
//everything is located in a single cell. That is easy!
|
||||
if(ex1 == ex2)
|
||||
{
|
||||
delta = y2 - y1;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += (fx1 + fx2) * delta;
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, we'll have to render a run of adjacent cells on the same
|
||||
//hline...
|
||||
p = (poly_subpixel_scale - fx1) * (y2 - y1);
|
||||
first = poly_subpixel_scale;
|
||||
incr = 1;
|
||||
|
||||
dx = x2 - x1;
|
||||
|
||||
if(dx < 0)
|
||||
{
|
||||
p = fx1 * (y2 - y1);
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dx = -dx;
|
||||
}
|
||||
|
||||
delta = p / dx;
|
||||
mod = p % dx;
|
||||
|
||||
if(mod < 0)
|
||||
{
|
||||
delta--;
|
||||
mod += dx;
|
||||
}
|
||||
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += (fx1 + first) * delta;
|
||||
|
||||
ex1 += incr;
|
||||
set_curr_cell(ex1, ey);
|
||||
y1 += delta;
|
||||
|
||||
if(ex1 != ex2)
|
||||
{
|
||||
p = poly_subpixel_scale * (y2 - y1 + delta);
|
||||
lift = p / dx;
|
||||
rem = p % dx;
|
||||
|
||||
if (rem < 0)
|
||||
{
|
||||
lift--;
|
||||
rem += dx;
|
||||
}
|
||||
|
||||
mod -= dx;
|
||||
|
||||
while (ex1 != ex2)
|
||||
{
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if(mod >= 0)
|
||||
{
|
||||
mod -= dx;
|
||||
delta++;
|
||||
}
|
||||
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += poly_subpixel_scale * delta;
|
||||
y1 += delta;
|
||||
ex1 += incr;
|
||||
set_curr_cell(ex1, ey);
|
||||
}
|
||||
}
|
||||
delta = y2 - y1;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += (fx2 + poly_subpixel_scale - first) * delta;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
AGG_INLINE void rasterizer_cells_aa<Cell>::style(const cell_type& style_cell)
|
||||
{
|
||||
m_style_cell.style(style_cell);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::line(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift };
|
||||
|
||||
int dx = x2 - x1;
|
||||
|
||||
if(dx >= dx_limit || dx <= -dx_limit)
|
||||
{
|
||||
int cx = (x1 + x2) >> 1;
|
||||
int cy = (y1 + y2) >> 1;
|
||||
line(x1, y1, cx, cy);
|
||||
line(cx, cy, x2, y2);
|
||||
}
|
||||
|
||||
int dy = y2 - y1;
|
||||
int ex1 = x1 >> poly_subpixel_shift;
|
||||
int ex2 = x2 >> poly_subpixel_shift;
|
||||
int ey1 = y1 >> poly_subpixel_shift;
|
||||
int ey2 = y2 >> poly_subpixel_shift;
|
||||
int fy1 = y1 & poly_subpixel_mask;
|
||||
int fy2 = y2 & poly_subpixel_mask;
|
||||
|
||||
int x_from, x_to;
|
||||
int p, rem, mod, lift, delta, first, incr;
|
||||
|
||||
if(ex1 < m_min_x) m_min_x = ex1;
|
||||
if(ex1 > m_max_x) m_max_x = ex1;
|
||||
if(ey1 < m_min_y) m_min_y = ey1;
|
||||
if(ey1 > m_max_y) m_max_y = ey1;
|
||||
if(ex2 < m_min_x) m_min_x = ex2;
|
||||
if(ex2 > m_max_x) m_max_x = ex2;
|
||||
if(ey2 < m_min_y) m_min_y = ey2;
|
||||
if(ey2 > m_max_y) m_max_y = ey2;
|
||||
|
||||
set_curr_cell(ex1, ey1);
|
||||
|
||||
//everything is on a single hline
|
||||
if(ey1 == ey2)
|
||||
{
|
||||
render_hline(ey1, x1, fy1, x2, fy2);
|
||||
return;
|
||||
}
|
||||
|
||||
//Vertical line - we have to calculate start and end cells,
|
||||
//and then - the common values of the area and coverage for
|
||||
//all cells of the line. We know exactly there's only one
|
||||
//cell, so, we don't have to call render_hline().
|
||||
incr = 1;
|
||||
if(dx == 0)
|
||||
{
|
||||
int ex = x1 >> poly_subpixel_shift;
|
||||
int two_fx = (x1 - (ex << poly_subpixel_shift)) << 1;
|
||||
int area;
|
||||
|
||||
first = poly_subpixel_scale;
|
||||
if(dy < 0)
|
||||
{
|
||||
first = 0;
|
||||
incr = -1;
|
||||
}
|
||||
|
||||
x_from = x1;
|
||||
|
||||
//render_hline(ey1, x_from, fy1, x_from, first);
|
||||
delta = first - fy1;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += two_fx * delta;
|
||||
|
||||
ey1 += incr;
|
||||
set_curr_cell(ex, ey1);
|
||||
|
||||
delta = first + first - poly_subpixel_scale;
|
||||
area = two_fx * delta;
|
||||
while(ey1 != ey2)
|
||||
{
|
||||
//render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, first);
|
||||
m_curr_cell.cover = delta;
|
||||
m_curr_cell.area = area;
|
||||
ey1 += incr;
|
||||
set_curr_cell(ex, ey1);
|
||||
}
|
||||
//render_hline(ey1, x_from, poly_subpixel_scale - first, x_from, fy2);
|
||||
delta = fy2 - poly_subpixel_scale + first;
|
||||
m_curr_cell.cover += delta;
|
||||
m_curr_cell.area += two_fx * delta;
|
||||
return;
|
||||
}
|
||||
|
||||
//ok, we have to render several hlines
|
||||
p = (poly_subpixel_scale - fy1) * dx;
|
||||
first = poly_subpixel_scale;
|
||||
|
||||
if(dy < 0)
|
||||
{
|
||||
p = fy1 * dx;
|
||||
first = 0;
|
||||
incr = -1;
|
||||
dy = -dy;
|
||||
}
|
||||
|
||||
delta = p / dy;
|
||||
mod = p % dy;
|
||||
|
||||
if(mod < 0)
|
||||
{
|
||||
delta--;
|
||||
mod += dy;
|
||||
}
|
||||
|
||||
x_from = x1 + delta;
|
||||
render_hline(ey1, x1, fy1, x_from, first);
|
||||
|
||||
ey1 += incr;
|
||||
set_curr_cell(x_from >> poly_subpixel_shift, ey1);
|
||||
|
||||
if(ey1 != ey2)
|
||||
{
|
||||
p = poly_subpixel_scale * dx;
|
||||
lift = p / dy;
|
||||
rem = p % dy;
|
||||
|
||||
if(rem < 0)
|
||||
{
|
||||
lift--;
|
||||
rem += dy;
|
||||
}
|
||||
mod -= dy;
|
||||
|
||||
while(ey1 != ey2)
|
||||
{
|
||||
delta = lift;
|
||||
mod += rem;
|
||||
if (mod >= 0)
|
||||
{
|
||||
mod -= dy;
|
||||
delta++;
|
||||
}
|
||||
|
||||
x_to = x_from + delta;
|
||||
render_hline(ey1, x_from, poly_subpixel_scale - first, x_to, first);
|
||||
x_from = x_to;
|
||||
|
||||
ey1 += incr;
|
||||
set_curr_cell(x_from >> poly_subpixel_shift, ey1);
|
||||
}
|
||||
}
|
||||
render_hline(ey1, x_from, poly_subpixel_scale - first, x2, fy2);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::allocate_block()
|
||||
{
|
||||
if(m_curr_block >= m_num_blocks)
|
||||
{
|
||||
if(m_num_blocks >= m_max_blocks)
|
||||
{
|
||||
cell_type** new_cells =
|
||||
pod_allocator<cell_type*>::allocate(m_max_blocks +
|
||||
cell_block_pool);
|
||||
|
||||
if(m_cells)
|
||||
{
|
||||
memcpy(new_cells, m_cells, m_max_blocks * sizeof(cell_type*));
|
||||
pod_allocator<cell_type*>::deallocate(m_cells, m_max_blocks);
|
||||
}
|
||||
m_cells = new_cells;
|
||||
m_max_blocks += cell_block_pool;
|
||||
}
|
||||
|
||||
m_cells[m_num_blocks++] =
|
||||
pod_allocator<cell_type>::allocate(cell_block_size);
|
||||
|
||||
}
|
||||
m_curr_cell_ptr = m_cells[m_curr_block++];
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template <class T> static AGG_INLINE void swap_cells(T* a, T* b)
|
||||
{
|
||||
T temp = *a;
|
||||
*a = *b;
|
||||
*b = temp;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
enum
|
||||
{
|
||||
qsort_threshold = 9
|
||||
};
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void qsort_cells(Cell** start, unsigned num)
|
||||
{
|
||||
Cell** stack[80];
|
||||
Cell*** top;
|
||||
Cell** limit;
|
||||
Cell** base;
|
||||
|
||||
limit = start + num;
|
||||
base = start;
|
||||
top = stack;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
int len = int(limit - base);
|
||||
|
||||
Cell** i;
|
||||
Cell** j;
|
||||
Cell** pivot;
|
||||
|
||||
if(len > qsort_threshold)
|
||||
{
|
||||
// we use base + len/2 as the pivot
|
||||
pivot = base + len / 2;
|
||||
swap_cells(base, pivot);
|
||||
|
||||
i = base + 1;
|
||||
j = limit - 1;
|
||||
|
||||
// now ensure that *i <= *base <= *j
|
||||
if((*j)->x < (*i)->x)
|
||||
{
|
||||
swap_cells(i, j);
|
||||
}
|
||||
|
||||
if((*base)->x < (*i)->x)
|
||||
{
|
||||
swap_cells(base, i);
|
||||
}
|
||||
|
||||
if((*j)->x < (*base)->x)
|
||||
{
|
||||
swap_cells(base, j);
|
||||
}
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int x = (*base)->x;
|
||||
do i++; while( (*i)->x < x );
|
||||
do j--; while( x < (*j)->x );
|
||||
|
||||
if(i > j)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
swap_cells(i, j);
|
||||
}
|
||||
|
||||
swap_cells(base, j);
|
||||
|
||||
// now, push the largest sub-array
|
||||
if(j - base > limit - i)
|
||||
{
|
||||
top[0] = base;
|
||||
top[1] = j;
|
||||
base = i;
|
||||
}
|
||||
else
|
||||
{
|
||||
top[0] = i;
|
||||
top[1] = limit;
|
||||
limit = j;
|
||||
}
|
||||
top += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
// the sub-array is small, perform insertion sort
|
||||
j = base;
|
||||
i = j + 1;
|
||||
|
||||
for(; i < limit; j = i, i++)
|
||||
{
|
||||
for(; j[1]->x < (*j)->x; j--)
|
||||
{
|
||||
swap_cells(j + 1, j);
|
||||
if (j == base)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(top > stack)
|
||||
{
|
||||
top -= 2;
|
||||
base = top[0];
|
||||
limit = top[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Cell>
|
||||
void rasterizer_cells_aa<Cell>::sort_cells()
|
||||
{
|
||||
if(m_sorted) return; //Perform sort only the first time.
|
||||
|
||||
add_curr_cell();
|
||||
m_curr_cell.x = 0x7FFFFFFF;
|
||||
m_curr_cell.y = 0x7FFFFFFF;
|
||||
m_curr_cell.cover = 0;
|
||||
m_curr_cell.area = 0;
|
||||
|
||||
if(m_num_cells == 0) return;
|
||||
|
||||
// DBG: Check to see if min/max works well.
|
||||
//for(unsigned nc = 0; nc < m_num_cells; nc++)
|
||||
//{
|
||||
// cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask);
|
||||
// if(cell->x < m_min_x ||
|
||||
// cell->y < m_min_y ||
|
||||
// cell->x > m_max_x ||
|
||||
// cell->y > m_max_y)
|
||||
// {
|
||||
// cell = cell; // Breakpoint here
|
||||
// }
|
||||
//}
|
||||
// Allocate the array of cell pointers
|
||||
m_sorted_cells.allocate(m_num_cells, 16);
|
||||
|
||||
// Allocate and zero the Y array
|
||||
m_sorted_y.allocate(m_max_y - m_min_y + 1, 16);
|
||||
m_sorted_y.zero();
|
||||
|
||||
// Create the Y-histogram (count the numbers of cells for each Y)
|
||||
cell_type** block_ptr = m_cells;
|
||||
cell_type* cell_ptr;
|
||||
unsigned nb = m_num_cells;
|
||||
unsigned i;
|
||||
while(nb)
|
||||
{
|
||||
cell_ptr = *block_ptr++;
|
||||
i = (nb > cell_block_size) ? cell_block_size : nb;
|
||||
nb -= i;
|
||||
while(i--)
|
||||
{
|
||||
m_sorted_y[cell_ptr->y - m_min_y].start++;
|
||||
++cell_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Convert the Y-histogram into the array of starting indexes
|
||||
unsigned start = 0;
|
||||
for(i = 0; i < m_sorted_y.size(); i++)
|
||||
{
|
||||
unsigned v = m_sorted_y[i].start;
|
||||
m_sorted_y[i].start = start;
|
||||
start += v;
|
||||
}
|
||||
|
||||
// Fill the cell pointer array sorted by Y
|
||||
block_ptr = m_cells;
|
||||
nb = m_num_cells;
|
||||
while(nb)
|
||||
{
|
||||
cell_ptr = *block_ptr++;
|
||||
i = (nb > cell_block_size) ? cell_block_size : nb;
|
||||
nb -= i;
|
||||
while(i--)
|
||||
{
|
||||
sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y];
|
||||
m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr;
|
||||
++curr_y.num;
|
||||
++cell_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// Finally arrange the X-arrays
|
||||
for(i = 0; i < m_sorted_y.size(); i++)
|
||||
{
|
||||
const sorted_y& curr_y = m_sorted_y[i];
|
||||
if(curr_y.num)
|
||||
{
|
||||
qsort_cells(m_sorted_cells.data() + curr_y.start, curr_y.num);
|
||||
}
|
||||
}
|
||||
m_sorted = true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------scanline_hit_test
|
||||
class scanline_hit_test
|
||||
{
|
||||
public:
|
||||
scanline_hit_test(int x) : m_x(x), m_hit(false) {}
|
||||
|
||||
void reset_spans() {}
|
||||
void finalize(int) {}
|
||||
void add_cell(int x, int)
|
||||
{
|
||||
if(m_x == x) m_hit = true;
|
||||
}
|
||||
void add_span(int x, int len, int)
|
||||
{
|
||||
if(m_x >= x && m_x < x+len) m_hit = true;
|
||||
}
|
||||
unsigned num_spans() const { return 1; }
|
||||
bool hit() const { return m_hit; }
|
||||
|
||||
private:
|
||||
int m_x;
|
||||
bool m_hit;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
481
3rd/agg/include/agg_rasterizer_scanline_aa.h
Normal file
481
3rd/agg/include/agg_rasterizer_scanline_aa.h
Normal file
@ -0,0 +1,481 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_SCANLINE_AA_INCLUDED
|
||||
#define AGG_RASTERIZER_SCANLINE_AA_INCLUDED
|
||||
|
||||
#include "agg_rasterizer_cells_aa.h"
|
||||
#include "agg_rasterizer_sl_clip.h"
|
||||
#include "agg_rasterizer_scanline_aa_nogamma.h"
|
||||
#include "agg_gamma_functions.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//==================================================rasterizer_scanline_aa
|
||||
// Polygon rasterizer that is used to render filled polygons with
|
||||
// high-quality Anti-Aliasing. Internally, by default, the class uses
|
||||
// integer coordinates in format 24.8, i.e. 24 bits for integer part
|
||||
// and 8 bits for fractional - see poly_subpixel_shift. This class can be
|
||||
// used in the following way:
|
||||
//
|
||||
// 1. filling_rule(filling_rule_e ft) - optional.
|
||||
//
|
||||
// 2. gamma() - optional.
|
||||
//
|
||||
// 3. reset()
|
||||
//
|
||||
// 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create
|
||||
// more than one contour, but each contour must consist of at least 3
|
||||
// vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
|
||||
// is the absolute minimum of vertices that define a triangle.
|
||||
// The algorithm does not check either the number of vertices nor
|
||||
// coincidence of their coordinates, but in the worst case it just
|
||||
// won't draw anything.
|
||||
// The orger of the vertices (clockwise or counterclockwise)
|
||||
// is important when using the non-zero filling rule (fill_non_zero).
|
||||
// In this case the vertex order of all the contours must be the same
|
||||
// if you want your intersecting polygons to be without "holes".
|
||||
// You actually can use different vertices order. If the contours do not
|
||||
// intersect each other the order is not important anyway. If they do,
|
||||
// contours with the same vertex order will be rendered without "holes"
|
||||
// while the intersecting contours with different orders will have "holes".
|
||||
//
|
||||
// filling_rule() and gamma() can be called anytime before "sweeping".
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa
|
||||
{
|
||||
enum status
|
||||
{
|
||||
status_initial,
|
||||
status_move_to,
|
||||
status_line_to,
|
||||
status_closed
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Clip clip_type;
|
||||
typedef typename Clip::conv_type conv_type;
|
||||
typedef typename Clip::coord_type coord_type;
|
||||
|
||||
enum aa_scale_e
|
||||
{
|
||||
aa_shift = 8,
|
||||
aa_scale = 1 << aa_shift,
|
||||
aa_mask = aa_scale - 1,
|
||||
aa_scale2 = aa_scale * 2,
|
||||
aa_mask2 = aa_scale2 - 1
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rasterizer_scanline_aa() :
|
||||
m_outline(),
|
||||
m_clipper(),
|
||||
m_filling_rule(fill_non_zero),
|
||||
m_auto_close(true),
|
||||
m_start_x(0),
|
||||
m_start_y(0),
|
||||
m_status(status_initial)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < aa_scale; i++) m_gamma[i] = i;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class GammaF>
|
||||
rasterizer_scanline_aa(const GammaF& gamma_function) :
|
||||
m_outline(),
|
||||
m_clipper(m_outline),
|
||||
m_filling_rule(fill_non_zero),
|
||||
m_auto_close(true),
|
||||
m_start_x(0),
|
||||
m_start_y(0),
|
||||
m_status(status_initial)
|
||||
{
|
||||
gamma(gamma_function);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset();
|
||||
void reset_clipping();
|
||||
void clip_box(double x1, double y1, double x2, double y2);
|
||||
void filling_rule(filling_rule_e filling_rule);
|
||||
void auto_close(bool flag) { m_auto_close = flag; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class GammaF> void gamma(const GammaF& gamma_function)
|
||||
{
|
||||
int i;
|
||||
for(i = 0; i < aa_scale; i++)
|
||||
{
|
||||
m_gamma[i] = uround(gamma_function(double(i) / aa_mask) * aa_mask);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned apply_gamma(unsigned cover) const
|
||||
{
|
||||
return m_gamma[cover];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void move_to(int x, int y);
|
||||
void line_to(int x, int y);
|
||||
void move_to_d(double x, double y);
|
||||
void line_to_d(double x, double y);
|
||||
void close_polygon();
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
void edge(int x1, int y1, int x2, int y2);
|
||||
void edge_d(double x1, double y1, double x2, double y2);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
template<class VertexSource>
|
||||
void add_path(VertexSource& vs, unsigned path_id=0)
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
|
||||
unsigned cmd;
|
||||
vs.rewind(path_id);
|
||||
if(m_outline.sorted()) reset();
|
||||
while(!is_stop(cmd = vs.vertex(&x, &y)))
|
||||
{
|
||||
add_vertex(x, y, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int min_x() const { return m_outline.min_x(); }
|
||||
int min_y() const { return m_outline.min_y(); }
|
||||
int max_x() const { return m_outline.max_x(); }
|
||||
int max_y() const { return m_outline.max_y(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void sort();
|
||||
bool rewind_scanlines();
|
||||
bool navigate_scanline(int y);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE unsigned calculate_alpha(int area) const
|
||||
{
|
||||
int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift);
|
||||
|
||||
if(cover < 0) cover = -cover;
|
||||
if(m_filling_rule == fill_even_odd)
|
||||
{
|
||||
cover &= aa_mask2;
|
||||
if(cover > aa_scale)
|
||||
{
|
||||
cover = aa_scale2 - cover;
|
||||
}
|
||||
}
|
||||
if(cover > aa_mask) cover = aa_mask;
|
||||
return m_gamma[cover];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> bool sweep_scanline(Scanline& sl)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(m_scan_y > m_outline.max_y()) return false;
|
||||
sl.reset_spans();
|
||||
unsigned num_cells = m_outline.scanline_num_cells(m_scan_y);
|
||||
const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y);
|
||||
int cover = 0;
|
||||
|
||||
while(num_cells)
|
||||
{
|
||||
const cell_aa* cur_cell = *cells;
|
||||
int x = cur_cell->x;
|
||||
int area = cur_cell->area;
|
||||
unsigned alpha;
|
||||
|
||||
cover += cur_cell->cover;
|
||||
|
||||
//accumulate all cells with the same X
|
||||
while(--num_cells)
|
||||
{
|
||||
cur_cell = *++cells;
|
||||
if(cur_cell->x != x) break;
|
||||
area += cur_cell->area;
|
||||
cover += cur_cell->cover;
|
||||
}
|
||||
|
||||
if(area)
|
||||
{
|
||||
alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area);
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_cell(x, alpha);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
if(num_cells && cur_cell->x > x)
|
||||
{
|
||||
alpha = calculate_alpha(cover << (poly_subpixel_shift + 1));
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_span(x, cur_cell->x - x, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sl.num_spans()) break;
|
||||
++m_scan_y;
|
||||
}
|
||||
|
||||
sl.finalize(m_scan_y);
|
||||
++m_scan_y;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool hit_test(int tx, int ty);
|
||||
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
// Disable copying
|
||||
rasterizer_scanline_aa(const rasterizer_scanline_aa<Clip>&);
|
||||
const rasterizer_scanline_aa<Clip>&
|
||||
operator = (const rasterizer_scanline_aa<Clip>&);
|
||||
|
||||
private:
|
||||
rasterizer_cells_aa<cell_aa> m_outline;
|
||||
clip_type m_clipper;
|
||||
int m_gamma[aa_scale];
|
||||
filling_rule_e m_filling_rule;
|
||||
bool m_auto_close;
|
||||
coord_type m_start_x;
|
||||
coord_type m_start_y;
|
||||
unsigned m_status;
|
||||
int m_scan_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::reset()
|
||||
{
|
||||
m_outline.reset();
|
||||
m_status = status_initial;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::filling_rule(filling_rule_e filling_rule)
|
||||
{
|
||||
m_filling_rule = filling_rule;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::clip_box(double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
reset();
|
||||
m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1),
|
||||
conv_type::upscale(x2), conv_type::upscale(y2));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::reset_clipping()
|
||||
{
|
||||
reset();
|
||||
m_clipper.reset_clipping();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::close_polygon()
|
||||
{
|
||||
if(m_status == status_line_to)
|
||||
{
|
||||
m_clipper.line_to(m_outline, m_start_x, m_start_y);
|
||||
m_status = status_closed;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::move_to(int x, int y)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
if(m_auto_close) close_polygon();
|
||||
m_clipper.move_to(m_start_x = conv_type::downscale(x),
|
||||
m_start_y = conv_type::downscale(y));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::line_to(int x, int y)
|
||||
{
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::downscale(x),
|
||||
conv_type::downscale(y));
|
||||
m_status = status_line_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::move_to_d(double x, double y)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
if(m_auto_close) close_polygon();
|
||||
m_clipper.move_to(m_start_x = conv_type::upscale(x),
|
||||
m_start_y = conv_type::upscale(y));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::line_to_d(double x, double y)
|
||||
{
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::upscale(x),
|
||||
conv_type::upscale(y));
|
||||
m_status = status_line_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
move_to_d(x, y);
|
||||
}
|
||||
else
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
line_to_d(x, y);
|
||||
}
|
||||
else
|
||||
if(is_close(cmd))
|
||||
{
|
||||
close_polygon();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::edge(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1));
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::downscale(x2),
|
||||
conv_type::downscale(y2));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::edge_d(double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1));
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::upscale(x2),
|
||||
conv_type::upscale(y2));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa<Clip>::sort()
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
AGG_INLINE bool rasterizer_scanline_aa<Clip>::rewind_scanlines()
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
if(m_outline.total_cells() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_scan_y = m_outline.min_y();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
AGG_INLINE bool rasterizer_scanline_aa<Clip>::navigate_scanline(int y)
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
if(m_outline.total_cells() == 0 ||
|
||||
y < m_outline.min_y() ||
|
||||
y > m_outline.max_y())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_scan_y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
bool rasterizer_scanline_aa<Clip>::hit_test(int tx, int ty)
|
||||
{
|
||||
if(!navigate_scanline(ty)) return false;
|
||||
scanline_hit_test sl(tx);
|
||||
sweep_scanline(sl);
|
||||
return sl.hit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
482
3rd/agg/include/agg_rasterizer_scanline_aa_nogamma.h
Normal file
482
3rd/agg/include/agg_rasterizer_scanline_aa_nogamma.h
Normal file
@ -0,0 +1,482 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// The author gratefully acknowleges the support of David Turner,
|
||||
// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType
|
||||
// libray - in producing this work. See http://www.freetype.org for details.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
// Contact: mcseem@antigrain.com
|
||||
// mcseemagg@yahoo.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Adaptation for 32-bit screen coordinates 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED
|
||||
#define AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED
|
||||
|
||||
#include "agg_rasterizer_cells_aa.h"
|
||||
#include "agg_rasterizer_sl_clip.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
|
||||
//-----------------------------------------------------------------cell_aa
|
||||
// A pixel cell. There're no constructors defined and it was done
|
||||
// intentionally in order to avoid extra overhead when allocating an
|
||||
// array of cells.
|
||||
struct cell_aa
|
||||
{
|
||||
int x;
|
||||
int y;
|
||||
int cover;
|
||||
int area;
|
||||
|
||||
void initial()
|
||||
{
|
||||
x = 0x7FFFFFFF;
|
||||
y = 0x7FFFFFFF;
|
||||
cover = 0;
|
||||
area = 0;
|
||||
}
|
||||
|
||||
void style(const cell_aa&) {}
|
||||
|
||||
int not_equal(int ex, int ey, const cell_aa&) const
|
||||
{
|
||||
return (ex - x) | (ey - y);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//==================================================rasterizer_scanline_aa_nogamma
|
||||
// Polygon rasterizer that is used to render filled polygons with
|
||||
// high-quality Anti-Aliasing. Internally, by default, the class uses
|
||||
// integer coordinates in format 24.8, i.e. 24 bits for integer part
|
||||
// and 8 bits for fractional - see poly_subpixel_shift. This class can be
|
||||
// used in the following way:
|
||||
//
|
||||
// 1. filling_rule(filling_rule_e ft) - optional.
|
||||
//
|
||||
// 2. gamma() - optional.
|
||||
//
|
||||
// 3. reset()
|
||||
//
|
||||
// 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create
|
||||
// more than one contour, but each contour must consist of at least 3
|
||||
// vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3);
|
||||
// is the absolute minimum of vertices that define a triangle.
|
||||
// The algorithm does not check either the number of vertices nor
|
||||
// coincidence of their coordinates, but in the worst case it just
|
||||
// won't draw anything.
|
||||
// The orger of the vertices (clockwise or counterclockwise)
|
||||
// is important when using the non-zero filling rule (fill_non_zero).
|
||||
// In this case the vertex order of all the contours must be the same
|
||||
// if you want your intersecting polygons to be without "holes".
|
||||
// You actually can use different vertices order. If the contours do not
|
||||
// intersect each other the order is not important anyway. If they do,
|
||||
// contours with the same vertex order will be rendered without "holes"
|
||||
// while the intersecting contours with different orders will have "holes".
|
||||
//
|
||||
// filling_rule() and gamma() can be called anytime before "sweeping".
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip=rasterizer_sl_clip_int> class rasterizer_scanline_aa_nogamma
|
||||
{
|
||||
enum status
|
||||
{
|
||||
status_initial,
|
||||
status_move_to,
|
||||
status_line_to,
|
||||
status_closed
|
||||
};
|
||||
|
||||
public:
|
||||
typedef Clip clip_type;
|
||||
typedef typename Clip::conv_type conv_type;
|
||||
typedef typename Clip::coord_type coord_type;
|
||||
|
||||
enum aa_scale_e
|
||||
{
|
||||
aa_shift = 8,
|
||||
aa_scale = 1 << aa_shift,
|
||||
aa_mask = aa_scale - 1,
|
||||
aa_scale2 = aa_scale * 2,
|
||||
aa_mask2 = aa_scale2 - 1
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rasterizer_scanline_aa_nogamma() :
|
||||
m_outline(),
|
||||
m_clipper(),
|
||||
m_filling_rule(fill_non_zero),
|
||||
m_auto_close(true),
|
||||
m_start_x(0),
|
||||
m_start_y(0),
|
||||
m_status(status_initial)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset();
|
||||
void reset_clipping();
|
||||
void clip_box(double x1, double y1, double x2, double y2);
|
||||
void filling_rule(filling_rule_e filling_rule);
|
||||
void auto_close(bool flag) { m_auto_close = flag; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned apply_gamma(unsigned cover) const
|
||||
{
|
||||
return cover;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void move_to(int x, int y);
|
||||
void line_to(int x, int y);
|
||||
void move_to_d(double x, double y);
|
||||
void line_to_d(double x, double y);
|
||||
void close_polygon();
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
void edge(int x1, int y1, int x2, int y2);
|
||||
void edge_d(double x1, double y1, double x2, double y2);
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
template<class VertexSource>
|
||||
void add_path(VertexSource& vs, unsigned path_id=0)
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
|
||||
unsigned cmd;
|
||||
vs.rewind(path_id);
|
||||
if(m_outline.sorted()) reset();
|
||||
while(!is_stop(cmd = vs.vertex(&x, &y)))
|
||||
{
|
||||
add_vertex(x, y, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int min_x() const { return m_outline.min_x(); }
|
||||
int min_y() const { return m_outline.min_y(); }
|
||||
int max_x() const { return m_outline.max_x(); }
|
||||
int max_y() const { return m_outline.max_y(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void sort();
|
||||
bool rewind_scanlines();
|
||||
bool navigate_scanline(int y);
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE unsigned calculate_alpha(int area) const
|
||||
{
|
||||
int cover = area >> (poly_subpixel_shift*2 + 1 - aa_shift);
|
||||
|
||||
if(cover < 0) cover = -cover;
|
||||
if(m_filling_rule == fill_even_odd)
|
||||
{
|
||||
cover &= aa_mask2;
|
||||
if(cover > aa_scale)
|
||||
{
|
||||
cover = aa_scale2 - cover;
|
||||
}
|
||||
}
|
||||
if(cover > aa_mask) cover = aa_mask;
|
||||
return cover;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> bool sweep_scanline(Scanline& sl)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
if(m_scan_y > m_outline.max_y()) return false;
|
||||
sl.reset_spans();
|
||||
unsigned num_cells = m_outline.scanline_num_cells(m_scan_y);
|
||||
const cell_aa* const* cells = m_outline.scanline_cells(m_scan_y);
|
||||
int cover = 0;
|
||||
|
||||
while(num_cells)
|
||||
{
|
||||
const cell_aa* cur_cell = *cells;
|
||||
int x = cur_cell->x;
|
||||
int area = cur_cell->area;
|
||||
unsigned alpha;
|
||||
|
||||
cover += cur_cell->cover;
|
||||
|
||||
//accumulate all cells with the same X
|
||||
while(--num_cells)
|
||||
{
|
||||
cur_cell = *++cells;
|
||||
if(cur_cell->x != x) break;
|
||||
area += cur_cell->area;
|
||||
cover += cur_cell->cover;
|
||||
}
|
||||
|
||||
if(area)
|
||||
{
|
||||
alpha = calculate_alpha((cover << (poly_subpixel_shift + 1)) - area);
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_cell(x, alpha);
|
||||
}
|
||||
x++;
|
||||
}
|
||||
|
||||
if(num_cells && cur_cell->x > x)
|
||||
{
|
||||
alpha = calculate_alpha(cover << (poly_subpixel_shift + 1));
|
||||
if(alpha)
|
||||
{
|
||||
sl.add_span(x, cur_cell->x - x, alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sl.num_spans()) break;
|
||||
++m_scan_y;
|
||||
}
|
||||
|
||||
sl.finalize(m_scan_y);
|
||||
++m_scan_y;
|
||||
return true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool hit_test(int tx, int ty);
|
||||
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
// Disable copying
|
||||
rasterizer_scanline_aa_nogamma(const rasterizer_scanline_aa_nogamma<Clip>&);
|
||||
const rasterizer_scanline_aa_nogamma<Clip>&
|
||||
operator = (const rasterizer_scanline_aa_nogamma<Clip>&);
|
||||
|
||||
private:
|
||||
rasterizer_cells_aa<cell_aa> m_outline;
|
||||
clip_type m_clipper;
|
||||
filling_rule_e m_filling_rule;
|
||||
bool m_auto_close;
|
||||
coord_type m_start_x;
|
||||
coord_type m_start_y;
|
||||
unsigned m_status;
|
||||
int m_scan_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::reset()
|
||||
{
|
||||
m_outline.reset();
|
||||
m_status = status_initial;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::filling_rule(filling_rule_e filling_rule)
|
||||
{
|
||||
m_filling_rule = filling_rule;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::clip_box(double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
reset();
|
||||
m_clipper.clip_box(conv_type::upscale(x1), conv_type::upscale(y1),
|
||||
conv_type::upscale(x2), conv_type::upscale(y2));
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::reset_clipping()
|
||||
{
|
||||
reset();
|
||||
m_clipper.reset_clipping();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::close_polygon()
|
||||
{
|
||||
if(m_status == status_line_to)
|
||||
{
|
||||
m_clipper.line_to(m_outline, m_start_x, m_start_y);
|
||||
m_status = status_closed;
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::move_to(int x, int y)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
if(m_auto_close) close_polygon();
|
||||
m_clipper.move_to(m_start_x = conv_type::downscale(x),
|
||||
m_start_y = conv_type::downscale(y));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::line_to(int x, int y)
|
||||
{
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::downscale(x),
|
||||
conv_type::downscale(y));
|
||||
m_status = status_line_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::move_to_d(double x, double y)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
if(m_auto_close) close_polygon();
|
||||
m_clipper.move_to(m_start_x = conv_type::upscale(x),
|
||||
m_start_y = conv_type::upscale(y));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::line_to_d(double x, double y)
|
||||
{
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::upscale(x),
|
||||
conv_type::upscale(y));
|
||||
m_status = status_line_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
move_to_d(x, y);
|
||||
}
|
||||
else
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
line_to_d(x, y);
|
||||
}
|
||||
else
|
||||
if(is_close(cmd))
|
||||
{
|
||||
close_polygon();
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::edge(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
m_clipper.move_to(conv_type::downscale(x1), conv_type::downscale(y1));
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::downscale(x2),
|
||||
conv_type::downscale(y2));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::edge_d(double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
if(m_outline.sorted()) reset();
|
||||
m_clipper.move_to(conv_type::upscale(x1), conv_type::upscale(y1));
|
||||
m_clipper.line_to(m_outline,
|
||||
conv_type::upscale(x2),
|
||||
conv_type::upscale(y2));
|
||||
m_status = status_move_to;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
void rasterizer_scanline_aa_nogamma<Clip>::sort()
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
AGG_INLINE bool rasterizer_scanline_aa_nogamma<Clip>::rewind_scanlines()
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
if(m_outline.total_cells() == 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_scan_y = m_outline.min_y();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
AGG_INLINE bool rasterizer_scanline_aa_nogamma<Clip>::navigate_scanline(int y)
|
||||
{
|
||||
if(m_auto_close) close_polygon();
|
||||
m_outline.sort_cells();
|
||||
if(m_outline.total_cells() == 0 ||
|
||||
y < m_outline.min_y() ||
|
||||
y > m_outline.max_y())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
m_scan_y = y;
|
||||
return true;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class Clip>
|
||||
bool rasterizer_scanline_aa_nogamma<Clip>::hit_test(int tx, int ty)
|
||||
{
|
||||
if(!navigate_scanline(ty)) return false;
|
||||
scanline_hit_test sl(tx);
|
||||
sweep_scanline(sl);
|
||||
return sl.hit();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
351
3rd/agg/include/agg_rasterizer_sl_clip.h
Normal file
351
3rd/agg/include/agg_rasterizer_sl_clip.h
Normal file
@ -0,0 +1,351 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED
|
||||
#define AGG_RASTERIZER_SL_CLIP_INCLUDED
|
||||
|
||||
#include "agg_clip_liang_barsky.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//--------------------------------------------------------poly_max_coord_e
|
||||
enum poly_max_coord_e
|
||||
{
|
||||
poly_max_coord = (1 << 30) - 1 //----poly_max_coord
|
||||
};
|
||||
|
||||
//------------------------------------------------------------ras_conv_int
|
||||
struct ras_conv_int
|
||||
{
|
||||
typedef int coord_type;
|
||||
static AGG_INLINE int mul_div(double a, double b, double c)
|
||||
{
|
||||
return iround(a * b / c);
|
||||
}
|
||||
static int xi(int v) { return v; }
|
||||
static int yi(int v) { return v; }
|
||||
static int upscale(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static int downscale(int v) { return v; }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------ras_conv_int_sat
|
||||
struct ras_conv_int_sat
|
||||
{
|
||||
typedef int coord_type;
|
||||
static AGG_INLINE int mul_div(double a, double b, double c)
|
||||
{
|
||||
return saturation<poly_max_coord>::iround(a * b / c);
|
||||
}
|
||||
static int xi(int v) { return v; }
|
||||
static int yi(int v) { return v; }
|
||||
static int upscale(double v)
|
||||
{
|
||||
return saturation<poly_max_coord>::iround(v * poly_subpixel_scale);
|
||||
}
|
||||
static int downscale(int v) { return v; }
|
||||
};
|
||||
|
||||
//---------------------------------------------------------ras_conv_int_3x
|
||||
struct ras_conv_int_3x
|
||||
{
|
||||
typedef int coord_type;
|
||||
static AGG_INLINE int mul_div(double a, double b, double c)
|
||||
{
|
||||
return iround(a * b / c);
|
||||
}
|
||||
static int xi(int v) { return v * 3; }
|
||||
static int yi(int v) { return v; }
|
||||
static int upscale(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static int downscale(int v) { return v; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------ras_conv_dbl
|
||||
struct ras_conv_dbl
|
||||
{
|
||||
typedef double coord_type;
|
||||
static AGG_INLINE double mul_div(double a, double b, double c)
|
||||
{
|
||||
return a * b / c;
|
||||
}
|
||||
static int xi(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static int yi(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static double upscale(double v) { return v; }
|
||||
static double downscale(int v) { return v / double(poly_subpixel_scale); }
|
||||
};
|
||||
|
||||
//--------------------------------------------------------ras_conv_dbl_3x
|
||||
struct ras_conv_dbl_3x
|
||||
{
|
||||
typedef double coord_type;
|
||||
static AGG_INLINE double mul_div(double a, double b, double c)
|
||||
{
|
||||
return a * b / c;
|
||||
}
|
||||
static int xi(double v) { return iround(v * poly_subpixel_scale * 3); }
|
||||
static int yi(double v) { return iround(v * poly_subpixel_scale); }
|
||||
static double upscale(double v) { return v; }
|
||||
static double downscale(int v) { return v / double(poly_subpixel_scale); }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------rasterizer_sl_clip
|
||||
template<class Conv> class rasterizer_sl_clip
|
||||
{
|
||||
public:
|
||||
typedef Conv conv_type;
|
||||
typedef typename Conv::coord_type coord_type;
|
||||
typedef rect_base<coord_type> rect_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rasterizer_sl_clip() :
|
||||
m_clip_box(0,0,0,0),
|
||||
m_x1(0),
|
||||
m_y1(0),
|
||||
m_f1(0),
|
||||
m_clipping(false)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_clipping()
|
||||
{
|
||||
m_clipping = false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2)
|
||||
{
|
||||
m_clip_box = rect_type(x1, y1, x2, y2);
|
||||
m_clip_box.normalize();
|
||||
m_clipping = true;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void move_to(coord_type x1, coord_type y1)
|
||||
{
|
||||
m_x1 = x1;
|
||||
m_y1 = y1;
|
||||
if(m_clipping) m_f1 = clipping_flags(x1, y1, m_clip_box);
|
||||
}
|
||||
|
||||
private:
|
||||
//------------------------------------------------------------------------
|
||||
template<class Rasterizer>
|
||||
AGG_INLINE void line_clip_y(Rasterizer& ras,
|
||||
coord_type x1, coord_type y1,
|
||||
coord_type x2, coord_type y2,
|
||||
unsigned f1, unsigned f2) const
|
||||
{
|
||||
f1 &= 10;
|
||||
f2 &= 10;
|
||||
if((f1 | f2) == 0)
|
||||
{
|
||||
// Fully visible
|
||||
ras.line(Conv::xi(x1), Conv::yi(y1), Conv::xi(x2), Conv::yi(y2));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(f1 == f2)
|
||||
{
|
||||
// Invisible by Y
|
||||
return;
|
||||
}
|
||||
|
||||
coord_type tx1 = x1;
|
||||
coord_type ty1 = y1;
|
||||
coord_type tx2 = x2;
|
||||
coord_type ty2 = y2;
|
||||
|
||||
if(f1 & 8) // y1 < clip.y1
|
||||
{
|
||||
tx1 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1);
|
||||
ty1 = m_clip_box.y1;
|
||||
}
|
||||
|
||||
if(f1 & 2) // y1 > clip.y2
|
||||
{
|
||||
tx1 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1);
|
||||
ty1 = m_clip_box.y2;
|
||||
}
|
||||
|
||||
if(f2 & 8) // y2 < clip.y1
|
||||
{
|
||||
tx2 = x1 + Conv::mul_div(m_clip_box.y1-y1, x2-x1, y2-y1);
|
||||
ty2 = m_clip_box.y1;
|
||||
}
|
||||
|
||||
if(f2 & 2) // y2 > clip.y2
|
||||
{
|
||||
tx2 = x1 + Conv::mul_div(m_clip_box.y2-y1, x2-x1, y2-y1);
|
||||
ty2 = m_clip_box.y2;
|
||||
}
|
||||
ras.line(Conv::xi(tx1), Conv::yi(ty1),
|
||||
Conv::xi(tx2), Conv::yi(ty2));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------
|
||||
template<class Rasterizer>
|
||||
void line_to(Rasterizer& ras, coord_type x2, coord_type y2)
|
||||
{
|
||||
if(m_clipping)
|
||||
{
|
||||
unsigned f2 = clipping_flags(x2, y2, m_clip_box);
|
||||
|
||||
if((m_f1 & 10) == (f2 & 10) && (m_f1 & 10) != 0)
|
||||
{
|
||||
// Invisible by Y
|
||||
m_x1 = x2;
|
||||
m_y1 = y2;
|
||||
m_f1 = f2;
|
||||
return;
|
||||
}
|
||||
|
||||
coord_type x1 = m_x1;
|
||||
coord_type y1 = m_y1;
|
||||
unsigned f1 = m_f1;
|
||||
coord_type y3, y4;
|
||||
unsigned f3, f4;
|
||||
|
||||
switch(((f1 & 5) << 1) | (f2 & 5))
|
||||
{
|
||||
case 0: // Visible by X
|
||||
line_clip_y(ras, x1, y1, x2, y2, f1, f2);
|
||||
break;
|
||||
|
||||
case 1: // x2 > clip.x2
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, x1, y1, m_clip_box.x2, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x2, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 2: // x1 > clip.x2
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x2, y3, x2, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 3: // x1 > clip.x2 && x2 > clip.x2
|
||||
line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y2, f1, f2);
|
||||
break;
|
||||
|
||||
case 4: // x2 < clip.x1
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, x1, y1, m_clip_box.x1, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x1, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 6: // x1 > clip.x2 && x2 < clip.x1
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
y4 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
f4 = clipping_flags_y(y4, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x2, y1, m_clip_box.x2, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x2, y3, m_clip_box.x1, y4, f3, f4);
|
||||
line_clip_y(ras, m_clip_box.x1, y4, m_clip_box.x1, y2, f4, f2);
|
||||
break;
|
||||
|
||||
case 8: // x1 < clip.x1
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x1, y3, x2, y2, f3, f2);
|
||||
break;
|
||||
|
||||
case 9: // x1 < clip.x1 && x2 > clip.x2
|
||||
y3 = y1 + Conv::mul_div(m_clip_box.x1-x1, y2-y1, x2-x1);
|
||||
y4 = y1 + Conv::mul_div(m_clip_box.x2-x1, y2-y1, x2-x1);
|
||||
f3 = clipping_flags_y(y3, m_clip_box);
|
||||
f4 = clipping_flags_y(y4, m_clip_box);
|
||||
line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y3, f1, f3);
|
||||
line_clip_y(ras, m_clip_box.x1, y3, m_clip_box.x2, y4, f3, f4);
|
||||
line_clip_y(ras, m_clip_box.x2, y4, m_clip_box.x2, y2, f4, f2);
|
||||
break;
|
||||
|
||||
case 12: // x1 < clip.x1 && x2 < clip.x1
|
||||
line_clip_y(ras, m_clip_box.x1, y1, m_clip_box.x1, y2, f1, f2);
|
||||
break;
|
||||
}
|
||||
m_f1 = f2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ras.line(Conv::xi(m_x1), Conv::yi(m_y1),
|
||||
Conv::xi(x2), Conv::yi(y2));
|
||||
}
|
||||
m_x1 = x2;
|
||||
m_y1 = y2;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
rect_type m_clip_box;
|
||||
coord_type m_x1;
|
||||
coord_type m_y1;
|
||||
unsigned m_f1;
|
||||
bool m_clipping;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//---------------------------------------------------rasterizer_sl_no_clip
|
||||
class rasterizer_sl_no_clip
|
||||
{
|
||||
public:
|
||||
typedef ras_conv_int conv_type;
|
||||
typedef int coord_type;
|
||||
|
||||
rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {}
|
||||
|
||||
void reset_clipping() {}
|
||||
void clip_box(coord_type x1, coord_type y1, coord_type x2, coord_type y2) {}
|
||||
void move_to(coord_type x1, coord_type y1) { m_x1 = x1; m_y1 = y1; }
|
||||
|
||||
template<class Rasterizer>
|
||||
void line_to(Rasterizer& ras, coord_type x2, coord_type y2)
|
||||
{
|
||||
ras.line(m_x1, m_y1, x2, y2);
|
||||
m_x1 = x2;
|
||||
m_y1 = y2;
|
||||
}
|
||||
|
||||
private:
|
||||
int m_x1, m_y1;
|
||||
};
|
||||
|
||||
|
||||
// -----rasterizer_sl_clip_int
|
||||
// -----rasterizer_sl_clip_int_sat
|
||||
// -----rasterizer_sl_clip_int_3x
|
||||
// -----rasterizer_sl_clip_dbl
|
||||
// -----rasterizer_sl_clip_dbl_3x
|
||||
//------------------------------------------------------------------------
|
||||
typedef rasterizer_sl_clip<ras_conv_int> rasterizer_sl_clip_int;
|
||||
typedef rasterizer_sl_clip<ras_conv_int_sat> rasterizer_sl_clip_int_sat;
|
||||
typedef rasterizer_sl_clip<ras_conv_int_3x> rasterizer_sl_clip_int_3x;
|
||||
typedef rasterizer_sl_clip<ras_conv_dbl> rasterizer_sl_clip_dbl;
|
||||
typedef rasterizer_sl_clip<ras_conv_dbl_3x> rasterizer_sl_clip_dbl_3x;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
731
3rd/agg/include/agg_renderer_base.h
Normal file
731
3rd/agg/include/agg_renderer_base.h
Normal file
@ -0,0 +1,731 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class renderer_base
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERER_BASE_INCLUDED
|
||||
#define AGG_RENDERER_BASE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-----------------------------------------------------------renderer_base
|
||||
template<class PixelFormat> class renderer_base
|
||||
{
|
||||
public:
|
||||
typedef PixelFormat pixfmt_type;
|
||||
typedef typename pixfmt_type::color_type color_type;
|
||||
typedef typename pixfmt_type::row_data row_data;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {}
|
||||
explicit renderer_base(pixfmt_type& ren) :
|
||||
m_ren(&ren),
|
||||
m_clip_box(0, 0, ren.width() - 1, ren.height() - 1)
|
||||
{}
|
||||
void attach(pixfmt_type& ren)
|
||||
{
|
||||
m_ren = &ren;
|
||||
m_clip_box = rect_i(0, 0, ren.width() - 1, ren.height() - 1);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const pixfmt_type& ren() const { return *m_ren; }
|
||||
pixfmt_type& ren() { return *m_ren; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
unsigned width() const { return m_ren->width(); }
|
||||
unsigned height() const { return m_ren->height(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool clip_box(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
rect_i cb(x1, y1, x2, y2);
|
||||
cb.normalize();
|
||||
if(cb.clip(rect_i(0, 0, width() - 1, height() - 1)))
|
||||
{
|
||||
m_clip_box = cb;
|
||||
return true;
|
||||
}
|
||||
m_clip_box.x1 = 1;
|
||||
m_clip_box.y1 = 1;
|
||||
m_clip_box.x2 = 0;
|
||||
m_clip_box.y2 = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_clipping(bool visibility)
|
||||
{
|
||||
if(visibility)
|
||||
{
|
||||
m_clip_box.x1 = 0;
|
||||
m_clip_box.y1 = 0;
|
||||
m_clip_box.x2 = width() - 1;
|
||||
m_clip_box.y2 = height() - 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_clip_box.x1 = 1;
|
||||
m_clip_box.y1 = 1;
|
||||
m_clip_box.x2 = 0;
|
||||
m_clip_box.y2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clip_box_naked(int x1, int y1, int x2, int y2)
|
||||
{
|
||||
m_clip_box.x1 = x1;
|
||||
m_clip_box.y1 = y1;
|
||||
m_clip_box.x2 = x2;
|
||||
m_clip_box.y2 = y2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
bool inbox(int x, int y) const
|
||||
{
|
||||
return x >= m_clip_box.x1 && y >= m_clip_box.y1 &&
|
||||
x <= m_clip_box.x2 && y <= m_clip_box.y2;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rect_i& clip_box() const { return m_clip_box; }
|
||||
int xmin() const { return m_clip_box.x1; }
|
||||
int ymin() const { return m_clip_box.y1; }
|
||||
int xmax() const { return m_clip_box.x2; }
|
||||
int ymax() const { return m_clip_box.y2; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
const rect_i& bounding_clip_box() const { return m_clip_box; }
|
||||
int bounding_xmin() const { return m_clip_box.x1; }
|
||||
int bounding_ymin() const { return m_clip_box.y1; }
|
||||
int bounding_xmax() const { return m_clip_box.x2; }
|
||||
int bounding_ymax() const { return m_clip_box.y2; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(const color_type& c)
|
||||
{
|
||||
unsigned y;
|
||||
if(width())
|
||||
{
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
m_ren->copy_hline(0, y, width(), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void fill(const color_type& c)
|
||||
{
|
||||
unsigned y;
|
||||
if(width())
|
||||
{
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
m_ren->blend_hline(0, y, width(), c, cover_mask);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_pixel(int x, int y, const color_type& c)
|
||||
{
|
||||
if(inbox(x, y))
|
||||
{
|
||||
m_ren->copy_pixel(x, y, c);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_pixel(int x, int y, const color_type& c, cover_type cover)
|
||||
{
|
||||
if(inbox(x, y))
|
||||
{
|
||||
m_ren->blend_pixel(x, y, c, cover);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
color_type pixel(int x, int y) const
|
||||
{
|
||||
return inbox(x, y) ?
|
||||
m_ren->pixel(x, y) :
|
||||
color_type::no_color();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_hline(int x1, int y, int x2, const color_type& c)
|
||||
{
|
||||
if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
if(x1 > xmax()) return;
|
||||
if(x2 < xmin()) return;
|
||||
|
||||
if(x1 < xmin()) x1 = xmin();
|
||||
if(x2 > xmax()) x2 = xmax();
|
||||
|
||||
m_ren->copy_hline(x1, y, x2 - x1 + 1, c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_vline(int x, int y1, int y2, const color_type& c)
|
||||
{
|
||||
if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
if(y1 > ymax()) return;
|
||||
if(y2 < ymin()) return;
|
||||
|
||||
if(y1 < ymin()) y1 = ymin();
|
||||
if(y2 > ymax()) y2 = ymax();
|
||||
|
||||
m_ren->copy_vline(x, y1, y2 - y1 + 1, c);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_hline(int x1, int y, int x2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
if(x1 > x2) { int t = x2; x2 = x1; x1 = t; }
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
if(x1 > xmax()) return;
|
||||
if(x2 < xmin()) return;
|
||||
|
||||
if(x1 < xmin()) x1 = xmin();
|
||||
if(x2 > xmax()) x2 = xmax();
|
||||
|
||||
m_ren->blend_hline(x1, y, x2 - x1 + 1, c, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_vline(int x, int y1, int y2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
if(y1 > y2) { int t = y2; y2 = y1; y1 = t; }
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
if(y1 > ymax()) return;
|
||||
if(y2 < ymin()) return;
|
||||
|
||||
if(y1 < ymin()) y1 = ymin();
|
||||
if(y2 > ymax()) y2 = ymax();
|
||||
|
||||
m_ren->blend_vline(x, y1, y2 - y1 + 1, c, cover);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_bar(int x1, int y1, int x2, int y2, const color_type& c)
|
||||
{
|
||||
rect_i rc(x1, y1, x2, y2);
|
||||
rc.normalize();
|
||||
if(rc.clip(clip_box()))
|
||||
{
|
||||
int y;
|
||||
for(y = rc.y1; y <= rc.y2; y++)
|
||||
{
|
||||
m_ren->copy_hline(rc.x1, y, unsigned(rc.x2 - rc.x1 + 1), c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_bar(int x1, int y1, int x2, int y2,
|
||||
const color_type& c, cover_type cover)
|
||||
{
|
||||
rect_i rc(x1, y1, x2, y2);
|
||||
rc.normalize();
|
||||
if(rc.clip(clip_box()))
|
||||
{
|
||||
int y;
|
||||
for(y = rc.y1; y <= rc.y2; y++)
|
||||
{
|
||||
m_ren->blend_hline(rc.x1,
|
||||
y,
|
||||
unsigned(rc.x2 - rc.x1 + 1),
|
||||
c,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_hspan(int x, int y, int len,
|
||||
const color_type& c,
|
||||
const cover_type* covers)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
len -= xmin() - x;
|
||||
if(len <= 0) return;
|
||||
covers += xmin() - x;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_solid_hspan(x, y, len, c, covers);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_solid_vspan(int x, int y, int len,
|
||||
const color_type& c,
|
||||
const cover_type* covers)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
len -= ymin() - y;
|
||||
if(len <= 0) return;
|
||||
covers += ymin() - y;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_solid_vspan(x, y, len, c, covers);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_color_hspan(int x, int y, int len, const color_type* colors)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
int d = xmin() - x;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
colors += d;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->copy_color_hspan(x, y, len, colors);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void copy_color_vspan(int x, int y, int len, const color_type* colors)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
int d = ymin() - y;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
colors += d;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->copy_color_vspan(x, y, len, colors);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_hspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
if(y > ymax()) return;
|
||||
if(y < ymin()) return;
|
||||
|
||||
if(x < xmin())
|
||||
{
|
||||
int d = xmin() - x;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
x = xmin();
|
||||
}
|
||||
if(x + len > xmax())
|
||||
{
|
||||
len = xmax() - x + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_color_hspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void blend_color_vspan(int x, int y, int len,
|
||||
const color_type* colors,
|
||||
const cover_type* covers,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
if(x > xmax()) return;
|
||||
if(x < xmin()) return;
|
||||
|
||||
if(y < ymin())
|
||||
{
|
||||
int d = ymin() - y;
|
||||
len -= d;
|
||||
if(len <= 0) return;
|
||||
if(covers) covers += d;
|
||||
colors += d;
|
||||
y = ymin();
|
||||
}
|
||||
if(y + len > ymax())
|
||||
{
|
||||
len = ymax() - y + 1;
|
||||
if(len <= 0) return;
|
||||
}
|
||||
m_ren->blend_color_vspan(x, y, len, colors, covers, cover);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
rect_i clip_rect_area(rect_i& dst, rect_i& src, int wsrc, int hsrc) const
|
||||
{
|
||||
rect_i rc(0,0,0,0);
|
||||
rect_i cb = clip_box();
|
||||
++cb.x2;
|
||||
++cb.y2;
|
||||
|
||||
if(src.x1 < 0)
|
||||
{
|
||||
dst.x1 -= src.x1;
|
||||
src.x1 = 0;
|
||||
}
|
||||
if(src.y1 < 0)
|
||||
{
|
||||
dst.y1 -= src.y1;
|
||||
src.y1 = 0;
|
||||
}
|
||||
|
||||
if(src.x2 > wsrc) src.x2 = wsrc;
|
||||
if(src.y2 > hsrc) src.y2 = hsrc;
|
||||
|
||||
if(dst.x1 < cb.x1)
|
||||
{
|
||||
src.x1 += cb.x1 - dst.x1;
|
||||
dst.x1 = cb.x1;
|
||||
}
|
||||
if(dst.y1 < cb.y1)
|
||||
{
|
||||
src.y1 += cb.y1 - dst.y1;
|
||||
dst.y1 = cb.y1;
|
||||
}
|
||||
|
||||
if(dst.x2 > cb.x2) dst.x2 = cb.x2;
|
||||
if(dst.y2 > cb.y2) dst.y2 = cb.y2;
|
||||
|
||||
rc.x2 = dst.x2 - dst.x1;
|
||||
rc.y2 = dst.y2 - dst.y1;
|
||||
|
||||
if(rc.x2 > src.x2 - src.x1) rc.x2 = src.x2 - src.x1;
|
||||
if(rc.y2 > src.y2 - src.y1) rc.y2 = src.y2 - src.y1;
|
||||
return rc;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf>
|
||||
void copy_from(const RenBuf& src,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
m_ren->copy_from(src,
|
||||
rdst.x1, rdst.y1,
|
||||
rsrc.x1, rsrc.y1,
|
||||
rc.x2);
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from(const SrcPixelFormatRenderer& src,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
|
||||
if(rw.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(rw.x1 > x1src)
|
||||
{
|
||||
x1dst += rw.x1 - x1src;
|
||||
len -= rw.x1 - x1src;
|
||||
x1src = rw.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > rw.x2)
|
||||
{
|
||||
len -= x1src + len - rw.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from(src,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_color(const SrcPixelFormatRenderer& src,
|
||||
const color_type& color,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
|
||||
if(rw.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(rw.x1 > x1src)
|
||||
{
|
||||
x1dst += rw.x1 - x1src;
|
||||
len -= rw.x1 - x1src;
|
||||
x1src = rw.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > rw.x2)
|
||||
{
|
||||
len -= x1src + len - rw.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from_color(src,
|
||||
color,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class SrcPixelFormatRenderer>
|
||||
void blend_from_lut(const SrcPixelFormatRenderer& src,
|
||||
const color_type* color_lut,
|
||||
const rect_i* rect_src_ptr = 0,
|
||||
int dx = 0,
|
||||
int dy = 0,
|
||||
cover_type cover = agg::cover_full)
|
||||
{
|
||||
rect_i rsrc(0, 0, src.width(), src.height());
|
||||
if(rect_src_ptr)
|
||||
{
|
||||
rsrc.x1 = rect_src_ptr->x1;
|
||||
rsrc.y1 = rect_src_ptr->y1;
|
||||
rsrc.x2 = rect_src_ptr->x2 + 1;
|
||||
rsrc.y2 = rect_src_ptr->y2 + 1;
|
||||
}
|
||||
|
||||
// Version with xdst, ydst (absolute positioning)
|
||||
//rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1);
|
||||
|
||||
// Version with dx, dy (relative positioning)
|
||||
rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy);
|
||||
rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height());
|
||||
|
||||
if(rc.x2 > 0)
|
||||
{
|
||||
int incy = 1;
|
||||
if(rdst.y1 > rsrc.y1)
|
||||
{
|
||||
rsrc.y1 += rc.y2 - 1;
|
||||
rdst.y1 += rc.y2 - 1;
|
||||
incy = -1;
|
||||
}
|
||||
while(rc.y2 > 0)
|
||||
{
|
||||
typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1);
|
||||
if(rw.ptr)
|
||||
{
|
||||
int x1src = rsrc.x1;
|
||||
int x1dst = rdst.x1;
|
||||
int len = rc.x2;
|
||||
if(rw.x1 > x1src)
|
||||
{
|
||||
x1dst += rw.x1 - x1src;
|
||||
len -= rw.x1 - x1src;
|
||||
x1src = rw.x1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
if(x1src + len-1 > rw.x2)
|
||||
{
|
||||
len -= x1src + len - rw.x2 - 1;
|
||||
}
|
||||
if(len > 0)
|
||||
{
|
||||
m_ren->blend_from_lut(src,
|
||||
color_lut,
|
||||
x1dst, rdst.y1,
|
||||
x1src, rsrc.y1,
|
||||
len,
|
||||
cover);
|
||||
}
|
||||
}
|
||||
}
|
||||
rdst.y1 += incy;
|
||||
rsrc.y1 += incy;
|
||||
--rc.y2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
pixfmt_type* m_ren;
|
||||
rect_i m_clip_box;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
852
3rd/agg/include/agg_renderer_scanline.h
Normal file
852
3rd/agg/include/agg_renderer_scanline.h
Normal file
@ -0,0 +1,852 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERER_SCANLINE_INCLUDED
|
||||
#define AGG_RENDERER_SCANLINE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_renderer_base.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//================================================render_scanline_aa_solid
|
||||
template<class Scanline, class BaseRenderer, class ColorT>
|
||||
void render_scanline_aa_solid(const Scanline& sl,
|
||||
BaseRenderer& ren,
|
||||
const ColorT& color)
|
||||
{
|
||||
int y = sl.y();
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
if(span->len > 0)
|
||||
{
|
||||
ren.blend_solid_hspan(x, y, (unsigned)span->len,
|
||||
color,
|
||||
span->covers);
|
||||
}
|
||||
else
|
||||
{
|
||||
ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
|
||||
color,
|
||||
*(span->covers));
|
||||
}
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//===============================================render_scanlines_aa_solid
|
||||
template<class Rasterizer, class Scanline,
|
||||
class BaseRenderer, class ColorT>
|
||||
void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl,
|
||||
BaseRenderer& ren, const ColorT& color)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
// Explicitly convert "color" to the BaseRenderer color type.
|
||||
// For example, it can be called with color type "rgba", while
|
||||
// "rgba8" is needed. Otherwise it will be implicitly
|
||||
// converted in the loop many times.
|
||||
//----------------------
|
||||
typename BaseRenderer::color_type ren_color = color;
|
||||
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
//render_scanline_aa_solid(sl, ren, ren_color);
|
||||
|
||||
// This code is equivalent to the above call (copy/paste).
|
||||
// It's just a "manual" optimization for old compilers,
|
||||
// like Microsoft Visual C++ v6.0
|
||||
//-------------------------------
|
||||
int y = sl.y();
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
if(span->len > 0)
|
||||
{
|
||||
ren.blend_solid_hspan(x, y, (unsigned)span->len,
|
||||
ren_color,
|
||||
span->covers);
|
||||
}
|
||||
else
|
||||
{
|
||||
ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
|
||||
ren_color,
|
||||
*(span->covers));
|
||||
}
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================renderer_scanline_aa_solid
|
||||
template<class BaseRenderer> class renderer_scanline_aa_solid
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef typename base_ren_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa_solid() : m_ren(0) {}
|
||||
explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {}
|
||||
void attach(base_ren_type& ren)
|
||||
{
|
||||
m_ren = &ren;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void color(const color_type& c) { m_color = c; }
|
||||
const color_type& color() const { return m_color; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_aa_solid(sl, *m_ren, m_color);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
color_type m_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//======================================================render_scanline_aa
|
||||
template<class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanline_aa(const Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
int y = sl.y();
|
||||
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
const typename Scanline::cover_type* covers = span->covers;
|
||||
|
||||
if(len < 0) len = -len;
|
||||
typename BaseRenderer::color_type* colors = alloc.allocate(len);
|
||||
span_gen.generate(colors, x, y, len);
|
||||
ren.blend_color_hspan(x, y, len, colors,
|
||||
(span->len < 0) ? 0 : covers, *covers);
|
||||
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================render_scanlines_aa
|
||||
template<class Rasterizer, class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
span_gen.prepare();
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
render_scanline_aa(sl, ren, alloc, span_gen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================renderer_scanline_aa
|
||||
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
|
||||
class renderer_scanline_aa
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef SpanAllocator alloc_type;
|
||||
typedef SpanGenerator span_gen_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {}
|
||||
renderer_scanline_aa(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_alloc(&alloc),
|
||||
m_span_gen(&span_gen)
|
||||
{}
|
||||
void attach(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen)
|
||||
{
|
||||
m_ren = &ren;
|
||||
m_alloc = &alloc;
|
||||
m_span_gen = &span_gen;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() { m_span_gen->prepare(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
alloc_type* m_alloc;
|
||||
span_gen_type* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//===============================================render_scanline_bin_solid
|
||||
template<class Scanline, class BaseRenderer, class ColorT>
|
||||
void render_scanline_bin_solid(const Scanline& sl,
|
||||
BaseRenderer& ren,
|
||||
const ColorT& color)
|
||||
{
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
ren.blend_hline(span->x,
|
||||
sl.y(),
|
||||
span->x - 1 + ((span->len < 0) ?
|
||||
-span->len :
|
||||
span->len),
|
||||
color,
|
||||
cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================render_scanlines_bin_solid
|
||||
template<class Rasterizer, class Scanline,
|
||||
class BaseRenderer, class ColorT>
|
||||
void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl,
|
||||
BaseRenderer& ren, const ColorT& color)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
// Explicitly convert "color" to the BaseRenderer color type.
|
||||
// For example, it can be called with color type "rgba", while
|
||||
// "rgba8" is needed. Otherwise it will be implicitly
|
||||
// converted in the loop many times.
|
||||
//----------------------
|
||||
typename BaseRenderer::color_type ren_color(color);
|
||||
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
//render_scanline_bin_solid(sl, ren, ren_color);
|
||||
|
||||
// This code is equivalent to the above call (copy/paste).
|
||||
// It's just a "manual" optimization for old compilers,
|
||||
// like Microsoft Visual C++ v6.0
|
||||
//-------------------------------
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
ren.blend_hline(span->x,
|
||||
sl.y(),
|
||||
span->x - 1 + ((span->len < 0) ?
|
||||
-span->len :
|
||||
span->len),
|
||||
ren_color,
|
||||
cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================renderer_scanline_bin_solid
|
||||
template<class BaseRenderer> class renderer_scanline_bin_solid
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef typename base_ren_type::color_type color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin_solid() : m_ren(0) {}
|
||||
explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {}
|
||||
void attach(base_ren_type& ren)
|
||||
{
|
||||
m_ren = &ren;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void color(const color_type& c) { m_color = c; }
|
||||
const color_type& color() const { return m_color; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_bin_solid(sl, *m_ren, m_color);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
color_type m_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//======================================================render_scanline_bin
|
||||
template<class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanline_bin(const Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
int y = sl.y();
|
||||
|
||||
unsigned num_spans = sl.num_spans();
|
||||
typename Scanline::const_iterator span = sl.begin();
|
||||
for(;;)
|
||||
{
|
||||
int x = span->x;
|
||||
int len = span->len;
|
||||
if(len < 0) len = -len;
|
||||
typename BaseRenderer::color_type* colors = alloc.allocate(len);
|
||||
span_gen.generate(colors, x, y, len);
|
||||
ren.blend_color_hspan(x, y, len, colors, 0, cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span;
|
||||
}
|
||||
}
|
||||
|
||||
//=====================================================render_scanlines_bin
|
||||
template<class Rasterizer, class Scanline, class BaseRenderer,
|
||||
class SpanAllocator, class SpanGenerator>
|
||||
void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
|
||||
SpanAllocator& alloc, SpanGenerator& span_gen)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
span_gen.prepare();
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
render_scanline_bin(sl, ren, alloc, span_gen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//====================================================renderer_scanline_bin
|
||||
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
|
||||
class renderer_scanline_bin
|
||||
{
|
||||
public:
|
||||
typedef BaseRenderer base_ren_type;
|
||||
typedef SpanAllocator alloc_type;
|
||||
typedef SpanGenerator span_gen_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {}
|
||||
renderer_scanline_bin(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen) :
|
||||
m_ren(&ren),
|
||||
m_alloc(&alloc),
|
||||
m_span_gen(&span_gen)
|
||||
{}
|
||||
void attach(base_ren_type& ren,
|
||||
alloc_type& alloc,
|
||||
span_gen_type& span_gen)
|
||||
{
|
||||
m_ren = &ren;
|
||||
m_alloc = &alloc;
|
||||
m_span_gen = &span_gen;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() { m_span_gen->prepare(); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class Scanline> void render(const Scanline& sl)
|
||||
{
|
||||
render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen);
|
||||
}
|
||||
|
||||
private:
|
||||
base_ren_type* m_ren;
|
||||
alloc_type* m_alloc;
|
||||
span_gen_type* m_span_gen;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================================render_scanlines
|
||||
template<class Rasterizer, class Scanline, class Renderer>
|
||||
void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
sl.reset(ras.min_x(), ras.max_x());
|
||||
ren.prepare();
|
||||
while(ras.sweep_scanline(sl))
|
||||
{
|
||||
ren.render(sl);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//========================================================render_all_paths
|
||||
template<class Rasterizer, class Scanline, class Renderer,
|
||||
class VertexSource, class ColorStorage, class PathId>
|
||||
void render_all_paths(Rasterizer& ras,
|
||||
Scanline& sl,
|
||||
Renderer& r,
|
||||
VertexSource& vs,
|
||||
const ColorStorage& as,
|
||||
const PathId& path_id,
|
||||
unsigned num_paths)
|
||||
{
|
||||
for(unsigned i = 0; i < num_paths; i++)
|
||||
{
|
||||
ras.reset();
|
||||
ras.add_path(vs, path_id[i]);
|
||||
r.color(as[i]);
|
||||
render_scanlines(ras, sl, r);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=============================================render_scanlines_compound
|
||||
template<class Rasterizer,
|
||||
class ScanlineAA,
|
||||
class ScanlineBin,
|
||||
class BaseRenderer,
|
||||
class SpanAllocator,
|
||||
class StyleHandler>
|
||||
void render_scanlines_compound(Rasterizer& ras,
|
||||
ScanlineAA& sl_aa,
|
||||
ScanlineBin& sl_bin,
|
||||
BaseRenderer& ren,
|
||||
SpanAllocator& alloc,
|
||||
StyleHandler& sh)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
int min_x = ras.min_x();
|
||||
int len = ras.max_x() - min_x + 2;
|
||||
sl_aa.reset(min_x, ras.max_x());
|
||||
sl_bin.reset(min_x, ras.max_x());
|
||||
|
||||
typedef typename BaseRenderer::color_type color_type;
|
||||
color_type* color_span = alloc.allocate(len * 2);
|
||||
color_type* mix_buffer = color_span + len;
|
||||
unsigned num_spans;
|
||||
|
||||
unsigned num_styles;
|
||||
unsigned style;
|
||||
bool solid;
|
||||
while((num_styles = ras.sweep_styles()) > 0)
|
||||
{
|
||||
typename ScanlineAA::const_iterator span_aa;
|
||||
if(num_styles == 1)
|
||||
{
|
||||
// Optimization for a single style. Happens often
|
||||
//-------------------------
|
||||
if(ras.sweep_scanline(sl_aa, 0))
|
||||
{
|
||||
style = ras.style(0);
|
||||
if(sh.is_solid(style))
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
render_scanline_aa_solid(sl_aa, ren, sh.color(style));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
sh.generate_span(color_span,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
|
||||
ren.blend_color_hspan(span_aa->x,
|
||||
sl_aa.y(),
|
||||
span_aa->len,
|
||||
color_span,
|
||||
span_aa->covers);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(ras.sweep_scanline(sl_bin, -1))
|
||||
{
|
||||
// Clear the spans of the mix_buffer
|
||||
//--------------------
|
||||
typename ScanlineBin::const_iterator span_bin = sl_bin.begin();
|
||||
num_spans = sl_bin.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
memset(mix_buffer + span_bin->x - min_x,
|
||||
0,
|
||||
span_bin->len * sizeof(color_type));
|
||||
|
||||
if(--num_spans == 0) break;
|
||||
++span_bin;
|
||||
}
|
||||
|
||||
unsigned i;
|
||||
for(i = 0; i < num_styles; i++)
|
||||
{
|
||||
style = ras.style(i);
|
||||
solid = sh.is_solid(style);
|
||||
|
||||
if(ras.sweep_scanline(sl_aa, i))
|
||||
{
|
||||
color_type* colors;
|
||||
color_type* cspan;
|
||||
typename ScanlineAA::cover_type* covers;
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
if(solid)
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
color_type c = sh.color(style);
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
covers = span_aa->covers;
|
||||
do
|
||||
{
|
||||
if(*covers == cover_full)
|
||||
{
|
||||
*colors = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
colors->add(c, *covers);
|
||||
}
|
||||
++colors;
|
||||
++covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
cspan = color_span;
|
||||
sh.generate_span(cspan,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
covers = span_aa->covers;
|
||||
do
|
||||
{
|
||||
if(*covers == cover_full)
|
||||
{
|
||||
*colors = *cspan;
|
||||
}
|
||||
else
|
||||
{
|
||||
colors->add(*cspan, *covers);
|
||||
}
|
||||
++cspan;
|
||||
++colors;
|
||||
++covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emit the blended result as a color hspan
|
||||
//-------------------------
|
||||
span_bin = sl_bin.begin();
|
||||
num_spans = sl_bin.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
ren.blend_color_hspan(span_bin->x,
|
||||
sl_bin.y(),
|
||||
span_bin->len,
|
||||
mix_buffer + span_bin->x - min_x,
|
||||
0,
|
||||
cover_full);
|
||||
if(--num_spans == 0) break;
|
||||
++span_bin;
|
||||
}
|
||||
} // if(ras.sweep_scanline(sl_bin, -1))
|
||||
} // if(num_styles == 1) ... else
|
||||
} // while((num_styles = ras.sweep_styles()) > 0)
|
||||
} // if(ras.rewind_scanlines())
|
||||
}
|
||||
|
||||
//=======================================render_scanlines_compound_layered
|
||||
template<class Rasterizer,
|
||||
class ScanlineAA,
|
||||
class BaseRenderer,
|
||||
class SpanAllocator,
|
||||
class StyleHandler>
|
||||
void render_scanlines_compound_layered(Rasterizer& ras,
|
||||
ScanlineAA& sl_aa,
|
||||
BaseRenderer& ren,
|
||||
SpanAllocator& alloc,
|
||||
StyleHandler& sh)
|
||||
{
|
||||
if(ras.rewind_scanlines())
|
||||
{
|
||||
int min_x = ras.min_x();
|
||||
int len = ras.max_x() - min_x + 2;
|
||||
sl_aa.reset(min_x, ras.max_x());
|
||||
|
||||
typedef typename BaseRenderer::color_type color_type;
|
||||
color_type* color_span = alloc.allocate(len * 2);
|
||||
color_type* mix_buffer = color_span + len;
|
||||
cover_type* cover_buffer = ras.allocate_cover_buffer(len);
|
||||
unsigned num_spans;
|
||||
|
||||
unsigned num_styles;
|
||||
unsigned style;
|
||||
bool solid;
|
||||
while((num_styles = ras.sweep_styles()) > 0)
|
||||
{
|
||||
typename ScanlineAA::const_iterator span_aa;
|
||||
if(num_styles == 1)
|
||||
{
|
||||
// Optimization for a single style. Happens often
|
||||
//-------------------------
|
||||
if(ras.sweep_scanline(sl_aa, 0))
|
||||
{
|
||||
style = ras.style(0);
|
||||
if(sh.is_solid(style))
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
render_scanline_aa_solid(sl_aa, ren, sh.color(style));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
sh.generate_span(color_span,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
|
||||
ren.blend_color_hspan(span_aa->x,
|
||||
sl_aa.y(),
|
||||
span_aa->len,
|
||||
color_span,
|
||||
span_aa->covers);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int sl_start = ras.scanline_start();
|
||||
unsigned sl_len = ras.scanline_length();
|
||||
|
||||
if(sl_len)
|
||||
{
|
||||
memset(mix_buffer + sl_start - min_x,
|
||||
0,
|
||||
sl_len * sizeof(color_type));
|
||||
|
||||
memset(cover_buffer + sl_start - min_x,
|
||||
0,
|
||||
sl_len * sizeof(cover_type));
|
||||
|
||||
int sl_y = 0x7FFFFFFF;
|
||||
unsigned i;
|
||||
for(i = 0; i < num_styles; i++)
|
||||
{
|
||||
style = ras.style(i);
|
||||
solid = sh.is_solid(style);
|
||||
|
||||
if(ras.sweep_scanline(sl_aa, i))
|
||||
{
|
||||
unsigned cover;
|
||||
color_type* colors;
|
||||
color_type* cspan;
|
||||
cover_type* src_covers;
|
||||
cover_type* dst_covers;
|
||||
span_aa = sl_aa.begin();
|
||||
num_spans = sl_aa.num_spans();
|
||||
sl_y = sl_aa.y();
|
||||
if(solid)
|
||||
{
|
||||
// Just solid fill
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
color_type c = sh.color(style);
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
src_covers = span_aa->covers;
|
||||
dst_covers = cover_buffer + span_aa->x - min_x;
|
||||
do
|
||||
{
|
||||
cover = *src_covers;
|
||||
if(*dst_covers + cover > cover_full)
|
||||
{
|
||||
cover = cover_full - *dst_covers;
|
||||
}
|
||||
if(cover)
|
||||
{
|
||||
colors->add(c, cover);
|
||||
*dst_covers += cover;
|
||||
}
|
||||
++colors;
|
||||
++src_covers;
|
||||
++dst_covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Arbitrary span generator
|
||||
//-----------------------
|
||||
for(;;)
|
||||
{
|
||||
len = span_aa->len;
|
||||
colors = mix_buffer + span_aa->x - min_x;
|
||||
cspan = color_span;
|
||||
sh.generate_span(cspan,
|
||||
span_aa->x,
|
||||
sl_aa.y(),
|
||||
len,
|
||||
style);
|
||||
src_covers = span_aa->covers;
|
||||
dst_covers = cover_buffer + span_aa->x - min_x;
|
||||
do
|
||||
{
|
||||
cover = *src_covers;
|
||||
if(*dst_covers + cover > cover_full)
|
||||
{
|
||||
cover = cover_full - *dst_covers;
|
||||
}
|
||||
if(cover)
|
||||
{
|
||||
colors->add(*cspan, cover);
|
||||
*dst_covers += cover;
|
||||
}
|
||||
++cspan;
|
||||
++colors;
|
||||
++src_covers;
|
||||
++dst_covers;
|
||||
}
|
||||
while(--len);
|
||||
if(--num_spans == 0) break;
|
||||
++span_aa;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ren.blend_color_hspan(sl_start,
|
||||
sl_y,
|
||||
sl_len,
|
||||
mix_buffer + sl_start - min_x,
|
||||
0,
|
||||
cover_full);
|
||||
} //if(sl_len)
|
||||
} //if(num_styles == 1) ... else
|
||||
} //while((num_styles = ras.sweep_styles()) > 0)
|
||||
} //if(ras.rewind_scanlines())
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
300
3rd/agg/include/agg_rendering_buffer.h
Normal file
300
3rd/agg/include/agg_rendering_buffer.h
Normal file
@ -0,0 +1,300 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// class rendering_buffer
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_RENDERING_BUFFER_INCLUDED
|
||||
#define AGG_RENDERING_BUFFER_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===========================================================row_accessor
|
||||
template<class T> class row_accessor
|
||||
{
|
||||
public:
|
||||
typedef const_row_info<T> row_data;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
row_accessor() :
|
||||
m_buf(0),
|
||||
m_start(0),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
row_accessor(T* buf, unsigned width, unsigned height, int stride) :
|
||||
m_buf(0),
|
||||
m_start(0),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
attach(buf, width, height, stride);
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void attach(T* buf, unsigned width, unsigned height, int stride)
|
||||
{
|
||||
m_buf = m_start = buf;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_stride = stride;
|
||||
if(stride < 0)
|
||||
{
|
||||
m_start = m_buf - int(height - 1) * stride;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* buf() { return m_buf; }
|
||||
AGG_INLINE const T* buf() const { return m_buf; }
|
||||
AGG_INLINE unsigned width() const { return m_width; }
|
||||
AGG_INLINE unsigned height() const { return m_height; }
|
||||
AGG_INLINE int stride() const { return m_stride; }
|
||||
AGG_INLINE unsigned stride_abs() const
|
||||
{
|
||||
return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* row_ptr(int, int y, unsigned)
|
||||
{
|
||||
return m_start + y * m_stride;
|
||||
}
|
||||
AGG_INLINE T* row_ptr(int y) { return m_start + y * m_stride; }
|
||||
AGG_INLINE const T* row_ptr(int y) const { return m_start + y * m_stride; }
|
||||
AGG_INLINE row_data row (int y) const
|
||||
{
|
||||
return row_data(0, m_width-1, row_ptr(y));
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf>
|
||||
void copy_from(const RenBuf& src)
|
||||
{
|
||||
unsigned h = height();
|
||||
if(src.height() < h) h = src.height();
|
||||
|
||||
unsigned l = stride_abs();
|
||||
if(src.stride_abs() < l) l = src.stride_abs();
|
||||
|
||||
l *= sizeof(T);
|
||||
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(row_ptr(0, y, w), src.row_ptr(y), l);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(T value)
|
||||
{
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
unsigned stride = stride_abs();
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
T* p = row_ptr(0, y, w);
|
||||
unsigned x;
|
||||
for(x = 0; x < stride; x++)
|
||||
{
|
||||
*p++ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
T* m_buf; // Pointer to renrdering buffer
|
||||
T* m_start; // Pointer to first pixel depending on stride
|
||||
unsigned m_width; // Width in pixels
|
||||
unsigned m_height; // Height in pixels
|
||||
int m_stride; // Number of bytes per row. Can be < 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================row_ptr_cache
|
||||
template<class T> class row_ptr_cache
|
||||
{
|
||||
public:
|
||||
typedef const_row_info<T> row_data;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
row_ptr_cache() :
|
||||
m_buf(0),
|
||||
m_rows(),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
row_ptr_cache(T* buf, unsigned width, unsigned height, int stride) :
|
||||
m_buf(0),
|
||||
m_rows(),
|
||||
m_width(0),
|
||||
m_height(0),
|
||||
m_stride(0)
|
||||
{
|
||||
attach(buf, width, height, stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void attach(T* buf, unsigned width, unsigned height, int stride)
|
||||
{
|
||||
m_buf = buf;
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
m_stride = stride;
|
||||
if(height > m_rows.size())
|
||||
{
|
||||
m_rows.resize(height);
|
||||
}
|
||||
|
||||
T* row_ptr = m_buf;
|
||||
|
||||
if(stride < 0)
|
||||
{
|
||||
row_ptr = m_buf - int(height - 1) * stride;
|
||||
}
|
||||
|
||||
T** rows = &m_rows[0];
|
||||
|
||||
while(height--)
|
||||
{
|
||||
*rows++ = row_ptr;
|
||||
row_ptr += stride;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* buf() { return m_buf; }
|
||||
AGG_INLINE const T* buf() const { return m_buf; }
|
||||
AGG_INLINE unsigned width() const { return m_width; }
|
||||
AGG_INLINE unsigned height() const { return m_height; }
|
||||
AGG_INLINE int stride() const { return m_stride; }
|
||||
AGG_INLINE unsigned stride_abs() const
|
||||
{
|
||||
return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE T* row_ptr(int, int y, unsigned)
|
||||
{
|
||||
return m_rows[y];
|
||||
}
|
||||
AGG_INLINE T* row_ptr(int y) { return m_rows[y]; }
|
||||
AGG_INLINE const T* row_ptr(int y) const { return m_rows[y]; }
|
||||
AGG_INLINE row_data row (int y) const
|
||||
{
|
||||
return row_data(0, m_width-1, m_rows[y]);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
T const* const* rows() const { return &m_rows[0]; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
template<class RenBuf>
|
||||
void copy_from(const RenBuf& src)
|
||||
{
|
||||
unsigned h = height();
|
||||
if(src.height() < h) h = src.height();
|
||||
|
||||
unsigned l = stride_abs();
|
||||
if(src.stride_abs() < l) l = src.stride_abs();
|
||||
|
||||
l *= sizeof(T);
|
||||
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
for (y = 0; y < h; y++)
|
||||
{
|
||||
memcpy(row_ptr(0, y, w), src.row_ptr(y), l);
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void clear(T value)
|
||||
{
|
||||
unsigned y;
|
||||
unsigned w = width();
|
||||
unsigned stride = stride_abs();
|
||||
for(y = 0; y < height(); y++)
|
||||
{
|
||||
T* p = row_ptr(0, y, w);
|
||||
unsigned x;
|
||||
for(x = 0; x < stride; x++)
|
||||
{
|
||||
*p++ = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
//--------------------------------------------------------------------
|
||||
T* m_buf; // Pointer to renrdering buffer
|
||||
pod_array<T*> m_rows; // Pointers to each row of the buffer
|
||||
unsigned m_width; // Width in pixels
|
||||
unsigned m_height; // Height in pixels
|
||||
int m_stride; // Number of bytes per row. Can be < 0
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================================rendering_buffer
|
||||
//
|
||||
// The definition of the main type for accessing the rows in the frame
|
||||
// buffer. It provides functionality to navigate to the rows in a
|
||||
// rectangular matrix, from top to bottom or from bottom to top depending
|
||||
// on stride.
|
||||
//
|
||||
// row_accessor is cheap to create/destroy, but performs one multiplication
|
||||
// when calling row_ptr().
|
||||
//
|
||||
// row_ptr_cache creates an array of pointers to rows, so, the access
|
||||
// via row_ptr() may be faster. But it requires memory allocation
|
||||
// when creating. For example, on typical Intel Pentium hardware
|
||||
// row_ptr_cache speeds span_image_filter_rgb_nn up to 10%
|
||||
//
|
||||
// It's used only in short hand typedefs like pixfmt_rgba32 and can be
|
||||
// redefined in agg_config.h
|
||||
// In real applications you can use both, depending on your needs
|
||||
//------------------------------------------------------------------------
|
||||
#ifdef AGG_RENDERING_BUFFER
|
||||
typedef AGG_RENDERING_BUFFER rendering_buffer;
|
||||
#else
|
||||
// typedef row_ptr_cache<int8u> rendering_buffer;
|
||||
typedef row_accessor<int8u> rendering_buffer;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
499
3rd/agg/include/agg_scanline_u.h
Normal file
499
3rd/agg/include/agg_scanline_u.h
Normal file
@ -0,0 +1,499 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SCANLINE_U_INCLUDED
|
||||
#define AGG_SCANLINE_U_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//=============================================================scanline_u8
|
||||
//
|
||||
// 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.
|
||||
//------------------------------------------------------------------------
|
||||
class scanline_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline_u8 self_type;
|
||||
typedef int8u cover_type;
|
||||
typedef int16 coord_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
struct span
|
||||
{
|
||||
coord_type x;
|
||||
coord_type len;
|
||||
cover_type* covers;
|
||||
};
|
||||
|
||||
typedef span* iterator;
|
||||
typedef const span* const_iterator;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
scanline_u8() :
|
||||
m_min_x(0),
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_cur_span(0)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 2;
|
||||
if(max_len > m_spans.size())
|
||||
{
|
||||
m_spans.resize(max_len);
|
||||
m_covers.resize(max_len);
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_min_x = min_x;
|
||||
m_cur_span = &m_spans[0];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cell(int x, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
m_covers[x] = (cover_type)cover;
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (coord_type)(x + m_min_x);
|
||||
m_cur_span->len = 1;
|
||||
m_cur_span->covers = &m_covers[x];
|
||||
}
|
||||
m_last_x = x;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cells(int x, unsigned len, const cover_type* covers)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memcpy(&m_covers[x], covers, len * sizeof(cover_type));
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len += (coord_type)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (coord_type)(x + m_min_x);
|
||||
m_cur_span->len = (coord_type)len;
|
||||
m_cur_span->covers = &m_covers[x];
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memset(&m_covers[x], cover, len);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_cur_span->len += (coord_type)len;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_cur_span++;
|
||||
m_cur_span->x = (coord_type)(x + m_min_x);
|
||||
m_cur_span->len = (coord_type)len;
|
||||
m_cur_span->covers = &m_covers[x];
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int y)
|
||||
{
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_cur_span = &m_spans[0];
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return unsigned(m_cur_span - &m_spans[0]); }
|
||||
const_iterator begin() const { return &m_spans[1]; }
|
||||
iterator begin() { return &m_spans[1]; }
|
||||
|
||||
private:
|
||||
scanline_u8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
private:
|
||||
int m_min_x;
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
pod_array<cover_type> m_covers;
|
||||
pod_array<span> m_spans;
|
||||
span* m_cur_span;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==========================================================scanline_u8_am
|
||||
//
|
||||
// The scanline container with alpha-masking
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
template<class AlphaMask>
|
||||
class scanline_u8_am : public scanline_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline_u8 base_type;
|
||||
typedef AlphaMask alpha_mask_type;
|
||||
typedef base_type::cover_type cover_type;
|
||||
typedef base_type::coord_type coord_type;
|
||||
|
||||
scanline_u8_am() : base_type(), m_alpha_mask(0) {}
|
||||
scanline_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int span_y)
|
||||
{
|
||||
base_type::finalize(span_y);
|
||||
if(m_alpha_mask)
|
||||
{
|
||||
typename base_type::iterator span = base_type::begin();
|
||||
unsigned count = base_type::num_spans();
|
||||
do
|
||||
{
|
||||
m_alpha_mask->combine_hspan(span->x,
|
||||
base_type::y(),
|
||||
span->covers,
|
||||
span->len);
|
||||
++span;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AlphaMask* m_alpha_mask;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//===========================================================scanline32_u8
|
||||
class scanline32_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline32_u8 self_type;
|
||||
typedef int8u cover_type;
|
||||
typedef int32 coord_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
struct span
|
||||
{
|
||||
span() {}
|
||||
span(coord_type x_, coord_type len_, cover_type* covers_) :
|
||||
x(x_), len(len_), covers(covers_) {}
|
||||
|
||||
coord_type x;
|
||||
coord_type len;
|
||||
cover_type* covers;
|
||||
};
|
||||
|
||||
typedef pod_bvector<span, 4> span_array_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
class const_iterator
|
||||
{
|
||||
public:
|
||||
const_iterator(const span_array_type& spans) :
|
||||
m_spans(spans),
|
||||
m_span_idx(0)
|
||||
{}
|
||||
|
||||
const span& operator*() const { return m_spans[m_span_idx]; }
|
||||
const span* operator->() const { return &m_spans[m_span_idx]; }
|
||||
|
||||
void operator ++ () { ++m_span_idx; }
|
||||
|
||||
private:
|
||||
const span_array_type& m_spans;
|
||||
unsigned m_span_idx;
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
class iterator
|
||||
{
|
||||
public:
|
||||
iterator(span_array_type& spans) :
|
||||
m_spans(spans),
|
||||
m_span_idx(0)
|
||||
{}
|
||||
|
||||
span& operator*() { return m_spans[m_span_idx]; }
|
||||
span* operator->() { return &m_spans[m_span_idx]; }
|
||||
|
||||
void operator ++ () { ++m_span_idx; }
|
||||
|
||||
private:
|
||||
span_array_type& m_spans;
|
||||
unsigned m_span_idx;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
scanline32_u8() :
|
||||
m_min_x(0),
|
||||
m_last_x(0x7FFFFFF0),
|
||||
m_covers()
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset(int min_x, int max_x)
|
||||
{
|
||||
unsigned max_len = max_x - min_x + 2;
|
||||
if(max_len > m_covers.size())
|
||||
{
|
||||
m_covers.resize(max_len);
|
||||
}
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_min_x = min_x;
|
||||
m_spans.remove_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cell(int x, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
m_covers[x] = cover_type(cover);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_spans.last().len++;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x + m_min_x), 1, &m_covers[x]));
|
||||
}
|
||||
m_last_x = x;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_cells(int x, unsigned len, const cover_type* covers)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memcpy(&m_covers[x], covers, len * sizeof(cover_type));
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_spans.last().len += coord_type(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x + m_min_x),
|
||||
coord_type(len),
|
||||
&m_covers[x]));
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void add_span(int x, unsigned len, unsigned cover)
|
||||
{
|
||||
x -= m_min_x;
|
||||
memset(&m_covers[x], cover, len);
|
||||
if(x == m_last_x+1)
|
||||
{
|
||||
m_spans.last().len += coord_type(len);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_spans.add(span(coord_type(x + m_min_x),
|
||||
coord_type(len),
|
||||
&m_covers[x]));
|
||||
}
|
||||
m_last_x = x + len - 1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int y)
|
||||
{
|
||||
m_y = y;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void reset_spans()
|
||||
{
|
||||
m_last_x = 0x7FFFFFF0;
|
||||
m_spans.remove_all();
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int y() const { return m_y; }
|
||||
unsigned num_spans() const { return m_spans.size(); }
|
||||
const_iterator begin() const { return const_iterator(m_spans); }
|
||||
iterator begin() { return iterator(m_spans); }
|
||||
|
||||
private:
|
||||
scanline32_u8(const self_type&);
|
||||
const self_type& operator = (const self_type&);
|
||||
|
||||
private:
|
||||
int m_min_x;
|
||||
int m_last_x;
|
||||
int m_y;
|
||||
pod_array<cover_type> m_covers;
|
||||
span_array_type m_spans;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//========================================================scanline32_u8_am
|
||||
//
|
||||
// The scanline container with alpha-masking
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
template<class AlphaMask>
|
||||
class scanline32_u8_am : public scanline32_u8
|
||||
{
|
||||
public:
|
||||
typedef scanline32_u8 base_type;
|
||||
typedef AlphaMask alpha_mask_type;
|
||||
typedef base_type::cover_type cover_type;
|
||||
typedef base_type::coord_type coord_type;
|
||||
|
||||
|
||||
scanline32_u8_am() : base_type(), m_alpha_mask(0) {}
|
||||
scanline32_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void finalize(int span_y)
|
||||
{
|
||||
base_type::finalize(span_y);
|
||||
if(m_alpha_mask)
|
||||
{
|
||||
typename base_type::iterator span = base_type::begin();
|
||||
unsigned count = base_type::num_spans();
|
||||
do
|
||||
{
|
||||
m_alpha_mask->combine_hspan(span->x,
|
||||
base_type::y(),
|
||||
span->covers,
|
||||
span->len);
|
||||
++span;
|
||||
}
|
||||
while(--count);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
AlphaMask* m_alpha_mask;
|
||||
};
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
66
3rd/agg/include/agg_shorten_path.h
Normal file
66
3rd/agg/include/agg_shorten_path.h
Normal file
@ -0,0 +1,66 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SHORTEN_PATH_INCLUDED
|
||||
#define AGG_SHORTEN_PATH_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_vertex_sequence.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===========================================================shorten_path
|
||||
template<class VertexSequence>
|
||||
void shorten_path(VertexSequence& vs, double s, unsigned closed = 0)
|
||||
{
|
||||
typedef typename VertexSequence::value_type vertex_type;
|
||||
|
||||
if(s > 0.0 && vs.size() > 1)
|
||||
{
|
||||
double d;
|
||||
int n = int(vs.size() - 2);
|
||||
while(n)
|
||||
{
|
||||
d = vs[n].dist;
|
||||
if(d > s) break;
|
||||
vs.remove_last();
|
||||
s -= d;
|
||||
--n;
|
||||
}
|
||||
if(vs.size() < 2)
|
||||
{
|
||||
vs.remove_all();
|
||||
}
|
||||
else
|
||||
{
|
||||
n = vs.size() - 1;
|
||||
vertex_type& prev = vs[n-1];
|
||||
vertex_type& last = vs[n];
|
||||
d = (prev.dist - s) / prev.dist;
|
||||
double x = prev.x + (last.x - prev.x) * d;
|
||||
double y = prev.y + (last.y - prev.y) * d;
|
||||
last.x = x;
|
||||
last.y = y;
|
||||
if(!prev(last)) vs.remove_last();
|
||||
vs.close(closed != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
54
3rd/agg/include/agg_span_allocator.h
Normal file
54
3rd/agg/include/agg_span_allocator.h
Normal file
@ -0,0 +1,54 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SPAN_ALLOCATOR_INCLUDED
|
||||
#define AGG_SPAN_ALLOCATOR_INCLUDED
|
||||
|
||||
#include "agg_array.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//----------------------------------------------------------span_allocator
|
||||
template<class ColorT> class span_allocator
|
||||
{
|
||||
public:
|
||||
typedef ColorT color_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
AGG_INLINE color_type* allocate(unsigned span_len)
|
||||
{
|
||||
if(span_len > m_span.size())
|
||||
{
|
||||
// To reduce the number of reallocs we align the
|
||||
// span_len to 256 color elements.
|
||||
// Well, I just like this number and it looks reasonable.
|
||||
//-----------------------
|
||||
m_span.resize(((span_len + 255) >> 8) << 8);
|
||||
}
|
||||
return &m_span[0];
|
||||
}
|
||||
|
||||
AGG_INLINE color_type* span() { return &m_span[0]; }
|
||||
AGG_INLINE unsigned max_span_len() const { return m_span.size(); }
|
||||
|
||||
private:
|
||||
pod_array<color_type> m_span;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
246
3rd/agg/include/agg_span_image_filter.h
Normal file
246
3rd/agg/include/agg_span_image_filter.h
Normal file
@ -0,0 +1,246 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Image transformations with filtering. Span generator base class
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_SPAN_IMAGE_FILTER_INCLUDED
|
||||
#define AGG_SPAN_IMAGE_FILTER_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_image_filters.h"
|
||||
#include "agg_span_interpolator_linear.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//-------------------------------------------------------span_image_filter
|
||||
template<class Source, class Interpolator> class span_image_filter
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter() {}
|
||||
span_image_filter(source_type& src,
|
||||
interpolator_type& interpolator,
|
||||
image_filter_lut* filter) :
|
||||
m_src(&src),
|
||||
m_interpolator(&interpolator),
|
||||
m_filter(filter),
|
||||
m_dx_dbl(0.5),
|
||||
m_dy_dbl(0.5),
|
||||
m_dx_int(image_subpixel_scale / 2),
|
||||
m_dy_int(image_subpixel_scale / 2)
|
||||
{}
|
||||
void attach(source_type& v) { m_src = &v; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
source_type& source() { return *m_src; }
|
||||
const source_type& source() const { return *m_src; }
|
||||
const image_filter_lut& filter() const { return *m_filter; }
|
||||
int filter_dx_int() const { return m_dx_int; }
|
||||
int filter_dy_int() const { return m_dy_int; }
|
||||
double filter_dx_dbl() const { return m_dx_dbl; }
|
||||
double filter_dy_dbl() const { return m_dy_dbl; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void interpolator(interpolator_type& v) { m_interpolator = &v; }
|
||||
void filter(image_filter_lut& v) { m_filter = &v; }
|
||||
void filter_offset(double dx, double dy)
|
||||
{
|
||||
m_dx_dbl = dx;
|
||||
m_dy_dbl = dy;
|
||||
m_dx_int = iround(dx * image_subpixel_scale);
|
||||
m_dy_int = iround(dy * image_subpixel_scale);
|
||||
}
|
||||
void filter_offset(double d) { filter_offset(d, d); }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
interpolator_type& interpolator() { return *m_interpolator; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare() {}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
private:
|
||||
source_type* m_src;
|
||||
interpolator_type* m_interpolator;
|
||||
image_filter_lut* m_filter;
|
||||
double m_dx_dbl;
|
||||
double m_dy_dbl;
|
||||
unsigned m_dx_int;
|
||||
unsigned m_dy_int;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
//==============================================span_image_resample_affine
|
||||
template<class Source>
|
||||
class span_image_resample_affine :
|
||||
public span_image_filter<Source, span_interpolator_linear<trans_affine> >
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef span_interpolator_linear<trans_affine> interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample_affine() :
|
||||
m_scale_limit(200.0),
|
||||
m_blur_x(1.0),
|
||||
m_blur_y(1.0)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample_affine(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, &filter),
|
||||
m_scale_limit(200.0),
|
||||
m_blur_x(1.0),
|
||||
m_blur_y(1.0)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int scale_limit() const { return uround(m_scale_limit); }
|
||||
void scale_limit(int v) { m_scale_limit = v; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
double blur_x() const { return m_blur_x; }
|
||||
double blur_y() const { return m_blur_y; }
|
||||
void blur_x(double v) { m_blur_x = v; }
|
||||
void blur_y(double v) { m_blur_y = v; }
|
||||
void blur(double v) { m_blur_x = m_blur_y = v; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void prepare()
|
||||
{
|
||||
double scale_x;
|
||||
double scale_y;
|
||||
|
||||
base_type::interpolator().transformer().scaling_abs(&scale_x, &scale_y);
|
||||
|
||||
if(scale_x * scale_y > m_scale_limit)
|
||||
{
|
||||
scale_x = scale_x * m_scale_limit / (scale_x * scale_y);
|
||||
scale_y = scale_y * m_scale_limit / (scale_x * scale_y);
|
||||
}
|
||||
|
||||
if(scale_x < 1) scale_x = 1;
|
||||
if(scale_y < 1) scale_y = 1;
|
||||
|
||||
if(scale_x > m_scale_limit) scale_x = m_scale_limit;
|
||||
if(scale_y > m_scale_limit) scale_y = m_scale_limit;
|
||||
|
||||
scale_x *= m_blur_x;
|
||||
scale_y *= m_blur_y;
|
||||
|
||||
if(scale_x < 1) scale_x = 1;
|
||||
if(scale_y < 1) scale_y = 1;
|
||||
|
||||
m_rx = uround( scale_x * double(image_subpixel_scale));
|
||||
m_rx_inv = uround(1.0/scale_x * double(image_subpixel_scale));
|
||||
|
||||
m_ry = uround( scale_y * double(image_subpixel_scale));
|
||||
m_ry_inv = uround(1.0/scale_y * double(image_subpixel_scale));
|
||||
}
|
||||
|
||||
protected:
|
||||
int m_rx;
|
||||
int m_ry;
|
||||
int m_rx_inv;
|
||||
int m_ry_inv;
|
||||
|
||||
private:
|
||||
double m_scale_limit;
|
||||
double m_blur_x;
|
||||
double m_blur_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=====================================================span_image_resample
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_resample :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample() :
|
||||
m_scale_limit(20),
|
||||
m_blur_x(image_subpixel_scale),
|
||||
m_blur_y(image_subpixel_scale)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, &filter),
|
||||
m_scale_limit(20),
|
||||
m_blur_x(image_subpixel_scale),
|
||||
m_blur_y(image_subpixel_scale)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
int scale_limit() const { return m_scale_limit; }
|
||||
void scale_limit(int v) { m_scale_limit = v; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
double blur_x() const { return double(m_blur_x) / double(image_subpixel_scale); }
|
||||
double blur_y() const { return double(m_blur_y) / double(image_subpixel_scale); }
|
||||
void blur_x(double v) { m_blur_x = uround(v * double(image_subpixel_scale)); }
|
||||
void blur_y(double v) { m_blur_y = uround(v * double(image_subpixel_scale)); }
|
||||
void blur(double v) { m_blur_x =
|
||||
m_blur_y = uround(v * double(image_subpixel_scale)); }
|
||||
|
||||
protected:
|
||||
AGG_INLINE void adjust_scale(int* rx, int* ry)
|
||||
{
|
||||
if(*rx < image_subpixel_scale) *rx = image_subpixel_scale;
|
||||
if(*ry < image_subpixel_scale) *ry = image_subpixel_scale;
|
||||
if(*rx > image_subpixel_scale * m_scale_limit)
|
||||
{
|
||||
*rx = image_subpixel_scale * m_scale_limit;
|
||||
}
|
||||
if(*ry > image_subpixel_scale * m_scale_limit)
|
||||
{
|
||||
*ry = image_subpixel_scale * m_scale_limit;
|
||||
}
|
||||
*rx = (*rx * m_blur_x) >> image_subpixel_shift;
|
||||
*ry = (*ry * m_blur_y) >> image_subpixel_shift;
|
||||
if(*rx < image_subpixel_scale) *rx = image_subpixel_scale;
|
||||
if(*ry < image_subpixel_scale) *ry = image_subpixel_scale;
|
||||
}
|
||||
|
||||
int m_scale_limit;
|
||||
int m_blur_x;
|
||||
int m_blur_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
861
3rd/agg/include/agg_span_image_filter_rgb.h
Normal file
861
3rd/agg/include/agg_span_image_filter_rgb.h
Normal file
@ -0,0 +1,861 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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 high precision colors 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_SPAN_IMAGE_FILTER_RGB_INCLUDED
|
||||
#define AGG_SPAN_IMAGE_FILTER_RGB_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_color_rgba.h"
|
||||
#include "agg_span_image_filter.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//===============================================span_image_filter_rgb_nn
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgb_nn :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgb_nn() {}
|
||||
span_image_filter_rgb_nn(source_type& src,
|
||||
interpolator_type& inter) :
|
||||
base_type(src, inter, 0)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
do
|
||||
{
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
const value_type* fg_ptr = (const value_type*)
|
||||
base_type::source().span(x >> image_subpixel_shift,
|
||||
y >> image_subpixel_shift,
|
||||
1);
|
||||
span->r = fg_ptr[order_type::R];
|
||||
span->g = fg_ptr[order_type::G];
|
||||
span->b = fg_ptr[order_type::B];
|
||||
span->a = color_type::full_value();
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==========================================span_image_filter_rgb_bilinear
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgb_bilinear :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgb_bilinear() {}
|
||||
span_image_filter_rgb_bilinear(source_type& src,
|
||||
interpolator_type& inter) :
|
||||
base_type(src, inter, 0)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
long_type fg[3];
|
||||
const value_type *fg_ptr;
|
||||
do
|
||||
{
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
|
||||
base_type::interpolator().coordinates(&x_hr, &y_hr);
|
||||
|
||||
x_hr -= base_type::filter_dx_int();
|
||||
y_hr -= base_type::filter_dy_int();
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
unsigned weight;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
|
||||
weight = (image_subpixel_scale - x_hr) *
|
||||
(image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = x_hr * (image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
weight = (image_subpixel_scale - x_hr) * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = x_hr * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
span->r = color_type::downshift(fg[order_type::R], image_subpixel_shift * 2);
|
||||
span->g = color_type::downshift(fg[order_type::G], image_subpixel_shift * 2);
|
||||
span->b = color_type::downshift(fg[order_type::B], image_subpixel_shift * 2);
|
||||
span->a = color_type::full_value();
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=====================================span_image_filter_rgb_bilinear_clip
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgb_bilinear_clip :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgb_bilinear_clip() {}
|
||||
span_image_filter_rgb_bilinear_clip(source_type& src,
|
||||
const color_type& back_color,
|
||||
interpolator_type& inter) :
|
||||
base_type(src, inter, 0),
|
||||
m_back_color(back_color)
|
||||
{}
|
||||
const color_type& background_color() const { return m_back_color; }
|
||||
void background_color(const color_type& v) { m_back_color = v; }
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
long_type fg[3];
|
||||
long_type src_alpha;
|
||||
value_type back_r = m_back_color.r;
|
||||
value_type back_g = m_back_color.g;
|
||||
value_type back_b = m_back_color.b;
|
||||
value_type back_a = m_back_color.a;
|
||||
|
||||
const value_type *fg_ptr;
|
||||
|
||||
int maxx = base_type::source().width() - 1;
|
||||
int maxy = base_type::source().height() - 1;
|
||||
|
||||
do
|
||||
{
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
|
||||
base_type::interpolator().coordinates(&x_hr, &y_hr);
|
||||
|
||||
x_hr -= base_type::filter_dx_int();
|
||||
y_hr -= base_type::filter_dy_int();
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
unsigned weight;
|
||||
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr < maxx && y_lr < maxy)
|
||||
{
|
||||
fg[0] = fg[1] = fg[2] = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) *
|
||||
(image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
|
||||
weight = x_hr * (image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
|
||||
++y_lr;
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
|
||||
weight = x_hr * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2);
|
||||
fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2);
|
||||
fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2);
|
||||
src_alpha = color_type::full_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_lr < -1 || y_lr < -1 ||
|
||||
x_lr > maxx || y_lr > maxy)
|
||||
{
|
||||
fg[order_type::R] = back_r;
|
||||
fg[order_type::G] = back_g;
|
||||
fg[order_type::B] = back_b;
|
||||
src_alpha = back_a;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[0] = fg[1] = fg[2] = src_alpha = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) *
|
||||
(image_subpixel_scale - y_hr);
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
src_alpha += weight * color_type::full_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
src_alpha += back_a * weight;
|
||||
}
|
||||
|
||||
x_lr++;
|
||||
|
||||
weight = x_hr * (image_subpixel_scale - y_hr);
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
src_alpha += weight * color_type::full_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
src_alpha += back_a * weight;
|
||||
}
|
||||
|
||||
x_lr--;
|
||||
y_lr++;
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) * y_hr;
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
src_alpha += weight * color_type::full_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
src_alpha += back_a * weight;
|
||||
}
|
||||
|
||||
x_lr++;
|
||||
|
||||
weight = x_hr * y_hr;
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + x_lr + x_lr + x_lr;
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
src_alpha += weight * color_type::full_value();
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
src_alpha += back_a * weight;
|
||||
}
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2);
|
||||
fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2);
|
||||
fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2);
|
||||
src_alpha = color_type::downshift(src_alpha, image_subpixel_shift * 2);
|
||||
}
|
||||
}
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = (value_type)src_alpha;
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
private:
|
||||
color_type m_back_color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===============================================span_image_filter_rgb_2x2
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgb_2x2 :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgb_2x2() {}
|
||||
span_image_filter_rgb_2x2(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, &filter)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[3];
|
||||
|
||||
const value_type *fg_ptr;
|
||||
const int16* weight_array = base_type::filter().weight_array() +
|
||||
((base_type::filter().diameter()/2 - 1) <<
|
||||
image_subpixel_shift);
|
||||
do
|
||||
{
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
|
||||
base_type::interpolator().coordinates(&x_hr, &y_hr);
|
||||
|
||||
x_hr -= base_type::filter_dx_int();
|
||||
y_hr -= base_type::filter_dy_int();
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
unsigned weight;
|
||||
fg[0] = fg[1] = fg[2] = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
|
||||
weight = (weight_array[x_hr + image_subpixel_scale] *
|
||||
weight_array[y_hr + image_subpixel_scale] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = (weight_array[x_hr] *
|
||||
weight_array[y_hr + image_subpixel_scale] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
weight = (weight_array[x_hr + image_subpixel_scale] *
|
||||
weight_array[y_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = (weight_array[x_hr] *
|
||||
weight_array[y_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_filter_shift);
|
||||
fg[1] = color_type::downshift(fg[1], image_filter_shift);
|
||||
fg[2] = color_type::downshift(fg[2], image_filter_shift);
|
||||
|
||||
if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value();
|
||||
if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value();
|
||||
if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value();
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = color_type::full_value();
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//===================================================span_image_filter_rgb
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgb :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgb() {}
|
||||
span_image_filter_rgb(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, &filter)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[3];
|
||||
const value_type *fg_ptr;
|
||||
|
||||
unsigned diameter = base_type::filter().diameter();
|
||||
int start = base_type::filter().start();
|
||||
const int16* weight_array = base_type::filter().weight_array();
|
||||
|
||||
int x_count;
|
||||
int weight_y;
|
||||
|
||||
do
|
||||
{
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
|
||||
x -= base_type::filter_dx_int();
|
||||
y -= base_type::filter_dy_int();
|
||||
|
||||
int x_hr = x;
|
||||
int y_hr = y;
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = 0;
|
||||
|
||||
int x_fract = x_hr & image_subpixel_mask;
|
||||
unsigned y_count = diameter;
|
||||
|
||||
y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask);
|
||||
fg_ptr = (const value_type*)base_type::source().span(x_lr + start,
|
||||
y_lr + start,
|
||||
diameter);
|
||||
for(;;)
|
||||
{
|
||||
x_count = diameter;
|
||||
weight_y = weight_array[y_hr];
|
||||
x_hr = image_subpixel_mask - x_fract;
|
||||
for(;;)
|
||||
{
|
||||
int weight = (weight_y * weight_array[x_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr;
|
||||
|
||||
if(--x_count == 0) break;
|
||||
x_hr += image_subpixel_scale;
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
}
|
||||
|
||||
if(--y_count == 0) break;
|
||||
y_hr += image_subpixel_scale;
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
}
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_filter_shift);
|
||||
fg[1] = color_type::downshift(fg[1], image_filter_shift);
|
||||
fg[2] = color_type::downshift(fg[2], image_filter_shift);
|
||||
|
||||
if(fg[0] < 0) fg[0] = 0;
|
||||
if(fg[1] < 0) fg[1] = 0;
|
||||
if(fg[2] < 0) fg[2] = 0;
|
||||
|
||||
if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value();
|
||||
if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value();
|
||||
if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value();
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = color_type::full_value();
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==========================================span_image_resample_rgb_affine
|
||||
template<class Source>
|
||||
class span_image_resample_rgb_affine :
|
||||
public span_image_resample_affine<Source>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef span_image_resample_affine<source_type> base_type;
|
||||
typedef typename base_type::interpolator_type interpolator_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
enum base_scale_e
|
||||
{
|
||||
downscale_shift = image_filter_shift
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample_rgb_affine() {}
|
||||
span_image_resample_rgb_affine(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, filter)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[3];
|
||||
|
||||
int diameter = base_type::filter().diameter();
|
||||
int filter_scale = diameter << image_subpixel_shift;
|
||||
int radius_x = (diameter * base_type::m_rx) >> 1;
|
||||
int radius_y = (diameter * base_type::m_ry) >> 1;
|
||||
int len_x_lr =
|
||||
(diameter * base_type::m_rx + image_subpixel_mask) >>
|
||||
image_subpixel_shift;
|
||||
|
||||
const int16* weight_array = base_type::filter().weight_array();
|
||||
|
||||
do
|
||||
{
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
|
||||
x += base_type::filter_dx_int() - radius_x;
|
||||
y += base_type::filter_dy_int() - radius_y;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = 0;
|
||||
|
||||
int y_lr = y >> image_subpixel_shift;
|
||||
int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
|
||||
base_type::m_ry_inv) >>
|
||||
image_subpixel_shift;
|
||||
int total_weight = 0;
|
||||
int x_lr = x >> image_subpixel_shift;
|
||||
int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
|
||||
base_type::m_rx_inv) >>
|
||||
image_subpixel_shift;
|
||||
|
||||
int x_hr2 = x_hr;
|
||||
const value_type* fg_ptr =
|
||||
(const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
|
||||
for(;;)
|
||||
{
|
||||
int weight_y = weight_array[y_hr];
|
||||
x_hr = x_hr2;
|
||||
for(;;)
|
||||
{
|
||||
int weight = (weight_y * weight_array[x_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
downscale_shift;
|
||||
|
||||
fg[0] += *fg_ptr++ * weight;
|
||||
fg[1] += *fg_ptr++ * weight;
|
||||
fg[2] += *fg_ptr * weight;
|
||||
total_weight += weight;
|
||||
x_hr += base_type::m_rx_inv;
|
||||
if(x_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
}
|
||||
y_hr += base_type::m_ry_inv;
|
||||
if(y_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
}
|
||||
|
||||
fg[0] /= total_weight;
|
||||
fg[1] /= total_weight;
|
||||
fg[2] /= total_weight;
|
||||
|
||||
if(fg[0] < 0) fg[0] = 0;
|
||||
if(fg[1] < 0) fg[1] = 0;
|
||||
if(fg[2] < 0) fg[2] = 0;
|
||||
|
||||
if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value();
|
||||
if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value();
|
||||
if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value();
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = color_type::full_value();
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=================================================span_image_resample_rgb
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_resample_rgb :
|
||||
public span_image_resample<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_resample<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
enum base_scale_e
|
||||
{
|
||||
downscale_shift = image_filter_shift
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample_rgb() {}
|
||||
span_image_resample_rgb(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, filter)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
long_type fg[3];
|
||||
|
||||
int diameter = base_type::filter().diameter();
|
||||
int filter_scale = diameter << image_subpixel_shift;
|
||||
|
||||
const int16* weight_array = base_type::filter().weight_array();
|
||||
do
|
||||
{
|
||||
int rx;
|
||||
int ry;
|
||||
int rx_inv = image_subpixel_scale;
|
||||
int ry_inv = image_subpixel_scale;
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
base_type::interpolator().local_scale(&rx, &ry);
|
||||
base_type::adjust_scale(&rx, &ry);
|
||||
|
||||
rx_inv = image_subpixel_scale * image_subpixel_scale / rx;
|
||||
ry_inv = image_subpixel_scale * image_subpixel_scale / ry;
|
||||
|
||||
int radius_x = (diameter * rx) >> 1;
|
||||
int radius_y = (diameter * ry) >> 1;
|
||||
int len_x_lr =
|
||||
(diameter * rx + image_subpixel_mask) >>
|
||||
image_subpixel_shift;
|
||||
|
||||
x += base_type::filter_dx_int() - radius_x;
|
||||
y += base_type::filter_dy_int() - radius_y;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = 0;
|
||||
|
||||
int y_lr = y >> image_subpixel_shift;
|
||||
int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
|
||||
ry_inv) >>
|
||||
image_subpixel_shift;
|
||||
int total_weight = 0;
|
||||
int x_lr = x >> image_subpixel_shift;
|
||||
int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
|
||||
rx_inv) >>
|
||||
image_subpixel_shift;
|
||||
int x_hr2 = x_hr;
|
||||
const value_type* fg_ptr =
|
||||
(const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int weight_y = weight_array[y_hr];
|
||||
x_hr = x_hr2;
|
||||
for(;;)
|
||||
{
|
||||
int weight = (weight_y * weight_array[x_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
downscale_shift;
|
||||
fg[0] += *fg_ptr++ * weight;
|
||||
fg[1] += *fg_ptr++ * weight;
|
||||
fg[2] += *fg_ptr * weight;
|
||||
total_weight += weight;
|
||||
x_hr += rx_inv;
|
||||
if(x_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
}
|
||||
y_hr += ry_inv;
|
||||
if(y_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
}
|
||||
|
||||
fg[0] /= total_weight;
|
||||
fg[1] /= total_weight;
|
||||
fg[2] /= total_weight;
|
||||
|
||||
if(fg[0] < 0) fg[0] = 0;
|
||||
if(fg[1] < 0) fg[1] = 0;
|
||||
if(fg[2] < 0) fg[2] = 0;
|
||||
|
||||
if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value();
|
||||
if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value();
|
||||
if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value();
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = color_type::full_value();
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
890
3rd/agg/include/agg_span_image_filter_rgba.h
Normal file
890
3rd/agg/include/agg_span_image_filter_rgba.h
Normal file
@ -0,0 +1,890 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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 high precision colors 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.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_SPAN_IMAGE_FILTER_RGBA_INCLUDED
|
||||
#define AGG_SPAN_IMAGE_FILTER_RGBA_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_color_rgba.h"
|
||||
#include "agg_span_image_filter.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//==============================================span_image_filter_rgba_nn
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgba_nn :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgba_nn() {}
|
||||
span_image_filter_rgba_nn(source_type& src,
|
||||
interpolator_type& inter) :
|
||||
base_type(src, inter, 0)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
do
|
||||
{
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
const value_type* fg_ptr = (const value_type*)
|
||||
base_type::source().span(x >> image_subpixel_shift,
|
||||
y >> image_subpixel_shift,
|
||||
1);
|
||||
span->r = fg_ptr[order_type::R];
|
||||
span->g = fg_ptr[order_type::G];
|
||||
span->b = fg_ptr[order_type::B];
|
||||
span->a = fg_ptr[order_type::A];
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=========================================span_image_filter_rgba_bilinear
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgba_bilinear :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgba_bilinear() {}
|
||||
span_image_filter_rgba_bilinear(source_type& src,
|
||||
interpolator_type& inter) :
|
||||
base_type(src, inter, 0)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[4];
|
||||
const value_type *fg_ptr;
|
||||
|
||||
do
|
||||
{
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
|
||||
base_type::interpolator().coordinates(&x_hr, &y_hr);
|
||||
|
||||
x_hr -= base_type::filter_dx_int();
|
||||
y_hr -= base_type::filter_dy_int();
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
unsigned weight;
|
||||
|
||||
fg[0] =
|
||||
fg[1] =
|
||||
fg[2] =
|
||||
fg[3] = image_subpixel_scale * image_subpixel_scale / 2;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
|
||||
weight = (image_subpixel_scale - x_hr) *
|
||||
(image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = x_hr * (image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
weight = (image_subpixel_scale - x_hr) * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = x_hr * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
span->r = value_type(color_type::downshift(fg[order_type::R], image_subpixel_shift * 2));
|
||||
span->g = value_type(color_type::downshift(fg[order_type::G], image_subpixel_shift * 2));
|
||||
span->b = value_type(color_type::downshift(fg[order_type::B], image_subpixel_shift * 2));
|
||||
span->a = value_type(color_type::downshift(fg[order_type::A], image_subpixel_shift * 2));
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//====================================span_image_filter_rgba_bilinear_clip
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgba_bilinear_clip :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgba_bilinear_clip() {}
|
||||
span_image_filter_rgba_bilinear_clip(source_type& src,
|
||||
const color_type& back_color,
|
||||
interpolator_type& inter) :
|
||||
base_type(src, inter, 0),
|
||||
m_back_color(back_color)
|
||||
{}
|
||||
const color_type& background_color() const { return m_back_color; }
|
||||
void background_color(const color_type& v) { m_back_color = v; }
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[4];
|
||||
value_type back_r = m_back_color.r;
|
||||
value_type back_g = m_back_color.g;
|
||||
value_type back_b = m_back_color.b;
|
||||
value_type back_a = m_back_color.a;
|
||||
|
||||
const value_type *fg_ptr;
|
||||
int maxx = base_type::source().width() - 1;
|
||||
int maxy = base_type::source().height() - 1;
|
||||
|
||||
do
|
||||
{
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
|
||||
base_type::interpolator().coordinates(&x_hr, &y_hr);
|
||||
|
||||
x_hr -= base_type::filter_dx_int();
|
||||
y_hr -= base_type::filter_dy_int();
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
unsigned weight;
|
||||
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr < maxx && y_lr < maxy)
|
||||
{
|
||||
fg[0] = fg[1] = fg[2] = fg[3] = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + (x_lr << 2);
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) *
|
||||
(image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
|
||||
weight = x_hr * (image_subpixel_scale - y_hr);
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
|
||||
++y_lr;
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + (x_lr << 2);
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
|
||||
weight = x_hr * y_hr;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2);
|
||||
fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2);
|
||||
fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2);
|
||||
fg[3] = color_type::downshift(fg[3], image_subpixel_shift * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(x_lr < -1 || y_lr < -1 ||
|
||||
x_lr > maxx || y_lr > maxy)
|
||||
{
|
||||
fg[order_type::R] = back_r;
|
||||
fg[order_type::G] = back_g;
|
||||
fg[order_type::B] = back_b;
|
||||
fg[order_type::A] = back_a;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[0] = fg[1] = fg[2] = fg[3] = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) *
|
||||
(image_subpixel_scale - y_hr);
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + (x_lr << 2);
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
fg[order_type::A] += back_a * weight;
|
||||
}
|
||||
|
||||
x_lr++;
|
||||
|
||||
weight = x_hr * (image_subpixel_scale - y_hr);
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + (x_lr << 2);
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
fg[order_type::A] += back_a * weight;
|
||||
}
|
||||
|
||||
x_lr--;
|
||||
y_lr++;
|
||||
|
||||
weight = (image_subpixel_scale - x_hr) * y_hr;
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + (x_lr << 2);
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
fg[order_type::A] += back_a * weight;
|
||||
}
|
||||
|
||||
x_lr++;
|
||||
|
||||
weight = x_hr * y_hr;
|
||||
if(x_lr >= 0 && y_lr >= 0 &&
|
||||
x_lr <= maxx && y_lr <= maxy)
|
||||
{
|
||||
fg_ptr = (const value_type*)
|
||||
base_type::source().row_ptr(y_lr) + (x_lr << 2);
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr++;
|
||||
}
|
||||
else
|
||||
{
|
||||
fg[order_type::R] += back_r * weight;
|
||||
fg[order_type::G] += back_g * weight;
|
||||
fg[order_type::B] += back_b * weight;
|
||||
fg[order_type::A] += back_a * weight;
|
||||
}
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2);
|
||||
fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2);
|
||||
fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2);
|
||||
fg[3] = color_type::downshift(fg[3], image_subpixel_shift * 2);
|
||||
}
|
||||
}
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = (value_type)fg[order_type::A];
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
private:
|
||||
color_type m_back_color;
|
||||
};
|
||||
|
||||
|
||||
//==============================================span_image_filter_rgba_2x2
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgba_2x2 :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgba_2x2() {}
|
||||
span_image_filter_rgba_2x2(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, &filter)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[4];
|
||||
|
||||
const value_type *fg_ptr;
|
||||
const int16* weight_array = base_type::filter().weight_array() +
|
||||
((base_type::filter().diameter()/2 - 1) <<
|
||||
image_subpixel_shift);
|
||||
|
||||
do
|
||||
{
|
||||
int x_hr;
|
||||
int y_hr;
|
||||
|
||||
base_type::interpolator().coordinates(&x_hr, &y_hr);
|
||||
|
||||
x_hr -= base_type::filter_dx_int();
|
||||
y_hr -= base_type::filter_dy_int();
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
unsigned weight;
|
||||
fg[0] = fg[1] = fg[2] = fg[3] = 0;
|
||||
|
||||
x_hr &= image_subpixel_mask;
|
||||
y_hr &= image_subpixel_mask;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().span(x_lr, y_lr, 2);
|
||||
weight = (weight_array[x_hr + image_subpixel_scale] *
|
||||
weight_array[y_hr + image_subpixel_scale] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = (weight_array[x_hr] *
|
||||
weight_array[y_hr + image_subpixel_scale] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
weight = (weight_array[x_hr + image_subpixel_scale] *
|
||||
weight_array[y_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
weight = (weight_array[x_hr] *
|
||||
weight_array[y_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_filter_shift);
|
||||
fg[1] = color_type::downshift(fg[1], image_filter_shift);
|
||||
fg[2] = color_type::downshift(fg[2], image_filter_shift);
|
||||
fg[3] = color_type::downshift(fg[3], image_filter_shift);
|
||||
|
||||
if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value();
|
||||
if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A];
|
||||
if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A];
|
||||
if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A];
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = (value_type)fg[order_type::A];
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==================================================span_image_filter_rgba
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_filter_rgba :
|
||||
public span_image_filter<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_filter<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::calc_type calc_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_filter_rgba() {}
|
||||
span_image_filter_rgba(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, &filter)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[4];
|
||||
const value_type *fg_ptr;
|
||||
|
||||
unsigned diameter = base_type::filter().diameter();
|
||||
int start = base_type::filter().start();
|
||||
const int16* weight_array = base_type::filter().weight_array();
|
||||
|
||||
int x_count;
|
||||
int weight_y;
|
||||
|
||||
do
|
||||
{
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
|
||||
x -= base_type::filter_dx_int();
|
||||
y -= base_type::filter_dy_int();
|
||||
|
||||
int x_hr = x;
|
||||
int y_hr = y;
|
||||
|
||||
int x_lr = x_hr >> image_subpixel_shift;
|
||||
int y_lr = y_hr >> image_subpixel_shift;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = fg[3] = 0;
|
||||
|
||||
int x_fract = x_hr & image_subpixel_mask;
|
||||
unsigned y_count = diameter;
|
||||
|
||||
y_hr = image_subpixel_mask - (y_hr & image_subpixel_mask);
|
||||
fg_ptr = (const value_type*)base_type::source().span(x_lr + start,
|
||||
y_lr + start,
|
||||
diameter);
|
||||
for(;;)
|
||||
{
|
||||
x_count = diameter;
|
||||
weight_y = weight_array[y_hr];
|
||||
x_hr = image_subpixel_mask - x_fract;
|
||||
for(;;)
|
||||
{
|
||||
int weight = (weight_y * weight_array[x_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
image_filter_shift;
|
||||
|
||||
fg[0] += weight * *fg_ptr++;
|
||||
fg[1] += weight * *fg_ptr++;
|
||||
fg[2] += weight * *fg_ptr++;
|
||||
fg[3] += weight * *fg_ptr;
|
||||
|
||||
if(--x_count == 0) break;
|
||||
x_hr += image_subpixel_scale;
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
}
|
||||
|
||||
if(--y_count == 0) break;
|
||||
y_hr += image_subpixel_scale;
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
}
|
||||
|
||||
fg[0] = color_type::downshift(fg[0], image_filter_shift);
|
||||
fg[1] = color_type::downshift(fg[1], image_filter_shift);
|
||||
fg[2] = color_type::downshift(fg[2], image_filter_shift);
|
||||
fg[3] = color_type::downshift(fg[3], image_filter_shift);
|
||||
|
||||
if(fg[0] < 0) fg[0] = 0;
|
||||
if(fg[1] < 0) fg[1] = 0;
|
||||
if(fg[2] < 0) fg[2] = 0;
|
||||
if(fg[3] < 0) fg[3] = 0;
|
||||
|
||||
if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value();
|
||||
if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A];
|
||||
if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A];
|
||||
if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A];
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = (value_type)fg[order_type::A];
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//========================================span_image_resample_rgba_affine
|
||||
template<class Source>
|
||||
class span_image_resample_rgba_affine :
|
||||
public span_image_resample_affine<Source>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef span_image_resample_affine<source_type> base_type;
|
||||
typedef typename base_type::interpolator_type interpolator_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
enum base_scale_e
|
||||
{
|
||||
downscale_shift = image_filter_shift
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample_rgba_affine() {}
|
||||
span_image_resample_rgba_affine(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, filter)
|
||||
{}
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
|
||||
long_type fg[4];
|
||||
|
||||
int diameter = base_type::filter().diameter();
|
||||
int filter_scale = diameter << image_subpixel_shift;
|
||||
int radius_x = (diameter * base_type::m_rx) >> 1;
|
||||
int radius_y = (diameter * base_type::m_ry) >> 1;
|
||||
int len_x_lr =
|
||||
(diameter * base_type::m_rx + image_subpixel_mask) >>
|
||||
image_subpixel_shift;
|
||||
|
||||
const int16* weight_array = base_type::filter().weight_array();
|
||||
|
||||
do
|
||||
{
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
|
||||
x += base_type::filter_dx_int() - radius_x;
|
||||
y += base_type::filter_dy_int() - radius_y;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = fg[3] = 0;
|
||||
|
||||
int y_lr = y >> image_subpixel_shift;
|
||||
int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
|
||||
base_type::m_ry_inv) >>
|
||||
image_subpixel_shift;
|
||||
int total_weight = 0;
|
||||
int x_lr = x >> image_subpixel_shift;
|
||||
int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
|
||||
base_type::m_rx_inv) >>
|
||||
image_subpixel_shift;
|
||||
|
||||
int x_hr2 = x_hr;
|
||||
const value_type* fg_ptr =
|
||||
(const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
|
||||
for(;;)
|
||||
{
|
||||
int weight_y = weight_array[y_hr];
|
||||
x_hr = x_hr2;
|
||||
for(;;)
|
||||
{
|
||||
int weight = (weight_y * weight_array[x_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
downscale_shift;
|
||||
|
||||
fg[0] += *fg_ptr++ * weight;
|
||||
fg[1] += *fg_ptr++ * weight;
|
||||
fg[2] += *fg_ptr++ * weight;
|
||||
fg[3] += *fg_ptr++ * weight;
|
||||
total_weight += weight;
|
||||
x_hr += base_type::m_rx_inv;
|
||||
if(x_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
}
|
||||
y_hr += base_type::m_ry_inv;
|
||||
if(y_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
}
|
||||
|
||||
fg[0] /= total_weight;
|
||||
fg[1] /= total_weight;
|
||||
fg[2] /= total_weight;
|
||||
fg[3] /= total_weight;
|
||||
|
||||
if(fg[0] < 0) fg[0] = 0;
|
||||
if(fg[1] < 0) fg[1] = 0;
|
||||
if(fg[2] < 0) fg[2] = 0;
|
||||
if(fg[3] < 0) fg[3] = 0;
|
||||
|
||||
if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value();
|
||||
if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A];
|
||||
if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A];
|
||||
if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A];
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = (value_type)fg[order_type::A];
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//==============================================span_image_resample_rgba
|
||||
template<class Source, class Interpolator>
|
||||
class span_image_resample_rgba :
|
||||
public span_image_resample<Source, Interpolator>
|
||||
{
|
||||
public:
|
||||
typedef Source source_type;
|
||||
typedef typename source_type::color_type color_type;
|
||||
typedef typename source_type::order_type order_type;
|
||||
typedef Interpolator interpolator_type;
|
||||
typedef span_image_resample<source_type, interpolator_type> base_type;
|
||||
typedef typename color_type::value_type value_type;
|
||||
typedef typename color_type::long_type long_type;
|
||||
enum base_scale_e
|
||||
{
|
||||
downscale_shift = image_filter_shift
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_image_resample_rgba() {}
|
||||
span_image_resample_rgba(source_type& src,
|
||||
interpolator_type& inter,
|
||||
image_filter_lut& filter) :
|
||||
base_type(src, inter, filter)
|
||||
{}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
void generate(color_type* span, int x, int y, unsigned len)
|
||||
{
|
||||
base_type::interpolator().begin(x + base_type::filter_dx_dbl(),
|
||||
y + base_type::filter_dy_dbl(), len);
|
||||
long_type fg[4];
|
||||
|
||||
int diameter = base_type::filter().diameter();
|
||||
int filter_scale = diameter << image_subpixel_shift;
|
||||
|
||||
const int16* weight_array = base_type::filter().weight_array();
|
||||
do
|
||||
{
|
||||
int rx;
|
||||
int ry;
|
||||
int rx_inv = image_subpixel_scale;
|
||||
int ry_inv = image_subpixel_scale;
|
||||
base_type::interpolator().coordinates(&x, &y);
|
||||
base_type::interpolator().local_scale(&rx, &ry);
|
||||
base_type::adjust_scale(&rx, &ry);
|
||||
|
||||
rx_inv = image_subpixel_scale * image_subpixel_scale / rx;
|
||||
ry_inv = image_subpixel_scale * image_subpixel_scale / ry;
|
||||
|
||||
int radius_x = (diameter * rx) >> 1;
|
||||
int radius_y = (diameter * ry) >> 1;
|
||||
int len_x_lr =
|
||||
(diameter * rx + image_subpixel_mask) >>
|
||||
image_subpixel_shift;
|
||||
|
||||
x += base_type::filter_dx_int() - radius_x;
|
||||
y += base_type::filter_dy_int() - radius_y;
|
||||
|
||||
fg[0] = fg[1] = fg[2] = fg[3] = 0;
|
||||
|
||||
int y_lr = y >> image_subpixel_shift;
|
||||
int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) *
|
||||
ry_inv) >>
|
||||
image_subpixel_shift;
|
||||
int total_weight = 0;
|
||||
int x_lr = x >> image_subpixel_shift;
|
||||
int x_hr = ((image_subpixel_mask - (x & image_subpixel_mask)) *
|
||||
rx_inv) >>
|
||||
image_subpixel_shift;
|
||||
int x_hr2 = x_hr;
|
||||
const value_type* fg_ptr =
|
||||
(const value_type*)base_type::source().span(x_lr, y_lr, len_x_lr);
|
||||
|
||||
for(;;)
|
||||
{
|
||||
int weight_y = weight_array[y_hr];
|
||||
x_hr = x_hr2;
|
||||
for(;;)
|
||||
{
|
||||
int weight = (weight_y * weight_array[x_hr] +
|
||||
image_filter_scale / 2) >>
|
||||
downscale_shift;
|
||||
fg[0] += *fg_ptr++ * weight;
|
||||
fg[1] += *fg_ptr++ * weight;
|
||||
fg[2] += *fg_ptr++ * weight;
|
||||
fg[3] += *fg_ptr++ * weight;
|
||||
total_weight += weight;
|
||||
x_hr += rx_inv;
|
||||
if(x_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_x();
|
||||
}
|
||||
y_hr += ry_inv;
|
||||
if(y_hr >= filter_scale) break;
|
||||
fg_ptr = (const value_type*)base_type::source().next_y();
|
||||
}
|
||||
|
||||
fg[0] /= total_weight;
|
||||
fg[1] /= total_weight;
|
||||
fg[2] /= total_weight;
|
||||
fg[3] /= total_weight;
|
||||
|
||||
if(fg[0] < 0) fg[0] = 0;
|
||||
if(fg[1] < 0) fg[1] = 0;
|
||||
if(fg[2] < 0) fg[2] = 0;
|
||||
if(fg[3] < 0) fg[3] = 0;
|
||||
|
||||
if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value();
|
||||
if(fg[order_type::R] > fg[order_type::R]) fg[order_type::R] = fg[order_type::R];
|
||||
if(fg[order_type::G] > fg[order_type::G]) fg[order_type::G] = fg[order_type::G];
|
||||
if(fg[order_type::B] > fg[order_type::B]) fg[order_type::B] = fg[order_type::B];
|
||||
|
||||
span->r = (value_type)fg[order_type::R];
|
||||
span->g = (value_type)fg[order_type::G];
|
||||
span->b = (value_type)fg[order_type::B];
|
||||
span->a = (value_type)fg[order_type::A];
|
||||
|
||||
++span;
|
||||
++base_type::interpolator();
|
||||
} while(--len);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
232
3rd/agg/include/agg_span_interpolator_linear.h
Normal file
232
3rd/agg/include/agg_span_interpolator_linear.h
Normal file
@ -0,0 +1,232 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED
|
||||
#define AGG_SPAN_INTERPOLATOR_LINEAR_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_dda_line.h"
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//================================================span_interpolator_linear
|
||||
template<class Transformer = trans_affine, unsigned SubpixelShift = 8>
|
||||
class span_interpolator_linear
|
||||
{
|
||||
public:
|
||||
typedef Transformer trans_type;
|
||||
|
||||
enum subpixel_scale_e
|
||||
{
|
||||
subpixel_shift = SubpixelShift,
|
||||
subpixel_scale = 1 << subpixel_shift
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
span_interpolator_linear() {}
|
||||
span_interpolator_linear(trans_type& trans) : m_trans(&trans) {}
|
||||
span_interpolator_linear(trans_type& trans,
|
||||
double x, double y, unsigned len) :
|
||||
m_trans(&trans)
|
||||
{
|
||||
begin(x, y, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
const trans_type& transformer() const { return *m_trans; }
|
||||
void transformer(trans_type& trans) { m_trans = &trans; }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void begin(double x, double y, unsigned len)
|
||||
{
|
||||
double tx;
|
||||
double ty;
|
||||
|
||||
tx = x;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
int x1 = iround(tx * subpixel_scale);
|
||||
int y1 = iround(ty * subpixel_scale);
|
||||
|
||||
tx = x + len;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
int x2 = iround(tx * subpixel_scale);
|
||||
int y2 = iround(ty * subpixel_scale);
|
||||
|
||||
m_li_x = dda2_line_interpolator(x1, x2, len);
|
||||
m_li_y = dda2_line_interpolator(y1, y2, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void resynchronize(double xe, double ye, unsigned len)
|
||||
{
|
||||
m_trans->transform(&xe, &ye);
|
||||
m_li_x = dda2_line_interpolator(m_li_x.y(), iround(xe * subpixel_scale), len);
|
||||
m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ye * subpixel_scale), len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void operator++()
|
||||
{
|
||||
++m_li_x;
|
||||
++m_li_y;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void coordinates(int* x, int* y) const
|
||||
{
|
||||
*x = m_li_x.y();
|
||||
*y = m_li_y.y();
|
||||
}
|
||||
|
||||
private:
|
||||
trans_type* m_trans;
|
||||
dda2_line_interpolator m_li_x;
|
||||
dda2_line_interpolator m_li_y;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//=====================================span_interpolator_linear_subdiv
|
||||
template<class Transformer = trans_affine, unsigned SubpixelShift = 8>
|
||||
class span_interpolator_linear_subdiv
|
||||
{
|
||||
public:
|
||||
typedef Transformer trans_type;
|
||||
|
||||
enum subpixel_scale_e
|
||||
{
|
||||
subpixel_shift = SubpixelShift,
|
||||
subpixel_scale = 1 << subpixel_shift
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------------
|
||||
span_interpolator_linear_subdiv() :
|
||||
m_subdiv_shift(4),
|
||||
m_subdiv_size(1 << m_subdiv_shift),
|
||||
m_subdiv_mask(m_subdiv_size - 1) {}
|
||||
|
||||
span_interpolator_linear_subdiv(trans_type& trans,
|
||||
unsigned subdiv_shift = 4) :
|
||||
m_subdiv_shift(subdiv_shift),
|
||||
m_subdiv_size(1 << m_subdiv_shift),
|
||||
m_subdiv_mask(m_subdiv_size - 1),
|
||||
m_trans(&trans) {}
|
||||
|
||||
span_interpolator_linear_subdiv(trans_type& trans,
|
||||
double x, double y, unsigned len,
|
||||
unsigned subdiv_shift = 4) :
|
||||
m_subdiv_shift(subdiv_shift),
|
||||
m_subdiv_size(1 << m_subdiv_shift),
|
||||
m_subdiv_mask(m_subdiv_size - 1),
|
||||
m_trans(&trans)
|
||||
{
|
||||
begin(x, y, len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
const trans_type& transformer() const { return *m_trans; }
|
||||
void transformer(const trans_type& trans) { m_trans = &trans; }
|
||||
|
||||
//----------------------------------------------------------------
|
||||
unsigned subdiv_shift() const { return m_subdiv_shift; }
|
||||
void subdiv_shift(unsigned shift)
|
||||
{
|
||||
m_subdiv_shift = shift;
|
||||
m_subdiv_size = 1 << m_subdiv_shift;
|
||||
m_subdiv_mask = m_subdiv_size - 1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void begin(double x, double y, unsigned len)
|
||||
{
|
||||
double tx;
|
||||
double ty;
|
||||
m_pos = 1;
|
||||
m_src_x = iround(x * subpixel_scale) + subpixel_scale;
|
||||
m_src_y = y;
|
||||
m_len = len;
|
||||
|
||||
if(len > m_subdiv_size) len = m_subdiv_size;
|
||||
tx = x;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
int x1 = iround(tx * subpixel_scale);
|
||||
int y1 = iround(ty * subpixel_scale);
|
||||
|
||||
tx = x + len;
|
||||
ty = y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
|
||||
m_li_x = dda2_line_interpolator(x1, iround(tx * subpixel_scale), len);
|
||||
m_li_y = dda2_line_interpolator(y1, iround(ty * subpixel_scale), len);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void operator++()
|
||||
{
|
||||
++m_li_x;
|
||||
++m_li_y;
|
||||
if(m_pos >= m_subdiv_size)
|
||||
{
|
||||
unsigned len = m_len;
|
||||
if(len > m_subdiv_size) len = m_subdiv_size;
|
||||
double tx = double(m_src_x) / double(subpixel_scale) + len;
|
||||
double ty = m_src_y;
|
||||
m_trans->transform(&tx, &ty);
|
||||
m_li_x = dda2_line_interpolator(m_li_x.y(), iround(tx * subpixel_scale), len);
|
||||
m_li_y = dda2_line_interpolator(m_li_y.y(), iround(ty * subpixel_scale), len);
|
||||
m_pos = 0;
|
||||
}
|
||||
m_src_x += subpixel_scale;
|
||||
++m_pos;
|
||||
--m_len;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------
|
||||
void coordinates(int* x, int* y) const
|
||||
{
|
||||
*x = m_li_x.y();
|
||||
*y = m_li_y.y();
|
||||
}
|
||||
|
||||
private:
|
||||
unsigned m_subdiv_shift;
|
||||
unsigned m_subdiv_size;
|
||||
unsigned m_subdiv_mask;
|
||||
trans_type* m_trans;
|
||||
dda2_line_interpolator m_li_x;
|
||||
dda2_line_interpolator m_li_y;
|
||||
int m_src_x;
|
||||
double m_src_y;
|
||||
unsigned m_pos;
|
||||
unsigned m_len;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
518
3rd/agg/include/agg_trans_affine.h
Normal file
518
3rd/agg/include/agg_trans_affine.h
Normal file
@ -0,0 +1,518 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Affine transformation classes.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_TRANS_AFFINE_INCLUDED
|
||||
#define AGG_TRANS_AFFINE_INCLUDED
|
||||
|
||||
#include <math.h>
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
const double affine_epsilon = 1e-14;
|
||||
|
||||
//============================================================trans_affine
|
||||
//
|
||||
// See Implementation agg_trans_affine.cpp
|
||||
//
|
||||
// Affine transformation are linear transformations in Cartesian coordinates
|
||||
// (strictly speaking not only in Cartesian, but for the beginning we will
|
||||
// think so). They are rotation, scaling, translation and skewing.
|
||||
// After any affine transformation a line segment remains a line segment
|
||||
// and it will never become a curve.
|
||||
//
|
||||
// There will be no math about matrix calculations, since it has been
|
||||
// described many times. Ask yourself a very simple question:
|
||||
// "why do we need to understand and use some matrix stuff instead of just
|
||||
// rotating, scaling and so on". The answers are:
|
||||
//
|
||||
// 1. Any combination of transformations can be done by only 4 multiplications
|
||||
// and 4 additions in floating point.
|
||||
// 2. One matrix transformation is equivalent to the number of consecutive
|
||||
// discrete transformations, i.e. the matrix "accumulates" all transformations
|
||||
// in the order of their settings. Suppose we have 4 transformations:
|
||||
// * rotate by 30 degrees,
|
||||
// * scale X to 2.0,
|
||||
// * scale Y to 1.5,
|
||||
// * move to (100, 100).
|
||||
// The result will depend on the order of these transformations,
|
||||
// and the advantage of matrix is that the sequence of discret calls:
|
||||
// rotate(30), scaleX(2.0), scaleY(1.5), move(100,100)
|
||||
// will have exactly the same result as the following matrix transformations:
|
||||
//
|
||||
// affine_matrix m;
|
||||
// m *= rotate_matrix(30);
|
||||
// m *= scaleX_matrix(2.0);
|
||||
// m *= scaleY_matrix(1.5);
|
||||
// m *= move_matrix(100,100);
|
||||
//
|
||||
// m.transform_my_point_at_last(x, y);
|
||||
//
|
||||
// What is the good of it? In real life we will set-up the matrix only once
|
||||
// and then transform many points, let alone the convenience to set any
|
||||
// combination of transformations.
|
||||
//
|
||||
// So, how to use it? Very easy - literally as it's shown above. Not quite,
|
||||
// let us write a correct example:
|
||||
//
|
||||
// agg::trans_affine m;
|
||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0);
|
||||
// m *= agg::trans_affine_scaling(2.0, 1.5);
|
||||
// m *= agg::trans_affine_translation(100.0, 100.0);
|
||||
// m.transform(&x, &y);
|
||||
//
|
||||
// The affine matrix is all you need to perform any linear transformation,
|
||||
// but all transformations have origin point (0,0). It means that we need to
|
||||
// use 2 translations if we want to rotate someting around (100,100):
|
||||
//
|
||||
// m *= agg::trans_affine_translation(-100.0, -100.0); // move to (0,0)
|
||||
// m *= agg::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate
|
||||
// m *= agg::trans_affine_translation(100.0, 100.0); // move back to (100,100)
|
||||
//----------------------------------------------------------------------
|
||||
struct trans_affine
|
||||
{
|
||||
double sx, shy, shx, sy, tx, ty;
|
||||
|
||||
//------------------------------------------ Construction
|
||||
// Identity matrix
|
||||
trans_affine() :
|
||||
sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0)
|
||||
{}
|
||||
|
||||
// Custom matrix. Usually used in derived classes
|
||||
trans_affine(double v0, double v1, double v2,
|
||||
double v3, double v4, double v5) :
|
||||
sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5)
|
||||
{}
|
||||
|
||||
// Custom matrix from m[6]
|
||||
explicit trans_affine(const double* m) :
|
||||
sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5])
|
||||
{}
|
||||
|
||||
// Rectangle to a parallelogram.
|
||||
trans_affine(double x1, double y1, double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
rect_to_parl(x1, y1, x2, y2, parl);
|
||||
}
|
||||
|
||||
// Parallelogram to a rectangle.
|
||||
trans_affine(const double* parl,
|
||||
double x1, double y1, double x2, double y2)
|
||||
{
|
||||
parl_to_rect(parl, x1, y1, x2, y2);
|
||||
}
|
||||
|
||||
// Arbitrary parallelogram transformation.
|
||||
trans_affine(const double* src, const double* dst)
|
||||
{
|
||||
parl_to_parl(src, dst);
|
||||
}
|
||||
|
||||
//---------------------------------- Parellelogram transformations
|
||||
// transform a parallelogram to another one. Src and dst are
|
||||
// pointers to arrays of three points (double[6], x1,y1,...) that
|
||||
// identify three corners of the parallelograms assuming implicit
|
||||
// fourth point. The arguments are arrays of double[6] mapped
|
||||
// to x1,y1, x2,y2, x3,y3 where the coordinates are:
|
||||
// *-----------------*
|
||||
// / (x3,y3)/
|
||||
// / /
|
||||
// /(x1,y1) (x2,y2)/
|
||||
// *-----------------*
|
||||
const trans_affine& parl_to_parl(const double* src,
|
||||
const double* dst);
|
||||
|
||||
const trans_affine& rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl);
|
||||
|
||||
const trans_affine& parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2);
|
||||
|
||||
|
||||
//------------------------------------------ Operations
|
||||
// Reset - load an identity matrix
|
||||
const trans_affine& reset();
|
||||
|
||||
// Direct transformations operations
|
||||
const trans_affine& translate(double x, double y);
|
||||
const trans_affine& rotate(double a);
|
||||
const trans_affine& scale(double s);
|
||||
const trans_affine& scale(double x, double y);
|
||||
|
||||
// Multiply matrix to another one
|
||||
const trans_affine& multiply(const trans_affine& m);
|
||||
|
||||
// Multiply "m" to "this" and assign the result to "this"
|
||||
const trans_affine& premultiply(const trans_affine& m);
|
||||
|
||||
// Multiply matrix to inverse of another one
|
||||
const trans_affine& multiply_inv(const trans_affine& m);
|
||||
|
||||
// Multiply inverse of "m" to "this" and assign the result to "this"
|
||||
const trans_affine& premultiply_inv(const trans_affine& m);
|
||||
|
||||
// Invert matrix. Do not try to invert degenerate matrices,
|
||||
// there's no check for validity. If you set scale to 0 and
|
||||
// then try to invert matrix, expect unpredictable result.
|
||||
const trans_affine& invert();
|
||||
|
||||
// Mirroring around X
|
||||
const trans_affine& flip_x();
|
||||
|
||||
// Mirroring around Y
|
||||
const trans_affine& flip_y();
|
||||
|
||||
//------------------------------------------- Load/Store
|
||||
// Store matrix to an array [6] of double
|
||||
void store_to(double* m) const
|
||||
{
|
||||
*m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty;
|
||||
}
|
||||
|
||||
// Load matrix from an array [6] of double
|
||||
const trans_affine& load_from(const double* m)
|
||||
{
|
||||
sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------- Operators
|
||||
|
||||
// Multiply the matrix by another one
|
||||
const trans_affine& operator *= (const trans_affine& m)
|
||||
{
|
||||
return multiply(m);
|
||||
}
|
||||
|
||||
// Multiply the matrix by inverse of another one
|
||||
const trans_affine& operator /= (const trans_affine& m)
|
||||
{
|
||||
return multiply_inv(m);
|
||||
}
|
||||
|
||||
// Multiply the matrix by another one and return
|
||||
// the result in a separete matrix.
|
||||
trans_affine operator * (const trans_affine& m) const
|
||||
{
|
||||
return trans_affine(*this).multiply(m);
|
||||
}
|
||||
|
||||
// Multiply the matrix by inverse of another one
|
||||
// and return the result in a separete matrix.
|
||||
trans_affine operator / (const trans_affine& m) const
|
||||
{
|
||||
return trans_affine(*this).multiply_inv(m);
|
||||
}
|
||||
|
||||
// Calculate and return the inverse matrix
|
||||
trans_affine operator ~ () const
|
||||
{
|
||||
trans_affine ret = *this;
|
||||
return ret.invert();
|
||||
}
|
||||
|
||||
// Equal operator with default epsilon
|
||||
bool operator == (const trans_affine& m) const
|
||||
{
|
||||
return is_equal(m, affine_epsilon);
|
||||
}
|
||||
|
||||
// Not Equal operator with default epsilon
|
||||
bool operator != (const trans_affine& m) const
|
||||
{
|
||||
return !is_equal(m, affine_epsilon);
|
||||
}
|
||||
|
||||
//-------------------------------------------- Transformations
|
||||
// Direct transformation of x and y
|
||||
void transform(double* x, double* y) const;
|
||||
|
||||
// Direct transformation of x and y, 2x2 matrix only, no translation
|
||||
void transform_2x2(double* x, double* y) const;
|
||||
|
||||
// Inverse transformation of x and y. It works slower than the
|
||||
// direct transformation. For massive operations it's better to
|
||||
// invert() the matrix and then use direct transformations.
|
||||
void inverse_transform(double* x, double* y) const;
|
||||
|
||||
//-------------------------------------------- Auxiliary
|
||||
// Calculate the determinant of matrix
|
||||
double determinant() const
|
||||
{
|
||||
return sx * sy - shy * shx;
|
||||
}
|
||||
|
||||
// Calculate the reciprocal of the determinant
|
||||
double determinant_reciprocal() const
|
||||
{
|
||||
return 1.0 / (sx * sy - shy * shx);
|
||||
}
|
||||
|
||||
// Get the average scale (by X and Y).
|
||||
// Basically used to calculate the approximation_scale when
|
||||
// decomposinting curves into line segments.
|
||||
double scale() const;
|
||||
|
||||
// Check to see if the matrix is not degenerate
|
||||
bool is_valid(double epsilon = affine_epsilon) const;
|
||||
|
||||
// Check to see if it's an identity matrix
|
||||
bool is_identity(double epsilon = affine_epsilon) const;
|
||||
|
||||
// Check to see if two matrices are equal
|
||||
bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const;
|
||||
|
||||
// Determine the major parameters. Use with caution considering
|
||||
// possible degenerate cases.
|
||||
double rotation() const;
|
||||
void translation(double* dx, double* dy) const;
|
||||
void scaling(double* x, double* y) const;
|
||||
void scaling_abs(double* x, double* y) const;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform(double* x, double* y) const
|
||||
{
|
||||
double tmp = *x;
|
||||
*x = tmp * sx + *y * shx + tx;
|
||||
*y = tmp * shy + *y * sy + ty;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::transform_2x2(double* x, double* y) const
|
||||
{
|
||||
double tmp = *x;
|
||||
*x = tmp * sx + *y * shx;
|
||||
*y = tmp * shy + *y * sy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::inverse_transform(double* x, double* y) const
|
||||
{
|
||||
double d = determinant_reciprocal();
|
||||
double a = (*x - tx) * d;
|
||||
double b = (*y - ty) * d;
|
||||
*x = a * sy - b * shx;
|
||||
*y = b * sx - a * shy;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline double trans_affine::scale() const
|
||||
{
|
||||
double x = 0.707106781 * sx + 0.707106781 * shx;
|
||||
double y = 0.707106781 * shy + 0.707106781 * sy;
|
||||
return sqrt(x*x + y*y);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::translate(double x, double y)
|
||||
{
|
||||
tx += x;
|
||||
ty += y;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::rotate(double a)
|
||||
{
|
||||
double ca = cos(a);
|
||||
double sa = sin(a);
|
||||
double t0 = sx * ca - shy * sa;
|
||||
double t2 = shx * ca - sy * sa;
|
||||
double t4 = tx * ca - ty * sa;
|
||||
shy = sx * sa + shy * ca;
|
||||
sy = shx * sa + sy * ca;
|
||||
ty = tx * sa + ty * ca;
|
||||
sx = t0;
|
||||
shx = t2;
|
||||
tx = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::scale(double x, double y)
|
||||
{
|
||||
double mm0 = x; // Possible hint for the optimizer
|
||||
double mm3 = y;
|
||||
sx *= mm0;
|
||||
shx *= mm0;
|
||||
tx *= mm0;
|
||||
shy *= mm3;
|
||||
sy *= mm3;
|
||||
ty *= mm3;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::scale(double s)
|
||||
{
|
||||
double m = s; // Possible hint for the optimizer
|
||||
sx *= m;
|
||||
shx *= m;
|
||||
tx *= m;
|
||||
shy *= m;
|
||||
sy *= m;
|
||||
ty *= m;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::premultiply(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
return *this = t.multiply(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::multiply_inv(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
t.invert();
|
||||
return multiply(t);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline const trans_affine& trans_affine::premultiply_inv(const trans_affine& m)
|
||||
{
|
||||
trans_affine t = m;
|
||||
t.invert();
|
||||
return *this = t.multiply(*this);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
inline void trans_affine::scaling_abs(double* x, double* y) const
|
||||
{
|
||||
// Used to calculate scaling coefficients in image resampling.
|
||||
// When there is considerable shear this method gives us much
|
||||
// better estimation than just sx, sy.
|
||||
*x = sqrt(sx * sx + shx * shx);
|
||||
*y = sqrt(shy * shy + sy * sy);
|
||||
}
|
||||
|
||||
//====================================================trans_affine_rotation
|
||||
// Rotation matrix. sin() and cos() are calculated twice for the same angle.
|
||||
// There's no harm because the performance of sin()/cos() is very good on all
|
||||
// modern processors. Besides, this operation is not going to be invoked too
|
||||
// often.
|
||||
class trans_affine_rotation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_rotation(double a) :
|
||||
trans_affine(cos(a), sin(a), -sin(a), cos(a), 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================trans_affine_scaling
|
||||
// Scaling matrix. x, y - scale coefficients by X and Y respectively
|
||||
class trans_affine_scaling : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_scaling(double x, double y) :
|
||||
trans_affine(x, 0.0, 0.0, y, 0.0, 0.0)
|
||||
{}
|
||||
|
||||
trans_affine_scaling(double s) :
|
||||
trans_affine(s, 0.0, 0.0, s, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
//================================================trans_affine_translation
|
||||
// Translation matrix
|
||||
class trans_affine_translation : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_translation(double x, double y) :
|
||||
trans_affine(1.0, 0.0, 0.0, 1.0, x, y)
|
||||
{}
|
||||
};
|
||||
|
||||
//====================================================trans_affine_skewing
|
||||
// Sckewing (shear) matrix
|
||||
class trans_affine_skewing : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_skewing(double x, double y) :
|
||||
trans_affine(1.0, tan(y), tan(x), 1.0, 0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//===============================================trans_affine_line_segment
|
||||
// Rotate, Scale and Translate, associating 0...dist with line segment
|
||||
// x1,y1,x2,y2
|
||||
class trans_affine_line_segment : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_line_segment(double x1, double y1, double x2, double y2,
|
||||
double dist)
|
||||
{
|
||||
double dx = x2 - x1;
|
||||
double dy = y2 - y1;
|
||||
if(dist > 0.0)
|
||||
{
|
||||
multiply(trans_affine_scaling(sqrt(dx * dx + dy * dy) / dist));
|
||||
}
|
||||
multiply(trans_affine_rotation(atan2(dy, dx)));
|
||||
multiply(trans_affine_translation(x1, y1));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
//============================================trans_affine_reflection_unit
|
||||
// Reflection matrix. Reflect coordinates across the line through
|
||||
// the origin containing the unit vector (ux, uy).
|
||||
// Contributed by John Horigan
|
||||
class trans_affine_reflection_unit : public trans_affine
|
||||
{
|
||||
public:
|
||||
trans_affine_reflection_unit(double ux, double uy) :
|
||||
trans_affine(2.0 * ux * ux - 1.0,
|
||||
2.0 * ux * uy,
|
||||
2.0 * ux * uy,
|
||||
2.0 * uy * uy - 1.0,
|
||||
0.0, 0.0)
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
//=================================================trans_affine_reflection
|
||||
// Reflection matrix. Reflect coordinates across the line through
|
||||
// the origin at the angle a or containing the non-unit vector (x, y).
|
||||
// Contributed by John Horigan
|
||||
class trans_affine_reflection : public trans_affine_reflection_unit
|
||||
{
|
||||
public:
|
||||
trans_affine_reflection(double a) :
|
||||
trans_affine_reflection_unit(cos(a), sin(a))
|
||||
{}
|
||||
|
||||
|
||||
trans_affine_reflection(double x, double y) :
|
||||
trans_affine_reflection_unit(x / sqrt(x * x + y * y), y / sqrt(x * x + y * y))
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
303
3rd/agg/include/agg_trans_viewport.h
Normal file
303
3rd/agg/include/agg_trans_viewport.h
Normal file
@ -0,0 +1,303 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Viewport transformer - simple orthogonal conversions from world coordinates
|
||||
// to screen (device) ones.
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_TRANS_VIEWPORT_INCLUDED
|
||||
#define AGG_TRANS_VIEWPORT_INCLUDED
|
||||
|
||||
#include <string.h>
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
enum aspect_ratio_e
|
||||
{
|
||||
aspect_ratio_stretch,
|
||||
aspect_ratio_meet,
|
||||
aspect_ratio_slice
|
||||
};
|
||||
|
||||
|
||||
//----------------------------------------------------------trans_viewport
|
||||
class trans_viewport
|
||||
{
|
||||
public:
|
||||
//-------------------------------------------------------------------
|
||||
trans_viewport() :
|
||||
m_world_x1(0.0),
|
||||
m_world_y1(0.0),
|
||||
m_world_x2(1.0),
|
||||
m_world_y2(1.0),
|
||||
m_device_x1(0.0),
|
||||
m_device_y1(0.0),
|
||||
m_device_x2(1.0),
|
||||
m_device_y2(1.0),
|
||||
m_aspect(aspect_ratio_stretch),
|
||||
m_is_valid(true),
|
||||
m_align_x(0.5),
|
||||
m_align_y(0.5),
|
||||
m_wx1(0.0),
|
||||
m_wy1(0.0),
|
||||
m_wx2(1.0),
|
||||
m_wy2(1.0),
|
||||
m_dx1(0.0),
|
||||
m_dy1(0.0),
|
||||
m_kx(1.0),
|
||||
m_ky(1.0)
|
||||
{}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void preserve_aspect_ratio(double alignx,
|
||||
double aligny,
|
||||
aspect_ratio_e aspect)
|
||||
{
|
||||
m_align_x = alignx;
|
||||
m_align_y = aligny;
|
||||
m_aspect = aspect;
|
||||
update();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void device_viewport(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
m_device_x1 = x1;
|
||||
m_device_y1 = y1;
|
||||
m_device_x2 = x2;
|
||||
m_device_y2 = y2;
|
||||
update();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void world_viewport(double x1, double y1, double x2, double y2)
|
||||
{
|
||||
m_world_x1 = x1;
|
||||
m_world_y1 = y1;
|
||||
m_world_x2 = x2;
|
||||
m_world_y2 = y2;
|
||||
update();
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void device_viewport(double* x1, double* y1, double* x2, double* y2) const
|
||||
{
|
||||
*x1 = m_device_x1;
|
||||
*y1 = m_device_y1;
|
||||
*x2 = m_device_x2;
|
||||
*y2 = m_device_y2;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void world_viewport(double* x1, double* y1, double* x2, double* y2) const
|
||||
{
|
||||
*x1 = m_world_x1;
|
||||
*y1 = m_world_y1;
|
||||
*x2 = m_world_x2;
|
||||
*y2 = m_world_y2;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void world_viewport_actual(double* x1, double* y1,
|
||||
double* x2, double* y2) const
|
||||
{
|
||||
*x1 = m_wx1;
|
||||
*y1 = m_wy1;
|
||||
*x2 = m_wx2;
|
||||
*y2 = m_wy2;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
bool is_valid() const { return m_is_valid; }
|
||||
double align_x() const { return m_align_x; }
|
||||
double align_y() const { return m_align_y; }
|
||||
aspect_ratio_e aspect_ratio() const { return m_aspect; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void transform(double* x, double* y) const
|
||||
{
|
||||
*x = (*x - m_wx1) * m_kx + m_dx1;
|
||||
*y = (*y - m_wy1) * m_ky + m_dy1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void transform_scale_only(double* x, double* y) const
|
||||
{
|
||||
*x *= m_kx;
|
||||
*y *= m_ky;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void inverse_transform(double* x, double* y) const
|
||||
{
|
||||
*x = (*x - m_dx1) / m_kx + m_wx1;
|
||||
*y = (*y - m_dy1) / m_ky + m_wy1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
void inverse_transform_scale_only(double* x, double* y) const
|
||||
{
|
||||
*x /= m_kx;
|
||||
*y /= m_ky;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
double device_dx() const { return m_dx1 - m_wx1 * m_kx; }
|
||||
double device_dy() const { return m_dy1 - m_wy1 * m_ky; }
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
double scale_x() const
|
||||
{
|
||||
return m_kx;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
double scale_y() const
|
||||
{
|
||||
return m_ky;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
double scale() const
|
||||
{
|
||||
return (m_kx + m_ky) * 0.5;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
trans_affine to_affine() const
|
||||
{
|
||||
trans_affine mtx = trans_affine_translation(-m_wx1, -m_wy1);
|
||||
mtx *= trans_affine_scaling(m_kx, m_ky);
|
||||
mtx *= trans_affine_translation(m_dx1, m_dy1);
|
||||
return mtx;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
trans_affine to_affine_scale_only() const
|
||||
{
|
||||
return trans_affine_scaling(m_kx, m_ky);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
unsigned byte_size() const
|
||||
{
|
||||
return sizeof(*this);
|
||||
}
|
||||
|
||||
void serialize(int8u* ptr) const
|
||||
{
|
||||
memcpy(ptr, this, sizeof(*this));
|
||||
}
|
||||
|
||||
void deserialize(const int8u* ptr)
|
||||
{
|
||||
memcpy(this, ptr, sizeof(*this));
|
||||
}
|
||||
|
||||
private:
|
||||
void update();
|
||||
|
||||
double m_world_x1;
|
||||
double m_world_y1;
|
||||
double m_world_x2;
|
||||
double m_world_y2;
|
||||
double m_device_x1;
|
||||
double m_device_y1;
|
||||
double m_device_x2;
|
||||
double m_device_y2;
|
||||
aspect_ratio_e m_aspect;
|
||||
bool m_is_valid;
|
||||
double m_align_x;
|
||||
double m_align_y;
|
||||
double m_wx1;
|
||||
double m_wy1;
|
||||
double m_wx2;
|
||||
double m_wy2;
|
||||
double m_dx1;
|
||||
double m_dy1;
|
||||
double m_kx;
|
||||
double m_ky;
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
inline void trans_viewport::update()
|
||||
{
|
||||
const double epsilon = 1e-30;
|
||||
if(fabs(m_world_x1 - m_world_x2) < epsilon ||
|
||||
fabs(m_world_y1 - m_world_y2) < epsilon ||
|
||||
fabs(m_device_x1 - m_device_x2) < epsilon ||
|
||||
fabs(m_device_y1 - m_device_y2) < epsilon)
|
||||
{
|
||||
m_wx1 = m_world_x1;
|
||||
m_wy1 = m_world_y1;
|
||||
m_wx2 = m_world_x1 + 1.0;
|
||||
m_wy2 = m_world_y2 + 1.0;
|
||||
m_dx1 = m_device_x1;
|
||||
m_dy1 = m_device_y1;
|
||||
m_kx = 1.0;
|
||||
m_ky = 1.0;
|
||||
m_is_valid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
double world_x1 = m_world_x1;
|
||||
double world_y1 = m_world_y1;
|
||||
double world_x2 = m_world_x2;
|
||||
double world_y2 = m_world_y2;
|
||||
double device_x1 = m_device_x1;
|
||||
double device_y1 = m_device_y1;
|
||||
double device_x2 = m_device_x2;
|
||||
double device_y2 = m_device_y2;
|
||||
if(m_aspect != aspect_ratio_stretch)
|
||||
{
|
||||
double d;
|
||||
m_kx = (device_x2 - device_x1) / (world_x2 - world_x1);
|
||||
m_ky = (device_y2 - device_y1) / (world_y2 - world_y1);
|
||||
|
||||
if((m_aspect == aspect_ratio_meet) == (m_kx < m_ky))
|
||||
{
|
||||
d = (world_y2 - world_y1) * m_ky / m_kx;
|
||||
world_y1 += (world_y2 - world_y1 - d) * m_align_y;
|
||||
world_y2 = world_y1 + d;
|
||||
}
|
||||
else
|
||||
{
|
||||
d = (world_x2 - world_x1) * m_kx / m_ky;
|
||||
world_x1 += (world_x2 - world_x1 - d) * m_align_x;
|
||||
world_x2 = world_x1 + d;
|
||||
}
|
||||
}
|
||||
m_wx1 = world_x1;
|
||||
m_wy1 = world_y1;
|
||||
m_wx2 = world_x2;
|
||||
m_wy2 = world_y2;
|
||||
m_dx1 = device_x1;
|
||||
m_dy1 = device_y1;
|
||||
m_kx = (device_x2 - device_x1) / (world_x2 - world_x1);
|
||||
m_ky = (device_y2 - device_y1) / (world_y2 - world_y1);
|
||||
m_is_valid = true;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif
|
102
3rd/agg/include/agg_vcgen_stroke.h
Normal file
102
3rd/agg/include/agg_vcgen_stroke.h
Normal file
@ -0,0 +1,102 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#ifndef AGG_VCGEN_STROKE_INCLUDED
|
||||
#define AGG_VCGEN_STROKE_INCLUDED
|
||||
|
||||
#include "agg_math_stroke.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//============================================================vcgen_stroke
|
||||
//
|
||||
// See Implementation agg_vcgen_stroke.cpp
|
||||
// Stroke generator
|
||||
//
|
||||
//------------------------------------------------------------------------
|
||||
class vcgen_stroke
|
||||
{
|
||||
enum status_e
|
||||
{
|
||||
initial,
|
||||
ready,
|
||||
cap1,
|
||||
cap2,
|
||||
outline1,
|
||||
close_first,
|
||||
outline2,
|
||||
out_vertices,
|
||||
end_poly1,
|
||||
end_poly2,
|
||||
stop
|
||||
};
|
||||
|
||||
public:
|
||||
typedef vertex_sequence<vertex_dist, 6> vertex_storage;
|
||||
typedef pod_bvector<point_d, 6> coord_storage;
|
||||
|
||||
vcgen_stroke();
|
||||
|
||||
void line_cap(line_cap_e lc) { m_stroker.line_cap(lc); }
|
||||
void line_join(line_join_e lj) { m_stroker.line_join(lj); }
|
||||
void inner_join(inner_join_e ij) { m_stroker.inner_join(ij); }
|
||||
|
||||
line_cap_e line_cap() const { return m_stroker.line_cap(); }
|
||||
line_join_e line_join() const { return m_stroker.line_join(); }
|
||||
inner_join_e inner_join() const { return m_stroker.inner_join(); }
|
||||
|
||||
void width(double w) { m_stroker.width(w); }
|
||||
void miter_limit(double ml) { m_stroker.miter_limit(ml); }
|
||||
void miter_limit_theta(double t) { m_stroker.miter_limit_theta(t); }
|
||||
void inner_miter_limit(double ml) { m_stroker.inner_miter_limit(ml); }
|
||||
void approximation_scale(double as) { m_stroker.approximation_scale(as); }
|
||||
|
||||
double width() const { return m_stroker.width(); }
|
||||
double miter_limit() const { return m_stroker.miter_limit(); }
|
||||
double inner_miter_limit() const { return m_stroker.inner_miter_limit(); }
|
||||
double approximation_scale() const { return m_stroker.approximation_scale(); }
|
||||
|
||||
void shorten(double s) { m_shorten = s; }
|
||||
double shorten() const { return m_shorten; }
|
||||
|
||||
// Vertex Generator Interface
|
||||
void remove_all();
|
||||
void add_vertex(double x, double y, unsigned cmd);
|
||||
|
||||
// Vertex Source Interface
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
|
||||
private:
|
||||
vcgen_stroke(const vcgen_stroke&);
|
||||
const vcgen_stroke& operator = (const vcgen_stroke&);
|
||||
|
||||
math_stroke<coord_storage> m_stroker;
|
||||
vertex_storage m_src_vertices;
|
||||
coord_storage m_out_vertices;
|
||||
double m_shorten;
|
||||
unsigned m_closed;
|
||||
status_e m_status;
|
||||
status_e m_prev_status;
|
||||
unsigned m_src_vertex;
|
||||
unsigned m_out_vertex;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
172
3rd/agg/include/agg_vertex_sequence.h
Normal file
172
3rd/agg/include/agg_vertex_sequence.h
Normal file
@ -0,0 +1,172 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// vertex_sequence container and vertex_dist struct
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#ifndef AGG_VERTEX_SEQUENCE_INCLUDED
|
||||
#define AGG_VERTEX_SEQUENCE_INCLUDED
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_array.h"
|
||||
#include "agg_math.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//----------------------------------------------------------vertex_sequence
|
||||
// Modified agg::pod_bvector. The data is interpreted as a sequence
|
||||
// of vertices. It means that the type T must expose:
|
||||
//
|
||||
// bool T::operator() (const T& val)
|
||||
//
|
||||
// that is called every time new vertex is being added. The main purpose
|
||||
// of this operator is the possibility to calculate some values during
|
||||
// adding and to return true if the vertex fits some criteria or false if
|
||||
// it doesn't. In the last case the new vertex is not added.
|
||||
//
|
||||
// The simple example is filtering coinciding vertices with calculation
|
||||
// of the distance between the current and previous ones:
|
||||
//
|
||||
// struct vertex_dist
|
||||
// {
|
||||
// double x;
|
||||
// double y;
|
||||
// double dist;
|
||||
//
|
||||
// vertex_dist() {}
|
||||
// vertex_dist(double x_, double y_) :
|
||||
// x(x_),
|
||||
// y(y_),
|
||||
// dist(0.0)
|
||||
// {
|
||||
// }
|
||||
//
|
||||
// bool operator () (const vertex_dist& val)
|
||||
// {
|
||||
// return (dist = calc_distance(x, y, val.x, val.y)) > EPSILON;
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// Function close() calls this operator and removes the last vertex if
|
||||
// necessary.
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S=6>
|
||||
class vertex_sequence : public pod_bvector<T, S>
|
||||
{
|
||||
public:
|
||||
typedef pod_bvector<T, S> base_type;
|
||||
|
||||
void add(const T& val);
|
||||
void modify_last(const T& val);
|
||||
void close(bool remove_flag);
|
||||
};
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::add(const T& val)
|
||||
{
|
||||
if(base_type::size() > 1)
|
||||
{
|
||||
if(!(*this)[base_type::size() - 2]((*this)[base_type::size() - 1]))
|
||||
{
|
||||
base_type::remove_last();
|
||||
}
|
||||
}
|
||||
base_type::add(val);
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::modify_last(const T& val)
|
||||
{
|
||||
base_type::remove_last();
|
||||
add(val);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
template<class T, unsigned S>
|
||||
void vertex_sequence<T, S>::close(bool closed)
|
||||
{
|
||||
while(base_type::size() > 1)
|
||||
{
|
||||
if((*this)[base_type::size() - 2]((*this)[base_type::size() - 1])) break;
|
||||
T t = (*this)[base_type::size() - 1];
|
||||
base_type::remove_last();
|
||||
modify_last(t);
|
||||
}
|
||||
|
||||
if(closed)
|
||||
{
|
||||
while(base_type::size() > 1)
|
||||
{
|
||||
if((*this)[base_type::size() - 1]((*this)[0])) break;
|
||||
base_type::remove_last();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------------------vertex_dist
|
||||
// Vertex (x, y) with the distance to the next one. The last vertex has
|
||||
// distance between the last and the first points if the polygon is closed
|
||||
// and 0.0 if it's a polyline.
|
||||
struct vertex_dist
|
||||
{
|
||||
double x;
|
||||
double y;
|
||||
double dist;
|
||||
|
||||
vertex_dist() {}
|
||||
vertex_dist(double x_, double y_) :
|
||||
x(x_),
|
||||
y(y_),
|
||||
dist(0.0)
|
||||
{
|
||||
}
|
||||
|
||||
bool operator () (const vertex_dist& val)
|
||||
{
|
||||
bool ret = (dist = calc_distance(x, y, val.x, val.y)) > vertex_dist_epsilon;
|
||||
if(!ret) dist = 1.0 / vertex_dist_epsilon;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------vertex_dist_cmd
|
||||
// Save as the above but with additional "command" value
|
||||
struct vertex_dist_cmd : public vertex_dist
|
||||
{
|
||||
unsigned cmd;
|
||||
|
||||
vertex_dist_cmd() {}
|
||||
vertex_dist_cmd(double x_, double y_, unsigned cmd_) :
|
||||
vertex_dist(x_, y_),
|
||||
cmd(cmd_)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
17
3rd/agg/src/agg_color_rgba.cpp
Normal file
17
3rd/agg/src/agg_color_rgba.cpp
Normal file
@ -0,0 +1,17 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2009 John Horigan (http://www.antigrain.com)
|
||||
//
|
||||
// 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: john@glyphic.com.com
|
||||
// http://www.antigrain.com
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
// rgbaN construction from grayN types is no longer required,
|
||||
// as grayN types now define their own conversions to rgbaN.
|
103
3rd/agg/src/agg_image_filters.cpp
Normal file
103
3rd/agg/src/agg_image_filters.cpp
Normal file
@ -0,0 +1,103 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Filtering class image_filter_lut implemantation
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
|
||||
#include "agg_image_filters.h"
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
//--------------------------------------------------------------------
|
||||
void image_filter_lut::realloc_lut(double radius)
|
||||
{
|
||||
m_radius = radius;
|
||||
m_diameter = uceil(radius) * 2;
|
||||
m_start = -int(m_diameter / 2 - 1);
|
||||
unsigned size = m_diameter << image_subpixel_shift;
|
||||
if(size > m_weight_array.size())
|
||||
{
|
||||
m_weight_array.resize(size);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
// This function normalizes integer values and corrects the rounding
|
||||
// errors. It doesn't do anything with the source floating point values
|
||||
// (m_weight_array_dbl), it corrects only integers according to the rule
|
||||
// of 1.0 which means that any sum of pixel weights must be equal to 1.0.
|
||||
// So, the filter function must produce a graph of the proper shape.
|
||||
//--------------------------------------------------------------------
|
||||
void image_filter_lut::normalize()
|
||||
{
|
||||
unsigned i;
|
||||
int flip = 1;
|
||||
|
||||
for(i = 0; i < image_subpixel_scale; i++)
|
||||
{
|
||||
for(;;)
|
||||
{
|
||||
int sum = 0;
|
||||
unsigned j;
|
||||
for(j = 0; j < m_diameter; j++)
|
||||
{
|
||||
sum += m_weight_array[j * image_subpixel_scale + i];
|
||||
}
|
||||
|
||||
if(sum == image_filter_scale) break;
|
||||
|
||||
double k = double(image_filter_scale) / double(sum);
|
||||
sum = 0;
|
||||
for(j = 0; j < m_diameter; j++)
|
||||
{
|
||||
sum += m_weight_array[j * image_subpixel_scale + i] =
|
||||
iround(m_weight_array[j * image_subpixel_scale + i] * k);
|
||||
}
|
||||
|
||||
sum -= image_filter_scale;
|
||||
int inc = (sum > 0) ? -1 : 1;
|
||||
|
||||
for(j = 0; j < m_diameter && sum; j++)
|
||||
{
|
||||
flip ^= 1;
|
||||
unsigned idx = flip ? m_diameter/2 + j/2 : m_diameter/2 - j/2;
|
||||
int v = m_weight_array[idx * image_subpixel_scale + i];
|
||||
if(v < image_filter_scale)
|
||||
{
|
||||
m_weight_array[idx * image_subpixel_scale + i] += inc;
|
||||
sum += inc;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
unsigned pivot = m_diameter << (image_subpixel_shift - 1);
|
||||
|
||||
for(i = 0; i < pivot; i++)
|
||||
{
|
||||
m_weight_array[pivot + i] = m_weight_array[pivot - i];
|
||||
}
|
||||
unsigned end = (diameter() << image_subpixel_shift) - 1;
|
||||
m_weight_array[0] = m_weight_array[end];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
115
3rd/agg/src/agg_sqrt_tables.cpp
Normal file
115
3rd/agg/src/agg_sqrt_tables.cpp
Normal file
@ -0,0 +1,115 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// static tables for fast integer sqrt
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
int16u g_sqrt_table[1024] = //----------g_sqrt_table
|
||||
{
|
||||
0,
|
||||
2048,2896,3547,4096,4579,5017,5418,5793,6144,6476,6792,7094,7384,7663,7932,8192,8444,
|
||||
8689,8927,9159,9385,9606,9822,10033,10240,10443,10642,10837,11029,11217,11403,11585,
|
||||
11765,11942,12116,12288,12457,12625,12790,12953,13114,13273,13430,13585,13738,13890,
|
||||
14040,14189,14336,14482,14626,14768,14910,15050,15188,15326,15462,15597,15731,15864,
|
||||
15995,16126,16255,16384,16512,16638,16764,16888,17012,17135,17257,17378,17498,17618,
|
||||
17736,17854,17971,18087,18203,18318,18432,18545,18658,18770,18882,18992,19102,19212,
|
||||
19321,19429,19537,19644,19750,19856,19961,20066,20170,20274,20377,20480,20582,20684,
|
||||
20785,20886,20986,21085,21185,21283,21382,21480,21577,21674,21771,21867,21962,22058,
|
||||
22153,22247,22341,22435,22528,22621,22713,22806,22897,22989,23080,23170,23261,23351,
|
||||
23440,23530,23619,23707,23796,23884,23971,24059,24146,24232,24319,24405,24491,24576,
|
||||
24661,24746,24831,24915,24999,25083,25166,25249,25332,25415,25497,25580,25661,25743,
|
||||
25824,25905,25986,26067,26147,26227,26307,26387,26466,26545,26624,26703,26781,26859,
|
||||
26937,27015,27092,27170,27247,27324,27400,27477,27553,27629,27705,27780,27856,27931,
|
||||
28006,28081,28155,28230,28304,28378,28452,28525,28599,28672,28745,28818,28891,28963,
|
||||
29035,29108,29180,29251,29323,29394,29466,29537,29608,29678,29749,29819,29890,29960,
|
||||
30030,30099,30169,30238,30308,30377,30446,30515,30583,30652,30720,30788,30856,30924,
|
||||
30992,31059,31127,31194,31261,31328,31395,31462,31529,31595,31661,31727,31794,31859,
|
||||
31925,31991,32056,32122,32187,32252,32317,32382,32446,32511,32575,32640,32704,32768,
|
||||
32832,32896,32959,33023,33086,33150,33213,33276,33339,33402,33465,33527,33590,33652,
|
||||
33714,33776,33839,33900,33962,34024,34086,34147,34208,34270,34331,34392,34453,34514,
|
||||
34574,34635,34695,34756,34816,34876,34936,34996,35056,35116,35176,35235,35295,35354,
|
||||
35413,35472,35531,35590,35649,35708,35767,35825,35884,35942,36001,36059,36117,36175,
|
||||
36233,36291,36348,36406,36464,36521,36578,36636,36693,36750,36807,36864,36921,36978,
|
||||
37034,37091,37147,37204,37260,37316,37372,37429,37485,37540,37596,37652,37708,37763,
|
||||
37819,37874,37929,37985,38040,38095,38150,38205,38260,38315,38369,38424,38478,38533,
|
||||
38587,38642,38696,38750,38804,38858,38912,38966,39020,39073,39127,39181,39234,39287,
|
||||
39341,39394,39447,39500,39553,39606,39659,39712,39765,39818,39870,39923,39975,40028,
|
||||
40080,40132,40185,40237,40289,40341,40393,40445,40497,40548,40600,40652,40703,40755,
|
||||
40806,40857,40909,40960,41011,41062,41113,41164,41215,41266,41317,41368,41418,41469,
|
||||
41519,41570,41620,41671,41721,41771,41821,41871,41922,41972,42021,42071,42121,42171,
|
||||
42221,42270,42320,42369,42419,42468,42518,42567,42616,42665,42714,42763,42813,42861,
|
||||
42910,42959,43008,43057,43105,43154,43203,43251,43300,43348,43396,43445,43493,43541,
|
||||
43589,43637,43685,43733,43781,43829,43877,43925,43972,44020,44068,44115,44163,44210,
|
||||
44258,44305,44352,44400,44447,44494,44541,44588,44635,44682,44729,44776,44823,44869,
|
||||
44916,44963,45009,45056,45103,45149,45195,45242,45288,45334,45381,45427,45473,45519,
|
||||
45565,45611,45657,45703,45749,45795,45840,45886,45932,45977,46023,46069,46114,46160,
|
||||
46205,46250,46296,46341,46386,46431,46477,46522,46567,46612,46657,46702,46746,46791,
|
||||
46836,46881,46926,46970,47015,47059,47104,47149,47193,47237,47282,47326,47370,47415,
|
||||
47459,47503,47547,47591,47635,47679,47723,47767,47811,47855,47899,47942,47986,48030,
|
||||
48074,48117,48161,48204,48248,48291,48335,48378,48421,48465,48508,48551,48594,48637,
|
||||
48680,48723,48766,48809,48852,48895,48938,48981,49024,49067,49109,49152,49195,49237,
|
||||
49280,49322,49365,49407,49450,49492,49535,49577,49619,49661,49704,49746,49788,49830,
|
||||
49872,49914,49956,49998,50040,50082,50124,50166,50207,50249,50291,50332,50374,50416,
|
||||
50457,50499,50540,50582,50623,50665,50706,50747,50789,50830,50871,50912,50954,50995,
|
||||
51036,51077,51118,51159,51200,51241,51282,51323,51364,51404,51445,51486,51527,51567,
|
||||
51608,51649,51689,51730,51770,51811,51851,51892,51932,51972,52013,52053,52093,52134,
|
||||
52174,52214,52254,52294,52334,52374,52414,52454,52494,52534,52574,52614,52654,52694,
|
||||
52734,52773,52813,52853,52892,52932,52972,53011,53051,53090,53130,53169,53209,53248,
|
||||
53287,53327,53366,53405,53445,53484,53523,53562,53601,53640,53679,53719,53758,53797,
|
||||
53836,53874,53913,53952,53991,54030,54069,54108,54146,54185,54224,54262,54301,54340,
|
||||
54378,54417,54455,54494,54532,54571,54609,54647,54686,54724,54762,54801,54839,54877,
|
||||
54915,54954,54992,55030,55068,55106,55144,55182,55220,55258,55296,55334,55372,55410,
|
||||
55447,55485,55523,55561,55599,55636,55674,55712,55749,55787,55824,55862,55900,55937,
|
||||
55975,56012,56049,56087,56124,56162,56199,56236,56273,56311,56348,56385,56422,56459,
|
||||
56497,56534,56571,56608,56645,56682,56719,56756,56793,56830,56867,56903,56940,56977,
|
||||
57014,57051,57087,57124,57161,57198,57234,57271,57307,57344,57381,57417,57454,57490,
|
||||
57527,57563,57599,57636,57672,57709,57745,57781,57817,57854,57890,57926,57962,57999,
|
||||
58035,58071,58107,58143,58179,58215,58251,58287,58323,58359,58395,58431,58467,58503,
|
||||
58538,58574,58610,58646,58682,58717,58753,58789,58824,58860,58896,58931,58967,59002,
|
||||
59038,59073,59109,59144,59180,59215,59251,59286,59321,59357,59392,59427,59463,59498,
|
||||
59533,59568,59603,59639,59674,59709,59744,59779,59814,59849,59884,59919,59954,59989,
|
||||
60024,60059,60094,60129,60164,60199,60233,60268,60303,60338,60373,60407,60442,60477,
|
||||
60511,60546,60581,60615,60650,60684,60719,60753,60788,60822,60857,60891,60926,60960,
|
||||
60995,61029,61063,61098,61132,61166,61201,61235,61269,61303,61338,61372,61406,61440,
|
||||
61474,61508,61542,61576,61610,61644,61678,61712,61746,61780,61814,61848,61882,61916,
|
||||
61950,61984,62018,62051,62085,62119,62153,62186,62220,62254,62287,62321,62355,62388,
|
||||
62422,62456,62489,62523,62556,62590,62623,62657,62690,62724,62757,62790,62824,62857,
|
||||
62891,62924,62957,62991,63024,63057,63090,63124,63157,63190,63223,63256,63289,63323,
|
||||
63356,63389,63422,63455,63488,63521,63554,63587,63620,63653,63686,63719,63752,63785,
|
||||
63817,63850,63883,63916,63949,63982,64014,64047,64080,64113,64145,64178,64211,64243,
|
||||
64276,64309,64341,64374,64406,64439,64471,64504,64536,64569,64601,64634,64666,64699,
|
||||
64731,64763,64796,64828,64861,64893,64925,64957,64990,65022,65054,65086,65119,65151,
|
||||
65183,65215,65247,65279,65312,65344,65376,65408,65440,65472,65504
|
||||
};
|
||||
|
||||
|
||||
int8 g_elder_bit_table[256] = //---------g_elder_bit_table
|
||||
{
|
||||
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
|
||||
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
|
||||
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
|
||||
};
|
||||
|
||||
}
|
194
3rd/agg/src/agg_trans_affine.cpp
Normal file
194
3rd/agg/src/agg_trans_affine.cpp
Normal file
@ -0,0 +1,194 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Affine transformations
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include "agg_trans_affine.h"
|
||||
|
||||
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::parl_to_parl(const double* src,
|
||||
const double* dst)
|
||||
{
|
||||
sx = src[2] - src[0];
|
||||
shy = src[3] - src[1];
|
||||
shx = src[4] - src[0];
|
||||
sy = src[5] - src[1];
|
||||
tx = src[0];
|
||||
ty = src[1];
|
||||
invert();
|
||||
multiply(trans_affine(dst[2] - dst[0], dst[3] - dst[1],
|
||||
dst[4] - dst[0], dst[5] - dst[1],
|
||||
dst[0], dst[1]));
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::rect_to_parl(double x1, double y1,
|
||||
double x2, double y2,
|
||||
const double* parl)
|
||||
{
|
||||
double src[6];
|
||||
src[0] = x1; src[1] = y1;
|
||||
src[2] = x2; src[3] = y1;
|
||||
src[4] = x2; src[5] = y2;
|
||||
parl_to_parl(src, parl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::parl_to_rect(const double* parl,
|
||||
double x1, double y1,
|
||||
double x2, double y2)
|
||||
{
|
||||
double dst[6];
|
||||
dst[0] = x1; dst[1] = y1;
|
||||
dst[2] = x2; dst[3] = y1;
|
||||
dst[4] = x2; dst[5] = y2;
|
||||
parl_to_parl(parl, dst);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::multiply(const trans_affine& m)
|
||||
{
|
||||
double t0 = sx * m.sx + shy * m.shx;
|
||||
double t2 = shx * m.sx + sy * m.shx;
|
||||
double t4 = tx * m.sx + ty * m.shx + m.tx;
|
||||
shy = sx * m.shy + shy * m.sy;
|
||||
sy = shx * m.shy + sy * m.sy;
|
||||
ty = tx * m.shy + ty * m.sy + m.ty;
|
||||
sx = t0;
|
||||
shx = t2;
|
||||
tx = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::invert()
|
||||
{
|
||||
double d = determinant_reciprocal();
|
||||
|
||||
double t0 = sy * d;
|
||||
sy = sx * d;
|
||||
shy = -shy * d;
|
||||
shx = -shx * d;
|
||||
|
||||
double t4 = -tx * t0 - ty * shx;
|
||||
ty = -tx * shy - ty * sy;
|
||||
|
||||
sx = t0;
|
||||
tx = t4;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::flip_x()
|
||||
{
|
||||
sx = -sx;
|
||||
shy = -shy;
|
||||
tx = -tx;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::flip_y()
|
||||
{
|
||||
shx = -shx;
|
||||
sy = -sy;
|
||||
ty = -ty;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
const trans_affine& trans_affine::reset()
|
||||
{
|
||||
sx = sy = 1.0;
|
||||
shy = shx = tx = ty = 0.0;
|
||||
return *this;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_identity(double epsilon) const
|
||||
{
|
||||
return is_equal_eps(sx, 1.0, epsilon) &&
|
||||
is_equal_eps(shy, 0.0, epsilon) &&
|
||||
is_equal_eps(shx, 0.0, epsilon) &&
|
||||
is_equal_eps(sy, 1.0, epsilon) &&
|
||||
is_equal_eps(tx, 0.0, epsilon) &&
|
||||
is_equal_eps(ty, 0.0, epsilon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_valid(double epsilon) const
|
||||
{
|
||||
return fabs(sx) > epsilon && fabs(sy) > epsilon;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
bool trans_affine::is_equal(const trans_affine& m, double epsilon) const
|
||||
{
|
||||
return is_equal_eps(sx, m.sx, epsilon) &&
|
||||
is_equal_eps(shy, m.shy, epsilon) &&
|
||||
is_equal_eps(shx, m.shx, epsilon) &&
|
||||
is_equal_eps(sy, m.sy, epsilon) &&
|
||||
is_equal_eps(tx, m.tx, epsilon) &&
|
||||
is_equal_eps(ty, m.ty, epsilon);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
double trans_affine::rotation() const
|
||||
{
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double x2 = 1.0;
|
||||
double y2 = 0.0;
|
||||
transform(&x1, &y1);
|
||||
transform(&x2, &y2);
|
||||
return atan2(y2-y1, x2-x1);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void trans_affine::translation(double* dx, double* dy) const
|
||||
{
|
||||
*dx = tx;
|
||||
*dy = ty;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void trans_affine::scaling(double* x, double* y) const
|
||||
{
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double x2 = 1.0;
|
||||
double y2 = 1.0;
|
||||
trans_affine t(*this);
|
||||
t *= trans_affine_rotation(-rotation());
|
||||
t.transform(&x1, &y1);
|
||||
t.transform(&x2, &y2);
|
||||
*x = x2 - x1;
|
||||
*y = y2 - y1;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
213
3rd/agg/src/agg_vcgen_stroke.cpp
Normal file
213
3rd/agg/src/agg_vcgen_stroke.cpp
Normal file
@ -0,0 +1,213 @@
|
||||
//----------------------------------------------------------------------------
|
||||
// Anti-Grain Geometry - Version 2.4
|
||||
// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com)
|
||||
//
|
||||
// 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
|
||||
//----------------------------------------------------------------------------
|
||||
//
|
||||
// Stroke generator
|
||||
//
|
||||
//----------------------------------------------------------------------------
|
||||
#include <math.h>
|
||||
#include "agg_vcgen_stroke.h"
|
||||
#include "agg_shorten_path.h"
|
||||
|
||||
namespace agg
|
||||
{
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
vcgen_stroke::vcgen_stroke() :
|
||||
m_stroker(),
|
||||
m_src_vertices(),
|
||||
m_out_vertices(),
|
||||
m_shorten(0.0),
|
||||
m_closed(0),
|
||||
m_status(initial),
|
||||
m_src_vertex(0),
|
||||
m_out_vertex(0)
|
||||
{
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::remove_all()
|
||||
{
|
||||
m_src_vertices.remove_all();
|
||||
m_closed = 0;
|
||||
m_status = initial;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::add_vertex(double x, double y, unsigned cmd)
|
||||
{
|
||||
m_status = initial;
|
||||
if(is_move_to(cmd))
|
||||
{
|
||||
m_src_vertices.modify_last(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_vertex(cmd))
|
||||
{
|
||||
m_src_vertices.add(vertex_dist(x, y));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_closed = get_close_flag(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
void vcgen_stroke::rewind(unsigned)
|
||||
{
|
||||
if(m_status == initial)
|
||||
{
|
||||
m_src_vertices.close(m_closed != 0);
|
||||
shorten_path(m_src_vertices, m_shorten, m_closed);
|
||||
if(m_src_vertices.size() < 3) m_closed = 0;
|
||||
}
|
||||
m_status = ready;
|
||||
m_src_vertex = 0;
|
||||
m_out_vertex = 0;
|
||||
}
|
||||
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
unsigned vcgen_stroke::vertex(double* x, double* y)
|
||||
{
|
||||
unsigned cmd = path_cmd_line_to;
|
||||
while(!is_stop(cmd))
|
||||
{
|
||||
switch(m_status)
|
||||
{
|
||||
case initial:
|
||||
rewind(0);
|
||||
|
||||
case ready:
|
||||
if(m_src_vertices.size() < 2 + unsigned(m_closed != 0))
|
||||
{
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
m_status = m_closed ? outline1 : cap1;
|
||||
cmd = path_cmd_move_to;
|
||||
m_src_vertex = 0;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case cap1:
|
||||
m_stroker.calc_cap(m_out_vertices,
|
||||
m_src_vertices[0],
|
||||
m_src_vertices[1],
|
||||
m_src_vertices[0].dist);
|
||||
m_src_vertex = 1;
|
||||
m_prev_status = outline1;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case cap2:
|
||||
m_stroker.calc_cap(m_out_vertices,
|
||||
m_src_vertices[m_src_vertices.size() - 1],
|
||||
m_src_vertices[m_src_vertices.size() - 2],
|
||||
m_src_vertices[m_src_vertices.size() - 2].dist);
|
||||
m_prev_status = outline2;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case outline1:
|
||||
if(m_closed)
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size())
|
||||
{
|
||||
m_prev_status = close_first;
|
||||
m_status = end_poly1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(m_src_vertex >= m_src_vertices.size() - 1)
|
||||
{
|
||||
m_status = cap2;
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_stroker.calc_join(m_out_vertices,
|
||||
m_src_vertices.prev(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex),
|
||||
m_src_vertices.next(m_src_vertex),
|
||||
m_src_vertices.prev(m_src_vertex).dist,
|
||||
m_src_vertices.curr(m_src_vertex).dist);
|
||||
++m_src_vertex;
|
||||
m_prev_status = m_status;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case close_first:
|
||||
m_status = outline2;
|
||||
cmd = path_cmd_move_to;
|
||||
|
||||
case outline2:
|
||||
if(m_src_vertex <= unsigned(m_closed == 0))
|
||||
{
|
||||
m_status = end_poly2;
|
||||
m_prev_status = stop;
|
||||
break;
|
||||
}
|
||||
|
||||
--m_src_vertex;
|
||||
m_stroker.calc_join(m_out_vertices,
|
||||
m_src_vertices.next(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex),
|
||||
m_src_vertices.prev(m_src_vertex),
|
||||
m_src_vertices.curr(m_src_vertex).dist,
|
||||
m_src_vertices.prev(m_src_vertex).dist);
|
||||
|
||||
m_prev_status = m_status;
|
||||
m_status = out_vertices;
|
||||
m_out_vertex = 0;
|
||||
break;
|
||||
|
||||
case out_vertices:
|
||||
if(m_out_vertex >= m_out_vertices.size())
|
||||
{
|
||||
m_status = m_prev_status;
|
||||
}
|
||||
else
|
||||
{
|
||||
const point_d& c = m_out_vertices[m_out_vertex++];
|
||||
*x = c.x;
|
||||
*y = c.y;
|
||||
return cmd;
|
||||
}
|
||||
break;
|
||||
|
||||
case end_poly1:
|
||||
m_status = m_prev_status;
|
||||
return path_cmd_end_poly | path_flags_close | path_flags_ccw;
|
||||
|
||||
case end_poly2:
|
||||
m_status = m_prev_status;
|
||||
return path_cmd_end_poly | path_flags_close | path_flags_cw;
|
||||
|
||||
case stop:
|
||||
cmd = path_cmd_stop;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return cmd;
|
||||
}
|
||||
|
||||
}
|
@ -26,16 +26,59 @@ def copyFile(src, dst):
|
||||
shutil.copyfile(s, d)
|
||||
|
||||
H_FILES=[
|
||||
"agg_array.h",
|
||||
"agg_basics.h",
|
||||
"agg_clip_liang_barsky.h",
|
||||
"agg_color_gray.h",
|
||||
"agg_color_rgba.h",
|
||||
"agg_config.h",
|
||||
"agg_conv_adaptor_vcgen.h",
|
||||
"agg_conv_stroke.h",
|
||||
"agg_dda_line.h",
|
||||
"agg_gamma_functions.h",
|
||||
"agg_gamma_lut.h",
|
||||
"agg_image_accessors.h",
|
||||
"agg_image_filters.h",
|
||||
"agg_math.h",
|
||||
"agg_math_stroke.h",
|
||||
"agg_pixfmt_base.h",
|
||||
"agg_pixfmt_rgba.h",
|
||||
"agg_pixfmt_rgb.h",
|
||||
"agg_pixfmt_rgb_packed.h",
|
||||
"agg_rasterizer_cells_aa.h",
|
||||
"agg_rasterizer_scanline_aa.h",
|
||||
"agg_rasterizer_scanline_aa_nogamma.h",
|
||||
"agg_rasterizer_sl_clip.h",
|
||||
"agg_renderer_base.h",
|
||||
"agg_renderer_scanline.h",
|
||||
"agg_rendering_buffer.h",
|
||||
"agg_scanline_u.h",
|
||||
"agg_shorten_path.h",
|
||||
"agg_span_allocator.h",
|
||||
"agg_span_image_filter.h",
|
||||
"agg_span_image_filter_rgba.h",
|
||||
"agg_span_image_filter_rgb.h",
|
||||
"agg_span_interpolator_linear.h",
|
||||
"agg_trans_affine.h",
|
||||
"agg_trans_viewport.h",
|
||||
"agg_vcgen_stroke.h",
|
||||
"agg_vertex_sequence.h"
|
||||
]
|
||||
|
||||
for f in H_FILES:
|
||||
src=os.path.join('agg', f);
|
||||
dst=os.path.join('agg', f);
|
||||
src=os.path.join('include', f);
|
||||
dst=os.path.join('include', f);
|
||||
copyFile(src, dst)
|
||||
|
||||
SRC_FILES=[]
|
||||
SRC_FILES=[
|
||||
"agg_color_rgba.cpp",
|
||||
"agg_image_filters.cpp",
|
||||
"agg_sqrt_tables.cpp",
|
||||
"agg_trans_affine.cpp",
|
||||
"agg_vcgen_stroke.cpp"
|
||||
]
|
||||
for f in SRC_FILES:
|
||||
src=os.path.join('src/agg', f);
|
||||
dst=os.path.join('agg', f);
|
||||
src=os.path.join('src', f);
|
||||
dst=os.path.join('src', f);
|
||||
copyFile(src, dst)
|
||||
|
||||
|
13
3rd/nanovg/README.md
Normal file
13
3rd/nanovg/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# nanovg的backend
|
||||
|
||||
nanovg支持下列backend:
|
||||
|
||||
* 1.gl 基于OpenGL/GLES实现(nanovg内置)。
|
||||
|
||||
* 2.agg 基于agg实现。纯软件实现,渲染效果好,速度较慢,适合没有GPU的嵌入平台。(注意:目前不支持565格式的图片,请勿定义WITH\_BITMAP\_BGR565)。
|
||||
|
||||
* 3.agge 基于agg实现。纯软件实现,渲染效果一般,速度较agg快,适合没有GPU的嵌入平台。
|
||||
|
||||
* 4.bgfx 基于bgfx实现。支持多种渲染方式(OpenGL/metal/vulkan/DirectX),推荐在Android、iOS、Linux、MacOS、Windows等平台上使用。
|
||||
|
||||
|
@ -3,15 +3,26 @@ import os
|
||||
env=DefaultEnvironment().Clone()
|
||||
LIB_DIR=os.environ['LIB_DIR'];
|
||||
BIN_DIR=os.environ['BIN_DIR'];
|
||||
|
||||
env.Library(os.path.join(LIB_DIR, 'nanovg'), Glob('base/*.c'))
|
||||
|
||||
NANOVG_BACKEND=os.environ['NANOVG_BACKEND'];
|
||||
if NANOVG_BACKEND == 'AGG':
|
||||
env.Library(os.path.join(LIB_DIR, 'nanovg-agg'), Glob('agg/*.cpp'))
|
||||
|
||||
env['LIBS'] = ['nanovg-agg', 'agg', 'nanovg'] + env['LIBS']
|
||||
env.Program(os.path.join(BIN_DIR, 'agg_stroke'), Glob('demos/agg_stroke.c'));
|
||||
env.Program(os.path.join(BIN_DIR, 'agg_fill'), Glob('demos/agg_fill.c'));
|
||||
env.Program(os.path.join(BIN_DIR, 'agg_draw_image'), Glob('demos/agg_draw_image.c'));
|
||||
|
||||
elif NANOVG_BACKEND == 'AGGE':
|
||||
env.Library(os.path.join(LIB_DIR, 'nanovg-agge'), Glob('agge/*.cpp'))
|
||||
|
||||
env['LIBS'] = ['nanovg-agge', 'nanovg'] + env['LIBS']
|
||||
|
||||
env['LIBS'] = ['nanovg-agge', 'agge', 'nanovg'] + env['LIBS']
|
||||
env.Program(os.path.join(BIN_DIR, 'agge_stroke'), Glob('demos/agge_stroke.c'));
|
||||
env.Program(os.path.join(BIN_DIR, 'agge_fill'), Glob('demos/agge_fill.c'));
|
||||
env.Program(os.path.join(BIN_DIR, 'agge_draw_image'), Glob('demos/agge_draw_image.c'));
|
||||
elif NANOVG_BACKEND == 'BGFX':
|
||||
print("not supported yet");
|
||||
|
||||
|
||||
#env.Program(os.path.join(BIN_DIR, 'agg_stroke'), Glob('demos/agg_stroke.c'));
|
||||
#env.Program(os.path.join(BIN_DIR, 'agg_fill'), Glob('demos/agg_fill.c'));
|
||||
#env.Program(os.path.join(BIN_DIR, 'agg_draw_image'), Glob('demos/agg_draw_image.c'));
|
||||
|
434
3rd/nanovg/agg/nanovg_agg.cpp
Normal file
434
3rd/nanovg/agg/nanovg_agg.cpp
Normal file
@ -0,0 +1,434 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include "nanovg_agg.h"
|
||||
#include "nanovg_vertex.h"
|
||||
|
||||
#include "agg_basics.h"
|
||||
#include "agg_conv_stroke.h"
|
||||
#include "agg_scanline_u.h"
|
||||
#include "agg_pixfmt_rgb.h"
|
||||
#include "agg_pixfmt_rgba.h"
|
||||
#include "agg_pixfmt_rgb_packed.h"
|
||||
|
||||
#include "agg_platform_support.h"
|
||||
#include "agg_rendering_buffer.h"
|
||||
#include "agg_renderer_scanline.h"
|
||||
#include "agg_rasterizer_scanline_aa.h"
|
||||
|
||||
#include "agg_image_accessors.h"
|
||||
#include "agg_span_allocator.h"
|
||||
#include "agg_span_image_filter_rgb.h"
|
||||
#include "agg_span_image_filter_rgba.h"
|
||||
|
||||
struct AGGNVGtexture {
|
||||
int id;
|
||||
int tex;
|
||||
int width;
|
||||
int height;
|
||||
int type;
|
||||
int flags;
|
||||
const uint8_t* data;
|
||||
};
|
||||
typedef struct AGGNVGtexture AGGNVGtexture;
|
||||
|
||||
struct AGGNVGcontext {
|
||||
AGGNVGcontext() {
|
||||
this->w = 0;
|
||||
this->h = 0;
|
||||
this->data = NULL;
|
||||
this->textures = NULL;
|
||||
this->ntextures = 0;
|
||||
this->ctextures = 0;
|
||||
this->textureId = 0;
|
||||
}
|
||||
|
||||
~AGGNVGcontext() {
|
||||
free(this->textures);
|
||||
this->textures = NULL;
|
||||
}
|
||||
|
||||
int ntextures;
|
||||
int ctextures;
|
||||
int textureId;
|
||||
AGGNVGtexture* textures;
|
||||
|
||||
/*fill/stroke color*/
|
||||
uint8_t r;
|
||||
uint8_t g;
|
||||
uint8_t b;
|
||||
uint8_t a;
|
||||
|
||||
/*frame buffer*/
|
||||
int32_t w;
|
||||
int32_t h;
|
||||
int32_t stride;
|
||||
uint8_t* data;
|
||||
enum NVGtexture format;
|
||||
|
||||
/*agg related*/
|
||||
agg::rendering_buffer rbuf;
|
||||
agg::rasterizer_scanline_aa<> ras;
|
||||
};
|
||||
|
||||
static int aggnvg__maxi(int a, int b) {
|
||||
return a > b ? a : b;
|
||||
}
|
||||
|
||||
static AGGNVGtexture* aggnvg__allocTexture(AGGNVGcontext* agg) {
|
||||
int i;
|
||||
AGGNVGtexture* tex = NULL;
|
||||
|
||||
for (i = 0; i < agg->ntextures; i++) {
|
||||
if (agg->textures[i].id == 0) {
|
||||
tex = &agg->textures[i];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tex == NULL) {
|
||||
if (agg->ntextures + 1 > agg->ctextures) {
|
||||
AGGNVGtexture* textures;
|
||||
int ctextures =
|
||||
aggnvg__maxi(agg->ntextures + 1, 4) + agg->ctextures / 2; // 1.5x Overallocate
|
||||
textures = (AGGNVGtexture*)realloc(agg->textures, sizeof(AGGNVGtexture) * ctextures);
|
||||
if (textures == NULL) return NULL;
|
||||
agg->textures = textures;
|
||||
agg->ctextures = ctextures;
|
||||
}
|
||||
tex = &agg->textures[agg->ntextures++];
|
||||
}
|
||||
|
||||
memset(tex, 0, sizeof(*tex));
|
||||
tex->id = ++agg->textureId;
|
||||
|
||||
return tex;
|
||||
}
|
||||
|
||||
static AGGNVGtexture* aggnvg__findTexture(AGGNVGcontext* agg, int id) {
|
||||
int i;
|
||||
for (i = 0; i < agg->ntextures; i++)
|
||||
if (agg->textures[i].id == id) return &agg->textures[i];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int aggnvg__deleteTexture(AGGNVGcontext* agg, int id) {
|
||||
int i;
|
||||
for (i = 0; i < agg->ntextures; i++) {
|
||||
if (agg->textures[i].id == id) {
|
||||
memset(&agg->textures[i], 0, sizeof(agg->textures[i]));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int aggnvg__renderCreate(void* uptr) {
|
||||
NVG_NOTUSED(uptr);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aggnvg__renderCreateTexture(void* uptr, int type, int w, int h, int imageFlags,
|
||||
const unsigned char* data) {
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
AGGNVGtexture* tex = aggnvg__allocTexture(agg);
|
||||
|
||||
if (tex == NULL) return 0;
|
||||
|
||||
tex->width = w;
|
||||
tex->height = h;
|
||||
tex->type = type;
|
||||
tex->data = data;
|
||||
tex->flags = imageFlags;
|
||||
|
||||
return tex->id;
|
||||
}
|
||||
|
||||
static int aggnvg__renderDeleteTexture(void* uptr, int image) {
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
return aggnvg__deleteTexture(agg, image);
|
||||
}
|
||||
|
||||
static int aggnvg__renderUpdateTexture(void* uptr, int image, int x, int y, int w, int h,
|
||||
const unsigned char* data) {
|
||||
NVG_NOTUSED(x);
|
||||
NVG_NOTUSED(y);
|
||||
NVG_NOTUSED(w);
|
||||
NVG_NOTUSED(h);
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
AGGNVGtexture* tex = aggnvg__findTexture(agg, image);
|
||||
if (tex == NULL) return 0;
|
||||
|
||||
tex->data = data;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int aggnvg__renderGetTextureSize(void* uptr, int image, int* w, int* h) {
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
AGGNVGtexture* tex = aggnvg__findTexture(agg, image);
|
||||
if (tex == NULL) return 0;
|
||||
*w = tex->width;
|
||||
*h = tex->height;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void aggnvg__renderViewport(void* uptr, float width, float height, float devicePixelRatio) {
|
||||
NVG_NOTUSED(uptr);
|
||||
NVG_NOTUSED(width);
|
||||
NVG_NOTUSED(height);
|
||||
NVG_NOTUSED(devicePixelRatio);
|
||||
}
|
||||
|
||||
static void aggnvg__renderCancel(void* uptr) {
|
||||
NVG_NOTUSED(uptr);
|
||||
}
|
||||
|
||||
static void aggnvg__renderFlush(void* uptr) {
|
||||
NVG_NOTUSED(uptr);
|
||||
}
|
||||
|
||||
static void prepareRasterizer(AGGNVGcontext* agg, NVGscissor* scissor, NVGpaint* paint) {
|
||||
agg::rasterizer_scanline_aa<>& ras = agg->ras;
|
||||
agg::rendering_buffer& rbuf = agg->rbuf;
|
||||
float_t clip_w = scissor->extent[0] * 2;
|
||||
float_t clip_h = scissor->extent[1] * 2;
|
||||
float_t clip_x = scissor->xform[4] - scissor->extent[0];
|
||||
float_t clip_y = scissor->xform[5] - scissor->extent[1];
|
||||
|
||||
rbuf.attach(agg->data, agg->w, agg->h, agg->stride);
|
||||
|
||||
ras.reset();
|
||||
if(clip_w > 0 && clip_h > 0) {
|
||||
ras.clip_box(clip_x, clip_y, clip_x+clip_w, clip_y+clip_h);
|
||||
}
|
||||
|
||||
agg->r = paint->innerColor.r * 0xff;
|
||||
agg->g = paint->innerColor.g * 0xff;
|
||||
agg->b = paint->innerColor.b * 0xff;
|
||||
agg->a = paint->innerColor.a * 0xff;
|
||||
}
|
||||
|
||||
template <typename PixelT>
|
||||
void renderPaint(AGGNVGcontext* agg, NVGpaint* paint) {
|
||||
agg::scanline_u8 sl;
|
||||
PixelT pixf(agg->rbuf);
|
||||
agg::span_allocator<agg::rgba8> sa;
|
||||
agg::renderer_base<PixelT> ren(pixf);
|
||||
agg::rasterizer_scanline_aa<>& ras = agg->ras;
|
||||
|
||||
if (paint->image > 0) {
|
||||
AGGNVGtexture* tex = aggnvg__findTexture(agg, paint->image);
|
||||
float invxform[6];
|
||||
int32_t img_w = tex->width;
|
||||
int32_t img_h = tex->height;
|
||||
uint8_t* img_data = (uint8_t*)(tex->data);
|
||||
|
||||
nvgTransformInverse(invxform, paint->xform);
|
||||
agg::trans_affine img_mtx(invxform[0], invxform[1], invxform[2], invxform[3], invxform[4], invxform[5]);
|
||||
agg::span_interpolator_linear<> interpolator(img_mtx);
|
||||
|
||||
switch (tex->type) {
|
||||
case NVG_TEXTURE_RGBA: {
|
||||
agg::rendering_buffer img_rbuf(img_data, img_w, img_h, img_w * 4);
|
||||
agg::pixfmt_rgba32 img_pixf(img_rbuf);
|
||||
agg::span_image_filter_rgba_bilinear_clip<agg::pixfmt_rgba32, agg::span_interpolator_linear<> > sg(img_pixf, agg::rgba(0, 0, 0, 0), interpolator);
|
||||
|
||||
agg::render_scanlines_aa(ras, sl, ren, sa, sg);
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_BGRA: {
|
||||
agg::rendering_buffer img_rbuf(img_data, img_w, img_h, img_w * 4);
|
||||
agg::pixfmt_bgra32 img_pixf(img_rbuf);
|
||||
agg::span_image_filter_rgba_bilinear_clip<agg::pixfmt_bgra32, agg::span_interpolator_linear<> > sg(img_pixf, agg::rgba(0, 0, 0, 0), interpolator);
|
||||
|
||||
agg::render_scanlines_aa(ras, sl, ren, sa, sg);
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_BGR565: {
|
||||
/*FIXME:*/
|
||||
assert(!"not supported format");
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_RGB: {
|
||||
agg::rendering_buffer img_rbuf(img_data, img_w, img_h, img_w * 3);
|
||||
agg::pixfmt_rgb24 img_pixf(img_rbuf);
|
||||
agg::span_image_filter_rgb_bilinear_clip<agg::pixfmt_rgb24, agg::span_interpolator_linear<> > sg(img_pixf, agg::rgba(0, 0, 0, 0), interpolator);
|
||||
|
||||
agg::render_scanlines_aa(ras, sl, ren, sa, sg);
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_BGR: {
|
||||
agg::rendering_buffer img_rbuf(img_data, img_w, img_h, img_w * 3);
|
||||
agg::pixfmt_bgr24 img_pixf(img_rbuf);
|
||||
agg::span_image_filter_rgb_bilinear_clip<agg::pixfmt_bgr24, agg::span_interpolator_linear<> > sg(img_pixf, agg::rgba(0, 0, 0, 0), interpolator);
|
||||
|
||||
agg::render_scanlines_aa(ras, sl, ren, sa, sg);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(!"not supported format");
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
agg::render_scanlines_aa_solid(ras, sl, ren, agg::srgba8(agg->r,agg->g,agg->b, agg->a));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <typename PixelT>
|
||||
void renderFill(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation,
|
||||
NVGscissor* scissor, float fringe, const float* bounds, const NVGpath* paths,
|
||||
int npaths) {
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
|
||||
prepareRasterizer(agg, scissor, paint);
|
||||
|
||||
agg::rasterizer_scanline_aa<>& ras = agg->ras;
|
||||
|
||||
ras.reset();
|
||||
for (int i = 0; i < npaths; i++) {
|
||||
const NVGpath* p = paths + i;
|
||||
for (int j = 0; j < p->nfill; j++) {
|
||||
const NVGvertex* v = p->fill + j;
|
||||
if (j == 0) {
|
||||
ras.move_to_d(v->x, v->y);
|
||||
} else {
|
||||
ras.line_to_d(v->x, v->y);
|
||||
}
|
||||
}
|
||||
ras.close_polygon();
|
||||
}
|
||||
|
||||
ras.sort();
|
||||
renderPaint<PixelT>(agg, paint);
|
||||
}
|
||||
|
||||
template <typename PixelT>
|
||||
void renderStroke(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation,
|
||||
NVGscissor* scissor, float fringe, float strokeWidth, const NVGpath* paths,
|
||||
int npaths) {
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
|
||||
prepareRasterizer(agg, scissor, paint);
|
||||
|
||||
agg::rasterizer_scanline_aa<>& ras = agg->ras;
|
||||
|
||||
ras.reset();
|
||||
for (int i = 0; i < npaths; i++) {
|
||||
const NVGpath* p = paths + i;
|
||||
|
||||
agg::nanovg_vertex v(p->stroke, p->nstroke);
|
||||
agg::conv_stroke<agg::nanovg_vertex> path(v);
|
||||
path.width(strokeWidth);
|
||||
ras.add_path(path);
|
||||
}
|
||||
|
||||
ras.sort();
|
||||
renderPaint<PixelT>(agg, paint);
|
||||
}
|
||||
|
||||
template <typename PixelT>
|
||||
void renderTriangles(void* uptr, NVGpaint* paint, NVGcompositeOperationState compositeOperation,
|
||||
NVGscissor* scissor, const NVGvertex* verts, int nverts) {
|
||||
}
|
||||
|
||||
static void aggnvg__renderDelete(void* uptr) {
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)uptr;
|
||||
if (agg == NULL) return;
|
||||
|
||||
delete agg;
|
||||
}
|
||||
|
||||
static void nvgInitAGG(AGGNVGcontext* agg, NVGparams* params, int32_t w, int32_t h,
|
||||
enum NVGtexture format, uint8_t* data) {
|
||||
agg->w = w;
|
||||
agg->h = h;
|
||||
agg->data = data;
|
||||
agg->format = format;
|
||||
params->renderTriangles = NULL;
|
||||
|
||||
switch (agg->format) {
|
||||
case NVG_TEXTURE_BGRA: {
|
||||
params->renderStroke = renderStroke<agg::pixfmt_bgra32>;
|
||||
params->renderFill = renderFill<agg::pixfmt_bgra32>;
|
||||
agg->stride = w * 4;
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_RGBA: {
|
||||
params->renderStroke = renderStroke<agg::pixfmt_rgba32>;
|
||||
params->renderFill = renderFill<agg::pixfmt_rgba32>;
|
||||
agg->stride = w * 4;
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_BGR: {
|
||||
params->renderStroke = renderStroke<agg::pixfmt_bgr24>;
|
||||
params->renderFill = renderFill<agg::pixfmt_bgr24>;
|
||||
agg->stride = w * 3;
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_RGB: {
|
||||
params->renderStroke = renderStroke<agg::pixfmt_rgb24>;
|
||||
params->renderFill = renderFill<agg::pixfmt_rgb24>;
|
||||
agg->stride = w * 3;
|
||||
break;
|
||||
}
|
||||
case NVG_TEXTURE_BGR565: {
|
||||
params->renderStroke = renderStroke<agg::pixfmt_rgb565>;
|
||||
params->renderFill = renderFill<agg::pixfmt_rgb565>;
|
||||
agg->stride = w * 2;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(!"not supported format");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, enum NVGtexture format,
|
||||
uint8_t* data) {
|
||||
NVGparams* params = nvgGetParams(ctx);
|
||||
AGGNVGcontext* agg = (AGGNVGcontext*)(params->userPtr);
|
||||
|
||||
nvgInitAGG(agg, params, w, h, format, data);
|
||||
}
|
||||
|
||||
NVGcontext* nvgCreateAGG(int32_t w, int32_t h, enum NVGtexture format, uint8_t* data) {
|
||||
NVGparams params;
|
||||
NVGcontext* ctx = NULL;
|
||||
AGGNVGcontext* agg = new AGGNVGcontext();
|
||||
|
||||
if (agg == NULL) goto error;
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
params.renderCreate = aggnvg__renderCreate;
|
||||
params.renderCreateTexture = aggnvg__renderCreateTexture;
|
||||
params.renderDeleteTexture = aggnvg__renderDeleteTexture;
|
||||
params.renderUpdateTexture = aggnvg__renderUpdateTexture;
|
||||
params.renderGetTextureSize = aggnvg__renderGetTextureSize;
|
||||
params.renderViewport = aggnvg__renderViewport;
|
||||
params.renderCancel = aggnvg__renderCancel;
|
||||
params.renderFlush = aggnvg__renderFlush;
|
||||
params.renderDelete = aggnvg__renderDelete;
|
||||
params.userPtr = agg;
|
||||
params.edgeAntiAlias = 1;
|
||||
|
||||
nvgInitAGG(agg, ¶ms, w, h, format, data);
|
||||
|
||||
ctx = nvgCreateInternal(¶ms);
|
||||
if (ctx == NULL) goto error;
|
||||
|
||||
return ctx;
|
||||
|
||||
error:
|
||||
if (ctx != NULL) nvgDeleteInternal(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void nvgDeleteAGG(NVGcontext* ctx) {
|
||||
nvgDeleteInternal(ctx);
|
||||
}
|
26
3rd/nanovg/agg/nanovg_agg.h
Normal file
26
3rd/nanovg/agg/nanovg_agg.h
Normal file
@ -0,0 +1,26 @@
|
||||
#ifndef NANOVG_AGG_H
|
||||
#define NANOVG_AGG_H
|
||||
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "nanovg.h"
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.1415926f
|
||||
#endif /*M_PI*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
NVGcontext* nvgCreateAGG(int32_t w, int32_t h, enum NVGtexture format, uint8_t* data);
|
||||
void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, enum NVGtexture, uint8_t* data);
|
||||
void nvgDeleteAGG(NVGcontext* ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* NANOVG_AGG_H */
|
52
3rd/nanovg/agg/nanovg_vertex.h
Normal file
52
3rd/nanovg/agg/nanovg_vertex.h
Normal file
@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "nanovg.h"
|
||||
#include "agg_basics.h"
|
||||
|
||||
namespace agg {
|
||||
class nanovg_vertex {
|
||||
public:
|
||||
class iterator;
|
||||
|
||||
public:
|
||||
nanovg_vertex(NVGvertex* vertex, int n) {
|
||||
_n = n;
|
||||
_index = 0;
|
||||
_vertex = vertex;
|
||||
}
|
||||
|
||||
void rewind(unsigned) {
|
||||
_index = 0;
|
||||
}
|
||||
|
||||
unsigned vertex(double* x, double* y) {
|
||||
int index = _index++;
|
||||
NVGvertex* p = _vertex + index;
|
||||
|
||||
if (index < _n) {
|
||||
*x = p->x;
|
||||
*y = p->y;
|
||||
|
||||
if (index == 0) {
|
||||
return path_cmd_move_to;
|
||||
} else if (index == (_n - 1)) {
|
||||
if (p->x == _vertex[0].x && p->y == _vertex[0].y) {
|
||||
return (path_cmd_end_poly | path_flags_close);
|
||||
} else {
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
} else {
|
||||
return path_cmd_line_to;
|
||||
}
|
||||
} else {
|
||||
return path_cmd_stop;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
int _n;
|
||||
int _index;
|
||||
NVGvertex* _vertex;
|
||||
};
|
||||
|
||||
} // namespace agg
|
@ -70,7 +70,7 @@ struct AGGENVGcontext {
|
||||
int32_t w;
|
||||
int32_t h;
|
||||
uint8_t* data;
|
||||
agge_bitmap_format_t format;
|
||||
enum NVGtexture format;
|
||||
|
||||
/*agge related*/
|
||||
agge::renderer ren;
|
||||
@ -331,38 +331,38 @@ static void aggenvg__renderDelete(void* uptr) {
|
||||
}
|
||||
|
||||
static void nvgInitAGGE(AGGENVGcontext* agge, NVGparams* params, int32_t w, int32_t h,
|
||||
agge_bitmap_format_t format, uint8_t* data) {
|
||||
enum NVGtexture format, uint8_t* data) {
|
||||
agge->w = w;
|
||||
agge->h = h;
|
||||
agge->data = data;
|
||||
agge->format = format;
|
||||
|
||||
switch (agge->format) {
|
||||
case AGGE_RGBA8888: {
|
||||
case NVG_TEXTURE_RGBA: {
|
||||
params->renderTriangles = renderTriangles<agge::pixel32_rgba>;
|
||||
params->renderStroke = renderStroke<agge::pixel32_rgba>;
|
||||
params->renderFill = renderFill<agge::pixel32_rgba>;
|
||||
break;
|
||||
}
|
||||
case AGGE_BGRA8888: {
|
||||
case NVG_TEXTURE_BGRA: {
|
||||
params->renderTriangles = renderTriangles<agge::pixel32_bgra>;
|
||||
params->renderStroke = renderStroke<agge::pixel32_bgra>;
|
||||
params->renderFill = renderFill<agge::pixel32_bgra>;
|
||||
break;
|
||||
}
|
||||
case AGGE_RGB888: {
|
||||
case NVG_TEXTURE_RGB: {
|
||||
params->renderTriangles = renderTriangles<agge::pixel24_rgb>;
|
||||
params->renderStroke = renderStroke<agge::pixel24_rgb>;
|
||||
params->renderFill = renderFill<agge::pixel24_rgb>;
|
||||
break;
|
||||
}
|
||||
case AGGE_BGR888: {
|
||||
case NVG_TEXTURE_BGR: {
|
||||
params->renderTriangles = renderTriangles<agge::pixel24_bgr>;
|
||||
params->renderStroke = renderStroke<agge::pixel24_bgr>;
|
||||
params->renderFill = renderFill<agge::pixel24_bgr>;
|
||||
break;
|
||||
}
|
||||
case AGGE_BGR565: {
|
||||
case NVG_TEXTURE_BGR565: {
|
||||
params->renderTriangles = renderTriangles<agge::pixel16_bgr565>;
|
||||
params->renderStroke = renderStroke<agge::pixel16_bgr565>;
|
||||
params->renderFill = renderFill<agge::pixel16_bgr565>;
|
||||
@ -375,7 +375,7 @@ static void nvgInitAGGE(AGGENVGcontext* agge, NVGparams* params, int32_t w, int3
|
||||
}
|
||||
}
|
||||
|
||||
void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, agge_bitmap_format_t format,
|
||||
void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, enum NVGtexture format,
|
||||
uint8_t* data) {
|
||||
NVGparams* params = nvgGetParams(ctx);
|
||||
AGGENVGcontext* agge = (AGGENVGcontext*)(params->userPtr);
|
||||
@ -383,7 +383,7 @@ void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, agge_bitmap_format_t f
|
||||
nvgInitAGGE(agge, params, w, h, format, data);
|
||||
}
|
||||
|
||||
NVGcontext* nvgCreateAGGE(int32_t w, int32_t h, agge_bitmap_format_t format, uint8_t* data) {
|
||||
NVGcontext* nvgCreateAGGE(int32_t w, int32_t h, enum NVGtexture format, uint8_t* data) {
|
||||
NVGparams params;
|
||||
NVGcontext* ctx = NULL;
|
||||
AGGENVGcontext* agge = new AGGENVGcontext();
|
||||
|
@ -15,17 +15,8 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef enum _agge_bitmap_format_t {
|
||||
AGGE_RGBA8888 = 0,
|
||||
AGGE_BGRA8888,
|
||||
AGGE_RGB888,
|
||||
AGGE_BGR888,
|
||||
AGGE_RGB565,
|
||||
AGGE_BGR565
|
||||
} agge_bitmap_format_t;
|
||||
|
||||
NVGcontext* nvgCreateAGGE(int32_t w, int32_t h, agge_bitmap_format_t format, uint8_t* data);
|
||||
void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, agge_bitmap_format_t format,
|
||||
NVGcontext* nvgCreateAGGE(int32_t w, int32_t h, enum NVGtexture format, uint8_t* data);
|
||||
void nvgReinitAgge(NVGcontext* ctx, int32_t w, int32_t h, enum NVGtexture format,
|
||||
uint8_t* data);
|
||||
void nvgDeleteAGGE(NVGcontext* ctx);
|
||||
|
||||
|
@ -621,7 +621,8 @@ enum NVGtexture {
|
||||
NVG_TEXTURE_BGRA = 0x04,
|
||||
NVG_TEXTURE_RGB = 0x08,
|
||||
NVG_TEXTURE_BGR = 0x16,
|
||||
NVG_TEXTURE_BGR565 = 0x32
|
||||
NVG_TEXTURE_RGB565 = 0x32,
|
||||
NVG_TEXTURE_BGR565 = 0x64
|
||||
};
|
||||
|
||||
struct NVGscissor {
|
||||
|
1
3rd/nanovg/bgfx/TODO
Normal file
1
3rd/nanovg/bgfx/TODO
Normal file
@ -0,0 +1 @@
|
||||
todo
|
@ -1,6 +1,6 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "nanovg_agg.h"
|
||||
#include "agg/nanovg_agg.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "../stb/stb_image_write.h"
|
||||
@ -10,18 +10,10 @@
|
||||
|
||||
#include "draw_image.inc"
|
||||
|
||||
static int load_image(NVGcontext* vg, const char* filename, int32_t* comp, int32_t* iw, int32_t* ih) {
|
||||
|
||||
uint8_t* data = stbi_load(filename, iw, ih, comp, 4);
|
||||
|
||||
return nvgCreateImageRaw(vg, *iw, *ih, NVG_TEXTURE_RGBA, 0, data);
|
||||
}
|
||||
|
||||
|
||||
static void run_test(int32_t w, int32_t h, int32_t BPP, const char* filename) {
|
||||
int32_t size = w * h * BPP;
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
NVGcontext* vg = nvgCreateAGG(w, h, BPP == 2 ? AGG_RGB565 : AGG_RGBA8888, data);
|
||||
NVGcontext* vg = nvgCreateAGG(w, h, BPP == 2 ? NVG_TEXTURE_BGR565 : NVG_TEXTURE_RGBA, data);
|
||||
|
||||
memset(data, 0xff, size);
|
||||
do_draw(vg, w, h);
|
||||
|
@ -1,6 +1,6 @@
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "nanovg-agg/nanovg_agg.h"
|
||||
#include "agg/nanovg_agg.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "../stb/stb_image_write.h"
|
||||
@ -13,7 +13,7 @@
|
||||
static void run_test(int32_t w, int32_t h, int32_t BPP, const char* filename) {
|
||||
int32_t size = w * h * BPP;
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
NVGcontext* vg = nvgCreateAGG(w, h, BPP == 2 ? AGGE_RGB565 : AGGE_RGBA8888, data);
|
||||
NVGcontext* vg = nvgCreateAGG(w, h, BPP == 2 ? NVG_TEXTURE_BGR565 : NVG_TEXTURE_RGBA, data);
|
||||
|
||||
memset(data, 0xff, size);
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "agge/nanovg_agg.h"
|
||||
#include "agg/nanovg_agg.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "../stb/stb_image_write.h"
|
||||
@ -14,7 +14,7 @@
|
||||
static void run_test(int32_t w, int32_t h, int32_t BPP, const char* filename) {
|
||||
int32_t size = w * h * BPP;
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
NVGcontext* vg = nvgCreateAGG(w, h, BPP == 2 ? AGG_RGB565 : AGG_RGBA8888, data);
|
||||
NVGcontext* vg = nvgCreateAGG(w, h, BPP == 2 ? NVG_TEXTURE_BGR565 : NVG_TEXTURE_RGBA, data);
|
||||
|
||||
memset(data, 0xff, size);
|
||||
do_stroke(vg, w, h);
|
||||
|
@ -13,7 +13,7 @@
|
||||
static void run_test(int32_t w, int32_t h, int32_t BPP, const char* filename) {
|
||||
int32_t size = w * h * BPP;
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
NVGcontext* vg = nvgCreateAGGE(w, h, BPP == 2 ? AGGE_BGR565 : AGGE_RGBA8888, data);
|
||||
NVGcontext* vg = nvgCreateAGGE(w, h, BPP == 2 ? NVG_TEXTURE_BGR565 : NVG_TEXTURE_BGRA, data);
|
||||
|
||||
memset(data, 0xff, size);
|
||||
do_draw(vg, w, h);
|
||||
|
@ -13,7 +13,7 @@
|
||||
static void run_test(int32_t w, int32_t h, int32_t BPP, const char* filename) {
|
||||
int32_t size = w * h * BPP;
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
NVGcontext* vg = nvgCreateAGGE(w, h, BPP == 2 ? AGGE_BGR565 : AGGE_RGBA8888, data);
|
||||
NVGcontext* vg = nvgCreateAGGE(w, h, BPP == 2 ? NVG_TEXTURE_BGR565 : NVG_TEXTURE_BGRA, data);
|
||||
|
||||
memset(data, 0xff, size);
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
static void run_test(int32_t w, int32_t h, int32_t BPP, const char* filename) {
|
||||
int32_t size = w * h * BPP;
|
||||
uint8_t* data = (uint8_t*)malloc(size);
|
||||
NVGcontext* vg = nvgCreateAGGE(w, h, BPP == 2 ? AGGE_BGR565 : AGGE_RGBA8888, data);
|
||||
NVGcontext* vg = nvgCreateAGGE(w, h, BPP == 2 ? NVG_TEXTURE_BGR565 : NVG_TEXTURE_BGRA, data);
|
||||
|
||||
memset(data, 0xff, size);
|
||||
do_stroke(vg, w, h);
|
||||
|
@ -27,7 +27,7 @@ static void do_draw(NVGcontext* vg, int32_t w, int32_t h) {
|
||||
int32_t iw = 0;
|
||||
int32_t ih = 0;
|
||||
int32_t comp = 4;
|
||||
int img = load_image(vg, "demos/rgb.png", &comp, &iw, &ih);
|
||||
int img = load_image(vg, "demos/assets/raw/images/x2/rgb.png", &comp, &iw, &ih);
|
||||
|
||||
nvgBeginFrame(vg, w, h, 1);
|
||||
|
||||
@ -37,7 +37,7 @@ static void do_draw(NVGcontext* vg, int32_t w, int32_t h) {
|
||||
draw_image(vg, imgPaint, 0, 0, iw, ih, 10, 100, iw*2, ih*2);
|
||||
|
||||
|
||||
int img2 = load_image(vg, "demos/rgba.png", &comp, &iw, &ih);
|
||||
int img2 = load_image(vg, "demos/assets/raw/images/x2/rgba.png", &comp, &iw, &ih);
|
||||
NVGpaint imgPaint2 = nvgImagePattern(vg, 0, 0, iw, ih, 0, img2, 1);
|
||||
|
||||
nvgTranslate(vg, 100, 100);
|
||||
|
11
README.md
11
README.md
@ -171,6 +171,17 @@ bin\demoui
|
||||
|
||||
## 最新动态
|
||||
|
||||
* 2018/10/15
|
||||
* 用agg实现nanovg的渲染后端。
|
||||
* 更新文档、编译脚本并测试。
|
||||
|
||||
* 2018/10/14
|
||||
* 用agg实现nanovg的渲染后端。
|
||||
|
||||
* 2018/10/13
|
||||
* 重新整理第三方库。
|
||||
* 集成修改过的SDL(Linux/Winodws支持高清屏)。
|
||||
|
||||
* 2018/10/12
|
||||
* 增加大字体demo。
|
||||
* 修改文本垂直居中的问题。
|
||||
|
50
SConstruct
50
SConstruct
@ -16,31 +16,54 @@ LIB_DIR=joinPath(TK_ROOT, 'lib')
|
||||
if OS_NAME == 'Windows':
|
||||
TK_ROOT=TK_ROOT.replace('\\', '\\\\');
|
||||
|
||||
INPUT_ENGINE='null'
|
||||
#INPUT_ENGINE='null'
|
||||
INPUT_ENGINE='pinyin'
|
||||
|
||||
LCD='SDL'
|
||||
#LCD='SDL'
|
||||
LCD='GL'
|
||||
|
||||
VGCANVAS='NANOVG'
|
||||
#NANOVG_BACKEND='AGGE'
|
||||
#NANOVG_BACKEND='BGFX'
|
||||
#NANOVG_BACKEND='GL3'
|
||||
#NANOVG_BACKEND='GLES'
|
||||
#NANOVG_BACKEND='AGG'
|
||||
NANOVG_BACKEND='AGGE'
|
||||
|
||||
FRAME_BUFFER_FORMAT='bgr888'
|
||||
FRAME_BUFFER_FORMAT='bgra8888'
|
||||
#FRAME_BUFFER_FORMAT='bgr888'
|
||||
#FRAME_BUFFER_FORMAT='bgra8888'
|
||||
FRAME_BUFFER_FORMAT='bgr565'
|
||||
|
||||
COMMON_CCFLAGS=' -DTK_ROOT=\\\"'+TK_ROOT+'\\\" -DHAS_STD_MALLOC -DWITH_SDL -DWITH_FS_RES -DHAS_STDIO -DWITH_DESKTOP_STYLE '
|
||||
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DSTBTT_STATIC -DSTB_IMAGE_STATIC -DWITH_STB_IMAGE -DWITH_STB_FONT -DWITH_VGCANVAS -DWITH_UNICODE_BREAK '
|
||||
|
||||
NANOVG_BACKEND_LIBS=[];
|
||||
NANOVG_BACKEND_PROJS=[];
|
||||
|
||||
if LCD == 'GL':
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG -DWITH_NANOVG_GL3 -DWITH_NANOVG_GL -DWITH_VGCANVAS_LCD'
|
||||
NANOVG_BACKEND='GL'
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG_GL -DWITH_VGCANVAS_LCD'
|
||||
else:
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_BITMAP_BGRA1 -DWITH_NANOVG_AGGE -DWITH_NANOVG_SOFT'
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_BITMAP_BGRA -DWITH_NANOVG_SOFT '
|
||||
if FRAME_BUFFER_FORMAT=='bgra8888':
|
||||
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_FB_BGRA8888=1 ';
|
||||
elif FRAME_BUFFER_FORMAT=='bgr888':
|
||||
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_FB_BGR888=1';
|
||||
else:
|
||||
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_FB_BGR565=1 -DWITH_BITMAP_BGR565';
|
||||
COMMON_CCFLAGS=COMMON_CCFLAGS+' -DWITH_FB_BGR565=1 ';
|
||||
|
||||
if NANOVG_BACKEND == 'AGG':
|
||||
NANOVG_BACKEND_LIBS=['nanovg-agg', 'agg'];
|
||||
NANOVG_BACKEND_PROJS=['3rd/agg/SConscript'];
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG_AGG '
|
||||
elif NANOVG_BACKEND == 'AGGE':
|
||||
NANOVG_BACKEND_LIBS=['nanovg-agge', 'agge'];
|
||||
NANOVG_BACKEND_PROJS=['3rd/agge/SConscript'];
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG_AGGE -DWITH_BITMAP_BGR565 '
|
||||
elif NANOVG_BACKEND == 'BGFX':
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG_BGFX '
|
||||
elif NANOVG_BACKEND == 'GLES':
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG_GLES '
|
||||
else:
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DWITH_NANOVG_GL3 '
|
||||
|
||||
os.environ['LCD'] = LCD
|
||||
os.environ['VGCANVAS'] = VGCANVAS
|
||||
@ -49,6 +72,7 @@ os.environ['LIB_DIR'] = LIB_DIR;
|
||||
os.environ['TK_ROOT'] = TK_ROOT;
|
||||
os.environ['GTEST_ROOT'] = GTEST_ROOT;
|
||||
os.environ['INPUT_ENGINE'] = INPUT_ENGINE;
|
||||
os.environ['NANOVG_BACKEND'] = NANOVG_BACKEND;
|
||||
os.environ['FRAME_BUFFER_FORMAT'] = FRAME_BUFFER_FORMAT;
|
||||
|
||||
OS_LIBS=[]
|
||||
@ -69,7 +93,7 @@ elif OS_NAME == 'Linux':
|
||||
OS_LIBS = ['GL'] + OS_LIBS + ['gtk-3','gdk-3','Xext', 'X11', 'sndio','stdc++', 'pthread', 'm', 'dl']
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DLINUX -DHAS_PTHREAD'
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DSDL_REAL_API -DSDL_TIMER_UNIX -DSDL_VIDEO_DRIVER_X11 -DSDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS '
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DSDL_AUDIO_DRIVER_SNDIO -DSDL_VIDEO_OPENGL_GLX '
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DSDL_AUDIO_DRIVER_SNDIO -DSDL_VIDEO_OPENGL_GLX -DSDL_VIDEO_RENDER_OGL '
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DSDL_LOADSO_DLOPEN -DSDL_VIDEO_OPENGL_EGL -DSDL_VIDEO_OPENGL_ES2 '
|
||||
COMMON_CCFLAGS = COMMON_CCFLAGS + ' -DSDL_REAL_API -DSDL_HAPTIC_DISABLED -DSDL_SENSOR_DISABLED -DSDL_JOYSTICK_DISABLED '
|
||||
OS_PROJECTS=['3rd/SDL/SConscript']
|
||||
@ -86,13 +110,14 @@ elif OS_NAME == 'Windows':
|
||||
LINKFLAGS=OS_LINKFLAGS;
|
||||
LIBPATH=[LIB_DIR] + OS_LIBPATH
|
||||
CCFLAGS=OS_FLAGS + COMMON_CCFLAGS
|
||||
LIBS=['awtk', 'gpinyin', 'awtk', 'agge', 'linebreak', 'nanovg-agge', 'nanovg', 'SDL2', 'glad'] + OS_LIBS
|
||||
LIBS=['awtk', 'gpinyin', 'awtk', 'linebreak'] + NANOVG_BACKEND_LIBS + ['nanovg', 'SDL2', 'glad'] + OS_LIBS
|
||||
|
||||
CPPPATH=[TK_ROOT,
|
||||
TK_SRC,
|
||||
TK_3RD_ROOT,
|
||||
joinPath(TK_SRC, 'ext_widgets'),
|
||||
joinPath(TK_3RD_ROOT, 'agge'),
|
||||
joinPath(TK_3RD_ROOT, 'agg/include'),
|
||||
joinPath(TK_3RD_ROOT, 'nanovg'),
|
||||
joinPath(TK_3RD_ROOT, 'nanovg/base'),
|
||||
joinPath(TK_3RD_ROOT, 'nanovg/gl'),
|
||||
@ -114,8 +139,7 @@ DefaultEnvironment(CCFLAGS = CCFLAGS,
|
||||
OS_SUBSYSTEM_WINDOWS=OS_SUBSYSTEM_WINDOWS
|
||||
)
|
||||
|
||||
SConscriptFiles=[
|
||||
'3rd/agge/SConscript',
|
||||
SConscriptFiles=NANOVG_BACKEND_PROJS + [
|
||||
'3rd/nanovg/SConscript',
|
||||
'3rd/glad/SConscript',
|
||||
'3rd/gpinyin/SConscript',
|
||||
|
@ -233,15 +233,11 @@ ret_t canvas_begin_frame(canvas_t* c, rect_t* dirty_rect, lcd_draw_mode_t draw_m
|
||||
c->ox = 0;
|
||||
c->oy = 0;
|
||||
|
||||
#ifdef WITH_NANOVG_SOFT
|
||||
if (lcd_is_swappable(c->lcd)) {
|
||||
canvas_set_clip_rect(c, NULL);
|
||||
} else {
|
||||
canvas_set_clip_rect(c, dirty_rect);
|
||||
}
|
||||
#else
|
||||
canvas_set_clip_rect(c, NULL);
|
||||
#endif/*WITH_NANOVG_SOFT*/
|
||||
|
||||
return lcd_begin_frame(c->lcd, dirty_rect, draw_mode);
|
||||
}
|
||||
|
@ -159,6 +159,9 @@ static ret_t main_loop_sdl2_dispatch_window_event(main_loop_simple_t* loop, SDL_
|
||||
break;
|
||||
case SDL_WINDOWEVENT_CLOSE:
|
||||
log_debug("Window %d closed\n", event->window.windowID);
|
||||
loop->user1 = NULL;
|
||||
loop->user2 = NULL;
|
||||
main_loop_quit(&(loop->base));
|
||||
break;
|
||||
#if SDL_VERSION_ATLEAST(2, 0, 5)
|
||||
case SDL_WINDOWEVENT_TAKE_FOCUS:
|
||||
@ -180,7 +183,7 @@ static ret_t main_loop_sdl2_dispatch(main_loop_simple_t* loop) {
|
||||
SDL_Event event;
|
||||
ret_t ret = RET_OK;
|
||||
|
||||
while (SDL_PollEvent(&event)) {
|
||||
while (SDL_PollEvent(&event) && loop->base.running) {
|
||||
switch (event.type) {
|
||||
case SDL_KEYDOWN:
|
||||
case SDL_KEYUP: {
|
||||
|
@ -41,6 +41,8 @@
|
||||
|
||||
#ifdef WITH_NANOVG_AGGE
|
||||
#include "agge/nanovg_agge.h"
|
||||
#elif defined(WITH_NANOVG_AGG)
|
||||
#include "agg/nanovg_agg.h"
|
||||
#else /*OpenGL*/
|
||||
#include "glad/glad.h"
|
||||
#include "nanovg_gl.h"
|
||||
@ -58,10 +60,9 @@ typedef struct _vgcanvas_nanovg_t {
|
||||
NVGcontext* vg;
|
||||
uint32_t text_align_v;
|
||||
uint32_t text_align_h;
|
||||
#ifdef WITH_NANOVG_AGGE
|
||||
#else
|
||||
#if defined(WITH_NANOVG_GL)
|
||||
SDL_Window* sdl_window;
|
||||
#endif /*WITH_NANOVG_AGGE*/
|
||||
#endif /*WITH_NANOVG_GL*/
|
||||
} vgcanvas_nanovg_t;
|
||||
|
||||
static int vgcanvas_nanovg_ensure_image(vgcanvas_nanovg_t* canvas, bitmap_t* img);
|
||||
@ -373,7 +374,7 @@ static float_t vgcanvas_nanovg_measure_text(vgcanvas_t* vgcanvas, const char* te
|
||||
return nvgTextBounds(vg, 0, 0, text, text + strlen(text), bounds);
|
||||
}
|
||||
|
||||
#ifndef WITH_NANOVG_AGGE
|
||||
#if defined(WITH_NANOVG_GL)
|
||||
static ret_t nanovg_on_bitmap_destroy(bitmap_t* img) {
|
||||
int32_t id = (char*)(img->specific) - (char*)NULL;
|
||||
NVGcontext* vg = (NVGcontext*)(img->specific_ctx);
|
||||
@ -387,7 +388,7 @@ static ret_t nanovg_on_bitmap_destroy(bitmap_t* img) {
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
#endif /*WITH_NANOVG_AGGE*/
|
||||
#endif /*WITH_NANOVG_GL*/
|
||||
|
||||
static ret_t vgcanvas_nanovg_draw_image(vgcanvas_t* vgcanvas, bitmap_t* img, float_t sx, float_t sy,
|
||||
float_t sw, float_t sh, float_t dx, float_t dy, float_t dw,
|
||||
@ -513,33 +514,33 @@ static ret_t vgcanvas_nanovg_restore(vgcanvas_t* vgcanvas) {
|
||||
return RET_OK;
|
||||
}
|
||||
|
||||
#if defined(WITH_NANOVG_AGGE)
|
||||
static agge_bitmap_format_t bitmap_format_to_agge(bitmap_format_t format) {
|
||||
agge_bitmap_format_t f = AGGE_RGBA8888;
|
||||
#if defined(WITH_NANOVG_SOFT)
|
||||
static enum NVGtexture bitmap_format_to_nanovg(bitmap_format_t format) {
|
||||
enum NVGtexture f = NVG_TEXTURE_BGRA;
|
||||
|
||||
switch (format) {
|
||||
case BITMAP_FMT_RGBA8888: {
|
||||
f = AGGE_RGBA8888;
|
||||
f = NVG_TEXTURE_RGBA;
|
||||
break;
|
||||
}
|
||||
case BITMAP_FMT_BGRA8888: {
|
||||
f = AGGE_BGRA8888;
|
||||
f = NVG_TEXTURE_BGRA;
|
||||
break;
|
||||
}
|
||||
case BITMAP_FMT_BGR888: {
|
||||
f = AGGE_BGR888;
|
||||
f = NVG_TEXTURE_BGR;
|
||||
break;
|
||||
}
|
||||
case BITMAP_FMT_RGB888: {
|
||||
f = AGGE_RGB888;
|
||||
f = NVG_TEXTURE_RGB;
|
||||
break;
|
||||
}
|
||||
case BITMAP_FMT_BGR565: {
|
||||
f = AGGE_BGR565;
|
||||
f = NVG_TEXTURE_BGR565;
|
||||
break;
|
||||
}
|
||||
case BITMAP_FMT_RGB565: {
|
||||
f = AGGE_RGB565;
|
||||
f = NVG_TEXTURE_RGB565;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@ -575,7 +576,7 @@ static ret_t vgcanvas_nanovg_reinit(vgcanvas_t* vgcanvas, uint32_t w, uint32_t h
|
||||
vgcanvas->w = w;
|
||||
vgcanvas->h = h;
|
||||
vgcanvas->buff = (uint32_t*)data;
|
||||
nvgReinitAgge(vg, w, h, bitmap_format_to_agge(format), data);
|
||||
nvgReinitAgge(vg, w, h, bitmap_format_to_nanovg(format), data);
|
||||
|
||||
return RET_OK;
|
||||
}
|
||||
@ -767,6 +768,8 @@ static ret_t vgcanvas_nanovg_destroy(vgcanvas_t* vgcanvas) {
|
||||
nvgDeleteGLES3(vg);
|
||||
#elif defined(WITH_NANOVG_AGGE)
|
||||
nvgDeleteAGGE(vg);
|
||||
#elif defined(WITH_NANOVG_AGG)
|
||||
nvgDeleteAGG(vg);
|
||||
#endif
|
||||
|
||||
return RET_OK;
|
||||
@ -821,9 +824,9 @@ static const vgcanvas_vtable_t vt = {vgcanvas_nanovg_reinit,
|
||||
vgcanvas_nanovg_unbind_fbo,
|
||||
vgcanvas_nanovg_destroy};
|
||||
|
||||
#if defined(WITH_NANOVG_AGGE)
|
||||
#if defined(WITH_NANOVG_SOFT)
|
||||
vgcanvas_t* vgcanvas_create(uint32_t w, uint32_t h, bitmap_format_t format, void* data) {
|
||||
agge_bitmap_format_t f = bitmap_format_to_agge(format);
|
||||
enum NVGtexture f = bitmap_format_to_nanovg(format);
|
||||
vgcanvas_nanovg_t* nanovg = (vgcanvas_nanovg_t*)TKMEM_ZALLOC(vgcanvas_nanovg_t);
|
||||
return_value_if_fail(nanovg != NULL, NULL);
|
||||
|
||||
@ -832,8 +835,13 @@ vgcanvas_t* vgcanvas_create(uint32_t w, uint32_t h, bitmap_format_t format, void
|
||||
nanovg->base.vt = &vt;
|
||||
nanovg->base.ratio = 1;
|
||||
nanovg->base.buff = (uint32_t*)data;
|
||||
|
||||
#if defined(WITH_NANOVG_AGG)
|
||||
nanovg->vg = nvgCreateAGG(w, h, f, (uint8_t*)data);
|
||||
#elif defined(WITH_NANOVG_AGGE)
|
||||
nanovg->vg = nvgCreateAGGE(w, h, f, (uint8_t*)data);
|
||||
#else
|
||||
#error "not supported"
|
||||
#endif
|
||||
|
||||
return &(nanovg->base);
|
||||
}
|
||||
|
@ -17,22 +17,6 @@ TEST(Canvas, draw_hline) {
|
||||
r = rect_init(100, 100, 200, 200);
|
||||
canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL);
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_hline(&c, 10, 20, 100);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_hline(&c, 10, 310, 100);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_hline(&c, 10, 110, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_hline(&c, 320, 110, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_hline(&c, 90, 110, 40);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "dhl(100,110,30);");
|
||||
@ -61,22 +45,6 @@ TEST(Canvas, draw_vline) {
|
||||
r = rect_init(100, 100, 200, 200);
|
||||
canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL);
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_vline(&c, 10, 20, 100);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_vline(&c, 310, 20, 100);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_vline(&c, 110, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_vline(&c, 110, 320, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_vline(&c, 110, 90, 40);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "dvl(110,100,30);");
|
||||
@ -105,34 +73,6 @@ TEST(Canvas, fill_rect) {
|
||||
r = rect_init(100, 100, 200, 200);
|
||||
canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL);
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 10, 10, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 10, 210, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 10, 310, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 310, 10, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 310, 210, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 310, 310, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 120, 10, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_fill_rect(&c, 120, 310, 10, 10);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
@ -229,22 +169,6 @@ TEST(Canvas, draw_glyph) {
|
||||
canvas_begin_frame(&c, &r, LCD_DRAW_NORMAL);
|
||||
canvas_set_font(&c, "demo0", font_size);
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_char(&c, 0, 0, 0);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_char(&c, 0, 0, 120);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_char(&c, 0, 120, 320);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_char(&c, 0, 330, 320);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "");
|
||||
|
||||
lcd_log_reset(lcd);
|
||||
canvas_draw_char(&c, 0, 95, 95);
|
||||
ASSERT_EQ(lcd_log_get_commands(lcd), "dg(5,5,5,5,100,100);");
|
||||
|
@ -66,8 +66,9 @@ uint32_t image_gen_buff(bitmap_t* image, uint8_t* output_buff, uint32_t buff_siz
|
||||
} else if (image->format == BITMAP_FMT_BGR565) {
|
||||
size = sizeof(uint16_t) * image->w * image->h;
|
||||
memcpy(header->data, image->data, size);
|
||||
} else {
|
||||
assert(!"not supported");
|
||||
} else if(image->format == BITMAP_FMT_BGRA8888) {
|
||||
size = sizeof(uint32_t) * image->w * image->h;
|
||||
memcpy(header->data, image->data, size);
|
||||
}
|
||||
} else {
|
||||
size = sizeof(uint32_t) * image->w * image->h;
|
||||
|
Loading…
Reference in New Issue
Block a user