From 9b15908a47af12658d6563cddac334505e27b60a Mon Sep 17 00:00:00 2001 From: bubnikv <bubnikv@gmail.com> Date: Thu, 7 Feb 2019 12:06:51 +0100 Subject: [PATCH] WIP: SVG import & rasterization Updated AntiGrain (agg) library to 2.5 Added agg_svg library from AntiGrain 2.5 added src/slic3r/Utils/SVGImport.cpp/hpp --- src/CMakeLists.txt | 1 + src/agg/AUTHORS | 5 +- src/agg/README | 21 + src/agg/VERSION | 2 - src/agg/agg_array.h | 30 +- src/agg/agg_basics.h | 83 +- src/agg/agg_bezier_arc.h | 36 +- src/agg/agg_bounding_rect.h | 122 + src/agg/agg_clip_liang_barsky.h | 34 +- src/agg/agg_color_gray.h | 1008 ++---- src/agg/agg_color_rgba.h | 1141 ++----- src/agg/agg_config.h | 2 +- src/agg/agg_conv_adaptor_vcgen.h | 166 + src/agg/agg_conv_contour.h | 71 + src/agg/agg_conv_curve.h | 206 ++ src/agg/agg_conv_stroke.h | 79 + src/agg/agg_conv_transform.h | 40 +- src/agg/agg_curves.h | 701 +++++ src/agg/agg_gamma_functions.h | 38 +- src/agg/agg_gamma_lut.h | 208 +- src/agg/agg_math.h | 29 +- src/agg/agg_math_stroke.h | 531 ++++ src/agg/agg_path_storage.h | 72 +- src/agg/agg_pixfmt_base.h | 97 - src/agg/agg_pixfmt_gray.h | 503 ++- src/agg/agg_pixfmt_rgb.h | 712 ++--- src/agg/agg_pixfmt_rgba.h | 2911 ++++++++++++++++++ src/agg/agg_rasterizer_cells_aa.h | 139 +- src/agg/agg_rasterizer_scanline_aa.h | 65 +- src/agg/agg_rasterizer_scanline_aa_nogamma.h | 483 --- src/agg/agg_rasterizer_sl_clip.h | 32 +- src/agg/agg_renderer_base.h | 46 +- src/agg/agg_renderer_scanline.h | 35 +- src/agg/agg_rendering_buffer.h | 55 +- src/agg/agg_scanline_p.h | 33 +- src/agg/agg_shorten_path.h | 75 + src/agg/agg_trans_affine.h | 48 +- src/agg/agg_vcgen_contour.h | 103 + src/agg/agg_vcgen_stroke.h | 111 + src/agg/agg_vertex_sequence.h | 178 ++ src/agg/copying | 366 ++- src/agg_svg/CMakeLists.txt | 22 + src/agg_svg/agg_bezier_arc.cpp | 261 ++ src/agg_svg/agg_curves.cpp | 620 ++++ src/agg_svg/agg_svg_exception.h | 69 + src/agg_svg/agg_svg_parser.cpp | 886 ++++++ src/agg_svg/agg_svg_parser.h | 85 + src/agg_svg/agg_svg_path_renderer.cpp | 366 +++ src/agg_svg/agg_svg_path_renderer.h | 321 ++ src/agg_svg/agg_svg_path_tokenizer.cpp | 151 + src/agg_svg/agg_svg_path_tokenizer.h | 114 + src/agg_svg/agg_trans_affine.cpp | 200 ++ src/agg_svg/agg_vcgen_contour.cpp | 170 + src/agg_svg/agg_vcgen_stroke.cpp | 219 ++ src/libslic3r/Rasterizer/Rasterizer.cpp | 9 +- src/slic3r/CMakeLists.txt | 7 +- src/slic3r/GUI/MainFrame.cpp | 4 + src/slic3r/Utils/SVGImport.cpp | 98 + src/slic3r/Utils/SVGImport.hpp | 12 + 59 files changed, 10646 insertions(+), 3586 deletions(-) create mode 100644 src/agg/README delete mode 100644 src/agg/VERSION create mode 100644 src/agg/agg_bounding_rect.h create mode 100644 src/agg/agg_conv_adaptor_vcgen.h create mode 100644 src/agg/agg_conv_contour.h create mode 100644 src/agg/agg_conv_curve.h create mode 100644 src/agg/agg_conv_stroke.h create mode 100644 src/agg/agg_curves.h create mode 100644 src/agg/agg_math_stroke.h delete mode 100644 src/agg/agg_pixfmt_base.h create mode 100644 src/agg/agg_pixfmt_rgba.h delete mode 100644 src/agg/agg_rasterizer_scanline_aa_nogamma.h create mode 100644 src/agg/agg_shorten_path.h create mode 100644 src/agg/agg_vcgen_contour.h create mode 100644 src/agg/agg_vcgen_stroke.h create mode 100644 src/agg/agg_vertex_sequence.h create mode 100644 src/agg_svg/CMakeLists.txt create mode 100644 src/agg_svg/agg_bezier_arc.cpp create mode 100644 src/agg_svg/agg_curves.cpp create mode 100644 src/agg_svg/agg_svg_exception.h create mode 100644 src/agg_svg/agg_svg_parser.cpp create mode 100644 src/agg_svg/agg_svg_parser.h create mode 100644 src/agg_svg/agg_svg_path_renderer.cpp create mode 100644 src/agg_svg/agg_svg_path_renderer.h create mode 100644 src/agg_svg/agg_svg_path_tokenizer.cpp create mode 100644 src/agg_svg/agg_svg_path_tokenizer.h create mode 100644 src/agg_svg/agg_trans_affine.cpp create mode 100644 src/agg_svg/agg_vcgen_contour.cpp create mode 100644 src/agg_svg/agg_vcgen_stroke.cpp create mode 100644 src/slic3r/Utils/SVGImport.cpp create mode 100644 src/slic3r/Utils/SVGImport.hpp diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index b38ae3665..572af70ad 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,7 @@ project(Slic3r-native) add_subdirectory(admesh) +add_subdirectory(agg_svg) add_subdirectory(avrdude) # boost/nowide add_subdirectory(boost) diff --git a/src/agg/AUTHORS b/src/agg/AUTHORS index 2bb6518ec..c0c4ea344 100644 --- a/src/agg/AUTHORS +++ b/src/agg/AUTHORS @@ -1,2 +1,3 @@ -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) +Anti-Grain Geometry (AGG) - Version 2.5 +A high quality rendering engine for C++ +Copyright (C) 2002-2006 Maxim Shemanarev diff --git a/src/agg/README b/src/agg/README new file mode 100644 index 000000000..28420a850 --- /dev/null +++ b/src/agg/README @@ -0,0 +1,21 @@ +Anti-Grain Geometry (AGG) - Version 2.5 +A high quality rendering engine for C++ +Copyright (C) 2002-2006 Maxim Shemanarev +Contact: mcseem@antigrain.com + mcseemagg@yahoo.com + http://antigrain.com + +AGG is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +AGG is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with AGG; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +MA 02110-1301, USA. \ No newline at end of file diff --git a/src/agg/VERSION b/src/agg/VERSION deleted file mode 100644 index c5de3e3b0..000000000 --- a/src/agg/VERSION +++ /dev/null @@ -1,2 +0,0 @@ -2.4 -svn revision 128 \ No newline at end of file diff --git a/src/agg/agg_array.h b/src/agg/agg_array.h index 8d5668384..5c6d390bf 100644 --- a/src/agg/agg_array.h +++ b/src/agg/agg_array.h @@ -1,17 +1,27 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- + #ifndef AGG_ARRAY_INCLUDED #define AGG_ARRAY_INCLUDED diff --git a/src/agg/agg_basics.h b/src/agg/agg_basics.h index 273850ba1..4a1b481fc 100644 --- a/src/agg/agg_basics.h +++ b/src/agg/agg_basics.h @@ -1,22 +1,31 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_BASICS_INCLUDED #define AGG_BASICS_INCLUDED -#include <cmath> +#include <math.h> #include "agg_config.h" //---------------------------------------------------------AGG_CUSTOM_ALLOCATOR @@ -143,18 +152,10 @@ namespace agg __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)); @@ -168,18 +169,10 @@ namespace agg { 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)); @@ -193,19 +186,10 @@ namespace agg { 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)); @@ -228,7 +212,7 @@ namespace agg { AGG_INLINE static unsigned mul(unsigned a, unsigned b) { - unsigned q = a * b + (1 << (Shift-1)); + register unsigned q = a * b + (1 << (Shift-1)); return (q + (q >> Shift)) >> Shift; } }; @@ -254,7 +238,7 @@ namespace agg { 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 + poly_subpixel_mask = poly_subpixel_scale-1, //----poly_subpixel_mask }; //----------------------------------------------------------filling_rule_e @@ -321,12 +305,6 @@ namespace agg { 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 @@ -551,22 +529,9 @@ namespace agg //------------------------------------------------------------is_equal_eps template<class T> inline bool is_equal_eps(T v1, T v2, T epsilon) { - bool neg1 = v1 < 0.0; - bool neg2 = v2 < 0.0; - - if (neg1 != neg2) - return std::fabs(v1) < epsilon && std::fabs(v2) < epsilon; - - int int1, int2; - std::frexp(v1, &int1); - std::frexp(v2, &int2); - int min12 = int1 < int2 ? int1 : int2; - - v1 = std::ldexp(v1, -min12); - v2 = std::ldexp(v2, -min12); - - return std::fabs(v1 - v2) < epsilon; + return fabs(v1 - v2) <= double(epsilon); } + } diff --git a/src/agg/agg_bezier_arc.h b/src/agg/agg_bezier_arc.h index cfd9308ea..a6f2b2221 100644 --- a/src/agg/agg_bezier_arc.h +++ b/src/agg/agg_bezier_arc.h @@ -1,21 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Arc generator. Produces at most 4 consecutive cubic bezier curves, i.e., -// 4, 7, 10, or 13 vertices. -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_BEZIER_ARC_INCLUDED @@ -68,7 +72,7 @@ namespace agg *x = m_vertices[m_vertex]; *y = m_vertices[m_vertex + 1]; m_vertex += 2; - return (m_vertex == 2) ? unsigned(path_cmd_move_to) : m_cmd; + return (m_vertex == 2) ? path_cmd_move_to : m_cmd; } // Supplemantary functions. num_vertices() actually returns doubled diff --git a/src/agg/agg_bounding_rect.h b/src/agg/agg_bounding_rect.h new file mode 100644 index 000000000..e82c181b2 --- /dev/null +++ b/src/agg/agg_bounding_rect.h @@ -0,0 +1,122 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#ifndef AGG_BOUNDING_RECT_INCLUDED +#define AGG_BOUNDING_RECT_INCLUDED + +#include "agg_basics.h" + +namespace agg +{ + + //-----------------------------------------------------------bounding_rect + template<class VertexSource, class GetId, class CoordT> + bool bounding_rect(VertexSource& vs, GetId& gi, + unsigned start, unsigned num, + CoordT* x1, CoordT* y1, CoordT* x2, CoordT* y2) + { + unsigned i; + double x; + double y; + bool first = true; + + *x1 = CoordT(1); + *y1 = CoordT(1); + *x2 = CoordT(0); + *y2 = CoordT(0); + + for(i = 0; i < num; i++) + { + vs.rewind(gi[start + i]); + unsigned cmd; + while(!is_stop(cmd = vs.vertex(&x, &y))) + { + if(is_vertex(cmd)) + { + if(first) + { + *x1 = CoordT(x); + *y1 = CoordT(y); + *x2 = CoordT(x); + *y2 = CoordT(y); + first = false; + } + else + { + if(CoordT(x) < *x1) *x1 = CoordT(x); + if(CoordT(y) < *y1) *y1 = CoordT(y); + if(CoordT(x) > *x2) *x2 = CoordT(x); + if(CoordT(y) > *y2) *y2 = CoordT(y); + } + } + } + } + return *x1 <= *x2 && *y1 <= *y2; + } + + + //-----------------------------------------------------bounding_rect_single + template<class VertexSource, class CoordT> + bool bounding_rect_single(VertexSource& vs, unsigned path_id, + CoordT* x1, CoordT* y1, CoordT* x2, CoordT* y2) + { + double x; + double y; + bool first = true; + + *x1 = CoordT(1); + *y1 = CoordT(1); + *x2 = CoordT(0); + *y2 = CoordT(0); + + vs.rewind(path_id); + unsigned cmd; + while(!is_stop(cmd = vs.vertex(&x, &y))) + { + if(is_vertex(cmd)) + { + if(first) + { + *x1 = CoordT(x); + *y1 = CoordT(y); + *x2 = CoordT(x); + *y2 = CoordT(y); + first = false; + } + else + { + if(CoordT(x) < *x1) *x1 = CoordT(x); + if(CoordT(y) < *y1) *y1 = CoordT(y); + if(CoordT(x) > *x2) *x2 = CoordT(x); + if(CoordT(y) > *y2) *y2 = CoordT(y); + } + } + } + return *x1 <= *x2 && *y1 <= *y2; + } + + +} + +#endif diff --git a/src/agg/agg_clip_liang_barsky.h b/src/agg/agg_clip_liang_barsky.h index 4b5fedbab..e89756024 100644 --- a/src/agg/agg_clip_liang_barsky.h +++ b/src/agg/agg_clip_liang_barsky.h @@ -1,21 +1,27 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Liang-Barsky clipping -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- + #ifndef AGG_CLIP_LIANG_BARSKY_INCLUDED #define AGG_CLIP_LIANG_BARSKY_INCLUDED diff --git a/src/agg/agg_color_gray.h b/src/agg/agg_color_gray.h index f66588c11..a4d50e8a3 100644 --- a/src/agg/agg_color_gray.h +++ b/src/agg/agg_color_gray.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // Adaptation for high precision colors has been sponsored by @@ -35,8 +44,7 @@ namespace agg { //===================================================================gray8 - template<class Colorspace> - struct gray8T + struct gray8 { typedef int8u value_type; typedef int32u calc_type; @@ -45,295 +53,63 @@ namespace agg { base_shift = 8, base_scale = 1 << base_shift, - base_mask = base_scale - 1, - base_MSB = 1 << (base_shift - 1) + base_mask = base_scale - 1 }; - typedef gray8T self_type; + typedef gray8 self_type; value_type v; value_type a; - static value_type luminance(const rgba& c) - { - // Calculate grayscale value as per ITU-R BT.709. - return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask)); - } - - static value_type luminance(const rgba8& c) - { - // Calculate grayscale value as per ITU-R BT.709. - return value_type((55u * c.r + 184u * c.g + 18u * c.b) >> 8); - } - - static void convert(gray8T<linear>& dst, const gray8T<sRGB>& src) - { - dst.v = sRGB_conv<value_type>::rgb_from_sRGB(src.v); - dst.a = src.a; - } - - static void convert(gray8T<sRGB>& dst, const gray8T<linear>& src) - { - dst.v = sRGB_conv<value_type>::rgb_to_sRGB(src.v); - dst.a = src.a; - } - - static void convert(gray8T<linear>& dst, const rgba8& src) - { - dst.v = luminance(src); - dst.a = src.a; - } - - static void convert(gray8T<linear>& dst, const srgba8& src) - { - // The RGB weights are only valid for linear values. - convert(dst, rgba8(src)); - } - - static void convert(gray8T<sRGB>& dst, const rgba8& src) - { - dst.v = sRGB_conv<value_type>::rgb_to_sRGB(luminance(src)); - dst.a = src.a; - } - - static void convert(gray8T<sRGB>& dst, const srgba8& src) - { - // The RGB weights are only valid for linear values. - convert(dst, rgba8(src)); - } + //-------------------------------------------------------------------- + gray8() {} //-------------------------------------------------------------------- - gray8T() {} - - //-------------------------------------------------------------------- - explicit gray8T(unsigned v_, unsigned a_ = base_mask) : + gray8(unsigned v_, unsigned a_=base_mask) : v(int8u(v_)), a(int8u(a_)) {} //-------------------------------------------------------------------- - gray8T(const self_type& c, unsigned a_) : + gray8(const self_type& c, unsigned a_) : v(c.v), a(value_type(a_)) {} //-------------------------------------------------------------------- - gray8T(const rgba& c) : - v(luminance(c)), - a(value_type(uround(c.a * base_mask))) {} + gray8(const rgba& c) : + v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), + a((value_type)uround(c.a * double(base_mask))) {} //-------------------------------------------------------------------- - template<class T> - gray8T(const gray8T<T>& c) - { - convert(*this, c); - } + gray8(const rgba& c, double a_) : + v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), + a((value_type)uround(a_ * double(base_mask))) {} //-------------------------------------------------------------------- - template<class T> - gray8T(const rgba8T<T>& c) - { - convert(*this, c); - } + gray8(const rgba8& c) : + v((c.r*77 + c.g*150 + c.b*29) >> 8), + a(c.a) {} //-------------------------------------------------------------------- - template<class T> - T convert_from_sRGB() const - { - typename T::value_type y = sRGB_conv<typename T::value_type>::rgb_from_sRGB(v); - return T(y, y, y, sRGB_conv<typename T::value_type>::alpha_from_sRGB(a)); - } - - template<class T> - T convert_to_sRGB() const - { - typename T::value_type y = sRGB_conv<typename T::value_type>::rgb_to_sRGB(v); - return T(y, y, y, sRGB_conv<typename T::value_type>::alpha_to_sRGB(a)); - } + gray8(const rgba8& c, unsigned a_) : + v((c.r*77 + c.g*150 + c.b*29) >> 8), + a(a_) {} //-------------------------------------------------------------------- - rgba8 make_rgba8(const linear&) const - { - return rgba8(v, v, v, a); - } - - rgba8 make_rgba8(const sRGB&) const - { - return convert_from_sRGB<srgba8>(); - } - - operator rgba8() const - { - return make_rgba8(Colorspace()); - } - - //-------------------------------------------------------------------- - srgba8 make_srgba8(const linear&) const - { - return convert_to_sRGB<rgba8>(); - } - - srgba8 make_srgba8(const sRGB&) const - { - return srgba8(v, v, v, a); - } - - operator srgba8() const - { - return make_rgba8(Colorspace()); - } - - //-------------------------------------------------------------------- - rgba16 make_rgba16(const linear&) const - { - rgba16::value_type rgb = (v << 8) | v; - return rgba16(rgb, rgb, rgb, (a << 8) | a); - } - - rgba16 make_rgba16(const sRGB&) const - { - return convert_from_sRGB<rgba16>(); - } - - operator rgba16() const - { - return make_rgba16(Colorspace()); - } - - //-------------------------------------------------------------------- - rgba32 make_rgba32(const linear&) const - { - rgba32::value_type v32 = v / 255.0f; - return rgba32(v32, v32, v32, a / 255.0f); - } - - rgba32 make_rgba32(const sRGB&) const - { - return convert_from_sRGB<rgba32>(); - } - - operator rgba32() const - { - return make_rgba32(Colorspace()); - } - - //-------------------------------------------------------------------- - static AGG_INLINE double to_double(value_type a) - { - return double(a) / base_mask; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type from_double(double a) - { - return value_type(uround(a * base_mask)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type empty_value() - { - return 0; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type full_value() - { - return base_mask; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_transparent() const - { - return a == 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_opaque() const - { - return a == base_mask; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, exact over int8u. - static AGG_INLINE value_type multiply(value_type a, value_type b) - { - calc_type t = a * b + base_MSB; - return value_type(((t >> base_shift) + t) >> base_shift); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) - { - if (a * b == 0) - { - return 0; - } - else if (a >= b) - { - return base_mask; - } - else return value_type((a * base_mask + (b >> 1)) / b); - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downscale(T a) - { - return a >> base_shift; - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downshift(T a, unsigned n) - { - return a >> n; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, exact over int8u. - // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, value_type b) - { - return multiply(a, b); - } - - //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) - { - return multiply(b, a); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) - { - return p + q - multiply(p, a); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) - { - int t = (q - p) * a + base_MSB - (p > q); - return value_type(p + (((t >> base_shift) + t) >> base_shift)); - } - - //-------------------------------------------------------------------- - self_type& clear() + void clear() { v = a = 0; - return *this; } //-------------------------------------------------------------------- - self_type& transparent() + const self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- - self_type& opacity(double a_) + void opacity(double a_) { - if (a_ < 0) a = 0; - else if (a_ > 1) a = 1; - else a = (value_type)uround(a_ * double(base_mask)); - return *this; + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = (value_type)uround(a_ * double(base_mask)); } //-------------------------------------------------------------------- @@ -341,33 +117,47 @@ namespace agg { return double(a) / double(base_mask); } - + + //-------------------------------------------------------------------- - self_type& premultiply() + const self_type& premultiply() { - if (a < base_mask) + if(a == base_mask) return *this; + if(a == 0) { - if (a == 0) v = 0; - else v = multiply(v, a); + v = 0; + return *this; } + v = value_type((calc_type(v) * a) >> base_shift); return *this; } //-------------------------------------------------------------------- - self_type& demultiply() + const self_type& premultiply(unsigned a_) { - if (a < base_mask) + if(a == base_mask && a_ >= base_mask) return *this; + if(a == 0 || a_ == 0) { - if (a == 0) - { - v = 0; - } - else - { - calc_type v_ = (calc_type(v) * base_mask) / a; - v = value_type((v_ > base_mask) ? (value_type)base_mask : v_); - } + v = a = 0; + return *this; } + calc_type v_ = (calc_type(v) * a_) / a; + v = value_type((v_ > a_) ? a_ : v_); + a = value_type(a_); + return *this; + } + + //-------------------------------------------------------------------- + const self_type& demultiply() + { + if(a == base_mask) return *this; + if(a == 0) + { + v = 0; + return *this; + } + calc_type v_ = (calc_type(v) * base_mask) / a; + v = value_type((v_ > base_mask) ? (value_type)base_mask : v_); return *this; } @@ -376,8 +166,8 @@ namespace agg { self_type ret; calc_type ik = uround(k * base_scale); - ret.v = lerp(v, c.v, ik); - ret.a = lerp(a, c.a, ik); + ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift)); + ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); return ret; } @@ -385,34 +175,59 @@ namespace agg AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cv, ca; - if (cover == cover_mask) + if(cover == cover_mask) { - if (c.a == base_mask) + if(c.a == base_mask) { *this = c; - return; } else { - cv = v + c.v; - ca = a + c.a; + cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } } else { - cv = v + mult_cover(c.v, cover); - ca = a + mult_cover(c.a, cover); + cv = v + ((c.v * cover + cover_mask/2) >> cover_shift); + ca = a + ((c.a * cover + cover_mask/2) >> cover_shift); + v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } - v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv); - a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- static self_type no_color() { return self_type(0,0); } }; - typedef gray8T<linear> gray8; - typedef gray8T<sRGB> sgray8; + + //-------------------------------------------------------------gray8_pre + inline gray8 gray8_pre(unsigned v, unsigned a = gray8::base_mask) + { + return gray8(v,a).premultiply(); + } + inline gray8 gray8_pre(const gray8& c, unsigned a) + { + return gray8(c,a).premultiply(); + } + inline gray8 gray8_pre(const rgba& c) + { + return gray8(c).premultiply(); + } + inline gray8 gray8_pre(const rgba& c, double a) + { + return gray8(c,a).premultiply(); + } + inline gray8 gray8_pre(const rgba8& c) + { + return gray8(c).premultiply(); + } + inline gray8 gray8_pre(const rgba8& c, unsigned a) + { + return gray8(c,a).premultiply(); + } + + //==================================================================gray16 @@ -425,46 +240,18 @@ namespace agg { base_shift = 16, base_scale = 1 << base_shift, - base_mask = base_scale - 1, - base_MSB = 1 << (base_shift - 1) + base_mask = base_scale - 1 }; typedef gray16 self_type; value_type v; value_type a; - static value_type luminance(const rgba& c) - { - // Calculate grayscale value as per ITU-R BT.709. - return value_type(uround((0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b) * base_mask)); - } - - static value_type luminance(const rgba16& c) - { - // Calculate grayscale value as per ITU-R BT.709. - return value_type((13933u * c.r + 46872u * c.g + 4732u * c.b) >> 16); - } - - static value_type luminance(const rgba8& c) - { - return luminance(rgba16(c)); - } - - static value_type luminance(const srgba8& c) - { - return luminance(rgba16(c)); - } - - static value_type luminance(const rgba32& c) - { - return luminance(rgba(c)); - } - //-------------------------------------------------------------------- gray16() {} //-------------------------------------------------------------------- - explicit gray16(unsigned v_, unsigned a_ = base_mask) : + gray16(unsigned v_, unsigned a_=base_mask) : v(int16u(v_)), a(int16u(a_)) {} //-------------------------------------------------------------------- @@ -473,196 +260,43 @@ namespace agg //-------------------------------------------------------------------- gray16(const rgba& c) : - v(luminance(c)), + v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), a((value_type)uround(c.a * double(base_mask))) {} + //-------------------------------------------------------------------- + gray16(const rgba& c, double a_) : + v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), + a((value_type)uround(a_ * double(base_mask))) {} + //-------------------------------------------------------------------- gray16(const rgba8& c) : - v(luminance(c)), + v(c.r*77 + c.g*150 + c.b*29), a((value_type(c.a) << 8) | c.a) {} //-------------------------------------------------------------------- - gray16(const srgba8& c) : - v(luminance(c)), - a((value_type(c.a) << 8) | c.a) {} + gray16(const rgba8& c, unsigned a_) : + v(c.r*77 + c.g*150 + c.b*29), + a((value_type(a_) << 8) | c.a) {} //-------------------------------------------------------------------- - gray16(const rgba16& c) : - v(luminance(c)), - a(c.a) {} - - //-------------------------------------------------------------------- - gray16(const gray8& c) : - v((value_type(c.v) << 8) | c.v), - a((value_type(c.a) << 8) | c.a) {} - - //-------------------------------------------------------------------- - gray16(const sgray8& c) : - v(sRGB_conv<value_type>::rgb_from_sRGB(c.v)), - a(sRGB_conv<value_type>::alpha_from_sRGB(c.a)) {} - - //-------------------------------------------------------------------- - operator rgba8() const - { - return rgba8(v >> 8, v >> 8, v >> 8, a >> 8); - } - - //-------------------------------------------------------------------- - operator srgba8() const - { - value_type y = sRGB_conv<value_type>::rgb_to_sRGB(v); - return srgba8(y, y, y, sRGB_conv<value_type>::alpha_to_sRGB(a)); - } - - //-------------------------------------------------------------------- - operator rgba16() const - { - return rgba16(v, v, v, a); - } - - //-------------------------------------------------------------------- - operator rgba32() const - { - rgba32::value_type v32 = v / 65535.0f; - return rgba32(v32, v32, v32, a / 65535.0f); - } - - //-------------------------------------------------------------------- - operator gray8() const - { - return gray8(v >> 8, a >> 8); - } - - //-------------------------------------------------------------------- - operator sgray8() const - { - return sgray8( - sRGB_conv<value_type>::rgb_to_sRGB(v), - sRGB_conv<value_type>::alpha_to_sRGB(a)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE double to_double(value_type a) - { - return double(a) / base_mask; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type from_double(double a) - { - return value_type(uround(a * base_mask)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type empty_value() - { - return 0; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type full_value() - { - return base_mask; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_transparent() const - { - return a == 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_opaque() const - { - return a == base_mask; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, exact over int16u. - static AGG_INLINE value_type multiply(value_type a, value_type b) - { - calc_type t = a * b + base_MSB; - return value_type(((t >> base_shift) + t) >> base_shift); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) - { - if (a * b == 0) - { - return 0; - } - else if (a >= b) - { - return base_mask; - } - else return value_type((a * base_mask + (b >> 1)) / b); - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downscale(T a) - { - return a >> base_shift; - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downshift(T a, unsigned n) - { - return a >> n; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, almost exact over int16u. - // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) - { - return multiply(a, b << 8 | b); - } - - //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) - { - return mult_cover(b, a) >> 8; - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) - { - return p + q - multiply(p, a); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) - { - int t = (q - p) * a + base_MSB - (p > q); - return value_type(p + (((t >> base_shift) + t) >> base_shift)); - } - - //-------------------------------------------------------------------- - self_type& clear() + void clear() { v = a = 0; - return *this; } //-------------------------------------------------------------------- - self_type& transparent() + const self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- - self_type& opacity(double a_) + void opacity(double a_) { - if (a_ < 0) a = 0; - else if(a_ > 1) a = 1; - else a = (value_type)uround(a_ * double(base_mask)); - return *this; + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = (value_type)uround(a_ * double(base_mask)); } //-------------------------------------------------------------------- @@ -673,31 +307,44 @@ namespace agg //-------------------------------------------------------------------- - self_type& premultiply() + const self_type& premultiply() { - if (a < base_mask) + if(a == base_mask) return *this; + if(a == 0) { - if(a == 0) v = 0; - else v = multiply(v, a); + v = 0; + return *this; } + v = value_type((calc_type(v) * a) >> base_shift); return *this; } //-------------------------------------------------------------------- - self_type& demultiply() + const self_type& premultiply(unsigned a_) { - if (a < base_mask) + if(a == base_mask && a_ >= base_mask) return *this; + if(a == 0 || a_ == 0) { - if (a == 0) - { - v = 0; - } - else - { - calc_type v_ = (calc_type(v) * base_mask) / a; - v = (v_ > base_mask) ? value_type(base_mask) : value_type(v_); - } + v = a = 0; + return *this; } + calc_type v_ = (calc_type(v) * a_) / a; + v = value_type((v_ > a_) ? a_ : v_); + a = value_type(a_); + return *this; + } + + //-------------------------------------------------------------------- + const self_type& demultiply() + { + if(a == base_mask) return *this; + if(a == 0) + { + v = 0; + return *this; + } + calc_type v_ = (calc_type(v) * base_mask) / a; + v = value_type((v_ > base_mask) ? base_mask : v_); return *this; } @@ -706,8 +353,8 @@ namespace agg { self_type ret; calc_type ik = uround(k * base_scale); - ret.v = lerp(v, c.v, ik); - ret.a = lerp(a, c.a, ik); + ret.v = value_type(calc_type(v) + (((calc_type(c.v) - v) * ik) >> base_shift)); + ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); return ret; } @@ -715,26 +362,25 @@ namespace agg AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cv, ca; - if (cover == cover_mask) + if(cover == cover_mask) { - if (c.a == base_mask) + if(c.a == base_mask) { *this = c; - return; } else { - cv = v + c.v; - ca = a + c.a; + cv = v + c.v; v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } } else { - cv = v + mult_cover(c.v, cover); - ca = a + mult_cover(c.a, cover); + cv = v + ((c.v * cover + cover_mask/2) >> cover_shift); + ca = a + ((c.a * cover + cover_mask/2) >> cover_shift); + v = (cv > calc_type(base_mask)) ? calc_type(base_mask) : cv; + a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } - v = (value_type)((cv > calc_type(base_mask)) ? calc_type(base_mask) : cv); - a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- @@ -742,303 +388,33 @@ namespace agg }; - //===================================================================gray32 - struct gray32 + //------------------------------------------------------------gray16_pre + inline gray16 gray16_pre(unsigned v, unsigned a = gray16::base_mask) { - typedef float value_type; - typedef double calc_type; - typedef double long_type; - typedef gray32 self_type; - - value_type v; - value_type a; - - // Calculate grayscale value as per ITU-R BT.709. - static value_type luminance(double r, double g, double b) - { - return value_type(0.2126 * r + 0.7152 * g + 0.0722 * b); - } - - static value_type luminance(const rgba& c) - { - return luminance(c.r, c.g, c.b); - } - - static value_type luminance(const rgba32& c) - { - return luminance(c.r, c.g, c.b); - } - - static value_type luminance(const rgba8& c) - { - return luminance(c.r / 255.0, c.g / 255.0, c.g / 255.0); - } - - static value_type luminance(const rgba16& c) - { - return luminance(c.r / 65535.0, c.g / 65535.0, c.g / 65535.0); - } - - //-------------------------------------------------------------------- - gray32() {} - - //-------------------------------------------------------------------- - explicit gray32(value_type v_, value_type a_ = 1) : - v(v_), a(a_) {} - - //-------------------------------------------------------------------- - gray32(const self_type& c, value_type a_) : - v(c.v), a(a_) {} - - //-------------------------------------------------------------------- - gray32(const rgba& c) : - v(luminance(c)), - a(value_type(c.a)) {} - - //-------------------------------------------------------------------- - gray32(const rgba8& c) : - v(luminance(c)), - a(value_type(c.a / 255.0)) {} - - //-------------------------------------------------------------------- - gray32(const srgba8& c) : - v(luminance(rgba32(c))), - a(value_type(c.a / 255.0)) {} - - //-------------------------------------------------------------------- - gray32(const rgba16& c) : - v(luminance(c)), - a(value_type(c.a / 65535.0)) {} - - //-------------------------------------------------------------------- - gray32(const rgba32& c) : - v(luminance(c)), - a(value_type(c.a)) {} - - //-------------------------------------------------------------------- - gray32(const gray8& c) : - v(value_type(c.v / 255.0)), - a(value_type(c.a / 255.0)) {} - - //-------------------------------------------------------------------- - gray32(const sgray8& c) : - v(sRGB_conv<value_type>::rgb_from_sRGB(c.v)), - a(sRGB_conv<value_type>::alpha_from_sRGB(c.a)) {} - - //-------------------------------------------------------------------- - gray32(const gray16& c) : - v(value_type(c.v / 65535.0)), - a(value_type(c.a / 65535.0)) {} - - //-------------------------------------------------------------------- - operator rgba() const - { - return rgba(v, v, v, a); - } - - //-------------------------------------------------------------------- - operator gray8() const - { - return gray8(uround(v * 255.0), uround(a * 255.0)); - } - - //-------------------------------------------------------------------- - operator sgray8() const - { - // Return (non-premultiplied) sRGB values. - return sgray8( - sRGB_conv<value_type>::rgb_to_sRGB(v), - sRGB_conv<value_type>::alpha_to_sRGB(a)); - } - - //-------------------------------------------------------------------- - operator gray16() const - { - return gray16(uround(v * 65535.0), uround(a * 65535.0)); - } - - //-------------------------------------------------------------------- - operator rgba8() const - { - rgba8::value_type y = uround(v * 255.0); - return rgba8(y, y, y, uround(a * 255.0)); - } - - //-------------------------------------------------------------------- - operator srgba8() const - { - srgba8::value_type y = sRGB_conv<value_type>::rgb_to_sRGB(v); - return srgba8(y, y, y, sRGB_conv<value_type>::alpha_to_sRGB(a)); - } - - //-------------------------------------------------------------------- - operator rgba16() const - { - rgba16::value_type y = uround(v * 65535.0); - return rgba16(y, y, y, uround(a * 65535.0)); - } - - //-------------------------------------------------------------------- - operator rgba32() const - { - return rgba32(v, v, v, a); - } - - //-------------------------------------------------------------------- - static AGG_INLINE double to_double(value_type a) - { - return a; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type from_double(double a) - { - return value_type(a); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type empty_value() - { - return 0; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type full_value() - { - return 1; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_transparent() const - { - return a <= 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_opaque() const - { - return a >= 1; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) - { - return 1 - x; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type multiply(value_type a, value_type b) - { - return value_type(a * b); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) - { - return (b == 0) ? 0 : value_type(a / b); - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downscale(T a) - { - return a; - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downshift(T a, unsigned n) - { - return n > 0 ? a / (1 << n) : a; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) - { - return value_type(a * b / cover_mask); - } - - //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) - { - return cover_type(uround(a * b)); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) - { - return (1 - a) * p + q; // more accurate than "p + q - p * a" - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) - { - // The form "p + a * (q - p)" avoids a multiplication, but may produce an - // inaccurate result. For example, "p + (q - p)" may not be exactly equal - // to q. Therefore, stick to the basic expression, which at least produces - // the correct result at either extreme. - return (1 - a) * p + a * q; - } - - //-------------------------------------------------------------------- - self_type& clear() - { - v = a = 0; - return *this; - } - - //-------------------------------------------------------------------- - self_type& transparent() - { - a = 0; - return *this; - } - - //-------------------------------------------------------------------- - self_type& opacity(double a_) - { - if (a_ < 0) a = 0; - else if (a_ > 1) a = 1; - else a = value_type(a_); - return *this; - } - - //-------------------------------------------------------------------- - double opacity() const - { - return a; - } + return gray16(v,a).premultiply(); + } + inline gray16 gray16_pre(const gray16& c, unsigned a) + { + return gray16(c,a).premultiply(); + } + inline gray16 gray16_pre(const rgba& c) + { + return gray16(c).premultiply(); + } + inline gray16 gray16_pre(const rgba& c, double a) + { + return gray16(c,a).premultiply(); + } + inline gray16 gray16_pre(const rgba8& c) + { + return gray16(c).premultiply(); + } + inline gray16 gray16_pre(const rgba8& c, unsigned a) + { + return gray16(c,a).premultiply(); + } - //-------------------------------------------------------------------- - self_type& premultiply() - { - if (a < 0) v = 0; - else if(a < 1) v *= a; - return *this; - } - - //-------------------------------------------------------------------- - self_type& demultiply() - { - if (a < 0) v = 0; - else if (a < 1) v /= a; - return *this; - } - - //-------------------------------------------------------------------- - self_type gradient(self_type c, double k) const - { - return self_type( - value_type(v + (c.v - v) * k), - value_type(a + (c.a - a) * k)); - } - - //-------------------------------------------------------------------- - static self_type no_color() { return self_type(0,0); } - }; } diff --git a/src/agg/agg_color_rgba.h b/src/agg/agg_color_rgba.h index ff33a1179..77efac8ee 100644 --- a/src/agg/agg_color_rgba.h +++ b/src/agg/agg_color_rgba.h @@ -1,12 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // Adaptation for high precision colors has been sponsored by @@ -26,22 +39,17 @@ #include <math.h> #include "agg_basics.h" -#include "agg_gamma_lut.h" namespace agg { - // Supported component orders for RGB and RGBA pixel formats + // Supported byte orders for RGB and RGBA pixel formats //======================================================================= - struct order_rgb { enum rgb_e { R=0, G=1, B=2, N=3 }; }; - struct order_bgr { enum bgr_e { B=0, G=1, R=2, N=3 }; }; - struct order_rgba { enum rgba_e { R=0, G=1, B=2, A=3, N=4 }; }; - struct order_argb { enum argb_e { A=0, R=1, G=2, B=3, N=4 }; }; - struct order_abgr { enum abgr_e { A=0, B=1, G=2, R=3, N=4 }; }; - struct order_bgra { enum bgra_e { B=0, G=1, R=2, A=3, N=4 }; }; - - // Colorspace tag types. - struct linear {}; - struct sRGB {}; + struct order_rgb { enum rgb_e { R=0, G=1, B=2, rgb_tag }; }; //----order_rgb + struct order_bgr { enum bgr_e { B=0, G=1, R=2, rgb_tag }; }; //----order_bgr + struct order_rgba { enum rgba_e { R=0, G=1, B=2, A=3, rgba_tag }; }; //----order_rgba + struct order_argb { enum argb_e { A=0, R=1, G=2, B=3, rgba_tag }; }; //----order_argb + struct order_abgr { enum abgr_e { A=0, B=1, G=2, R=3, rgba_tag }; }; //----order_abgr + struct order_bgra { enum bgra_e { B=0, G=1, R=2, A=3, rgba_tag }; }; //----order_bgra //====================================================================rgba struct rgba @@ -64,25 +72,24 @@ namespace agg rgba(const rgba& c, double a_) : r(c.r), g(c.g), b(c.b), a(a_) {} //-------------------------------------------------------------------- - rgba& clear() + void clear() { r = g = b = a = 0; - return *this; } //-------------------------------------------------------------------- - rgba& transparent() + const rgba& transparent() { - a = 0; + a = 0.0; return *this; } //-------------------------------------------------------------------- - rgba& opacity(double a_) + const rgba& opacity(double a_) { - if (a_ < 0) a = 0; - else if (a_ > 1) a = 1; - else a = a_; + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = a_; return *this; } @@ -93,7 +100,7 @@ namespace agg } //-------------------------------------------------------------------- - rgba& premultiply() + const rgba& premultiply() { r *= a; g *= a; @@ -102,37 +109,33 @@ namespace agg } //-------------------------------------------------------------------- - rgba& premultiply(double a_) + const rgba& premultiply(double a_) { - if (a <= 0 || a_ <= 0) + if(a <= 0.0 || a_ <= 0.0) { - r = g = b = a = 0; - } - else - { - a_ /= a; - r *= a_; - g *= a_; - b *= a_; - a = a_; + r = g = b = a = 0.0; + return *this; } + a_ /= a; + r *= a_; + g *= a_; + b *= a_; + a = a_; return *this; } //-------------------------------------------------------------------- - rgba& demultiply() + const rgba& demultiply() { - if (a == 0) + if(a == 0) { r = g = b = 0; + return *this; } - else - { - double a_ = 1.0 / a; - r *= a_; - g *= a_; - b *= a_; - } + double a_ = 1.0 / a; + r *= a_; + g *= a_; + b *= a_; return *this; } @@ -148,30 +151,12 @@ namespace agg return ret; } - rgba& operator+=(const rgba& c) - { - r += c.r; - g += c.g; - b += c.b; - a += c.a; - return *this; - } - - rgba& operator*=(double k) - { - r *= k; - g *= k; - b *= k; - a *= k; - return *this; - } - //-------------------------------------------------------------------- static rgba no_color() { return rgba(0,0,0,0); } //-------------------------------------------------------------------- static rgba from_wavelength(double wl, double gamma = 1.0); - + //-------------------------------------------------------------------- explicit rgba(double wavelen, double gamma=1.0) { @@ -180,14 +165,18 @@ namespace agg }; - inline rgba operator+(const rgba& a, const rgba& b) + //----------------------------------------------------------------rgba_pre + inline rgba rgba_pre(double r, double g, double b, double a=1.0) { - return rgba(a) += b; + return rgba(r, g, b, a).premultiply(); } - - inline rgba operator*(const rgba& a, double b) + inline rgba rgba_pre(const rgba& c) { - return rgba(a) *= b; + return rgba(c).premultiply(); + } + inline rgba rgba_pre(const rgba& c, double a) + { + return rgba(c, a).premultiply(); } //------------------------------------------------------------------------ @@ -195,39 +184,44 @@ namespace agg { rgba t(0.0, 0.0, 0.0); - if (wl >= 380.0 && wl <= 440.0) + if(wl >= 380.0 && wl <= 440.0) { t.r = -1.0 * (wl - 440.0) / (440.0 - 380.0); t.b = 1.0; } - else if (wl >= 440.0 && wl <= 490.0) + else + if(wl >= 440.0 && wl <= 490.0) { t.g = (wl - 440.0) / (490.0 - 440.0); t.b = 1.0; } - else if (wl >= 490.0 && wl <= 510.0) + else + if(wl >= 490.0 && wl <= 510.0) { t.g = 1.0; t.b = -1.0 * (wl - 510.0) / (510.0 - 490.0); } - else if (wl >= 510.0 && wl <= 580.0) + else + if(wl >= 510.0 && wl <= 580.0) { t.r = (wl - 510.0) / (580.0 - 510.0); t.g = 1.0; } - else if (wl >= 580.0 && wl <= 645.0) + else + if(wl >= 580.0 && wl <= 645.0) { t.r = 1.0; t.g = -1.0 * (wl - 645.0) / (645.0 - 580.0); } - else if (wl >= 645.0 && wl <= 780.0) + else + if(wl >= 645.0 && wl <= 780.0) { t.r = 1.0; } double s = 1.0; - if (wl > 700.0) s = 0.3 + 0.7 * (780.0 - wl) / (780.0 - 700.0); - else if (wl < 420.0) s = 0.3 + 0.7 * (wl - 380.0) / (420.0 - 380.0); + if(wl > 700.0) s = 0.3 + 0.7 * (780.0 - wl) / (780.0 - 700.0); + else if(wl < 420.0) s = 0.3 + 0.7 * (wl - 380.0) / (420.0 - 380.0); t.r = pow(t.r * s, gamma); t.g = pow(t.g * s, gamma); @@ -235,15 +229,11 @@ namespace agg return t; } - inline rgba rgba_pre(double r, double g, double b, double a) - { - return rgba(r, g, b, a).premultiply(); - } + //===================================================================rgba8 - template<class Colorspace> - struct rgba8T + struct rgba8 { typedef int8u value_type; typedef int32u calc_type; @@ -252,10 +242,9 @@ namespace agg { base_shift = 8, base_scale = 1 << base_shift, - base_mask = base_scale - 1, - base_MSB = 1 << (base_shift - 1) + base_mask = base_scale - 1 }; - typedef rgba8T self_type; + typedef rgba8 self_type; value_type r; @@ -263,218 +252,53 @@ namespace agg value_type b; value_type a; - static void convert(rgba8T<linear>& dst, const rgba8T<sRGB>& src) - { - dst.r = sRGB_conv<value_type>::rgb_from_sRGB(src.r); - dst.g = sRGB_conv<value_type>::rgb_from_sRGB(src.g); - dst.b = sRGB_conv<value_type>::rgb_from_sRGB(src.b); - dst.a = src.a; - } - - static void convert(rgba8T<sRGB>& dst, const rgba8T<linear>& src) - { - dst.r = sRGB_conv<value_type>::rgb_to_sRGB(src.r); - dst.g = sRGB_conv<value_type>::rgb_to_sRGB(src.g); - dst.b = sRGB_conv<value_type>::rgb_to_sRGB(src.b); - dst.a = src.a; - } - - static void convert(rgba8T<linear>& dst, const rgba& src) - { - dst.r = value_type(uround(src.r * base_mask)); - dst.g = value_type(uround(src.g * base_mask)); - dst.b = value_type(uround(src.b * base_mask)); - dst.a = value_type(uround(src.a * base_mask)); - } - - static void convert(rgba8T<sRGB>& dst, const rgba& src) - { - // Use the "float" table. - dst.r = sRGB_conv<float>::rgb_to_sRGB(float(src.r)); - dst.g = sRGB_conv<float>::rgb_to_sRGB(float(src.g)); - dst.b = sRGB_conv<float>::rgb_to_sRGB(float(src.b)); - dst.a = sRGB_conv<float>::alpha_to_sRGB(float(src.a)); - } - - static void convert(rgba& dst, const rgba8T<linear>& src) - { - dst.r = src.r / 255.0; - dst.g = src.g / 255.0; - dst.b = src.b / 255.0; - dst.a = src.a / 255.0; - } - - static void convert(rgba& dst, const rgba8T<sRGB>& src) - { - // Use the "float" table. - dst.r = sRGB_conv<float>::rgb_from_sRGB(src.r); - dst.g = sRGB_conv<float>::rgb_from_sRGB(src.g); - dst.b = sRGB_conv<float>::rgb_from_sRGB(src.b); - dst.a = sRGB_conv<float>::alpha_from_sRGB(src.a); - } + //-------------------------------------------------------------------- + rgba8() {} //-------------------------------------------------------------------- - rgba8T() {} - - //-------------------------------------------------------------------- - rgba8T(unsigned r_, unsigned g_, unsigned b_, unsigned a_ = base_mask) : + rgba8(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : r(value_type(r_)), g(value_type(g_)), b(value_type(b_)), a(value_type(a_)) {} //-------------------------------------------------------------------- - rgba8T(const rgba& c) - { - convert(*this, c); - } + rgba8(const rgba& c, double a_) : + r((value_type)uround(c.r * double(base_mask))), + g((value_type)uround(c.g * double(base_mask))), + b((value_type)uround(c.b * double(base_mask))), + a((value_type)uround(a_ * double(base_mask))) {} //-------------------------------------------------------------------- - rgba8T(const self_type& c, unsigned a_) : + rgba8(const self_type& c, unsigned a_) : r(c.r), g(c.g), b(c.b), a(value_type(a_)) {} //-------------------------------------------------------------------- - template<class T> - rgba8T(const rgba8T<T>& c) - { - convert(*this, c); - } + rgba8(const rgba& c) : + r((value_type)uround(c.r * double(base_mask))), + g((value_type)uround(c.g * double(base_mask))), + b((value_type)uround(c.b * double(base_mask))), + a((value_type)uround(c.a * double(base_mask))) {} //-------------------------------------------------------------------- - operator rgba() const - { - rgba c; - convert(c, *this); - return c; - } - - //-------------------------------------------------------------------- - static AGG_INLINE double to_double(value_type a) - { - return double(a) / base_mask; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type from_double(double a) - { - return value_type(uround(a * base_mask)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type empty_value() - { - return 0; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type full_value() - { - return base_mask; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_transparent() const - { - return a == 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_opaque() const - { - return a == base_mask; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) - { - return base_mask - x; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, exact over int8u. - static AGG_INLINE value_type multiply(value_type a, value_type b) - { - calc_type t = a * b + base_MSB; - return value_type(((t >> base_shift) + t) >> base_shift); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) - { - if (a * b == 0) - { - return 0; - } - else if (a >= b) - { - return base_mask; - } - else return value_type((a * base_mask + (b >> 1)) / b); - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downscale(T a) - { - return a >> base_shift; - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downshift(T a, unsigned n) - { - return a >> n; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, exact over int8u. - // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) - { - return multiply(a, b); - } - - //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) - { - return multiply(b, a); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) - { - return p + q - multiply(p, a); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) - { - int t = (q - p) * a + base_MSB - (p > q); - return value_type(p + (((t >> base_shift) + t) >> base_shift)); - } - - //-------------------------------------------------------------------- - self_type& clear() + void clear() { r = g = b = a = 0; - return *this; } //-------------------------------------------------------------------- - self_type& transparent() + const self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- - self_type& opacity(double a_) + const self_type& opacity(double a_) { - if (a_ < 0) a = 0; - else if (a_ > 1) a = 1; - else a = (value_type)uround(a_ * double(base_mask)); + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = (value_type)uround(a_ * double(base_mask)); return *this; } @@ -485,66 +309,54 @@ namespace agg } //-------------------------------------------------------------------- - AGG_INLINE self_type& premultiply() + AGG_INLINE const self_type& premultiply() { - if (a != base_mask) + if(a == base_mask) return *this; + if(a == 0) { - if (a == 0) - { - r = g = b = 0; - } - else - { - r = multiply(r, a); - g = multiply(g, a); - b = multiply(b, a); - } + r = g = b = 0; + return *this; } + r = value_type((calc_type(r) * a) >> base_shift); + g = value_type((calc_type(g) * a) >> base_shift); + b = value_type((calc_type(b) * a) >> base_shift); return *this; } //-------------------------------------------------------------------- - AGG_INLINE self_type& premultiply(unsigned a_) + AGG_INLINE const self_type& premultiply(unsigned a_) { - if (a != base_mask || a_ < base_mask) + if(a == base_mask && a_ >= base_mask) return *this; + if(a == 0 || a_ == 0) { - if (a == 0 || a_ == 0) - { - r = g = b = a = 0; - } - else - { - calc_type r_ = (calc_type(r) * a_) / a; - calc_type g_ = (calc_type(g) * a_) / a; - calc_type b_ = (calc_type(b) * a_) / a; - r = value_type((r_ > a_) ? a_ : r_); - g = value_type((g_ > a_) ? a_ : g_); - b = value_type((b_ > a_) ? a_ : b_); - a = value_type(a_); - } + r = g = b = a = 0; + return *this; } + calc_type r_ = (calc_type(r) * a_) / a; + calc_type g_ = (calc_type(g) * a_) / a; + calc_type b_ = (calc_type(b) * a_) / a; + r = value_type((r_ > a_) ? a_ : r_); + g = value_type((g_ > a_) ? a_ : g_); + b = value_type((b_ > a_) ? a_ : b_); + a = value_type(a_); return *this; } //-------------------------------------------------------------------- - AGG_INLINE self_type& demultiply() + AGG_INLINE const self_type& demultiply() { - if (a < base_mask) + if(a == base_mask) return *this; + if(a == 0) { - if (a == 0) - { - r = g = b = 0; - } - else - { - calc_type r_ = (calc_type(r) * base_mask) / a; - calc_type g_ = (calc_type(g) * base_mask) / a; - calc_type b_ = (calc_type(b) * base_mask) / a; - r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); - g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); - b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); - } + r = g = b = 0; + return *this; } + calc_type r_ = (calc_type(r) * base_mask) / a; + calc_type g_ = (calc_type(g) * base_mask) / a; + calc_type b_ = (calc_type(b) * base_mask) / a; + r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); + g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); + b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); return *this; } @@ -552,11 +364,11 @@ namespace agg AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; - calc_type ik = uround(k * base_mask); - ret.r = lerp(r, c.r, ik); - ret.g = lerp(g, c.g, ik); - ret.b = lerp(b, c.b, ik); - ret.a = lerp(a, c.a, ik); + calc_type ik = uround(k * base_scale); + ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift)); + ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift)); + ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift)); + ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); return ret; } @@ -564,32 +376,31 @@ namespace agg AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cr, cg, cb, ca; - if (cover == cover_mask) + if(cover == cover_mask) { - if (c.a == base_mask) + if(c.a == base_mask) { *this = c; - return; } else { - cr = r + c.r; - cg = g + c.g; - cb = b + c.b; - ca = a + c.a; + cr = r + c.r; r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; + cg = g + c.g; g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; + cb = b + c.b; b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; + ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } } else { - cr = r + mult_cover(c.r, cover); - cg = g + mult_cover(c.g, cover); - cb = b + mult_cover(c.b, cover); - ca = a + mult_cover(c.a, cover); + cr = r + ((c.r * cover + cover_mask/2) >> cover_shift); + cg = g + ((c.g * cover + cover_mask/2) >> cover_shift); + cb = b + ((c.b * cover + cover_mask/2) >> cover_shift); + ca = a + ((c.a * cover + cover_mask/2) >> cover_shift); + r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; + g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; + b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; + a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } - r = (value_type)((cr > calc_type(base_mask)) ? calc_type(base_mask) : cr); - g = (value_type)((cg > calc_type(base_mask)) ? calc_type(base_mask) : cg); - b = (value_type)((cb > calc_type(base_mask)) ? calc_type(base_mask) : cb); - a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- @@ -620,8 +431,29 @@ namespace agg } }; - typedef rgba8T<linear> rgba8; - typedef rgba8T<sRGB> srgba8; + + //-------------------------------------------------------------rgba8_pre + inline rgba8 rgba8_pre(unsigned r, unsigned g, unsigned b, + unsigned a = rgba8::base_mask) + { + return rgba8(r,g,b,a).premultiply(); + } + inline rgba8 rgba8_pre(const rgba8& c) + { + return rgba8(c).premultiply(); + } + inline rgba8 rgba8_pre(const rgba8& c, unsigned a) + { + return rgba8(c,a).premultiply(); + } + inline rgba8 rgba8_pre(const rgba& c) + { + return rgba8(c).premultiply(); + } + inline rgba8 rgba8_pre(const rgba& c, double a) + { + return rgba8(c,a).premultiply(); + } //-------------------------------------------------------------rgb8_packed @@ -658,6 +490,8 @@ namespace agg + + //==================================================================rgba16 struct rgba16 { @@ -668,8 +502,7 @@ namespace agg { base_shift = 16, base_scale = 1 << base_shift, - base_mask = base_scale - 1, - base_MSB = 1 << (base_shift - 1) + base_mask = base_scale - 1 }; typedef rgba16 self_type; @@ -699,6 +532,13 @@ namespace agg b((value_type)uround(c.b * double(base_mask))), a((value_type)uround(c.a * double(base_mask))) {} + //-------------------------------------------------------------------- + rgba16(const rgba& c, double a_) : + r((value_type)uround(c.r * double(base_mask))), + g((value_type)uround(c.g * double(base_mask))), + b((value_type)uround(c.b * double(base_mask))), + a((value_type)uround(a_ * double(base_mask))) {} + //-------------------------------------------------------------------- rgba16(const rgba8& c) : r(value_type((value_type(c.r) << 8) | c.r)), @@ -707,166 +547,31 @@ namespace agg a(value_type((value_type(c.a) << 8) | c.a)) {} //-------------------------------------------------------------------- - rgba16(const srgba8& c) : - r(sRGB_conv<value_type>::rgb_from_sRGB(c.r)), - g(sRGB_conv<value_type>::rgb_from_sRGB(c.g)), - b(sRGB_conv<value_type>::rgb_from_sRGB(c.b)), - a(sRGB_conv<value_type>::alpha_from_sRGB(c.a)) {} + rgba16(const rgba8& c, unsigned a_) : + r(value_type((value_type(c.r) << 8) | c.r)), + g(value_type((value_type(c.g) << 8) | c.g)), + b(value_type((value_type(c.b) << 8) | c.b)), + a(value_type(( a_ << 8) | c.a)) {} //-------------------------------------------------------------------- - operator rgba() const - { - return rgba( - r / 65535.0, - g / 65535.0, - b / 65535.0, - a / 65535.0); - } - - //-------------------------------------------------------------------- - operator rgba8() const - { - return rgba8(r >> 8, g >> 8, b >> 8, a >> 8); - } - - //-------------------------------------------------------------------- - operator srgba8() const - { - // Return (non-premultiplied) sRGB values. - return srgba8( - sRGB_conv<value_type>::rgb_to_sRGB(r), - sRGB_conv<value_type>::rgb_to_sRGB(g), - sRGB_conv<value_type>::rgb_to_sRGB(b), - sRGB_conv<value_type>::alpha_to_sRGB(a)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE double to_double(value_type a) - { - return double(a) / base_mask; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type from_double(double a) - { - return value_type(uround(a * base_mask)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type empty_value() - { - return 0; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type full_value() - { - return base_mask; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_transparent() const - { - return a == 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_opaque() const - { - return a == base_mask; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) - { - return base_mask - x; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, exact over int16u. - static AGG_INLINE value_type multiply(value_type a, value_type b) - { - calc_type t = a * b + base_MSB; - return value_type(((t >> base_shift) + t) >> base_shift); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) - { - if (a * b == 0) - { - return 0; - } - else if (a >= b) - { - return base_mask; - } - else return value_type((a * base_mask + (b >> 1)) / b); - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downscale(T a) - { - return a >> base_shift; - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downshift(T a, unsigned n) - { - return a >> n; - } - - //-------------------------------------------------------------------- - // Fixed-point multiply, almost exact over int16u. - // Specifically for multiplying a color component by a cover. - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) - { - return multiply(a, (b << 8) | b); - } - - //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) - { - return multiply((a << 8) | a, b) >> 8; - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) - { - return p + q - multiply(p, a); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) - { - int t = (q - p) * a + base_MSB - (p > q); - return value_type(p + (((t >> base_shift) + t) >> base_shift)); - } - - //-------------------------------------------------------------------- - self_type& clear() + void clear() { r = g = b = a = 0; - return *this; } //-------------------------------------------------------------------- - self_type& transparent() + const self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- - AGG_INLINE self_type& opacity(double a_) + AGG_INLINE const self_type& opacity(double a_) { - if (a_ < 0) a = 0; - if (a_ > 1) a = 1; - a = value_type(uround(a_ * double(base_mask))); + if(a_ < 0.0) a_ = 0.0; + if(a_ > 1.0) a_ = 1.0; + a = (value_type)uround(a_ * double(base_mask)); return *this; } @@ -877,66 +582,54 @@ namespace agg } //-------------------------------------------------------------------- - AGG_INLINE self_type& premultiply() + AGG_INLINE const self_type& premultiply() { - if (a != base_mask) + if(a == base_mask) return *this; + if(a == 0) { - if (a == 0) - { - r = g = b = 0; - } - else - { - r = multiply(r, a); - g = multiply(g, a); - b = multiply(b, a); - } + r = g = b = 0; + return *this; } + r = value_type((calc_type(r) * a) >> base_shift); + g = value_type((calc_type(g) * a) >> base_shift); + b = value_type((calc_type(b) * a) >> base_shift); return *this; } //-------------------------------------------------------------------- - AGG_INLINE self_type& premultiply(unsigned a_) + AGG_INLINE const self_type& premultiply(unsigned a_) { - if (a < base_mask || a_ < base_mask) + if(a == base_mask && a_ >= base_mask) return *this; + if(a == 0 || a_ == 0) { - if (a == 0 || a_ == 0) - { - r = g = b = a = 0; - } - else - { - calc_type r_ = (calc_type(r) * a_) / a; - calc_type g_ = (calc_type(g) * a_) / a; - calc_type b_ = (calc_type(b) * a_) / a; - r = value_type((r_ > a_) ? a_ : r_); - g = value_type((g_ > a_) ? a_ : g_); - b = value_type((b_ > a_) ? a_ : b_); - a = value_type(a_); - } + r = g = b = a = 0; + return *this; } + calc_type r_ = (calc_type(r) * a_) / a; + calc_type g_ = (calc_type(g) * a_) / a; + calc_type b_ = (calc_type(b) * a_) / a; + r = value_type((r_ > a_) ? a_ : r_); + g = value_type((g_ > a_) ? a_ : g_); + b = value_type((b_ > a_) ? a_ : b_); + a = value_type(a_); return *this; } //-------------------------------------------------------------------- - AGG_INLINE self_type& demultiply() + AGG_INLINE const self_type& demultiply() { - if (a < base_mask) + if(a == base_mask) return *this; + if(a == 0) { - if (a == 0) - { - r = g = b = 0; - } - else - { - calc_type r_ = (calc_type(r) * base_mask) / a; - calc_type g_ = (calc_type(g) * base_mask) / a; - calc_type b_ = (calc_type(b) * base_mask) / a; - r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); - g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); - b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); - } + r = g = b = 0; + return *this; } + calc_type r_ = (calc_type(r) * base_mask) / a; + calc_type g_ = (calc_type(g) * base_mask) / a; + calc_type b_ = (calc_type(b) * base_mask) / a; + r = value_type((r_ > calc_type(base_mask)) ? calc_type(base_mask) : r_); + g = value_type((g_ > calc_type(base_mask)) ? calc_type(base_mask) : g_); + b = value_type((b_ > calc_type(base_mask)) ? calc_type(base_mask) : b_); return *this; } @@ -944,11 +637,11 @@ namespace agg AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; - calc_type ik = uround(k * base_mask); - ret.r = lerp(r, c.r, ik); - ret.g = lerp(g, c.g, ik); - ret.b = lerp(b, c.b, ik); - ret.a = lerp(a, c.a, ik); + calc_type ik = uround(k * base_scale); + ret.r = value_type(calc_type(r) + (((calc_type(c.r) - r) * ik) >> base_shift)); + ret.g = value_type(calc_type(g) + (((calc_type(c.g) - g) * ik) >> base_shift)); + ret.b = value_type(calc_type(b) + (((calc_type(c.b) - b) * ik) >> base_shift)); + ret.a = value_type(calc_type(a) + (((calc_type(c.a) - a) * ik) >> base_shift)); return ret; } @@ -956,32 +649,31 @@ namespace agg AGG_INLINE void add(const self_type& c, unsigned cover) { calc_type cr, cg, cb, ca; - if (cover == cover_mask) + if(cover == cover_mask) { - if (c.a == base_mask) + if(c.a == base_mask) { *this = c; - return; } else { - cr = r + c.r; - cg = g + c.g; - cb = b + c.b; - ca = a + c.a; + cr = r + c.r; r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; + cg = g + c.g; g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; + cb = b + c.b; b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; + ca = a + c.a; a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } } else { - cr = r + mult_cover(c.r, cover); - cg = g + mult_cover(c.g, cover); - cb = b + mult_cover(c.b, cover); - ca = a + mult_cover(c.a, cover); + cr = r + ((c.r * cover + cover_mask) >> cover_shift); + cg = g + ((c.g * cover + cover_mask) >> cover_shift); + cb = b + ((c.b * cover + cover_mask) >> cover_shift); + ca = a + ((c.a * cover + cover_mask) >> cover_shift); + r = (cr > calc_type(base_mask)) ? calc_type(base_mask) : cr; + g = (cg > calc_type(base_mask)) ? calc_type(base_mask) : cg; + b = (cb > calc_type(base_mask)) ? calc_type(base_mask) : cb; + a = (ca > calc_type(base_mask)) ? calc_type(base_mask) : ca; } - r = (value_type)((cr > calc_type(base_mask)) ? calc_type(base_mask) : cr); - g = (value_type)((cg > calc_type(base_mask)) ? calc_type(base_mask) : cg); - b = (value_type)((cb > calc_type(base_mask)) ? calc_type(base_mask) : cb); - a = (value_type)((ca > calc_type(base_mask)) ? calc_type(base_mask) : ca); } //-------------------------------------------------------------------- @@ -1013,6 +705,35 @@ namespace agg }; + + //--------------------------------------------------------------rgba16_pre + inline rgba16 rgba16_pre(unsigned r, unsigned g, unsigned b, + unsigned a = rgba16::base_mask) + { + return rgba16(r,g,b,a).premultiply(); + } + inline rgba16 rgba16_pre(const rgba16& c, unsigned a) + { + return rgba16(c,a).premultiply(); + } + inline rgba16 rgba16_pre(const rgba& c) + { + return rgba16(c).premultiply(); + } + inline rgba16 rgba16_pre(const rgba& c, double a) + { + return rgba16(c,a).premultiply(); + } + inline rgba16 rgba16_pre(const rgba8& c) + { + return rgba16(c).premultiply(); + } + inline rgba16 rgba16_pre(const rgba8& c, unsigned a) + { + return rgba16(c,a).premultiply(); + } + + //------------------------------------------------------rgba16_gamma_dir template<class GammaLUT> rgba16 rgba16_gamma_dir(rgba16 c, const GammaLUT& gamma) @@ -1027,325 +748,7 @@ namespace agg return rgba16(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); } - //====================================================================rgba32 - struct rgba32 - { - typedef float value_type; - typedef double calc_type; - typedef double long_type; - typedef rgba32 self_type; - value_type r; - value_type g; - value_type b; - value_type a; - - //-------------------------------------------------------------------- - rgba32() {} - - //-------------------------------------------------------------------- - rgba32(value_type r_, value_type g_, value_type b_, value_type a_= 1) : - r(r_), g(g_), b(b_), a(a_) {} - - //-------------------------------------------------------------------- - rgba32(const self_type& c, float a_) : - r(c.r), g(c.g), b(c.b), a(a_) {} - - //-------------------------------------------------------------------- - rgba32(const rgba& c) : - r(value_type(c.r)), g(value_type(c.g)), b(value_type(c.b)), a(value_type(c.a)) {} - - //-------------------------------------------------------------------- - rgba32(const rgba8& c) : - r(value_type(c.r / 255.0)), - g(value_type(c.g / 255.0)), - b(value_type(c.b / 255.0)), - a(value_type(c.a / 255.0)) {} - - //-------------------------------------------------------------------- - rgba32(const srgba8& c) : - r(sRGB_conv<value_type>::rgb_from_sRGB(c.r)), - g(sRGB_conv<value_type>::rgb_from_sRGB(c.g)), - b(sRGB_conv<value_type>::rgb_from_sRGB(c.b)), - a(sRGB_conv<value_type>::alpha_from_sRGB(c.a)) {} - - //-------------------------------------------------------------------- - rgba32(const rgba16& c) : - r(value_type(c.r / 65535.0)), - g(value_type(c.g / 65535.0)), - b(value_type(c.b / 65535.0)), - a(value_type(c.a / 65535.0)) {} - - //-------------------------------------------------------------------- - operator rgba() const - { - return rgba(r, g, b, a); - } - - //-------------------------------------------------------------------- - operator rgba8() const - { - return rgba8( - uround(r * 255.0), - uround(g * 255.0), - uround(b * 255.0), - uround(a * 255.0)); - } - - //-------------------------------------------------------------------- - operator srgba8() const - { - return srgba8( - sRGB_conv<value_type>::rgb_to_sRGB(r), - sRGB_conv<value_type>::rgb_to_sRGB(g), - sRGB_conv<value_type>::rgb_to_sRGB(b), - sRGB_conv<value_type>::alpha_to_sRGB(a)); - } - - //-------------------------------------------------------------------- - operator rgba16() const - { - return rgba8( - uround(r * 65535.0), - uround(g * 65535.0), - uround(b * 65535.0), - uround(a * 65535.0)); - } - - //-------------------------------------------------------------------- - static AGG_INLINE double to_double(value_type a) - { - return a; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type from_double(double a) - { - return value_type(a); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type empty_value() - { - return 0; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type full_value() - { - return 1; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_transparent() const - { - return a <= 0; - } - - //-------------------------------------------------------------------- - AGG_INLINE bool is_opaque() const - { - return a >= 1; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type invert(value_type x) - { - return 1 - x; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type multiply(value_type a, value_type b) - { - return value_type(a * b); - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type demultiply(value_type a, value_type b) - { - return (b == 0) ? 0 : value_type(a / b); - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downscale(T a) - { - return a; - } - - //-------------------------------------------------------------------- - template<typename T> - static AGG_INLINE T downshift(T a, unsigned n) - { - return n > 0 ? a / (1 << n) : a; - } - - //-------------------------------------------------------------------- - static AGG_INLINE value_type mult_cover(value_type a, cover_type b) - { - return value_type(a * b / cover_mask); - } - - //-------------------------------------------------------------------- - static AGG_INLINE cover_type scale_cover(cover_type a, value_type b) - { - return cover_type(uround(a * b)); - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a, assuming q is premultiplied by a. - static AGG_INLINE value_type prelerp(value_type p, value_type q, value_type a) - { - return (1 - a) * p + q; // more accurate than "p + q - p * a" - } - - //-------------------------------------------------------------------- - // Interpolate p to q by a. - static AGG_INLINE value_type lerp(value_type p, value_type q, value_type a) - { - // The form "p + a * (q - p)" avoids a multiplication, but may produce an - // inaccurate result. For example, "p + (q - p)" may not be exactly equal - // to q. Therefore, stick to the basic expression, which at least produces - // the correct result at either extreme. - return (1 - a) * p + a * q; - } - - //-------------------------------------------------------------------- - self_type& clear() - { - r = g = b = a = 0; - return *this; - } - - //-------------------------------------------------------------------- - self_type& transparent() - { - a = 0; - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE self_type& opacity(double a_) - { - if (a_ < 0) a = 0; - else if (a_ > 1) a = 1; - else a = value_type(a_); - return *this; - } - - //-------------------------------------------------------------------- - double opacity() const - { - return a; - } - - //-------------------------------------------------------------------- - AGG_INLINE self_type& premultiply() - { - if (a < 1) - { - if (a <= 0) - { - r = g = b = 0; - } - else - { - r *= a; - g *= a; - b *= a; - } - } - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE self_type& demultiply() - { - if (a < 1) - { - if (a <= 0) - { - r = g = b = 0; - } - else - { - r /= a; - g /= a; - b /= a; - } - } - return *this; - } - - //-------------------------------------------------------------------- - AGG_INLINE self_type gradient(const self_type& c, double k) const - { - self_type ret; - ret.r = value_type(r + (c.r - r) * k); - ret.g = value_type(g + (c.g - g) * k); - ret.b = value_type(b + (c.b - b) * k); - ret.a = value_type(a + (c.a - a) * k); - return ret; - } - - //-------------------------------------------------------------------- - AGG_INLINE void add(const self_type& c, unsigned cover) - { - if (cover == cover_mask) - { - if (c.is_opaque()) - { - *this = c; - return; - } - else - { - r += c.r; - g += c.g; - b += c.b; - a += c.a; - } - } - else - { - r += mult_cover(c.r, cover); - g += mult_cover(c.g, cover); - b += mult_cover(c.b, cover); - a += mult_cover(c.a, cover); - } - if (a > 1) a = 1; - if (r > a) r = a; - if (g > a) g = a; - if (b > a) b = a; - } - - //-------------------------------------------------------------------- - template<class GammaLUT> - AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) - { - r = gamma.dir(r); - g = gamma.dir(g); - b = gamma.dir(b); - } - - //-------------------------------------------------------------------- - template<class GammaLUT> - AGG_INLINE void apply_gamma_inv(const GammaLUT& gamma) - { - r = gamma.inv(r); - g = gamma.inv(g); - b = gamma.inv(b); - } - - //-------------------------------------------------------------------- - static self_type no_color() { return self_type(0,0,0,0); } - - //-------------------------------------------------------------------- - static self_type from_wavelength(double wl, double gamma = 1) - { - return self_type(rgba::from_wavelength(wl, gamma)); - } - }; } diff --git a/src/agg/agg_config.h b/src/agg/agg_config.h index fa1dae2ba..81c75f124 100644 --- a/src/agg/agg_config.h +++ b/src/agg/agg_config.h @@ -37,7 +37,7 @@ // 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 +// You can still use both of them simultaneouslyin your applications // This #define is used only for default rendering_buffer type, // in short hand typedefs like pixfmt_rgba32. diff --git a/src/agg/agg_conv_adaptor_vcgen.h b/src/agg/agg_conv_adaptor_vcgen.h new file mode 100644 index 000000000..7bd9b0709 --- /dev/null +++ b/src/agg/agg_conv_adaptor_vcgen.h @@ -0,0 +1,166 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#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 diff --git a/src/agg/agg_conv_contour.h b/src/agg/agg_conv_contour.h new file mode 100644 index 000000000..dd29861b4 --- /dev/null +++ b/src/agg/agg_conv_contour.h @@ -0,0 +1,71 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#ifndef AGG_CONV_CONTOUR_INCLUDED +#define AGG_CONV_CONTOUR_INCLUDED + +#include "agg_basics.h" +#include "agg_vcgen_contour.h" +#include "agg_conv_adaptor_vcgen.h" + +namespace agg +{ + + //-----------------------------------------------------------conv_contour + template<class VertexSource> + struct conv_contour : public conv_adaptor_vcgen<VertexSource, vcgen_contour> + { + typedef conv_adaptor_vcgen<VertexSource, vcgen_contour> base_type; + + conv_contour(VertexSource& vs) : + conv_adaptor_vcgen<VertexSource, vcgen_contour>(vs) + { + } + + 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); } + 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); } + void auto_detect_orientation(bool v) { base_type::generator().auto_detect_orientation(v); } + + line_join_e line_join() const { return base_type::generator().line_join(); } + inner_join_e inner_join() const { return base_type::generator().inner_join(); } + 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(); } + bool auto_detect_orientation() const { return base_type::generator().auto_detect_orientation(); } + + private: + conv_contour(const conv_contour<VertexSource>&); + const conv_contour<VertexSource>& + operator = (const conv_contour<VertexSource>&); + }; + +} + +#endif diff --git a/src/agg/agg_conv_curve.h b/src/agg/agg_conv_curve.h new file mode 100644 index 000000000..1280903c0 --- /dev/null +++ b/src/agg/agg_conv_curve.h @@ -0,0 +1,206 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#ifndef AGG_CONV_CURVE_INCLUDED +#define AGG_CONV_CURVE_INCLUDED + +#include "agg_basics.h" +#include "agg_curves.h" + +namespace agg +{ + + + //---------------------------------------------------------------conv_curve + // Curve converter class. Any path storage can have Bezier curves defined + // by their control points. There're two types of curves supported: curve3 + // and curve4. Curve3 is a conic Bezier curve with 2 endpoints and 1 control + // point. Curve4 has 2 control points (4 points in total) and can be used + // to interpolate more complicated curves. Curve4, unlike curve3 can be used + // to approximate arcs, both circular and elliptical. Curves are approximated + // with straight lines and one of the approaches is just to store the whole + // sequence of vertices that approximate our curve. It takes additional + // memory, and at the same time the consecutive vertices can be calculated + // on demand. + // + // Initially, path storages are not suppose to keep all the vertices of the + // curves (although, nothing prevents us from doing so). Instead, path_storage + // keeps only vertices, needed to calculate a curve on demand. Those vertices + // are marked with special commands. So, if the path_storage contains curves + // (which are not real curves yet), and we render this storage directly, + // all we will see is only 2 or 3 straight line segments (for curve3 and + // curve4 respectively). If we need to see real curves drawn we need to + // include this class into the conversion pipeline. + // + // Class conv_curve recognizes commands path_cmd_curve3 and path_cmd_curve4 + // and converts these vertices into a move_to/line_to sequence. + //----------------------------------------------------------------------- + template<class VertexSource, + class Curve3=curve3, + class Curve4=curve4> class conv_curve + { + public: + typedef Curve3 curve3_type; + typedef Curve4 curve4_type; + typedef conv_curve<VertexSource, Curve3, Curve4> self_type; + + explicit conv_curve(VertexSource& source) : + m_source(&source), m_last_x(0.0), m_last_y(0.0) {} + void attach(VertexSource& source) { m_source = &source; } + + void approximation_method(curve_approximation_method_e v) + { + m_curve3.approximation_method(v); + m_curve4.approximation_method(v); + } + + curve_approximation_method_e approximation_method() const + { + return m_curve4.approximation_method(); + } + + void approximation_scale(double s) + { + m_curve3.approximation_scale(s); + m_curve4.approximation_scale(s); + } + + double approximation_scale() const + { + return m_curve4.approximation_scale(); + } + + void angle_tolerance(double v) + { + m_curve3.angle_tolerance(v); + m_curve4.angle_tolerance(v); + } + + double angle_tolerance() const + { + return m_curve4.angle_tolerance(); + } + + void cusp_limit(double v) + { + m_curve3.cusp_limit(v); + m_curve4.cusp_limit(v); + } + + double cusp_limit() const + { + return m_curve4.cusp_limit(); + } + + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); + + private: + conv_curve(const self_type&); + const self_type& operator = (const self_type&); + + VertexSource* m_source; + double m_last_x; + double m_last_y; + curve3_type m_curve3; + curve4_type m_curve4; + }; + + + + //------------------------------------------------------------------------ + template<class VertexSource, class Curve3, class Curve4> + void conv_curve<VertexSource, Curve3, Curve4>::rewind(unsigned path_id) + { + m_source->rewind(path_id); + m_last_x = 0.0; + m_last_y = 0.0; + m_curve3.reset(); + m_curve4.reset(); + } + + + //------------------------------------------------------------------------ + template<class VertexSource, class Curve3, class Curve4> + unsigned conv_curve<VertexSource, Curve3, Curve4>::vertex(double* x, double* y) + { + if(!is_stop(m_curve3.vertex(x, y))) + { + m_last_x = *x; + m_last_y = *y; + return path_cmd_line_to; + } + + if(!is_stop(m_curve4.vertex(x, y))) + { + m_last_x = *x; + m_last_y = *y; + return path_cmd_line_to; + } + + double ct2_x; + double ct2_y; + double end_x; + double end_y; + + unsigned cmd = m_source->vertex(x, y); + switch(cmd) + { + case path_cmd_curve3: + m_source->vertex(&end_x, &end_y); + + m_curve3.init(m_last_x, m_last_y, + *x, *y, + end_x, end_y); + + m_curve3.vertex(x, y); // First call returns path_cmd_move_to + m_curve3.vertex(x, y); // This is the first vertex of the curve + cmd = path_cmd_line_to; + break; + + case path_cmd_curve4: + m_source->vertex(&ct2_x, &ct2_y); + m_source->vertex(&end_x, &end_y); + + m_curve4.init(m_last_x, m_last_y, + *x, *y, + ct2_x, ct2_y, + end_x, end_y); + + m_curve4.vertex(x, y); // First call returns path_cmd_move_to + m_curve4.vertex(x, y); // This is the first vertex of the curve + cmd = path_cmd_line_to; + break; + } + m_last_x = *x; + m_last_y = *y; + return cmd; + } + + +} + + + +#endif diff --git a/src/agg/agg_conv_stroke.h b/src/agg/agg_conv_stroke.h new file mode 100644 index 000000000..271310078 --- /dev/null +++ b/src/agg/agg_conv_stroke.h @@ -0,0 +1,79 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#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 diff --git a/src/agg/agg_conv_transform.h b/src/agg/agg_conv_transform.h index 0c88a245b..33c19b6e2 100644 --- a/src/agg/agg_conv_transform.h +++ b/src/agg/agg_conv_transform.h @@ -1,21 +1,27 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class conv_transform -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- + #ifndef AGG_CONV_TRANSFORM_INCLUDED #define AGG_CONV_TRANSFORM_INCLUDED @@ -29,7 +35,7 @@ namespace agg template<class VertexSource, class Transformer=trans_affine> class conv_transform { public: - conv_transform(VertexSource& source, Transformer& tr) : + conv_transform(VertexSource& source, const Transformer& tr) : m_source(&source), m_trans(&tr) {} void attach(VertexSource& source) { m_source = &source; } @@ -48,7 +54,7 @@ namespace agg return cmd; } - void transformer(Transformer& tr) + void transformer(const Transformer& tr) { m_trans = &tr; } @@ -59,7 +65,7 @@ namespace agg operator = (const conv_transform<VertexSource>&); VertexSource* m_source; - Transformer* m_trans; + const Transformer* m_trans; }; diff --git a/src/agg/agg_curves.h b/src/agg/agg_curves.h new file mode 100644 index 000000000..25845cab3 --- /dev/null +++ b/src/agg/agg_curves.h @@ -0,0 +1,701 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#ifndef AGG_CURVES_INCLUDED +#define AGG_CURVES_INCLUDED + +#include "agg_array.h" + +namespace agg +{ + + // See Implementation agg_curves.cpp + + //--------------------------------------------curve_approximation_method_e + enum curve_approximation_method_e + { + curve_inc, + curve_div + }; + + //--------------------------------------------------------------curve3_inc + class curve3_inc + { + public: + curve3_inc() : + m_num_steps(0), m_step(0), m_scale(1.0) { } + + curve3_inc(double x1, double y1, + double x2, double y2, + double x3, double y3) : + m_num_steps(0), m_step(0), m_scale(1.0) + { + init(x1, y1, x2, y2, x3, y3); + } + + void reset() { m_num_steps = 0; m_step = -1; } + void init(double x1, double y1, + double x2, double y2, + double x3, double y3); + + void approximation_method(curve_approximation_method_e) {} + curve_approximation_method_e approximation_method() const { return curve_inc; } + + void approximation_scale(double s); + double approximation_scale() const; + + void angle_tolerance(double) {} + double angle_tolerance() const { return 0.0; } + + void cusp_limit(double) {} + double cusp_limit() const { return 0.0; } + + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); + + private: + int m_num_steps; + int m_step; + double m_scale; + double m_start_x; + double m_start_y; + double m_end_x; + double m_end_y; + double m_fx; + double m_fy; + double m_dfx; + double m_dfy; + double m_ddfx; + double m_ddfy; + double m_saved_fx; + double m_saved_fy; + double m_saved_dfx; + double m_saved_dfy; + }; + + + + + + //-------------------------------------------------------------curve3_div + class curve3_div + { + public: + curve3_div() : + m_approximation_scale(1.0), + m_angle_tolerance(0.0), + m_count(0) + {} + + curve3_div(double x1, double y1, + double x2, double y2, + double x3, double y3) : + m_approximation_scale(1.0), + m_angle_tolerance(0.0), + m_count(0) + { + init(x1, y1, x2, y2, x3, y3); + } + + void reset() { m_points.remove_all(); m_count = 0; } + void init(double x1, double y1, + double x2, double y2, + double x3, double y3); + + void approximation_method(curve_approximation_method_e) {} + curve_approximation_method_e approximation_method() const { return curve_div; } + + void approximation_scale(double s) { m_approximation_scale = s; } + double approximation_scale() const { return m_approximation_scale; } + + void angle_tolerance(double a) { m_angle_tolerance = a; } + double angle_tolerance() const { return m_angle_tolerance; } + + void cusp_limit(double) {} + double cusp_limit() const { return 0.0; } + + void rewind(unsigned) + { + m_count = 0; + } + + unsigned vertex(double* x, double* y) + { + if(m_count >= m_points.size()) return path_cmd_stop; + const point_d& p = m_points[m_count++]; + *x = p.x; + *y = p.y; + return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; + } + + private: + void bezier(double x1, double y1, + double x2, double y2, + double x3, double y3); + void recursive_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + unsigned level); + + double m_approximation_scale; + double m_distance_tolerance_square; + double m_angle_tolerance; + unsigned m_count; + pod_bvector<point_d> m_points; + }; + + + + + + + + //-------------------------------------------------------------curve4_points + struct curve4_points + { + double cp[8]; + curve4_points() {} + curve4_points(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; + cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; + } + void init(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + cp[0] = x1; cp[1] = y1; cp[2] = x2; cp[3] = y2; + cp[4] = x3; cp[5] = y3; cp[6] = x4; cp[7] = y4; + } + double operator [] (unsigned i) const { return cp[i]; } + double& operator [] (unsigned i) { return cp[i]; } + }; + + + + //-------------------------------------------------------------curve4_inc + class curve4_inc + { + public: + curve4_inc() : + m_num_steps(0), m_step(0), m_scale(1.0) { } + + curve4_inc(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) : + m_num_steps(0), m_step(0), m_scale(1.0) + { + init(x1, y1, x2, y2, x3, y3, x4, y4); + } + + curve4_inc(const curve4_points& cp) : + m_num_steps(0), m_step(0), m_scale(1.0) + { + init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } + + void reset() { m_num_steps = 0; m_step = -1; } + void init(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4); + + void init(const curve4_points& cp) + { + init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } + + void approximation_method(curve_approximation_method_e) {} + curve_approximation_method_e approximation_method() const { return curve_inc; } + + void approximation_scale(double s); + double approximation_scale() const; + + void angle_tolerance(double) {} + double angle_tolerance() const { return 0.0; } + + void cusp_limit(double) {} + double cusp_limit() const { return 0.0; } + + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); + + private: + int m_num_steps; + int m_step; + double m_scale; + double m_start_x; + double m_start_y; + double m_end_x; + double m_end_y; + double m_fx; + double m_fy; + double m_dfx; + double m_dfy; + double m_ddfx; + double m_ddfy; + double m_dddfx; + double m_dddfy; + double m_saved_fx; + double m_saved_fy; + double m_saved_dfx; + double m_saved_dfy; + double m_saved_ddfx; + double m_saved_ddfy; + }; + + + + //-------------------------------------------------------catrom_to_bezier + inline curve4_points catrom_to_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + // Trans. matrix Catmull-Rom to Bezier + // + // 0 1 0 0 + // -1/6 1 1/6 0 + // 0 1/6 1 -1/6 + // 0 0 1 0 + // + return curve4_points( + x2, + y2, + (-x1 + 6*x2 + x3) / 6, + (-y1 + 6*y2 + y3) / 6, + ( x2 + 6*x3 - x4) / 6, + ( y2 + 6*y3 - y4) / 6, + x3, + y3); + } + + + //----------------------------------------------------------------------- + inline curve4_points + catrom_to_bezier(const curve4_points& cp) + { + return catrom_to_bezier(cp[0], cp[1], cp[2], cp[3], + cp[4], cp[5], cp[6], cp[7]); + } + + + + //-----------------------------------------------------ubspline_to_bezier + inline curve4_points ubspline_to_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + // Trans. matrix Uniform BSpline to Bezier + // + // 1/6 4/6 1/6 0 + // 0 4/6 2/6 0 + // 0 2/6 4/6 0 + // 0 1/6 4/6 1/6 + // + return curve4_points( + (x1 + 4*x2 + x3) / 6, + (y1 + 4*y2 + y3) / 6, + (4*x2 + 2*x3) / 6, + (4*y2 + 2*y3) / 6, + (2*x2 + 4*x3) / 6, + (2*y2 + 4*y3) / 6, + (x2 + 4*x3 + x4) / 6, + (y2 + 4*y3 + y4) / 6); + } + + + //----------------------------------------------------------------------- + inline curve4_points + ubspline_to_bezier(const curve4_points& cp) + { + return ubspline_to_bezier(cp[0], cp[1], cp[2], cp[3], + cp[4], cp[5], cp[6], cp[7]); + } + + + + + //------------------------------------------------------hermite_to_bezier + inline curve4_points hermite_to_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + // Trans. matrix Hermite to Bezier + // + // 1 0 0 0 + // 1 0 1/3 0 + // 0 1 0 -1/3 + // 0 1 0 0 + // + return curve4_points( + x1, + y1, + (3*x1 + x3) / 3, + (3*y1 + y3) / 3, + (3*x2 - x4) / 3, + (3*y2 - y4) / 3, + x2, + y2); + } + + + + //----------------------------------------------------------------------- + inline curve4_points + hermite_to_bezier(const curve4_points& cp) + { + return hermite_to_bezier(cp[0], cp[1], cp[2], cp[3], + cp[4], cp[5], cp[6], cp[7]); + } + + + //-------------------------------------------------------------curve4_div + class curve4_div + { + public: + curve4_div() : + m_approximation_scale(1.0), + m_angle_tolerance(0.0), + m_cusp_limit(0.0), + m_count(0) + {} + + curve4_div(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) : + m_approximation_scale(1.0), + m_angle_tolerance(0.0), + m_cusp_limit(0.0), + m_count(0) + { + init(x1, y1, x2, y2, x3, y3, x4, y4); + } + + curve4_div(const curve4_points& cp) : + m_approximation_scale(1.0), + m_angle_tolerance(0.0), + m_count(0) + { + init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } + + void reset() { m_points.remove_all(); m_count = 0; } + void init(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4); + + void init(const curve4_points& cp) + { + init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } + + void approximation_method(curve_approximation_method_e) {} + + curve_approximation_method_e approximation_method() const + { + return curve_div; + } + + void approximation_scale(double s) { m_approximation_scale = s; } + double approximation_scale() const { return m_approximation_scale; } + + void angle_tolerance(double a) { m_angle_tolerance = a; } + double angle_tolerance() const { return m_angle_tolerance; } + + void cusp_limit(double v) + { + m_cusp_limit = (v == 0.0) ? 0.0 : pi - v; + } + + double cusp_limit() const + { + return (m_cusp_limit == 0.0) ? 0.0 : pi - m_cusp_limit; + } + + void rewind(unsigned) + { + m_count = 0; + } + + unsigned vertex(double* x, double* y) + { + if(m_count >= m_points.size()) return path_cmd_stop; + const point_d& p = m_points[m_count++]; + *x = p.x; + *y = p.y; + return (m_count == 1) ? path_cmd_move_to : path_cmd_line_to; + } + + private: + void bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4); + + void recursive_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4, + unsigned level); + + double m_approximation_scale; + double m_distance_tolerance_square; + double m_angle_tolerance; + double m_cusp_limit; + unsigned m_count; + pod_bvector<point_d> m_points; + }; + + + //-----------------------------------------------------------------curve3 + class curve3 + { + public: + curve3() : m_approximation_method(curve_div) {} + curve3(double x1, double y1, + double x2, double y2, + double x3, double y3) : + m_approximation_method(curve_div) + { + init(x1, y1, x2, y2, x3, y3); + } + + void reset() + { + m_curve_inc.reset(); + m_curve_div.reset(); + } + + void init(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + if(m_approximation_method == curve_inc) + { + m_curve_inc.init(x1, y1, x2, y2, x3, y3); + } + else + { + m_curve_div.init(x1, y1, x2, y2, x3, y3); + } + } + + void approximation_method(curve_approximation_method_e v) + { + m_approximation_method = v; + } + + curve_approximation_method_e approximation_method() const + { + return m_approximation_method; + } + + void approximation_scale(double s) + { + m_curve_inc.approximation_scale(s); + m_curve_div.approximation_scale(s); + } + + double approximation_scale() const + { + return m_curve_inc.approximation_scale(); + } + + void angle_tolerance(double a) + { + m_curve_div.angle_tolerance(a); + } + + double angle_tolerance() const + { + return m_curve_div.angle_tolerance(); + } + + void cusp_limit(double v) + { + m_curve_div.cusp_limit(v); + } + + double cusp_limit() const + { + return m_curve_div.cusp_limit(); + } + + void rewind(unsigned path_id) + { + if(m_approximation_method == curve_inc) + { + m_curve_inc.rewind(path_id); + } + else + { + m_curve_div.rewind(path_id); + } + } + + unsigned vertex(double* x, double* y) + { + if(m_approximation_method == curve_inc) + { + return m_curve_inc.vertex(x, y); + } + return m_curve_div.vertex(x, y); + } + + private: + curve3_inc m_curve_inc; + curve3_div m_curve_div; + curve_approximation_method_e m_approximation_method; + }; + + + + + + //-----------------------------------------------------------------curve4 + class curve4 + { + public: + curve4() : m_approximation_method(curve_div) {} + curve4(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) : + m_approximation_method(curve_div) + { + init(x1, y1, x2, y2, x3, y3, x4, y4); + } + + curve4(const curve4_points& cp) : + m_approximation_method(curve_div) + { + init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } + + void reset() + { + m_curve_inc.reset(); + m_curve_div.reset(); + } + + void init(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + if(m_approximation_method == curve_inc) + { + m_curve_inc.init(x1, y1, x2, y2, x3, y3, x4, y4); + } + else + { + m_curve_div.init(x1, y1, x2, y2, x3, y3, x4, y4); + } + } + + void init(const curve4_points& cp) + { + init(cp[0], cp[1], cp[2], cp[3], cp[4], cp[5], cp[6], cp[7]); + } + + void approximation_method(curve_approximation_method_e v) + { + m_approximation_method = v; + } + + curve_approximation_method_e approximation_method() const + { + return m_approximation_method; + } + + void approximation_scale(double s) + { + m_curve_inc.approximation_scale(s); + m_curve_div.approximation_scale(s); + } + double approximation_scale() const { return m_curve_inc.approximation_scale(); } + + void angle_tolerance(double v) + { + m_curve_div.angle_tolerance(v); + } + + double angle_tolerance() const + { + return m_curve_div.angle_tolerance(); + } + + void cusp_limit(double v) + { + m_curve_div.cusp_limit(v); + } + + double cusp_limit() const + { + return m_curve_div.cusp_limit(); + } + + void rewind(unsigned path_id) + { + if(m_approximation_method == curve_inc) + { + m_curve_inc.rewind(path_id); + } + else + { + m_curve_div.rewind(path_id); + } + } + + unsigned vertex(double* x, double* y) + { + if(m_approximation_method == curve_inc) + { + return m_curve_inc.vertex(x, y); + } + return m_curve_div.vertex(x, y); + } + + private: + curve4_inc m_curve_inc; + curve4_div m_curve_div; + curve_approximation_method_e m_approximation_method; + }; + + + + +} + +#endif diff --git a/src/agg/agg_gamma_functions.h b/src/agg/agg_gamma_functions.h index 5d720daa9..fa38a45ad 100644 --- a/src/agg/agg_gamma_functions.h +++ b/src/agg/agg_gamma_functions.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_GAMMA_FUNCTIONS_INCLUDED @@ -115,15 +124,6 @@ namespace agg 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 diff --git a/src/agg/agg_gamma_lut.h b/src/agg/agg_gamma_lut.h index e30873632..5240da798 100644 --- a/src/agg/agg_gamma_lut.h +++ b/src/agg/agg_gamma_lut.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_GAMMA_LUT_INCLUDED @@ -18,7 +27,6 @@ #include <math.h> #include "agg_basics.h" -#include "agg_gamma_functions.h" namespace agg { @@ -117,184 +125,6 @@ namespace agg 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 diff --git a/src/agg/agg_math.h b/src/agg/agg_math.h index 2ec49cf3f..4e512facb 100644 --- a/src/agg/agg_math.h +++ b/src/agg/agg_math.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // Bessel function (besj) was adapted for use in AGG library by Andy Wilk // Contact: castor.vulgaris@gmail.com diff --git a/src/agg/agg_math_stroke.h b/src/agg/agg_math_stroke.h new file mode 100644 index 000000000..ad09af27e --- /dev/null +++ b/src/agg/agg_math_stroke.h @@ -0,0 +1,531 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#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 diff --git a/src/agg/agg_path_storage.h b/src/agg/agg_path_storage.h index f55c89957..7be7393c9 100644 --- a/src/agg/agg_path_storage.h +++ b/src/agg/agg_path_storage.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_PATH_STORAGE_INCLUDED @@ -490,14 +499,14 @@ namespace agg m_stop(false) {} - poly_container_reverse_adaptor(Container& data, bool closed) : + poly_container_reverse_adaptor(const Container& data, bool closed) : m_container(&data), m_index(-1), m_closed(closed), m_stop(false) {} - void init(Container& data, bool closed) + void init(const Container& data, bool closed) { m_container = &data; m_index = m_container->size() - 1; @@ -531,7 +540,7 @@ namespace agg } private: - Container* m_container; + const Container* m_container; int m_index; bool m_closed; bool m_stop; @@ -835,43 +844,6 @@ namespace agg } - //-------------------------------------------------------------------- - // If the end points of a path are very, very close then make them - // exactly equal so that the stroke converter is not confused. - //-------------------------------------------------------------------- - unsigned align_path(unsigned idx = 0) - { - if (idx >= total_vertices() || !is_move_to(command(idx))) - { - return total_vertices(); - } - - double start_x, start_y; - for (; idx < total_vertices() && is_move_to(command(idx)); ++idx) - { - vertex(idx, &start_x, &start_y); - } - while (idx < total_vertices() && is_drawing(command(idx))) - ++idx; - - double x, y; - if (is_drawing(vertex(idx - 1, &x, &y)) && - is_equal_eps(x, start_x, 1e-8) && - is_equal_eps(y, start_y, 1e-8)) - { - modify_vertex(idx - 1, start_x, start_y); - } - - while (idx < total_vertices() && !is_move_to(command(idx))) - ++idx; - return idx; - } - - void align_all_paths() - { - for (unsigned i = 0; i < total_vertices(); i = align_path(i)); - } - private: unsigned perceive_polygon_orientation(unsigned start, unsigned end); diff --git a/src/agg/agg_pixfmt_base.h b/src/agg/agg_pixfmt_base.h deleted file mode 100644 index 57ae19cfe..000000000 --- a/src/agg/agg_pixfmt_base.h +++ /dev/null @@ -1,97 +0,0 @@ -//---------------------------------------------------------------------------- -// 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 diff --git a/src/agg/agg_pixfmt_gray.h b/src/agg/agg_pixfmt_gray.h index d03dc8650..8f3f4ec9d 100644 --- a/src/agg/agg_pixfmt_gray.h +++ b/src/agg/agg_pixfmt_gray.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // Adaptation for high precision colors has been sponsored by @@ -25,7 +34,8 @@ #define AGG_PIXFMT_GRAY_INCLUDED #include <string.h> -#include "agg_pixfmt_base.h" +#include "agg_basics.h" +#include "agg_color_gray.h" #include "agg_rendering_buffer.h" namespace agg @@ -37,22 +47,12 @@ namespace agg typedef ColorT color_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; + enum base_scale_e { base_shift = color_type::base_shift }; - // 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 cv, value_type alpha, cover_type cover) + static AGG_INLINE void blend_pix(value_type* p, unsigned cv, + unsigned alpha, unsigned cover=0) { - blend_pix(p, cv, color_type::mult_cover(alpha, cover)); - } - - static AGG_INLINE void blend_pix(value_type* p, - value_type cv, value_type alpha) - { - *p = color_type::lerp(*p, cv, alpha); + *p = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift); } }; @@ -63,21 +63,20 @@ namespace agg typedef ColorT color_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; + enum base_scale_e { base_shift = color_type::base_shift }; - // Blend pixels using the premultiplied form of Alvy-Ray Smith's - // compositing function. - - static AGG_INLINE void blend_pix(value_type* p, - value_type cv, value_type alpha, cover_type cover) + static AGG_INLINE void blend_pix(value_type* p, unsigned cv, + unsigned alpha, unsigned cover) { - blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover)); + alpha = color_type::base_mask - alpha; + cover = (cover + 1) << (base_shift - 8); + *p = (value_type)((*p * alpha + cv * cover) >> base_shift); } - static AGG_INLINE void blend_pix(value_type* p, - value_type cv, value_type alpha) + static AGG_INLINE void blend_pix(value_type* p, unsigned cv, + unsigned alpha) { - *p = color_type::prelerp(*p, cv, alpha); + *p = (value_type)(((*p * (color_type::base_mask - alpha)) >> base_shift) + cv); } }; @@ -122,11 +121,10 @@ namespace agg //=================================================pixfmt_alpha_blend_gray - template<class Blender, class RenBuf, unsigned Step = 1, unsigned Offset = 0> + template<class Blender, class RenBuf, unsigned Step=1, unsigned Offset=0> class pixfmt_alpha_blend_gray { public: - typedef pixfmt_gray_tag pixfmt_category; typedef RenBuf rbuf_type; typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; @@ -134,117 +132,54 @@ namespace agg typedef int order_type; // A fake one typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; - enum + enum base_scale_e { - num_components = 1, - pix_width = sizeof(value_type) * Step, - pix_step = Step, - pix_offset = Offset, - }; - struct pixel_type - { - value_type c[num_components]; - - void set(value_type v) - { - c[0] = v; - } - - void set(const color_type& color) - { - set(color.v); - } - - void get(value_type& v) const - { - v = c[0]; - } - - color_type get() const - { - return color_type(c[0]); - } - - 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); - } + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask, + pix_width = sizeof(value_type), + pix_step = Step, + pix_offset = Offset }; private: //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, - value_type v, value_type a, - unsigned cover) + static AGG_INLINE void copy_or_blend_pix(value_type* p, + const color_type& c, + unsigned cover) { - blender_type::blend_pix(p->c, v, a, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, value_type v, value_type a) - { - blender_type::blend_pix(p->c, v, a); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover) - { - blender_type::blend_pix(p->c, c.v, c.a, cover); - } - - //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) - { - blender_type::blend_pix(p->c, c.v, c.a); - } - - //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) - { - if (!c.is_transparent()) + if (c.a) { - if (c.is_opaque() && cover == cover_mask) + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) { - p->set(c); + *p = c.v; } else { - blend_pix(p, c, cover); + Blender::blend_pix(p, c.v, alpha, cover); } } } - //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) + + static AGG_INLINE void copy_or_blend_pix(value_type* p, + const color_type& c) { - if (!c.is_transparent()) + if (c.a) { - if (c.is_opaque()) + if(c.a == base_mask) { - p->set(c); + *p = c.v; } else { - blend_pix(p, c); + Blender::blend_pix(p, c.v, c.a); } } } + public: //-------------------------------------------------------------------- explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : @@ -257,7 +192,7 @@ namespace agg 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))) + 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), @@ -275,98 +210,61 @@ namespace agg AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- - int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } + int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } 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) + const int8u* pix_ptr(int x, int y) const { - return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); + return m_rbuf->row_ptr(y) + x * Step + 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* pix_ptr(int x, int y) { - 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) - { - // Grayscale 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(); + return m_rbuf->row_ptr(y) + x * Step + Offset; } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { - ((pixel_type*)p)->set(c); + *(value_type*)p = c.v; } //-------------------------------------------------------------------- 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(); + value_type* p = (value_type*)m_rbuf->row_ptr(y) + x * Step + Offset; + return color_type(*p); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { - pix_value_ptr(x, y, 1)->set(c); + *((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v; } //-------------------------------------------------------------------- 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); + copy_or_blend_pix((value_type*) + m_rbuf->row_ptr(x, y, 1) + x * Step + Offset, + 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); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + do { - p->set(c); - p = p->next(); + *p = c.v; + p += Step; } while(--len); } @@ -379,9 +277,12 @@ namespace agg { do { - pix_value_ptr(x, y++, 1)->set(c); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + *p = c.v; } - while (--len); + while(--len); } @@ -391,27 +292,29 @@ namespace agg const color_type& c, int8u cover) { - if (!c.is_transparent()) + if (c.a) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - if (c.is_opaque() && cover == cover_mask) + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) { do { - p->set(c); - p = p->next(); + *p = c.v; + p += Step; } - while (--len); + while(--len); } else { do { - blend_pix(p, c, cover); - p = p->next(); + Blender::blend_pix(p, c.v, alpha, cover); + p += Step; } - while (--len); + while(--len); } } } @@ -423,23 +326,31 @@ namespace agg const color_type& c, int8u cover) { - if (!c.is_transparent()) + if (c.a) { - if (c.is_opaque() && cover == cover_mask) + value_type* p; + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) { do { - pix_value_ptr(x, y++, 1)->set(c); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + *p = c.v; } - while (--len); + while(--len); } else { do { - blend_pix(pix_value_ptr(x, y++, 1), c, cover); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + Blender::blend_pix(p, c.v, alpha, cover); } - while (--len); + while(--len); } } } @@ -451,24 +362,26 @@ namespace agg const color_type& c, const int8u* covers) { - if (!c.is_transparent()) + if (c.a) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; do { - if (c.is_opaque() && *covers == cover_mask) + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + if(alpha == base_mask) { - p->set(c); + *p = c.v; } else { - blend_pix(p, c, *covers); + Blender::blend_pix(p, c.v, alpha, *covers); } - p = p->next(); + p += Step; ++covers; } - while (--len); + while(--len); } } @@ -479,23 +392,26 @@ namespace agg const color_type& c, const int8u* covers) { - if (!c.is_transparent()) + if (c.a) { do { - pixel_type* p = pix_value_ptr(x, y++, 1); + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if (c.is_opaque() && *covers == cover_mask) + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + if(alpha == base_mask) { - p->set(c); + *p = c.v; } else { - blend_pix(p, c, *covers); + Blender::blend_pix(p, c.v, alpha, *covers); } ++covers; } - while (--len); + while(--len); } } @@ -505,14 +421,16 @@ namespace agg unsigned len, const color_type* colors) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; do { - p->set(*colors++); - p = p->next(); + *p = colors->v; + p += Step; + ++colors; } - while (--len); + while(--len); } @@ -523,9 +441,12 @@ namespace agg { do { - pix_value_ptr(x, y++, 1)->set(*colors++); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + *p = colors->v; + ++colors; } - while (--len); + while(--len); } @@ -536,40 +457,50 @@ namespace agg const int8u* covers, int8u cover) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - if (covers) + if(covers) { do { copy_or_blend_pix(p, *colors++, *covers++); - p = p->next(); + p += Step; } - while (--len); + while(--len); } else { - if (cover == cover_mask) + if(cover == 255) { do { - copy_or_blend_pix(p, *colors++); - p = p->next(); + if(colors->a == base_mask) + { + *p = colors->v; + } + else + { + copy_or_blend_pix(p, *colors); + } + p += Step; + ++colors; } - while (--len); + while(--len); } else { do { copy_or_blend_pix(p, *colors++, cover); - p = p->next(); + p += Step; } - while (--len); + while(--len); } } } - + + //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, @@ -578,31 +509,49 @@ namespace agg const int8u* covers, int8u cover) { - if (covers) + value_type* p; + if(covers) { do { - copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + copy_or_blend_pix(p, *colors++, *covers++); } - while (--len); + while(--len); } else { - if (cover == cover_mask) + if(cover == 255) { do { - copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + if(colors->a == base_mask) + { + *p = colors->v; + } + else + { + copy_or_blend_pix(p, *colors); + } + ++colors; } - while (--len); + while(--len); } else { do { - copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; + + copy_or_blend_pix(p, *colors++, cover); } - while (--len); + while(--len); } } } @@ -611,19 +560,22 @@ namespace agg template<class Function> void for_each_pixel(Function f) { unsigned y; - for (y = 0; y < height(); ++y) + for(y = 0; y < height(); ++y) { row_data r = m_rbuf->row(y); - if (r.ptr) + if(r.ptr) { unsigned len = r.x2 - r.x1 + 1; - pixel_type* p = pix_value_ptr(r.x1, y, len); + + value_type* p = (value_type*) + m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset; + do { - f(p->c); - p = p->next(); + f(p); + p += Step; } - while (--len); + while(--len); } } } @@ -647,7 +599,8 @@ namespace agg int xsrc, int ysrc, unsigned len) { - if (const int8u* p = from.row_ptr(ysrc)) + const int8u* p = from.row_ptr(ysrc); + if(p) { memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, @@ -656,7 +609,6 @@ namespace agg } //-------------------------------------------------------------------- - // Blend from single color, using grayscale surface as alpha channel. template<class SrcPixelFormatRenderer> void blend_from_color(const SrcPixelFormatRenderer& from, const color_type& color, @@ -665,26 +617,25 @@ namespace agg 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)) + typedef typename SrcPixelFormatRenderer::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) { - pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; do { - copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); - psrc = psrc->next(); - pdst = pdst->next(); + copy_or_blend_pix(pdst, + color, + (*psrc * cover + base_mask) >> base_shift); + ++psrc; + ++pdst; } - while (--len); + 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, @@ -693,19 +644,19 @@ namespace agg unsigned len, int8u cover) { - typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; - - if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + typedef typename SrcPixelFormatRenderer::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) { - pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; do { - copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); - psrc = psrc->next(); - pdst = pdst->next(); + copy_or_blend_pix(pdst, color_lut[*psrc], cover); + ++psrc; + ++pdst; } - while (--len); + while(--len); } } @@ -713,25 +664,15 @@ namespace agg rbuf_type* m_rbuf; }; - typedef blender_gray<gray8> blender_gray8; - typedef blender_gray<sgray8> blender_sgray8; - typedef blender_gray<gray16> blender_gray16; - typedef blender_gray<gray32> blender_gray32; - - typedef blender_gray_pre<gray8> blender_gray8_pre; - typedef blender_gray_pre<sgray8> blender_sgray8_pre; + typedef blender_gray<gray8> blender_gray8; + typedef blender_gray_pre<gray8> blender_gray8_pre; + typedef blender_gray<gray16> blender_gray16; typedef blender_gray_pre<gray16> blender_gray16_pre; - typedef blender_gray_pre<gray32> blender_gray32_pre; - typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8; - typedef pixfmt_alpha_blend_gray<blender_sgray8, rendering_buffer> pixfmt_sgray8; - typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; - typedef pixfmt_alpha_blend_gray<blender_gray32, rendering_buffer> pixfmt_gray32; - - typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; - typedef pixfmt_alpha_blend_gray<blender_sgray8_pre, rendering_buffer> pixfmt_sgray8_pre; - typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; - typedef pixfmt_alpha_blend_gray<blender_gray32_pre, rendering_buffer> pixfmt_gray32_pre; + typedef pixfmt_alpha_blend_gray<blender_gray8, rendering_buffer> pixfmt_gray8; //----pixfmt_gray8 + typedef pixfmt_alpha_blend_gray<blender_gray8_pre, rendering_buffer> pixfmt_gray8_pre; //----pixfmt_gray8_pre + typedef pixfmt_alpha_blend_gray<blender_gray16, rendering_buffer> pixfmt_gray16; //----pixfmt_gray16 + typedef pixfmt_alpha_blend_gray<blender_gray16_pre, rendering_buffer> pixfmt_gray16_pre; //----pixfmt_gray16_pre } #endif diff --git a/src/agg/agg_pixfmt_rgb.h b/src/agg/agg_pixfmt_rgb.h index 6fa8772ce..48947178b 100644 --- a/src/agg/agg_pixfmt_rgb.h +++ b/src/agg/agg_pixfmt_rgb.h @@ -1,16 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // Adaptation for high precision colors has been sponsored by @@ -25,7 +34,8 @@ #define AGG_PIXFMT_RGB_INCLUDED #include <string.h> -#include "agg_pixfmt_base.h" +#include "agg_basics.h" +#include "agg_color_rgba.h" #include "agg_rendering_buffer.h" namespace agg @@ -73,73 +83,66 @@ namespace agg //=========================================================blender_rgb - template<class ColorT, class Order> - struct 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. + enum base_scale_e { base_shift = color_type::base_shift }; //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, - value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned cover=0) { - 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); + p[Order::R] += (value_type)(((cr - p[Order::R]) * alpha) >> base_shift); + p[Order::G] += (value_type)(((cg - p[Order::G]) * alpha) >> base_shift); + p[Order::B] += (value_type)(((cb - p[Order::B]) * alpha) >> base_shift); } }; + //======================================================blender_rgb_pre - template<class ColorT, class Order> - struct 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. + enum base_scale_e { base_shift = color_type::base_shift }; //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, - value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned 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)); + alpha = color_type::base_mask - alpha; + cover = (cover + 1) << (base_shift - 8); + p[Order::R] = (value_type)((p[Order::R] * alpha + cr * cover) >> base_shift); + p[Order::G] = (value_type)((p[Order::G] * alpha + cg * cover) >> base_shift); + p[Order::B] = (value_type)((p[Order::B] * alpha + cb * cover) >> base_shift); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, - value_type cr, value_type cg, value_type cb, value_type alpha) + unsigned cr, unsigned cg, unsigned cb, + unsigned 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); + alpha = color_type::base_mask - alpha; + p[Order::R] = (value_type)(((p[Order::R] * alpha) >> base_shift) + cr); + p[Order::G] = (value_type)(((p[Order::G] * alpha) >> base_shift) + cg); + p[Order::B] = (value_type)(((p[Order::B] * alpha) >> base_shift) + cb); } + }; + + //===================================================blender_rgb_gamma - template<class ColorT, class Order, class Gamma> - class blender_rgb_gamma : public blender_base<ColorT, Order> + template<class ColorT, class Order, class Gamma> class blender_rgb_gamma { public: typedef ColorT color_type; @@ -147,7 +150,7 @@ namespace agg 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; + enum base_scale_e { base_shift = color_type::base_shift }; //-------------------------------------------------------------------- blender_rgb_gamma() : m_gamma(0) {} @@ -155,34 +158,29 @@ namespace agg //-------------------------------------------------------------------- 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) + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned cover=0) { 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); + p[Order::R] = m_gamma->inv((((m_gamma->dir(cr) - r) * alpha) >> base_shift) + r); + p[Order::G] = m_gamma->inv((((m_gamma->dir(cg) - g) * alpha) >> base_shift) + g); + p[Order::B] = m_gamma->inv((((m_gamma->dir(cb) - b) * alpha) >> base_shift) + 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 + template<class Blender, class RenBuf> 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; @@ -190,125 +188,56 @@ namespace agg 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 + enum base_scale_e { - 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); - } + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask, + pix_width = sizeof(value_type) * 3 }; private: //-------------------------------------------------------------------- - AGG_INLINE void blend_pix(pixel_type* p, - value_type r, value_type g, value_type b, value_type a, - unsigned cover) + AGG_INLINE void copy_or_blend_pix(value_type* p, + const color_type& c, + 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.a) { - if (c.is_opaque() && cover == cover_mask) + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) { - p->set(c); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } else { - blend_pix(p, c, cover); + m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); } } } //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) + AGG_INLINE void copy_or_blend_pix(value_type* p, + const color_type& c) { - if (!c.is_transparent()) + if (c.a) { - if (c.is_opaque()) + if(c.a == base_mask) { - p->set(c); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } else { - blend_pix(p, c); + m_blender.blend_pix(p, c.r, c.g, c.b, c.a); } } } + public: //-------------------------------------------------------------------- explicit pixfmt_alpha_blend_rgb(rbuf_type& rb) : @@ -321,7 +250,7 @@ namespace agg 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))) + 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), @@ -349,91 +278,59 @@ namespace agg //-------------------------------------------------------------------- AGG_INLINE int8u* pix_ptr(int x, int y) { - return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); + return m_rbuf->row_ptr(y) + x * pix_width; } 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(); + return m_rbuf->row_ptr(y) + x * pix_width; } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { - ((pixel_type*)p)->set(c); + ((value_type*)p)[order_type::R] = c.r; + ((value_type*)p)[order_type::G] = c.g; + ((value_type*)p)[order_type::B] = c.b; } //-------------------------------------------------------------------- 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(); + value_type* p = (value_type*)m_rbuf->row_ptr(y) + x + x + x; + return color_type(p[order_type::R], + p[order_type::G], + p[order_type::B]); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { - pix_value_ptr(x, y, 1)->set(c); + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, 1) + x + x + x; + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } //-------------------------------------------------------------------- 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); + copy_or_blend_pix((value_type*)m_rbuf->row_ptr(x, y, 1) + x + x + x, 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); + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + x + x + x; do { - p->set(c); - p = p->next(); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; + p += 3; } while(--len); } @@ -446,38 +343,47 @@ namespace agg { do { - pix_value_ptr(x, y++, 1)->set(c); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } - while (--len); + while(--len); } + //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { - if (!c.is_transparent()) + if (c.a) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x + x + x; - if (c.is_opaque() && cover == cover_mask) + calc_type alpha = (calc_type(c.a) * (calc_type(cover) + 1)) >> 8; + if(alpha == base_mask) { do { - p->set(c); - p = p->next(); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; + p += 3; } - while (--len); + while(--len); } else { do { - blend_pix(p, c, cover); - p = p->next(); + m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); + p += 3; } - while (--len); + while(--len); } } } @@ -489,51 +395,66 @@ namespace agg const color_type& c, int8u cover) { - if (!c.is_transparent()) + if (c.a) { - if (c.is_opaque() && cover == cover_mask) + value_type* p; + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) { do { - pix_value_ptr(x, y++, 1)->set(c); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } - while (--len); + while(--len); } else { do { - blend_pix(pix_value_ptr(x, y++, 1), c, cover); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + + m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); } - while (--len); + while(--len); } } } + //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { - if (!c.is_transparent()) + if (c.a) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x + x + x; do { - if (c.is_opaque() && *covers == cover_mask) + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + if(alpha == base_mask) { - p->set(c); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } else { - blend_pix(p, c, *covers); + m_blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); } - p = p->next(); + p += 3; ++covers; } - while (--len); + while(--len); } } @@ -544,39 +465,48 @@ namespace agg const color_type& c, const int8u* covers) { - if (!c.is_transparent()) + if (c.a) { do { - pixel_type* p = pix_value_ptr(x, y++, 1); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; - if (c.is_opaque() && *covers == cover_mask) + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + if(alpha == base_mask) { - p->set(c); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; } else { - blend_pix(p, c, *covers); + m_blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); } ++covers; } - while (--len); + 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); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x + x + x; do { - p->set(*colors++); - p = p->next(); + p[order_type::R] = colors->r; + p[order_type::G] = colors->g; + p[order_type::B] = colors->b; + ++colors; + p += 3; } - while (--len); + while(--len); } @@ -587,11 +517,17 @@ namespace agg { do { - pix_value_ptr(x, y++, 1)->set(*colors++); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + p[order_type::R] = colors->r; + p[order_type::G] = colors->g; + p[order_type::B] = colors->b; + ++colors; } - while (--len); + while(--len); } + //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, @@ -599,40 +535,43 @@ namespace agg const int8u* covers, int8u cover) { - pixel_type* p = pix_value_ptr(x, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(x, y, len) + x + x + x; - if (covers) + if(covers) { do { copy_or_blend_pix(p, *colors++, *covers++); - p = p->next(); + p += 3; } - while (--len); + while(--len); } else { - if (cover == cover_mask) + if(cover == 255) { do { copy_or_blend_pix(p, *colors++); - p = p->next(); + p += 3; } - while (--len); + while(--len); } else { do { copy_or_blend_pix(p, *colors++, cover); - p = p->next(); + p += 3; } - while (--len); + while(--len); } } } + + //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, @@ -640,31 +579,41 @@ namespace agg const int8u* covers, int8u cover) { - if (covers) + value_type* p; + if(covers) { do { - copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + + copy_or_blend_pix(p, *colors++, *covers++); } - while (--len); + while(--len); } else { - if (cover == cover_mask) + if(cover == 255) { do { - copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + + copy_or_blend_pix(p, *colors++); } - while (--len); + while(--len); } else { do { - copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); + p = (value_type*) + m_rbuf->row_ptr(x, y++, 1) + x + x + x; + + copy_or_blend_pix(p, *colors++, cover); } - while (--len); + while(--len); } } } @@ -672,19 +621,21 @@ namespace agg //-------------------------------------------------------------------- template<class Function> void for_each_pixel(Function f) { - for (unsigned y = 0; y < height(); ++y) + unsigned y; + for(y = 0; y < height(); ++y) { row_data r = m_rbuf->row(y); - if (r.ptr) + if(r.ptr) { unsigned len = r.x2 - r.x1 + 1; - pixel_type* p = pix_value_ptr(r.x1, y, len); + value_type* p = (value_type*) + m_rbuf->row_ptr(r.x1, y, len) + r.x1 * 3; do { - f(p->c); - p = p->next(); + f(p); + p += 3; } - while (--len); + while(--len); } } } @@ -708,7 +659,8 @@ namespace agg int xsrc, int ysrc, unsigned len) { - if (const int8u* p = from.row_ptr(ysrc)) + const int8u* p = from.row_ptr(ysrc); + if(p) { memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, @@ -716,8 +668,8 @@ namespace agg } } + //-------------------------------------------------------------------- - // Blend from an RGBA surface. template<class SrcPixelFormatRenderer> void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, @@ -725,55 +677,61 @@ namespace agg 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)) + const value_type* psrc = (const value_type*)from.row_ptr(ysrc); + if(psrc) { - pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + psrc += xsrc * 4; + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; - if (cover == cover_mask) + if(cover == 255) { do { - value_type alpha = psrc->c[src_order::A]; - if (alpha <= color_type::empty_value()) + value_type alpha = psrc[src_order::A]; + if(alpha) { - if (alpha >= color_type::full_value()) + if(alpha == base_mask) { - 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]; + pdst[order_type::R] = psrc[src_order::R]; + pdst[order_type::G] = psrc[src_order::G]; + pdst[order_type::B] = psrc[src_order::B]; } else { - blend_pix(pdst, - psrc->c[src_order::R], - psrc->c[src_order::G], - psrc->c[src_order::B], - alpha); + m_blender.blend_pix(pdst, + psrc[src_order::R], + psrc[src_order::G], + psrc[src_order::B], + alpha); } } - psrc = psrc->next(); - pdst = pdst->next(); + psrc += 4; + pdst += 3; } while(--len); } else { + color_type color; do { - copy_or_blend_pix(pdst, psrc->get(), cover); - psrc = psrc->next(); - pdst = pdst->next(); + color.r = psrc[src_order::R]; + color.g = psrc[src_order::G]; + color.b = psrc[src_order::B]; + color.a = psrc[src_order::A]; + copy_or_blend_pix(pdst, color, cover); + psrc += 4; + pdst += 3; } - while (--len); + 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, @@ -782,26 +740,25 @@ namespace agg 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)) + typedef typename SrcPixelFormatRenderer::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) { - pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; do { - copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); - psrc = psrc->next(); - pdst = pdst->next(); + copy_or_blend_pix(pdst, + color, + (*psrc * cover + base_mask) >> base_shift); + ++psrc; + pdst += 3; } - while (--len); + 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, @@ -810,20 +767,22 @@ namespace agg unsigned len, int8u cover) { - typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; - - if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + typedef typename SrcPixelFormatRenderer::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) { - pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; - if (cover == cover_mask) + if(cover == 255) { do { - const color_type& color = color_lut[psrc->c[0]]; - blend_pix(pdst, color); - psrc = psrc->next(); - pdst = pdst->next(); + const color_type& color = color_lut[*psrc]; + m_blender.blend_pix(pdst, + color.r, color.g, color.b, color.a); + ++psrc; + pdst += 3; } while(--len); } @@ -831,9 +790,9 @@ namespace agg { do { - copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); - psrc = psrc->next(); - pdst = pdst->next(); + copy_or_blend_pix(pdst, color_lut[*psrc], cover); + ++psrc; + pdst += 3; } while(--len); } @@ -844,98 +803,24 @@ namespace agg 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_rgb<rgba8, order_rgb>, rendering_buffer> pixfmt_rgb24; //----pixfmt_rgb24 + typedef pixfmt_alpha_blend_rgb<blender_rgb<rgba8, order_bgr>, rendering_buffer> pixfmt_bgr24; //----pixfmt_bgr24 + typedef pixfmt_alpha_blend_rgb<blender_rgb<rgba16, order_rgb>, rendering_buffer> pixfmt_rgb48; //----pixfmt_rgb48 + typedef pixfmt_alpha_blend_rgb<blender_rgb<rgba16, order_bgr>, rendering_buffer> pixfmt_bgr48; //----pixfmt_bgr48 - 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; - + typedef pixfmt_alpha_blend_rgb<blender_rgb_pre<rgba8, order_rgb>, rendering_buffer> pixfmt_rgb24_pre; //----pixfmt_rgb24_pre + typedef pixfmt_alpha_blend_rgb<blender_rgb_pre<rgba8, order_bgr>, rendering_buffer> pixfmt_bgr24_pre; //----pixfmt_bgr24_pre + typedef pixfmt_alpha_blend_rgb<blender_rgb_pre<rgba16, order_rgb>, rendering_buffer> pixfmt_rgb48_pre; //----pixfmt_rgb48_pre + typedef pixfmt_alpha_blend_rgb<blender_rgb_pre<rgba16, order_bgr>, rendering_buffer> pixfmt_bgr48_pre; //----pixfmt_bgr48_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_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_rgb, Gamma>, rendering_buffer> { 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) + pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_rgb, Gamma>, rendering_buffer>(rb) { this->blender().gamma(g); } @@ -943,23 +828,11 @@ namespace agg //-----------------------------------------------------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_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_bgr, Gamma>, rendering_buffer> { 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) + pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba8, order_bgr, Gamma>, rendering_buffer>(rb) { this->blender().gamma(g); } @@ -967,11 +840,11 @@ namespace agg //-----------------------------------------------------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_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_rgb, Gamma>, rendering_buffer> { 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) + pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_rgb, Gamma>, rendering_buffer>(rb) { this->blender().gamma(g); } @@ -979,16 +852,17 @@ namespace agg //-----------------------------------------------------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_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_bgr, Gamma>, rendering_buffer> { 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) + pixfmt_alpha_blend_rgb<blender_rgb_gamma<rgba16, order_bgr, Gamma>, rendering_buffer>(rb) { this->blender().gamma(g); } }; - + + } #endif diff --git a/src/agg/agg_pixfmt_rgba.h b/src/agg/agg_pixfmt_rgba.h new file mode 100644 index 000000000..79d10dc84 --- /dev/null +++ b/src/agg/agg_pixfmt_rgba.h @@ -0,0 +1,2911 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- +// +// 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_RGBA_INCLUDED +#define AGG_PIXFMT_RGBA_INCLUDED + +#include <string.h> +#include <math.h> +#include "agg_basics.h" +#include "agg_color_rgba.h" +#include "agg_rendering_buffer.h" + +namespace agg +{ + + //=========================================================multiplier_rgba + template<class ColorT, class Order> struct multiplier_rgba + { + typedef typename ColorT::value_type value_type; + typedef typename ColorT::calc_type calc_type; + + //-------------------------------------------------------------------- + static AGG_INLINE void premultiply(value_type* p) + { + calc_type a = p[Order::A]; + if(a < ColorT::base_mask) + { + if(a == 0) + { + p[Order::R] = p[Order::G] = p[Order::B] = 0; + return; + } + p[Order::R] = value_type((p[Order::R] * a + ColorT::base_mask) >> ColorT::base_shift); + p[Order::G] = value_type((p[Order::G] * a + ColorT::base_mask) >> ColorT::base_shift); + p[Order::B] = value_type((p[Order::B] * a + ColorT::base_mask) >> ColorT::base_shift); + } + } + + + //-------------------------------------------------------------------- + static AGG_INLINE void demultiply(value_type* p) + { + calc_type a = p[Order::A]; + if(a < ColorT::base_mask) + { + if(a == 0) + { + p[Order::R] = p[Order::G] = p[Order::B] = 0; + return; + } + calc_type r = (calc_type(p[Order::R]) * ColorT::base_mask) / a; + calc_type g = (calc_type(p[Order::G]) * ColorT::base_mask) / a; + calc_type b = (calc_type(p[Order::B]) * ColorT::base_mask) / a; + p[Order::R] = value_type((r > ColorT::base_mask) ? ColorT::base_mask : r); + p[Order::G] = value_type((g > ColorT::base_mask) ? ColorT::base_mask : g); + p[Order::B] = value_type((b > ColorT::base_mask) ? ColorT::base_mask : b); + } + } + }; + + //=====================================================apply_gamma_dir_rgba + template<class ColorT, class Order, class GammaLut> class apply_gamma_dir_rgba + { + public: + typedef typename ColorT::value_type value_type; + + apply_gamma_dir_rgba(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_rgba + template<class ColorT, class Order, class GammaLut> class apply_gamma_inv_rgba + { + public: + typedef typename ColorT::value_type value_type; + + apply_gamma_inv_rgba(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_rgba + template<class ColorT, class Order> struct blender_rgba + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + //-------------------------------------------------------------------- + static AGG_INLINE void blend_pix(value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned cover=0) + { + calc_type r = p[Order::R]; + calc_type g = p[Order::G]; + calc_type b = p[Order::B]; + calc_type a = p[Order::A]; + p[Order::R] = (value_type)(((cr - r) * alpha + (r << base_shift)) >> base_shift); + p[Order::G] = (value_type)(((cg - g) * alpha + (g << base_shift)) >> base_shift); + p[Order::B] = (value_type)(((cb - b) * alpha + (b << base_shift)) >> base_shift); + p[Order::A] = (value_type)((alpha + a) - ((alpha * a + base_mask) >> base_shift)); + } + }; + + //=========================================================blender_rgba_pre + template<class ColorT, class Order> struct blender_rgba_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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + //-------------------------------------------------------------------- + static AGG_INLINE void blend_pix(value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned cover) + { + alpha = color_type::base_mask - alpha; + cover = (cover + 1) << (base_shift - 8); + p[Order::R] = (value_type)((p[Order::R] * alpha + cr * cover) >> base_shift); + p[Order::G] = (value_type)((p[Order::G] * alpha + cg * cover) >> base_shift); + p[Order::B] = (value_type)((p[Order::B] * alpha + cb * cover) >> base_shift); + p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift)); + } + + //-------------------------------------------------------------------- + static AGG_INLINE void blend_pix(value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha) + { + alpha = color_type::base_mask - alpha; + p[Order::R] = (value_type)(((p[Order::R] * alpha) >> base_shift) + cr); + p[Order::G] = (value_type)(((p[Order::G] * alpha) >> base_shift) + cg); + p[Order::B] = (value_type)(((p[Order::B] * alpha) >> base_shift) + cb); + p[Order::A] = (value_type)(base_mask - ((alpha * (base_mask - p[Order::A])) >> base_shift)); + } + }; + + //======================================================blender_rgba_plain + template<class ColorT, class Order> struct blender_rgba_plain + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e { base_shift = color_type::base_shift }; + + //-------------------------------------------------------------------- + static AGG_INLINE void blend_pix(value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned cover=0) + { + if(alpha == 0) return; + calc_type a = p[Order::A]; + calc_type r = p[Order::R] * a; + calc_type g = p[Order::G] * a; + calc_type b = p[Order::B] * a; + a = ((alpha + a) << base_shift) - alpha * a; + p[Order::A] = (value_type)(a >> base_shift); + p[Order::R] = (value_type)((((cr << base_shift) - r) * alpha + (r << base_shift)) / a); + p[Order::G] = (value_type)((((cg << base_shift) - g) * alpha + (g << base_shift)) / a); + p[Order::B] = (value_type)((((cb << base_shift) - b) * alpha + (b << base_shift)) / a); + } + }; + + + + + + + + + + + + //=========================================================comp_op_rgba_clear + template<class ColorT, class Order> struct comp_op_rgba_clear + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(value_type* p, + unsigned, unsigned, unsigned, unsigned, + unsigned cover) + { + if(cover < 255) + { + cover = 255 - cover; + p[Order::R] = (value_type)((p[Order::R] * cover + 255) >> 8); + p[Order::G] = (value_type)((p[Order::G] * cover + 255) >> 8); + p[Order::B] = (value_type)((p[Order::B] * cover + 255) >> 8); + p[Order::A] = (value_type)((p[Order::A] * cover + 255) >> 8); + } + else + { + p[0] = p[1] = p[2] = p[3] = 0; + } + } + }; + + //===========================================================comp_op_rgba_src + template<class ColorT, class Order> struct comp_op_rgba_src + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + unsigned alpha = 255 - cover; + p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((sr * cover + 255) >> 8)); + p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((sg * cover + 255) >> 8)); + p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((sb * cover + 255) >> 8)); + p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((sa * cover + 255) >> 8)); + } + else + { + p[Order::R] = sr; + p[Order::G] = sg; + p[Order::B] = sb; + p[Order::A] = sa; + } + } + }; + + //===========================================================comp_op_rgba_dst + template<class ColorT, class Order> struct comp_op_rgba_dst + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + + static AGG_INLINE void blend_pix(value_type*, + unsigned, unsigned, unsigned, + unsigned, unsigned) + { + } + }; + + //======================================================comp_op_rgba_src_over + template<class ColorT, class Order> struct comp_op_rgba_src_over + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + calc_type s1a = base_mask - sa; + p[Order::R] = (value_type)(sr + ((p[Order::R] * s1a + base_mask) >> base_shift)); + p[Order::G] = (value_type)(sg + ((p[Order::G] * s1a + base_mask) >> base_shift)); + p[Order::B] = (value_type)(sb + ((p[Order::B] * s1a + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); + } + }; + + //======================================================comp_op_rgba_dst_over + template<class ColorT, class Order> struct comp_op_rgba_dst_over + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Dca + Sca.(1 - Da) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + calc_type d1a = base_mask - p[Order::A]; + p[Order::R] = (value_type)(p[Order::R] + ((sr * d1a + base_mask) >> base_shift)); + p[Order::G] = (value_type)(p[Order::G] + ((sg * d1a + base_mask) >> base_shift)); + p[Order::B] = (value_type)(p[Order::B] + ((sb * d1a + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); + } + }; + + //======================================================comp_op_rgba_src_in + template<class ColorT, class Order> struct comp_op_rgba_src_in + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca.Da + // Da' = Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + calc_type da = p[Order::A]; + if(cover < 255) + { + unsigned alpha = 255 - cover; + p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((((sr * da + base_mask) >> base_shift) * cover + 255) >> 8)); + p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((((sg * da + base_mask) >> base_shift) * cover + 255) >> 8)); + p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((((sb * da + base_mask) >> base_shift) * cover + 255) >> 8)); + p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((((sa * da + base_mask) >> base_shift) * cover + 255) >> 8)); + } + else + { + p[Order::R] = (value_type)((sr * da + base_mask) >> base_shift); + p[Order::G] = (value_type)((sg * da + base_mask) >> base_shift); + p[Order::B] = (value_type)((sb * da + base_mask) >> base_shift); + p[Order::A] = (value_type)((sa * da + base_mask) >> base_shift); + } + } + }; + + //======================================================comp_op_rgba_dst_in + template<class ColorT, class Order> struct comp_op_rgba_dst_in + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Dca.Sa + // Da' = Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned, unsigned, unsigned, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sa = base_mask - ((cover * (base_mask - sa) + 255) >> 8); + } + p[Order::R] = (value_type)((p[Order::R] * sa + base_mask) >> base_shift); + p[Order::G] = (value_type)((p[Order::G] * sa + base_mask) >> base_shift); + p[Order::B] = (value_type)((p[Order::B] * sa + base_mask) >> base_shift); + p[Order::A] = (value_type)((p[Order::A] * sa + base_mask) >> base_shift); + } + }; + + //======================================================comp_op_rgba_src_out + template<class ColorT, class Order> struct comp_op_rgba_src_out + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca.(1 - Da) + // Da' = Sa.(1 - Da) + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + calc_type da = base_mask - p[Order::A]; + if(cover < 255) + { + unsigned alpha = 255 - cover; + p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((((sr * da + base_mask) >> base_shift) * cover + 255) >> 8)); + p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((((sg * da + base_mask) >> base_shift) * cover + 255) >> 8)); + p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((((sb * da + base_mask) >> base_shift) * cover + 255) >> 8)); + p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((((sa * da + base_mask) >> base_shift) * cover + 255) >> 8)); + } + else + { + p[Order::R] = (value_type)((sr * da + base_mask) >> base_shift); + p[Order::G] = (value_type)((sg * da + base_mask) >> base_shift); + p[Order::B] = (value_type)((sb * da + base_mask) >> base_shift); + p[Order::A] = (value_type)((sa * da + base_mask) >> base_shift); + } + } + }; + + //======================================================comp_op_rgba_dst_out + template<class ColorT, class Order> struct comp_op_rgba_dst_out + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Dca.(1 - Sa) + // Da' = Da.(1 - Sa) + static AGG_INLINE void blend_pix(value_type* p, + unsigned, unsigned, unsigned, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sa = (sa * cover + 255) >> 8; + } + sa = base_mask - sa; + p[Order::R] = (value_type)((p[Order::R] * sa + base_shift) >> base_shift); + p[Order::G] = (value_type)((p[Order::G] * sa + base_shift) >> base_shift); + p[Order::B] = (value_type)((p[Order::B] * sa + base_shift) >> base_shift); + p[Order::A] = (value_type)((p[Order::A] * sa + base_shift) >> base_shift); + } + }; + + //=====================================================comp_op_rgba_src_atop + template<class ColorT, class Order> struct comp_op_rgba_src_atop + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca.Da + Dca.(1 - Sa) + // Da' = Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + calc_type da = p[Order::A]; + sa = base_mask - sa; + p[Order::R] = (value_type)((sr * da + p[Order::R] * sa + base_mask) >> base_shift); + p[Order::G] = (value_type)((sg * da + p[Order::G] * sa + base_mask) >> base_shift); + p[Order::B] = (value_type)((sb * da + p[Order::B] * sa + base_mask) >> base_shift); + } + }; + + //=====================================================comp_op_rgba_dst_atop + template<class ColorT, class Order> struct comp_op_rgba_dst_atop + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Dca.Sa + Sca.(1 - Da) + // Da' = Sa + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + calc_type da = base_mask - p[Order::A]; + if(cover < 255) + { + unsigned alpha = 255 - cover; + sr = (p[Order::R] * sa + sr * da + base_mask) >> base_shift; + sg = (p[Order::G] * sa + sg * da + base_mask) >> base_shift; + sb = (p[Order::B] * sa + sb * da + base_mask) >> base_shift; + p[Order::R] = (value_type)(((p[Order::R] * alpha + 255) >> 8) + ((sr * cover + 255) >> 8)); + p[Order::G] = (value_type)(((p[Order::G] * alpha + 255) >> 8) + ((sg * cover + 255) >> 8)); + p[Order::B] = (value_type)(((p[Order::B] * alpha + 255) >> 8) + ((sb * cover + 255) >> 8)); + p[Order::A] = (value_type)(((p[Order::A] * alpha + 255) >> 8) + ((sa * cover + 255) >> 8)); + + } + else + { + p[Order::R] = (value_type)((p[Order::R] * sa + sr * da + base_mask) >> base_shift); + p[Order::G] = (value_type)((p[Order::G] * sa + sg * da + base_mask) >> base_shift); + p[Order::B] = (value_type)((p[Order::B] * sa + sb * da + base_mask) >> base_shift); + p[Order::A] = (value_type)sa; + } + } + }; + + //=========================================================comp_op_rgba_xor + template<class ColorT, class Order> struct comp_op_rgba_xor + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) + // Da' = Sa + Da - 2.Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type s1a = base_mask - sa; + calc_type d1a = base_mask - p[Order::A]; + p[Order::R] = (value_type)((p[Order::R] * s1a + sr * d1a + base_mask) >> base_shift); + p[Order::G] = (value_type)((p[Order::G] * s1a + sg * d1a + base_mask) >> base_shift); + p[Order::B] = (value_type)((p[Order::B] * s1a + sb * d1a + base_mask) >> base_shift); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask/2) >> (base_shift - 1))); + } + } + }; + + //=========================================================comp_op_rgba_plus + template<class ColorT, class Order> struct comp_op_rgba_plus + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca + Dca + // Da' = Sa + Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type dr = p[Order::R] + sr; + calc_type dg = p[Order::G] + sg; + calc_type db = p[Order::B] + sb; + calc_type da = p[Order::A] + sa; + p[Order::R] = (dr > base_mask) ? (value_type)base_mask : dr; + p[Order::G] = (dg > base_mask) ? (value_type)base_mask : dg; + p[Order::B] = (db > base_mask) ? (value_type)base_mask : db; + p[Order::A] = (da > base_mask) ? (value_type)base_mask : da; + } + } + }; + + //========================================================comp_op_rgba_minus + template<class ColorT, class Order> struct comp_op_rgba_minus + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Dca - Sca + // Da' = 1 - (1 - Sa).(1 - Da) + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type dr = p[Order::R] - sr; + calc_type dg = p[Order::G] - sg; + calc_type db = p[Order::B] - sb; + p[Order::R] = (dr > base_mask) ? 0 : dr; + p[Order::G] = (dg > base_mask) ? 0 : dg; + p[Order::B] = (db > base_mask) ? 0 : db; + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); + //p[Order::A] = (value_type)(base_mask - (((base_mask - sa) * (base_mask - p[Order::A]) + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_multiply + template<class ColorT, class Order> struct comp_op_rgba_multiply + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type s1a = base_mask - sa; + calc_type d1a = base_mask - p[Order::A]; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + p[Order::R] = (value_type)((sr * dr + sr * d1a + dr * s1a + base_mask) >> base_shift); + p[Order::G] = (value_type)((sg * dg + sg * d1a + dg * s1a + base_mask) >> base_shift); + p[Order::B] = (value_type)((sb * db + sb * d1a + db * s1a + base_mask) >> base_shift); + p[Order::A] = (value_type)(sa + p[Order::A] - ((sa * p[Order::A] + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_screen + template<class ColorT, class Order> struct comp_op_rgba_screen + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = Sca + Dca - Sca.Dca + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + p[Order::R] = (value_type)(sr + dr - ((sr * dr + base_mask) >> base_shift)); + p[Order::G] = (value_type)(sg + dg - ((sg * dg + base_mask) >> base_shift)); + p[Order::B] = (value_type)(sb + db - ((sb * db + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_overlay + template<class ColorT, class Order> struct comp_op_rgba_overlay + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // if 2.Dca < Da + // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise + // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) + // + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + calc_type sada = sa * p[Order::A]; + + p[Order::R] = (value_type)(((2*dr < da) ? + 2*sr*dr + sr*d1a + dr*s1a : + sada - 2*(da - dr)*(sa - sr) + sr*d1a + dr*s1a + base_mask) >> base_shift); + + p[Order::G] = (value_type)(((2*dg < da) ? + 2*sg*dg + sg*d1a + dg*s1a : + sada - 2*(da - dg)*(sa - sg) + sg*d1a + dg*s1a + base_mask) >> base_shift); + + p[Order::B] = (value_type)(((2*db < da) ? + 2*sb*db + sb*d1a + db*s1a : + sada - 2*(da - db)*(sa - sb) + sb*d1a + db*s1a + base_mask) >> base_shift); + + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + + template<class T> inline T sd_min(T a, T b) { return (a < b) ? a : b; } + template<class T> inline T sd_max(T a, T b) { return (a > b) ? a : b; } + + //=====================================================comp_op_rgba_darken + template<class ColorT, class Order> struct comp_op_rgba_darken + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = min(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + + p[Order::R] = (value_type)((sd_min(sr * da, dr * sa) + sr * d1a + dr * s1a + base_mask) >> base_shift); + p[Order::G] = (value_type)((sd_min(sg * da, dg * sa) + sg * d1a + dg * s1a + base_mask) >> base_shift); + p[Order::B] = (value_type)((sd_min(sb * da, db * sa) + sb * d1a + db * s1a + base_mask) >> base_shift); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_lighten + template<class ColorT, class Order> struct comp_op_rgba_lighten + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = max(Sca.Da, Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + + p[Order::R] = (value_type)((sd_max(sr * da, dr * sa) + sr * d1a + dr * s1a + base_mask) >> base_shift); + p[Order::G] = (value_type)((sd_max(sg * da, dg * sa) + sg * d1a + dg * s1a + base_mask) >> base_shift); + p[Order::B] = (value_type)((sd_max(sb * da, db * sa) + sb * d1a + db * s1a + base_mask) >> base_shift); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_color_dodge + template<class ColorT, class Order> struct comp_op_rgba_color_dodge + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // if Sca.Da + Dca.Sa >= Sa.Da + // Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise + // Dca' = Dca.Sa/(1-Sca/Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + // + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + long_type drsa = dr * sa; + long_type dgsa = dg * sa; + long_type dbsa = db * sa; + long_type srda = sr * da; + long_type sgda = sg * da; + long_type sbda = sb * da; + long_type sada = sa * da; + + p[Order::R] = (value_type)((srda + drsa >= sada) ? + (sada + sr * d1a + dr * s1a + base_mask) >> base_shift : + drsa / (base_mask - (sr << base_shift) / sa) + ((sr * d1a + dr * s1a + base_mask) >> base_shift)); + + p[Order::G] = (value_type)((sgda + dgsa >= sada) ? + (sada + sg * d1a + dg * s1a + base_mask) >> base_shift : + dgsa / (base_mask - (sg << base_shift) / sa) + ((sg * d1a + dg * s1a + base_mask) >> base_shift)); + + p[Order::B] = (value_type)((sbda + dbsa >= sada) ? + (sada + sb * d1a + db * s1a + base_mask) >> base_shift : + dbsa / (base_mask - (sb << base_shift) / sa) + ((sb * d1a + db * s1a + base_mask) >> base_shift)); + + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_color_burn + template<class ColorT, class Order> struct comp_op_rgba_color_burn + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // if Sca.Da + Dca.Sa <= Sa.Da + // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise + // Dca' = Sa.(Sca.Da + Dca.Sa - Sa.Da)/Sca + Sca.(1 - Da) + Dca.(1 - Sa) + // + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + long_type drsa = dr * sa; + long_type dgsa = dg * sa; + long_type dbsa = db * sa; + long_type srda = sr * da; + long_type sgda = sg * da; + long_type sbda = sb * da; + long_type sada = sa * da; + + p[Order::R] = (value_type)(((srda + drsa <= sada) ? + sr * d1a + dr * s1a : + sa * (srda + drsa - sada) / sr + sr * d1a + dr * s1a + base_mask) >> base_shift); + + p[Order::G] = (value_type)(((sgda + dgsa <= sada) ? + sg * d1a + dg * s1a : + sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a + base_mask) >> base_shift); + + p[Order::B] = (value_type)(((sbda + dbsa <= sada) ? + sb * d1a + db * s1a : + sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a + base_mask) >> base_shift); + + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_hard_light + template<class ColorT, class Order> struct comp_op_rgba_hard_light + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // if 2.Sca < Sa + // Dca' = 2.Sca.Dca + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise + // Dca' = Sa.Da - 2.(Da - Dca).(Sa - Sca) + Sca.(1 - Da) + Dca.(1 - Sa) + // + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + calc_type sada = sa * da; + + p[Order::R] = (value_type)(((2*sr < sa) ? + 2*sr*dr + sr*d1a + dr*s1a : + sada - 2*(da - dr)*(sa - sr) + sr*d1a + dr*s1a + base_mask) >> base_shift); + + p[Order::G] = (value_type)(((2*sg < sa) ? + 2*sg*dg + sg*d1a + dg*s1a : + sada - 2*(da - dg)*(sa - sg) + sg*d1a + dg*s1a + base_mask) >> base_shift); + + p[Order::B] = (value_type)(((2*sb < sa) ? + 2*sb*db + sb*d1a + db*s1a : + sada - 2*(da - db)*(sa - sb) + sb*d1a + db*s1a + base_mask) >> base_shift); + + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_soft_light + template<class ColorT, class Order> struct comp_op_rgba_soft_light + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // if 2.Sca < Sa + // Dca' = Dca.(Sa + (1 - Dca/Da).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise if 8.Dca <= Da + // Dca' = Dca.(Sa + (1 - Dca/Da).(2.Sca - Sa).(3 - 8.Dca/Da)) + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise + // Dca' = (Dca.Sa + ((Dca/Da)^(0.5).Da - Dca).(2.Sca - Sa)) + Sca.(1 - Da) + Dca.(1 - Sa) + // + // Da' = Sa + Da - Sa.Da + + static AGG_INLINE void blend_pix(value_type* p, + unsigned r, unsigned g, unsigned b, + unsigned a, unsigned cover) + { + double sr = double(r * cover) / (base_mask * 255); + double sg = double(g * cover) / (base_mask * 255); + double sb = double(b * cover) / (base_mask * 255); + double sa = double(a * cover) / (base_mask * 255); + if(sa > 0) + { + double dr = double(p[Order::R]) / base_mask; + double dg = double(p[Order::G]) / base_mask; + double db = double(p[Order::B]) / base_mask; + double da = double(p[Order::A] ? p[Order::A] : 1) / base_mask; + if(cover < 255) + { + a = (a * cover + 255) >> 8; + } + + if(2*sr < sa) dr = dr*(sa + (1 - dr/da)*(2*sr - sa)) + sr*(1 - da) + dr*(1 - sa); + else if(8*dr <= da) dr = dr*(sa + (1 - dr/da)*(2*sr - sa)*(3 - 8*dr/da)) + sr*(1 - da) + dr*(1 - sa); + else dr = (dr*sa + (sqrt(dr/da)*da - dr)*(2*sr - sa)) + sr*(1 - da) + dr*(1 - sa); + + if(2*sg < sa) dg = dg*(sa + (1 - dg/da)*(2*sg - sa)) + sg*(1 - da) + dg*(1 - sa); + else if(8*dg <= da) dg = dg*(sa + (1 - dg/da)*(2*sg - sa)*(3 - 8*dg/da)) + sg*(1 - da) + dg*(1 - sa); + else dg = (dg*sa + (sqrt(dg/da)*da - dg)*(2*sg - sa)) + sg*(1 - da) + dg*(1 - sa); + + if(2*sb < sa) db = db*(sa + (1 - db/da)*(2*sb - sa)) + sb*(1 - da) + db*(1 - sa); + else if(8*db <= da) db = db*(sa + (1 - db/da)*(2*sb - sa)*(3 - 8*db/da)) + sb*(1 - da) + db*(1 - sa); + else db = (db*sa + (sqrt(db/da)*da - db)*(2*sb - sa)) + sb*(1 - da) + db*(1 - sa); + + p[Order::R] = (value_type)uround(dr * base_mask); + p[Order::G] = (value_type)uround(dg * base_mask); + p[Order::B] = (value_type)uround(db * base_mask); + p[Order::A] = (value_type)(a + p[Order::A] - ((a * p[Order::A] + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_difference + template<class ColorT, class Order> struct comp_op_rgba_difference + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask + }; + + // Dca' = Sca + Dca - 2.min(Sca.Da, Dca.Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + p[Order::R] = (value_type)(sr + dr - ((2 * sd_min(sr*da, dr*sa) + base_mask) >> base_shift)); + p[Order::G] = (value_type)(sg + dg - ((2 * sd_min(sg*da, dg*sa) + base_mask) >> base_shift)); + p[Order::B] = (value_type)(sb + db - ((2 * sd_min(sb*da, db*sa) + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_exclusion + template<class ColorT, class Order> struct comp_op_rgba_exclusion + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = (Sca.Da + Dca.Sa - 2.Sca.Dca) + Sca.(1 - Da) + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type d1a = base_mask - p[Order::A]; + calc_type s1a = base_mask - sa; + calc_type dr = p[Order::R]; + calc_type dg = p[Order::G]; + calc_type db = p[Order::B]; + calc_type da = p[Order::A]; + p[Order::R] = (value_type)((sr*da + dr*sa - 2*sr*dr + sr*d1a + dr*s1a + base_mask) >> base_shift); + p[Order::G] = (value_type)((sg*da + dg*sa - 2*sg*dg + sg*d1a + dg*s1a + base_mask) >> base_shift); + p[Order::B] = (value_type)((sb*da + db*sa - 2*sb*db + sb*d1a + db*s1a + base_mask) >> base_shift); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=====================================================comp_op_rgba_contrast + template<class ColorT, class Order> struct comp_op_rgba_contrast + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + long_type dr = p[Order::R]; + long_type dg = p[Order::G]; + long_type db = p[Order::B]; + int da = p[Order::A]; + long_type d2a = da >> 1; + unsigned s2a = sa >> 1; + + int r = (int)((((dr - d2a) * int((sr - s2a)*2 + base_mask)) >> base_shift) + d2a); + int g = (int)((((dg - d2a) * int((sg - s2a)*2 + base_mask)) >> base_shift) + d2a); + int b = (int)((((db - d2a) * int((sb - s2a)*2 + base_mask)) >> base_shift) + d2a); + + r = (r < 0) ? 0 : r; + g = (g < 0) ? 0 : g; + b = (b < 0) ? 0 : b; + + p[Order::R] = (value_type)((r > da) ? da : r); + p[Order::G] = (value_type)((g > da) ? da : g); + p[Order::B] = (value_type)((b > da) ? da : b); + } + }; + + //=====================================================comp_op_rgba_invert + template<class ColorT, class Order> struct comp_op_rgba_invert + { + 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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = (Da - Dca) * Sa + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + sa = (sa * cover + 255) >> 8; + if(sa) + { + calc_type da = p[Order::A]; + calc_type dr = ((da - p[Order::R]) * sa + base_mask) >> base_shift; + calc_type dg = ((da - p[Order::G]) * sa + base_mask) >> base_shift; + calc_type db = ((da - p[Order::B]) * sa + base_mask) >> base_shift; + calc_type s1a = base_mask - sa; + p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift)); + p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift)); + p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + //=================================================comp_op_rgba_invert_rgb + template<class ColorT, class Order> struct comp_op_rgba_invert_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; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + // Dca' = (Da - Dca) * Sca + Dca.(1 - Sa) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, + unsigned sa, unsigned cover) + { + if(cover < 255) + { + sr = (sr * cover + 255) >> 8; + sg = (sg * cover + 255) >> 8; + sb = (sb * cover + 255) >> 8; + sa = (sa * cover + 255) >> 8; + } + if(sa) + { + calc_type da = p[Order::A]; + calc_type dr = ((da - p[Order::R]) * sr + base_mask) >> base_shift; + calc_type dg = ((da - p[Order::G]) * sg + base_mask) >> base_shift; + calc_type db = ((da - p[Order::B]) * sb + base_mask) >> base_shift; + calc_type s1a = base_mask - sa; + p[Order::R] = (value_type)(dr + ((p[Order::R] * s1a + base_mask) >> base_shift)); + p[Order::G] = (value_type)(dg + ((p[Order::G] * s1a + base_mask) >> base_shift)); + p[Order::B] = (value_type)(db + ((p[Order::B] * s1a + base_mask) >> base_shift)); + p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); + } + } + }; + + + + + + //======================================================comp_op_table_rgba + template<class ColorT, class Order> struct comp_op_table_rgba + { + typedef typename ColorT::value_type value_type; + typedef void (*comp_op_func_type)(value_type* p, + unsigned cr, + unsigned cg, + unsigned cb, + unsigned ca, + unsigned cover); + static comp_op_func_type g_comp_op_func[]; + }; + + //==========================================================g_comp_op_func + template<class ColorT, class Order> + typename comp_op_table_rgba<ColorT, Order>::comp_op_func_type + comp_op_table_rgba<ColorT, Order>::g_comp_op_func[] = + { + comp_op_rgba_clear <ColorT,Order>::blend_pix, + comp_op_rgba_src <ColorT,Order>::blend_pix, + comp_op_rgba_dst <ColorT,Order>::blend_pix, + comp_op_rgba_src_over <ColorT,Order>::blend_pix, + comp_op_rgba_dst_over <ColorT,Order>::blend_pix, + comp_op_rgba_src_in <ColorT,Order>::blend_pix, + comp_op_rgba_dst_in <ColorT,Order>::blend_pix, + comp_op_rgba_src_out <ColorT,Order>::blend_pix, + comp_op_rgba_dst_out <ColorT,Order>::blend_pix, + comp_op_rgba_src_atop <ColorT,Order>::blend_pix, + comp_op_rgba_dst_atop <ColorT,Order>::blend_pix, + comp_op_rgba_xor <ColorT,Order>::blend_pix, + comp_op_rgba_plus <ColorT,Order>::blend_pix, + comp_op_rgba_minus <ColorT,Order>::blend_pix, + comp_op_rgba_multiply <ColorT,Order>::blend_pix, + comp_op_rgba_screen <ColorT,Order>::blend_pix, + comp_op_rgba_overlay <ColorT,Order>::blend_pix, + comp_op_rgba_darken <ColorT,Order>::blend_pix, + comp_op_rgba_lighten <ColorT,Order>::blend_pix, + comp_op_rgba_color_dodge<ColorT,Order>::blend_pix, + comp_op_rgba_color_burn <ColorT,Order>::blend_pix, + comp_op_rgba_hard_light <ColorT,Order>::blend_pix, + comp_op_rgba_soft_light <ColorT,Order>::blend_pix, + comp_op_rgba_difference <ColorT,Order>::blend_pix, + comp_op_rgba_exclusion <ColorT,Order>::blend_pix, + comp_op_rgba_contrast <ColorT,Order>::blend_pix, + comp_op_rgba_invert <ColorT,Order>::blend_pix, + comp_op_rgba_invert_rgb <ColorT,Order>::blend_pix, + 0 + }; + + + //==============================================================comp_op_e + enum comp_op_e + { + comp_op_clear, //----comp_op_clear + comp_op_src, //----comp_op_src + comp_op_dst, //----comp_op_dst + comp_op_src_over, //----comp_op_src_over + comp_op_dst_over, //----comp_op_dst_over + comp_op_src_in, //----comp_op_src_in + comp_op_dst_in, //----comp_op_dst_in + comp_op_src_out, //----comp_op_src_out + comp_op_dst_out, //----comp_op_dst_out + comp_op_src_atop, //----comp_op_src_atop + comp_op_dst_atop, //----comp_op_dst_atop + comp_op_xor, //----comp_op_xor + comp_op_plus, //----comp_op_plus + comp_op_minus, //----comp_op_minus + comp_op_multiply, //----comp_op_multiply + comp_op_screen, //----comp_op_screen + comp_op_overlay, //----comp_op_overlay + comp_op_darken, //----comp_op_darken + comp_op_lighten, //----comp_op_lighten + comp_op_color_dodge, //----comp_op_color_dodge + comp_op_color_burn, //----comp_op_color_burn + comp_op_hard_light, //----comp_op_hard_light + comp_op_soft_light, //----comp_op_soft_light + comp_op_difference, //----comp_op_difference + comp_op_exclusion, //----comp_op_exclusion + comp_op_contrast, //----comp_op_contrast + comp_op_invert, //----comp_op_invert + comp_op_invert_rgb, //----comp_op_invert_rgb + + end_of_comp_op_e + }; + + + + + + + + //====================================================comp_op_adaptor_rgba + template<class ColorT, class Order> struct comp_op_adaptor_rgba + { + typedef Order order_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op] + (p, (cr * ca + base_mask) >> base_shift, + (cg * ca + base_mask) >> base_shift, + (cb * ca + base_mask) >> base_shift, + ca, cover); + } + }; + + //=========================================comp_op_adaptor_clip_to_dst_rgba + template<class ColorT, class Order> struct comp_op_adaptor_clip_to_dst_rgba + { + typedef Order order_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + cr = (cr * ca + base_mask) >> base_shift; + cg = (cg * ca + base_mask) >> base_shift; + cb = (cb * ca + base_mask) >> base_shift; + unsigned da = p[Order::A]; + comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op] + (p, (cr * da + base_mask) >> base_shift, + (cg * da + base_mask) >> base_shift, + (cb * da + base_mask) >> base_shift, + (ca * da + base_mask) >> base_shift, + cover); + } + }; + + //================================================comp_op_adaptor_rgba_pre + template<class ColorT, class Order> struct comp_op_adaptor_rgba_pre + { + typedef Order order_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op](p, cr, cg, cb, ca, cover); + } + }; + + //=====================================comp_op_adaptor_clip_to_dst_rgba_pre + template<class ColorT, class Order> struct comp_op_adaptor_clip_to_dst_rgba_pre + { + typedef Order order_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + unsigned da = p[Order::A]; + comp_op_table_rgba<ColorT, Order>::g_comp_op_func[op] + (p, (cr * da + base_mask) >> base_shift, + (cg * da + base_mask) >> base_shift, + (cb * da + base_mask) >> base_shift, + (ca * da + base_mask) >> base_shift, + cover); + } + }; + + //=======================================================comp_adaptor_rgba + template<class BlenderPre> struct comp_adaptor_rgba + { + typedef typename BlenderPre::order_type order_type; + typedef typename BlenderPre::color_type color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + BlenderPre::blend_pix(p, + (cr * ca + base_mask) >> base_shift, + (cg * ca + base_mask) >> base_shift, + (cb * ca + base_mask) >> base_shift, + ca, cover); + } + }; + + //==========================================comp_adaptor_clip_to_dst_rgba + template<class BlenderPre> struct comp_adaptor_clip_to_dst_rgba + { + typedef typename BlenderPre::order_type order_type; + typedef typename BlenderPre::color_type color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + cr = (cr * ca + base_mask) >> base_shift; + cg = (cg * ca + base_mask) >> base_shift; + cb = (cb * ca + base_mask) >> base_shift; + unsigned da = p[order_type::A]; + BlenderPre::blend_pix(p, + (cr * da + base_mask) >> base_shift, + (cg * da + base_mask) >> base_shift, + (cb * da + base_mask) >> base_shift, + (ca * da + base_mask) >> base_shift, + cover); + } + }; + + //======================================comp_adaptor_clip_to_dst_rgba_pre + template<class BlenderPre> struct comp_adaptor_clip_to_dst_rgba_pre + { + typedef typename BlenderPre::order_type order_type; + typedef typename BlenderPre::color_type color_type; + typedef typename color_type::value_type value_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_mask = color_type::base_mask + }; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned ca, + unsigned cover) + { + unsigned da = p[order_type::A]; + BlenderPre::blend_pix(p, + (cr * da + base_mask) >> base_shift, + (cg * da + base_mask) >> base_shift, + (cb * da + base_mask) >> base_shift, + (ca * da + base_mask) >> base_shift, + cover); + } + }; + + + + + + + //===============================================copy_or_blend_rgba_wrapper + template<class Blender> struct copy_or_blend_rgba_wrapper + { + typedef typename Blender::color_type color_type; + typedef typename Blender::order_type order_type; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask + }; + + //-------------------------------------------------------------------- + static AGG_INLINE void copy_or_blend_pix(value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha) + { + if(alpha) + { + if(alpha == base_mask) + { + p[order_type::R] = cr; + p[order_type::G] = cg; + p[order_type::B] = cb; + p[order_type::A] = base_mask; + } + else + { + Blender::blend_pix(p, cr, cg, cb, alpha); + } + } + } + + //-------------------------------------------------------------------- + static AGG_INLINE void copy_or_blend_pix(value_type* p, + unsigned cr, unsigned cg, unsigned cb, + unsigned alpha, + unsigned cover) + { + if(cover == 255) + { + copy_or_blend_pix(p, cr, cg, cb, alpha); + } + else + { + if(alpha) + { + alpha = (alpha * (cover + 1)) >> 8; + if(alpha == base_mask) + { + p[order_type::R] = cr; + p[order_type::G] = cg; + p[order_type::B] = cb; + p[order_type::A] = base_mask; + } + else + { + Blender::blend_pix(p, cr, cg, cb, alpha, cover); + } + } + } + } + }; + + + + + + + //=================================================pixfmt_alpha_blend_rgba + template<class Blender, class RenBuf, class PixelT = int32u> + class pixfmt_alpha_blend_rgba + { + public: + typedef RenBuf rbuf_type; + typedef typename rbuf_type::row_data row_data; + typedef PixelT pixel_type; + typedef Blender blender_type; + 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; + typedef copy_or_blend_rgba_wrapper<blender_type> cob_type; + enum base_scale_e + { + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask, + pix_width = sizeof(pixel_type) + }; + + //-------------------------------------------------------------------- + pixfmt_alpha_blend_rgba() : m_rbuf(0) {} + explicit pixfmt_alpha_blend_rgba(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; + } + + //-------------------------------------------------------------------- + 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) + x * pix_width; + } + + AGG_INLINE const int8u* pix_ptr(int x, int y) const + { + return m_rbuf->row_ptr(y) + x * pix_width; + } + + + //-------------------------------------------------------------------- + AGG_INLINE static void make_pix(int8u* p, const color_type& c) + { + ((value_type*)p)[order_type::R] = c.r; + ((value_type*)p)[order_type::G] = c.g; + ((value_type*)p)[order_type::B] = c.b; + ((value_type*)p)[order_type::A] = c.a; + } + + //-------------------------------------------------------------------- + AGG_INLINE color_type pixel(int x, int y) const + { + const value_type* p = (const value_type*)m_rbuf->row_ptr(y); + if(p) + { + p += x << 2; + return color_type(p[order_type::R], + p[order_type::G], + p[order_type::B], + p[order_type::A]); + } + return color_type::no_color(); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_pixel(int x, int y, const color_type& c) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2); + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; + p[order_type::A] = c.a; + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) + { + cob_type::copy_or_blend_pix( + (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2), + c.r, c.g, c.b, c.a, + cover); + } + + + //-------------------------------------------------------------------- + AGG_INLINE void copy_hline(int x, int y, + unsigned len, + const color_type& c) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + pixel_type v; + ((value_type*)&v)[order_type::R] = c.r; + ((value_type*)&v)[order_type::G] = c.g; + ((value_type*)&v)[order_type::B] = c.b; + ((value_type*)&v)[order_type::A] = c.a; + do + { + *(pixel_type*)p = v; + p += 4; + } + while(--len); + } + + + //-------------------------------------------------------------------- + AGG_INLINE void copy_vline(int x, int y, + unsigned len, + const color_type& c) + { + pixel_type v; + ((value_type*)&v)[order_type::R] = c.r; + ((value_type*)&v)[order_type::G] = c.g; + ((value_type*)&v)[order_type::B] = c.b; + ((value_type*)&v)[order_type::A] = c.a; + do + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + *(pixel_type*)p = v; + } + while(--len); + } + + + //-------------------------------------------------------------------- + void blend_hline(int x, int y, + unsigned len, + const color_type& c, + int8u cover) + { + if (c.a) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) + { + pixel_type v; + ((value_type*)&v)[order_type::R] = c.r; + ((value_type*)&v)[order_type::G] = c.g; + ((value_type*)&v)[order_type::B] = c.b; + ((value_type*)&v)[order_type::A] = c.a; + do + { + *(pixel_type*)p = v; + p += 4; + } + while(--len); + } + else + { + if(cover == 255) + { + do + { + blender_type::blend_pix(p, c.r, c.g, c.b, alpha); + p += 4; + } + while(--len); + } + else + { + do + { + blender_type::blend_pix(p, c.r, c.g, c.b, alpha, cover); + p += 4; + } + while(--len); + } + } + } + } + + + //-------------------------------------------------------------------- + void blend_vline(int x, int y, + unsigned len, + const color_type& c, + int8u cover) + { + if (c.a) + { + value_type* p; + calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; + if(alpha == base_mask) + { + pixel_type v; + ((value_type*)&v)[order_type::R] = c.r; + ((value_type*)&v)[order_type::G] = c.g; + ((value_type*)&v)[order_type::B] = c.b; + ((value_type*)&v)[order_type::A] = c.a; + do + { + p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + *(pixel_type*)p = v; + } + while(--len); + } + else + { + if(cover == 255) + { + do + { + p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + blender_type::blend_pix(p, c.r, c.g, c.b, alpha); + } + while(--len); + } + else + { + do + { + p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + blender_type::blend_pix(p, c.r, c.g, c.b, alpha, cover); + } + while(--len); + } + } + } + } + + + //-------------------------------------------------------------------- + void blend_solid_hspan(int x, int y, + unsigned len, + const color_type& c, + const int8u* covers) + { + if (c.a) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + do + { + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + if(alpha == base_mask) + { + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; + p[order_type::A] = base_mask; + } + else + { + blender_type::blend_pix(p, c.r, c.g, c.b, alpha, *covers); + } + p += 4; + ++covers; + } + while(--len); + } + } + + + //-------------------------------------------------------------------- + void blend_solid_vspan(int x, int y, + unsigned len, + const color_type& c, + const int8u* covers) + { + if (c.a) + { + do + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + if(alpha == base_mask) + { + p[order_type::R] = c.r; + p[order_type::G] = c.g; + p[order_type::B] = c.b; + p[order_type::A] = base_mask; + } + else + { + blender_type::blend_pix(p, c.r, c.g, c.b, alpha, *covers); + } + ++covers; + } + while(--len); + } + } + + + //-------------------------------------------------------------------- + void copy_color_hspan(int x, int y, + unsigned len, + const color_type* colors) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + do + { + p[order_type::R] = colors->r; + p[order_type::G] = colors->g; + p[order_type::B] = colors->b; + p[order_type::A] = colors->a; + ++colors; + p += 4; + } + while(--len); + } + + + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + p[order_type::R] = colors->r; + p[order_type::G] = colors->g; + p[order_type::B] = colors->b; + p[order_type::A] = colors->a; + ++colors; + } + while(--len); + } + + + //-------------------------------------------------------------------- + void blend_color_hspan(int x, int y, + unsigned len, + const color_type* colors, + const int8u* covers, + int8u cover) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + if(covers) + { + do + { + cob_type::copy_or_blend_pix(p, + colors->r, + colors->g, + colors->b, + colors->a, + *covers++); + p += 4; + ++colors; + } + while(--len); + } + else + { + if(cover == 255) + { + do + { + cob_type::copy_or_blend_pix(p, + colors->r, + colors->g, + colors->b, + colors->a); + p += 4; + ++colors; + } + while(--len); + } + else + { + do + { + cob_type::copy_or_blend_pix(p, + colors->r, + colors->g, + colors->b, + colors->a, + cover); + p += 4; + ++colors; + } + while(--len); + } + } + } + + + + //-------------------------------------------------------------------- + void blend_color_vspan(int x, int y, + unsigned len, + const color_type* colors, + const int8u* covers, + int8u cover) + { + value_type* p; + if(covers) + { + do + { + p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + cob_type::copy_or_blend_pix(p, + colors->r, + colors->g, + colors->b, + colors->a, + *covers++); + ++colors; + } + while(--len); + } + else + { + if(cover == 255) + { + do + { + p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + cob_type::copy_or_blend_pix(p, + colors->r, + colors->g, + colors->b, + colors->a); + ++colors; + } + while(--len); + } + else + { + do + { + p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + cob_type::copy_or_blend_pix(p, + colors->r, + colors->g, + colors->b, + colors->a, + cover); + ++colors; + } + while(--len); + } + } + } + + //-------------------------------------------------------------------- + template<class Function> void for_each_pixel(Function f) + { + unsigned y; + for(y = 0; y < height(); ++y) + { + row_data r = m_rbuf->row(y); + if(r.ptr) + { + unsigned len = r.x2 - r.x1 + 1; + value_type* p = + (value_type*)m_rbuf->row_ptr(r.x1, y, len) + (r.x1 << 2); + do + { + f(p); + p += 4; + } + while(--len); + } + } + } + + //-------------------------------------------------------------------- + void premultiply() + { + for_each_pixel(multiplier_rgba<color_type, order_type>::premultiply); + } + + //-------------------------------------------------------------------- + void demultiply() + { + for_each_pixel(multiplier_rgba<color_type, order_type>::demultiply); + } + + //-------------------------------------------------------------------- + template<class GammaLut> void apply_gamma_dir(const GammaLut& g) + { + for_each_pixel(apply_gamma_dir_rgba<color_type, order_type, GammaLut>(g)); + } + + //-------------------------------------------------------------------- + template<class GammaLut> void apply_gamma_inv(const GammaLut& g) + { + for_each_pixel(apply_gamma_inv_rgba<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) + { + const int8u* p = from.row_ptr(ysrc); + if(p) + { + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, + len * pix_width); + } + } + + //-------------------------------------------------------------------- + template<class SrcPixelFormatRenderer> + void blend_from(const SrcPixelFormatRenderer& from, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::order_type src_order; + const value_type* psrc = (value_type*)from.row_ptr(ysrc); + if(psrc) + { + psrc += xsrc << 2; + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + int incp = 4; + if(xdst > xsrc) + { + psrc += (len-1) << 2; + pdst += (len-1) << 2; + incp = -4; + } + + if(cover == 255) + { + do + { + cob_type::copy_or_blend_pix(pdst, + psrc[src_order::R], + psrc[src_order::G], + psrc[src_order::B], + psrc[src_order::A]); + psrc += incp; + pdst += incp; + } + while(--len); + } + else + { + do + { + cob_type::copy_or_blend_pix(pdst, + psrc[src_order::R], + psrc[src_order::G], + psrc[src_order::B], + psrc[src_order::A], + cover); + psrc += incp; + pdst += incp; + } + while(--len); + } + } + } + + //-------------------------------------------------------------------- + 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::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + do + { + cob_type::copy_or_blend_pix(pdst, + color.r, color.g, color.b, color.a, + (*psrc * cover + base_mask) >> base_shift); + ++psrc; + pdst += 4; + } + while(--len); + } + } + + //-------------------------------------------------------------------- + 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::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + + if(cover == 255) + { + do + { + const color_type& color = color_lut[*psrc]; + cob_type::copy_or_blend_pix(pdst, + color.r, color.g, color.b, color.a); + ++psrc; + pdst += 4; + } + while(--len); + } + else + { + do + { + const color_type& color = color_lut[*psrc]; + cob_type::copy_or_blend_pix(pdst, + color.r, color.g, color.b, color.a, + cover); + ++psrc; + pdst += 4; + } + while(--len); + } + } + } + + private: + rbuf_type* m_rbuf; + }; + + + + + //================================================pixfmt_custom_blend_rgba + template<class Blender, class RenBuf> class pixfmt_custom_blend_rgba + { + public: + typedef RenBuf rbuf_type; + typedef typename rbuf_type::row_data row_data; + typedef Blender blender_type; + 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 base_scale_e + { + base_shift = color_type::base_shift, + base_scale = color_type::base_scale, + base_mask = color_type::base_mask, + pix_width = sizeof(value_type) * 4 + }; + + + //-------------------------------------------------------------------- + pixfmt_custom_blend_rgba() : m_rbuf(0), m_comp_op(3) {} + explicit pixfmt_custom_blend_rgba(rbuf_type& rb, unsigned comp_op=3) : + m_rbuf(&rb), + m_comp_op(comp_op) + {} + 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; + } + + //-------------------------------------------------------------------- + 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) + x * pix_width; + } + + AGG_INLINE const int8u* pix_ptr(int x, int y) const + { + return m_rbuf->row_ptr(y) + x * pix_width; + } + + //-------------------------------------------------------------------- + void comp_op(unsigned op) { m_comp_op = op; } + unsigned comp_op() const { return m_comp_op; } + + //-------------------------------------------------------------------- + AGG_INLINE static void make_pix(int8u* p, const color_type& c) + { + ((value_type*)p)[order_type::R] = c.r; + ((value_type*)p)[order_type::G] = c.g; + ((value_type*)p)[order_type::B] = c.b; + ((value_type*)p)[order_type::A] = c.a; + } + + //-------------------------------------------------------------------- + color_type pixel(int x, int y) const + { + const value_type* p = (value_type*)m_rbuf->row_ptr(y) + (x << 2); + return color_type(p[order_type::R], + p[order_type::G], + p[order_type::B], + p[order_type::A]); + } + + //-------------------------------------------------------------------- + void copy_pixel(int x, int y, const color_type& c) + { + blender_type::blend_pix( + m_comp_op, + (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2), + c.r, c.g, c.b, c.a, 255); + } + + //-------------------------------------------------------------------- + void blend_pixel(int x, int y, const color_type& c, int8u cover) + { + blender_type::blend_pix( + m_comp_op, + (value_type*)m_rbuf->row_ptr(x, y, 1) + (x << 2), + c.r, c.g, c.b, c.a, + cover); + } + + //-------------------------------------------------------------------- + void copy_hline(int x, int y, unsigned len, const color_type& c) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2);; + do + { + blender_type::blend_pix(m_comp_op, p, c.r, c.g, c.b, c.a, 255); + p += 4; + } + while(--len); + } + + //-------------------------------------------------------------------- + void copy_vline(int x, int y, unsigned len, const color_type& c) + { + do + { + blender_type::blend_pix( + m_comp_op, + (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), + c.r, c.g, c.b, c.a, 255); + } + while(--len); + } + + //-------------------------------------------------------------------- + void blend_hline(int x, int y, unsigned len, + const color_type& c, int8u cover) + { + + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + do + { + blender_type::blend_pix(m_comp_op, p, c.r, c.g, c.b, c.a, cover); + p += 4; + } + while(--len); + } + + //-------------------------------------------------------------------- + void blend_vline(int x, int y, unsigned len, + const color_type& c, int8u cover) + { + + do + { + blender_type::blend_pix( + m_comp_op, + (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), + c.r, c.g, c.b, c.a, + cover); + } + while(--len); + } + + //-------------------------------------------------------------------- + void blend_solid_hspan(int x, int y, unsigned len, + const color_type& c, const int8u* covers) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + do + { + blender_type::blend_pix(m_comp_op, + p, c.r, c.g, c.b, c.a, + *covers++); + p += 4; + } + while(--len); + } + + //-------------------------------------------------------------------- + void blend_solid_vspan(int x, int y, unsigned len, + const color_type& c, const int8u* covers) + { + do + { + blender_type::blend_pix( + m_comp_op, + (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), + c.r, c.g, c.b, c.a, + *covers++); + } + while(--len); + } + + //-------------------------------------------------------------------- + void copy_color_hspan(int x, int y, + unsigned len, + const color_type* colors) + { + + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + do + { + p[order_type::R] = colors->r; + p[order_type::G] = colors->g; + p[order_type::B] = colors->b; + p[order_type::A] = colors->a; + ++colors; + p += 4; + } + while(--len); + } + + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); + p[order_type::R] = colors->r; + p[order_type::G] = colors->g; + p[order_type::B] = colors->b; + p[order_type::A] = colors->a; + ++colors; + } + while(--len); + } + + //-------------------------------------------------------------------- + void blend_color_hspan(int x, int y, unsigned len, + const color_type* colors, + const int8u* covers, + int8u cover) + { + value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); + do + { + blender_type::blend_pix(m_comp_op, + p, + colors->r, + colors->g, + colors->b, + colors->a, + covers ? *covers++ : cover); + p += 4; + ++colors; + } + while(--len); + } + + //-------------------------------------------------------------------- + void blend_color_vspan(int x, int y, unsigned len, + const color_type* colors, + const int8u* covers, + int8u cover) + { + do + { + blender_type::blend_pix( + m_comp_op, + (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2), + colors->r, + colors->g, + colors->b, + colors->a, + covers ? *covers++ : cover); + ++colors; + } + while(--len); + + } + + //-------------------------------------------------------------------- + template<class Function> void for_each_pixel(Function f) + { + unsigned y; + for(y = 0; y < height(); ++y) + { + row_data r = m_rbuf->row(y); + if(r.ptr) + { + unsigned len = r.x2 - r.x1 + 1; + value_type* p = + (value_type*)m_rbuf->row_ptr(r.x1, y, len) + (r.x1 << 2); + do + { + f(p); + p += 4; + } + while(--len); + } + } + } + + //-------------------------------------------------------------------- + void premultiply() + { + for_each_pixel(multiplier_rgba<color_type, order_type>::premultiply); + } + + //-------------------------------------------------------------------- + void demultiply() + { + for_each_pixel(multiplier_rgba<color_type, order_type>::demultiply); + } + + //-------------------------------------------------------------------- + template<class GammaLut> void apply_gamma_dir(const GammaLut& g) + { + for_each_pixel(apply_gamma_dir_rgba<color_type, order_type, GammaLut>(g)); + } + + //-------------------------------------------------------------------- + template<class GammaLut> void apply_gamma_inv(const GammaLut& g) + { + for_each_pixel(apply_gamma_inv_rgba<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) + { + const int8u* p = from.row_ptr(ysrc); + if(p) + { + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, + len * pix_width); + } + } + + //-------------------------------------------------------------------- + template<class SrcPixelFormatRenderer> + void blend_from(const SrcPixelFormatRenderer& from, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::order_type src_order; + const value_type* psrc = (const value_type*)from.row_ptr(ysrc); + if(psrc) + { + psrc += xsrc << 2; + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + + int incp = 4; + if(xdst > xsrc) + { + psrc += (len-1) << 2; + pdst += (len-1) << 2; + incp = -4; + } + + do + { + blender_type::blend_pix(m_comp_op, + pdst, + psrc[src_order::R], + psrc[src_order::G], + psrc[src_order::B], + psrc[src_order::A], + cover); + psrc += incp; + pdst += incp; + } + while(--len); + } + } + + //-------------------------------------------------------------------- + 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::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + do + { + blender_type::blend_pix(m_comp_op, + pdst, + color.r, color.g, color.b, color.a, + (*psrc * cover + base_mask) >> base_shift); + ++psrc; + pdst += 4; + } + while(--len); + } + } + + //-------------------------------------------------------------------- + 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::value_type src_value_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + value_type* pdst = + (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + do + { + const color_type& color = color_lut[*psrc]; + blender_type::blend_pix(m_comp_op, + pdst, + color.r, color.g, color.b, color.a, + cover); + ++psrc; + pdst += 4; + } + while(--len); + } + } + + private: + rbuf_type* m_rbuf; + unsigned m_comp_op; + }; + + + + + //----------------------------------------------------------------------- + typedef blender_rgba<rgba8, order_rgba> blender_rgba32; //----blender_rgba32 + typedef blender_rgba<rgba8, order_argb> blender_argb32; //----blender_argb32 + typedef blender_rgba<rgba8, order_abgr> blender_abgr32; //----blender_abgr32 + typedef blender_rgba<rgba8, order_bgra> blender_bgra32; //----blender_bgra32 + + typedef blender_rgba_pre<rgba8, order_rgba> blender_rgba32_pre; //----blender_rgba32_pre + typedef blender_rgba_pre<rgba8, order_argb> blender_argb32_pre; //----blender_argb32_pre + typedef blender_rgba_pre<rgba8, order_abgr> blender_abgr32_pre; //----blender_abgr32_pre + typedef blender_rgba_pre<rgba8, order_bgra> blender_bgra32_pre; //----blender_bgra32_pre + + typedef blender_rgba_plain<rgba8, order_rgba> blender_rgba32_plain; //----blender_rgba32_plain + typedef blender_rgba_plain<rgba8, order_argb> blender_argb32_plain; //----blender_argb32_plain + typedef blender_rgba_plain<rgba8, order_abgr> blender_abgr32_plain; //----blender_abgr32_plain + typedef blender_rgba_plain<rgba8, order_bgra> blender_bgra32_plain; //----blender_bgra32_plain + + typedef blender_rgba<rgba16, order_rgba> blender_rgba64; //----blender_rgba64 + typedef blender_rgba<rgba16, order_argb> blender_argb64; //----blender_argb64 + typedef blender_rgba<rgba16, order_abgr> blender_abgr64; //----blender_abgr64 + typedef blender_rgba<rgba16, order_bgra> blender_bgra64; //----blender_bgra64 + + typedef blender_rgba_pre<rgba16, order_rgba> blender_rgba64_pre; //----blender_rgba64_pre + typedef blender_rgba_pre<rgba16, order_argb> blender_argb64_pre; //----blender_argb64_pre + typedef blender_rgba_pre<rgba16, order_abgr> blender_abgr64_pre; //----blender_abgr64_pre + typedef blender_rgba_pre<rgba16, order_bgra> blender_bgra64_pre; //----blender_bgra64_pre + + + //----------------------------------------------------------------------- + typedef int32u pixel32_type; + typedef pixfmt_alpha_blend_rgba<blender_rgba32, rendering_buffer, pixel32_type> pixfmt_rgba32; //----pixfmt_rgba32 + typedef pixfmt_alpha_blend_rgba<blender_argb32, rendering_buffer, pixel32_type> pixfmt_argb32; //----pixfmt_argb32 + typedef pixfmt_alpha_blend_rgba<blender_abgr32, rendering_buffer, pixel32_type> pixfmt_abgr32; //----pixfmt_abgr32 + typedef pixfmt_alpha_blend_rgba<blender_bgra32, rendering_buffer, pixel32_type> pixfmt_bgra32; //----pixfmt_bgra32 + + typedef pixfmt_alpha_blend_rgba<blender_rgba32_pre, rendering_buffer, pixel32_type> pixfmt_rgba32_pre; //----pixfmt_rgba32_pre + typedef pixfmt_alpha_blend_rgba<blender_argb32_pre, rendering_buffer, pixel32_type> pixfmt_argb32_pre; //----pixfmt_argb32_pre + typedef pixfmt_alpha_blend_rgba<blender_abgr32_pre, rendering_buffer, pixel32_type> pixfmt_abgr32_pre; //----pixfmt_abgr32_pre + typedef pixfmt_alpha_blend_rgba<blender_bgra32_pre, rendering_buffer, pixel32_type> pixfmt_bgra32_pre; //----pixfmt_bgra32_pre + + typedef pixfmt_alpha_blend_rgba<blender_rgba32_plain, rendering_buffer, pixel32_type> pixfmt_rgba32_plain; //----pixfmt_rgba32_plain + typedef pixfmt_alpha_blend_rgba<blender_argb32_plain, rendering_buffer, pixel32_type> pixfmt_argb32_plain; //----pixfmt_argb32_plain + typedef pixfmt_alpha_blend_rgba<blender_abgr32_plain, rendering_buffer, pixel32_type> pixfmt_abgr32_plain; //----pixfmt_abgr32_plain + typedef pixfmt_alpha_blend_rgba<blender_bgra32_plain, rendering_buffer, pixel32_type> pixfmt_bgra32_plain; //----pixfmt_bgra32_plain + + struct pixel64_type { int16u c[4]; }; + typedef pixfmt_alpha_blend_rgba<blender_rgba64, rendering_buffer, pixel64_type> pixfmt_rgba64; //----pixfmt_rgba64 + typedef pixfmt_alpha_blend_rgba<blender_argb64, rendering_buffer, pixel64_type> pixfmt_argb64; //----pixfmt_argb64 + typedef pixfmt_alpha_blend_rgba<blender_abgr64, rendering_buffer, pixel64_type> pixfmt_abgr64; //----pixfmt_abgr64 + typedef pixfmt_alpha_blend_rgba<blender_bgra64, rendering_buffer, pixel64_type> pixfmt_bgra64; //----pixfmt_bgra64 + + typedef pixfmt_alpha_blend_rgba<blender_rgba64_pre, rendering_buffer, pixel64_type> pixfmt_rgba64_pre; //----pixfmt_rgba64_pre + typedef pixfmt_alpha_blend_rgba<blender_argb64_pre, rendering_buffer, pixel64_type> pixfmt_argb64_pre; //----pixfmt_argb64_pre + typedef pixfmt_alpha_blend_rgba<blender_abgr64_pre, rendering_buffer, pixel64_type> pixfmt_abgr64_pre; //----pixfmt_abgr64_pre + typedef pixfmt_alpha_blend_rgba<blender_bgra64_pre, rendering_buffer, pixel64_type> pixfmt_bgra64_pre; //----pixfmt_bgra64_pre +} + +#endif + diff --git a/src/agg/agg_rasterizer_cells_aa.h b/src/agg/agg_rasterizer_cells_aa.h index 1147148fa..d3bb1387c 100644 --- a/src/agg/agg_rasterizer_cells_aa.h +++ b/src/agg/agg_rasterizer_cells_aa.h @@ -1,12 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // The author gratefully acknowleges the support of David Turner, @@ -14,10 +27,6 @@ // 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 @@ -26,12 +35,12 @@ // PostScript and PDF technology for software developers. // //---------------------------------------------------------------------------- + #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED #define AGG_RASTERIZER_CELLS_AA_INCLUDED #include <string.h> -#include <cstdlib> -#include <limits> +#include <math.h> #include "agg_math.h" #include "agg_array.h" @@ -151,10 +160,10 @@ namespace agg m_curr_cell_ptr(0), m_sorted_cells(), m_sorted_y(), - m_min_x(std::numeric_limits<int>::max()), - m_min_y(std::numeric_limits<int>::max()), - m_max_x(std::numeric_limits<int>::min()), - m_max_y(std::numeric_limits<int>::min()), + m_min_x(0x7FFFFFFF), + m_min_y(0x7FFFFFFF), + m_max_x(-0x7FFFFFFF), + m_max_y(-0x7FFFFFFF), m_sorted(false) { m_style_cell.initial(); @@ -170,10 +179,10 @@ namespace agg m_curr_cell.initial(); m_style_cell.initial(); m_sorted = false; - m_min_x = std::numeric_limits<int>::max(); - m_min_y = std::numeric_limits<int>::max(); - m_max_x = std::numeric_limits<int>::min(); - m_max_y = std::numeric_limits<int>::min(); + m_min_x = 0x7FFFFFFF; + m_min_y = 0x7FFFFFFF; + m_max_x = -0x7FFFFFFF; + m_max_y = -0x7FFFFFFF; } //------------------------------------------------------------------------ @@ -218,8 +227,7 @@ namespace agg int fx1 = x1 & poly_subpixel_mask; int fx2 = x2 & poly_subpixel_mask; - int delta, p, first; - long long dx; + int delta, p, first, dx; int incr, lift, mod, rem; //trivial case. Happens often @@ -244,7 +252,7 @@ namespace agg first = poly_subpixel_scale; incr = 1; - dx = (long long)x2 - (long long)x1; + dx = x2 - x1; if(dx < 0) { @@ -254,13 +262,13 @@ namespace agg dx = -dx; } - delta = (int)(p / dx); - mod = (int)(p % dx); + delta = p / dx; + mod = p % dx; if(mod < 0) { delta--; - mod += static_cast<int>(dx); + mod += dx; } m_curr_cell.cover += delta; @@ -273,16 +281,16 @@ namespace agg if(ex1 != ex2) { p = poly_subpixel_scale * (y2 - y1 + delta); - lift = (int)(p / dx); - rem = (int)(p % dx); + lift = p / dx; + rem = p % dx; if (rem < 0) { lift--; - rem += static_cast<int>(dx); + rem += dx; } - mod -= static_cast<int>(dx); + mod -= dx; while (ex1 != ex2) { @@ -290,7 +298,7 @@ namespace agg mod += rem; if(mod >= 0) { - mod -= static_cast<int>(dx); + mod -= dx; delta++; } @@ -319,17 +327,17 @@ namespace agg { enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift }; - long long dx = (long long)x2 - (long long)x1; + int dx = x2 - x1; if(dx >= dx_limit || dx <= -dx_limit) { - int cx = (int)(((long long)x1 + (long long)x2) >> 1); - int cy = (int)(((long long)y1 + (long long)y2) >> 1); + int cx = (x1 + x2) >> 1; + int cy = (y1 + y2) >> 1; line(x1, y1, cx, cy); line(cx, cy, x2, y2); } - long long dy = (long long)y2 - (long long)y1; + int dy = y2 - y1; int ex1 = x1 >> poly_subpixel_shift; int ex2 = x2 >> poly_subpixel_shift; int ey1 = y1 >> poly_subpixel_shift; @@ -338,8 +346,7 @@ namespace agg int fy2 = y2 & poly_subpixel_mask; int x_from, x_to; - int rem, mod, lift, delta, first, incr; - long long p; + 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; @@ -416,13 +423,13 @@ namespace agg dy = -dy; } - delta = (int)(p / dy); - mod = (int)(p % dy); + delta = p / dy; + mod = p % dy; if(mod < 0) { delta--; - mod += static_cast<int>(dy); + mod += dy; } x_from = x1 + delta; @@ -434,15 +441,15 @@ namespace agg if(ey1 != ey2) { p = poly_subpixel_scale * dx; - lift = (int)(p / dy); - rem = (int)(p % dy); + lift = p / dy; + rem = p % dy; if(rem < 0) { lift--; - rem += static_cast<int>(dy); + rem += dy; } - mod -= static_cast<int>(dy); + mod -= dy; while(ey1 != ey2) { @@ -450,7 +457,7 @@ namespace agg mod += rem; if (mod >= 0) { - mod -= static_cast<int>(dy); + mod -= dy; delta++; } @@ -628,8 +635,8 @@ namespace agg if(m_sorted) return; //Perform sort only the first time. add_curr_cell(); - m_curr_cell.x = std::numeric_limits<int>::max(); - m_curr_cell.y = std::numeric_limits<int>::max(); + m_curr_cell.x = 0x7FFFFFFF; + m_curr_cell.y = 0x7FFFFFFF; m_curr_cell.cover = 0; m_curr_cell.area = 0; @@ -657,13 +664,12 @@ namespace agg // 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 nb = m_num_cells >> cell_block_shift; unsigned i; - while(nb) + while(nb--) { cell_ptr = *block_ptr++; - i = (nb > cell_block_size) ? unsigned(cell_block_size) : nb; - nb -= i; + i = cell_block_size; while(i--) { m_sorted_y[cell_ptr->y - m_min_y].start++; @@ -671,6 +677,14 @@ namespace agg } } + cell_ptr = *block_ptr++; + i = m_num_cells & cell_block_mask; + 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++) @@ -682,13 +696,12 @@ namespace agg // Fill the cell pointer array sorted by Y block_ptr = m_cells; - nb = m_num_cells; - while(nb) + nb = m_num_cells >> cell_block_shift; + while(nb--) { cell_ptr = *block_ptr++; - i = (nb > cell_block_size) ? unsigned(cell_block_size) : nb; - nb -= i; - while(i--) + i = cell_block_size; + 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; @@ -697,6 +710,16 @@ namespace agg } } + cell_ptr = *block_ptr++; + i = m_num_cells & cell_block_mask; + 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++) { diff --git a/src/agg/agg_rasterizer_scanline_aa.h b/src/agg/agg_rasterizer_scanline_aa.h index ffc2ddf94..80e138c2e 100644 --- a/src/agg/agg_rasterizer_scanline_aa.h +++ b/src/agg/agg_rasterizer_scanline_aa.h @@ -1,12 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // The author gratefully acknowleges the support of David Turner, @@ -14,10 +27,6 @@ // 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 @@ -26,17 +35,47 @@ // 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 { + + + //-----------------------------------------------------------------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 // Polygon rasterizer that is used to render filled polygons with // high-quality Anti-Aliasing. Internally, by default, the class uses diff --git a/src/agg/agg_rasterizer_scanline_aa_nogamma.h b/src/agg/agg_rasterizer_scanline_aa_nogamma.h deleted file mode 100644 index 9a809aa5a..000000000 --- a/src/agg/agg_rasterizer_scanline_aa_nogamma.h +++ /dev/null @@ -1,483 +0,0 @@ -//---------------------------------------------------------------------------- -// 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 <limits> -#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 = std::numeric_limits<int>::max(); - y = std::numeric_limits<int>::max(); - cover = 0; - area = 0; - } - - void style(const cell_aa&) {} - - int not_equal(int ex, int ey, const cell_aa&) const - { - return ((unsigned)ex - (unsigned)x) | ((unsigned)ey - (unsigned)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 - diff --git a/src/agg/agg_rasterizer_sl_clip.h b/src/agg/agg_rasterizer_sl_clip.h index 3a7f3a103..cdfee1af0 100644 --- a/src/agg/agg_rasterizer_sl_clip.h +++ b/src/agg/agg_rasterizer_sl_clip.h @@ -1,17 +1,27 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- + #ifndef AGG_RASTERIZER_SL_CLIP_INCLUDED #define AGG_RASTERIZER_SL_CLIP_INCLUDED @@ -317,7 +327,7 @@ namespace agg rasterizer_sl_no_clip() : m_x1(0), m_y1(0) {} void reset_clipping() {} - void clip_box(coord_type, coord_type, coord_type, coord_type) {} + 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> diff --git a/src/agg/agg_renderer_base.h b/src/agg/agg_renderer_base.h index 527c62f78..180894465 100644 --- a/src/agg/agg_renderer_base.h +++ b/src/agg/agg_renderer_base.h @@ -1,20 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class renderer_base -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_BASE_INCLUDED @@ -134,19 +139,6 @@ namespace agg } - //-------------------------------------------------------------------- - 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) { diff --git a/src/agg/agg_renderer_scanline.h b/src/agg/agg_renderer_scanline.h index 311e9f739..c3bb6f05b 100644 --- a/src/agg/agg_renderer_scanline.h +++ b/src/agg/agg_renderer_scanline.h @@ -1,23 +1,30 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_SCANLINE_INCLUDED #define AGG_RENDERER_SCANLINE_INCLUDED -#include <limits> -#include <cstdlib> #include "agg_basics.h" #include "agg_renderer_base.h" @@ -67,7 +74,7 @@ namespace agg // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- - typename BaseRenderer::color_type ren_color = color; + typename BaseRenderer::color_type ren_color(color); sl.reset(ras.min_x(), ras.max_x()); while(ras.sweep_scanline(sl)) @@ -747,7 +754,7 @@ namespace agg 0, sl_len * sizeof(cover_type)); - int sl_y = std::numeric_limits<int>::max(); + int sl_y = 0x7FFFFFFF; unsigned i; for(i = 0; i < num_styles; i++) { diff --git a/src/agg/agg_rendering_buffer.h b/src/agg/agg_rendering_buffer.h index 0eff6ff27..3a39caa81 100644 --- a/src/agg/agg_rendering_buffer.h +++ b/src/agg/agg_rendering_buffer.h @@ -1,20 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// class rendering_buffer -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- #ifndef AGG_RENDERING_BUFFER_INCLUDED @@ -56,14 +61,14 @@ namespace agg //-------------------------------------------------------------------- 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_buf = m_start = buf; + m_width = width; + m_height = height; + m_stride = stride; + if(stride < 0) { - m_start = m_buf - int(height - 1) * stride; - } + m_start = m_buf - int(height - 1) * stride; + } } //-------------------------------------------------------------------- @@ -78,13 +83,13 @@ namespace agg } //-------------------------------------------------------------------- - AGG_INLINE T* row_ptr(int, int y, unsigned) + 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 + 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)); } diff --git a/src/agg/agg_scanline_p.h b/src/agg/agg_scanline_p.h index 1d1cbe72f..0c29638d6 100644 --- a/src/agg/agg_scanline_p.h +++ b/src/agg/agg_scanline_p.h @@ -1,20 +1,25 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Class scanline_p - a general purpose scanline container with packed spans. -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- // // Adaptation for 32-bit screen coordinates (scanline32_p) has been sponsored by diff --git a/src/agg/agg_shorten_path.h b/src/agg/agg_shorten_path.h new file mode 100644 index 000000000..ba72b947b --- /dev/null +++ b/src/agg/agg_shorten_path.h @@ -0,0 +1,75 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#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 diff --git a/src/agg/agg_trans_affine.h b/src/agg/agg_trans_affine.h index 1a6116388..a662099f2 100644 --- a/src/agg/agg_trans_affine.h +++ b/src/agg/agg_trans_affine.h @@ -1,21 +1,27 @@ //---------------------------------------------------------------------------- -// 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. -// -//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com -// http://www.antigrain.com -//---------------------------------------------------------------------------- -// -// Affine transformation classes. -// +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. //---------------------------------------------------------------------------- + #ifndef AGG_TRANS_AFFINE_INCLUDED #define AGG_TRANS_AFFINE_INCLUDED @@ -211,14 +217,14 @@ namespace agg // Multiply the matrix by another one and return // the result in a separete matrix. - trans_affine operator * (const trans_affine& m) const + trans_affine operator * (const trans_affine& m) { 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 + trans_affine operator / (const trans_affine& m) { return trans_affine(*this).multiply_inv(m); } @@ -292,7 +298,7 @@ namespace agg //------------------------------------------------------------------------ inline void trans_affine::transform(double* x, double* y) const { - double tmp = *x; + register double tmp = *x; *x = tmp * sx + *y * shx + tx; *y = tmp * shy + *y * sy + ty; } @@ -300,7 +306,7 @@ namespace agg //------------------------------------------------------------------------ inline void trans_affine::transform_2x2(double* x, double* y) const { - double tmp = *x; + register double tmp = *x; *x = tmp * sx + *y * shx; *y = tmp * shy + *y * sy; } @@ -308,9 +314,9 @@ namespace agg //------------------------------------------------------------------------ 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; + register double d = determinant_reciprocal(); + register double a = (*x - tx) * d; + register double b = (*y - ty) * d; *x = a * sy - b * shx; *y = b * sx - a * shy; } diff --git a/src/agg/agg_vcgen_contour.h b/src/agg/agg_vcgen_contour.h new file mode 100644 index 000000000..1a3a4bcad --- /dev/null +++ b/src/agg/agg_vcgen_contour.h @@ -0,0 +1,103 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#ifndef AGG_VCGEN_CONTOUR_INCLUDED +#define AGG_VCGEN_CONTOUR_INCLUDED + +#include "agg_math_stroke.h" + +namespace agg +{ + + //----------------------------------------------------------vcgen_contour + // + // See Implementation agg_vcgen_contour.cpp + // + class vcgen_contour + { + enum status_e + { + initial, + ready, + outline, + out_vertices, + end_poly, + stop + }; + + public: + typedef vertex_sequence<vertex_dist, 6> vertex_storage; + typedef pod_bvector<point_d, 6> coord_storage; + + vcgen_contour(); + + 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(m_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_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 auto_detect_orientation(bool v) { m_auto_detect = v; } + bool auto_detect_orientation() const { return m_auto_detect; } + + // 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_contour(const vcgen_contour&); + const vcgen_contour& operator = (const vcgen_contour&); + + math_stroke<coord_storage> m_stroker; + double m_width; + vertex_storage m_src_vertices; + coord_storage m_out_vertices; + status_e m_status; + unsigned m_src_vertex; + unsigned m_out_vertex; + unsigned m_closed; + unsigned m_orientation; + bool m_auto_detect; + }; + +} + +#endif diff --git a/src/agg/agg_vcgen_stroke.h b/src/agg/agg_vcgen_stroke.h new file mode 100644 index 000000000..4edba7660 --- /dev/null +++ b/src/agg/agg_vcgen_stroke.h @@ -0,0 +1,111 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#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 diff --git a/src/agg/agg_vertex_sequence.h b/src/agg/agg_vertex_sequence.h new file mode 100644 index 000000000..f3ef35cf1 --- /dev/null +++ b/src/agg/agg_vertex_sequence.h @@ -0,0 +1,178 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#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 diff --git a/src/agg/copying b/src/agg/copying index b6028e519..d511905c1 100644 --- a/src/agg/copying +++ b/src/agg/copying @@ -1,65 +1,339 @@ -The Anti-Grain Geometry Project -A high quality rendering engine for C++ -http://antigrain.com + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 -Anti-Grain Geometry has dual licensing model. The Modified BSD -License was first added in version v2.4 just for convenience. -It is a simple, permissive non-copyleft free software license, -compatible with the GNU GPL. It's well proven and recognizable. -See http://www.fsf.org/licensing/licenses/index_html#ModifiedBSD -for details. + Copyright (C) 1989, 1991 Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. -Note that the Modified BSD license DOES NOT restrict your rights -if you choose the Anti-Grain Geometry Public License. + Preamble + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Lesser General Public License instead.) You can apply it to +your programs, too. + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. -Anti-Grain Geometry Public License -==================================================== + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. -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. + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + The precise terms and conditions for copying, distribution and +modification follow. + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". -Modified BSD License -==================================================== -Anti-Grain Geometry - Version 2.4 -Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. - 1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. - 2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in - the documentation and/or other materials provided with the - distribution. + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: - 3. The name of the author may not be used to endorse or promote - products derived from this software without specific prior - written permission. + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. -THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, -INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) -HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, -STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING -IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. diff --git a/src/agg_svg/CMakeLists.txt b/src/agg_svg/CMakeLists.txt new file mode 100644 index 000000000..5790ce9e9 --- /dev/null +++ b/src/agg_svg/CMakeLists.txt @@ -0,0 +1,22 @@ +project(agg_svg) +cmake_minimum_required(VERSION 2.6) + +add_library(agg_svg STATIC + agg_svg_exception.h + agg_svg_parser.cpp + agg_svg_parser.h + agg_svg_path_renderer.cpp + agg_svg_path_renderer.h + agg_svg_path_tokenizer.cpp + agg_svg_path_tokenizer.h + +# agg_bezier_arc.cpp + agg_curves.cpp + agg_trans_affine.cpp + agg_vcgen_contour.cpp + agg_vcgen_stroke.cpp + ) + +target_include_directories(agg_svg PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) + +target_link_libraries(agg_svg ${EXPAT_LIBRARIES}) diff --git a/src/agg_svg/agg_bezier_arc.cpp b/src/agg_svg/agg_bezier_arc.cpp new file mode 100644 index 000000000..8d5425a35 --- /dev/null +++ b/src/agg_svg/agg_bezier_arc.cpp @@ -0,0 +1,261 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#include <math.h> +#include "agg_bezier_arc.h" + + +namespace agg +{ + + // This epsilon is used to prevent us from adding degenerate curves + // (converging to a single point). + // The value isn't very critical. Function arc_to_bezier() has a limit + // of the sweep_angle. If fabs(sweep_angle) exceeds pi/2 the curve + // becomes inaccurate. But slight exceeding is quite appropriate. + //-------------------------------------------------bezier_arc_angle_epsilon + const double bezier_arc_angle_epsilon = 0.01; + + //------------------------------------------------------------arc_to_bezier + void arc_to_bezier(double cx, double cy, double rx, double ry, + double start_angle, double sweep_angle, + double* curve) + { + double x0 = cos(sweep_angle / 2.0); + double y0 = sin(sweep_angle / 2.0); + double tx = (1.0 - x0) * 4.0 / 3.0; + double ty = y0 - tx * x0 / y0; + double px[4]; + double py[4]; + px[0] = x0; + py[0] = -y0; + px[1] = x0 + tx; + py[1] = -ty; + px[2] = x0 + tx; + py[2] = ty; + px[3] = x0; + py[3] = y0; + + double sn = sin(start_angle + sweep_angle / 2.0); + double cs = cos(start_angle + sweep_angle / 2.0); + + unsigned i; + for(i = 0; i < 4; i++) + { + curve[i * 2] = cx + rx * (px[i] * cs - py[i] * sn); + curve[i * 2 + 1] = cy + ry * (px[i] * sn + py[i] * cs); + } + } + + + + //------------------------------------------------------------------------ + void bezier_arc::init(double x, double y, + double rx, double ry, + double start_angle, + double sweep_angle) + { + start_angle = fmod(start_angle, 2.0 * pi); + if(sweep_angle >= 2.0 * pi) sweep_angle = 2.0 * pi; + if(sweep_angle <= -2.0 * pi) sweep_angle = -2.0 * pi; + + if(fabs(sweep_angle) < 1e-10) + { + m_num_vertices = 4; + m_cmd = path_cmd_line_to; + m_vertices[0] = x + rx * cos(start_angle); + m_vertices[1] = y + ry * sin(start_angle); + m_vertices[2] = x + rx * cos(start_angle + sweep_angle); + m_vertices[3] = y + ry * sin(start_angle + sweep_angle); + return; + } + + double total_sweep = 0.0; + double local_sweep = 0.0; + double prev_sweep; + m_num_vertices = 2; + m_cmd = path_cmd_curve4; + bool done = false; + do + { + if(sweep_angle < 0.0) + { + prev_sweep = total_sweep; + local_sweep = -pi * 0.5; + total_sweep -= pi * 0.5; + if(total_sweep <= sweep_angle + bezier_arc_angle_epsilon) + { + local_sweep = sweep_angle - prev_sweep; + done = true; + } + } + else + { + prev_sweep = total_sweep; + local_sweep = pi * 0.5; + total_sweep += pi * 0.5; + if(total_sweep >= sweep_angle - bezier_arc_angle_epsilon) + { + local_sweep = sweep_angle - prev_sweep; + done = true; + } + } + + arc_to_bezier(x, y, rx, ry, + start_angle, + local_sweep, + m_vertices + m_num_vertices - 2); + + m_num_vertices += 6; + start_angle += local_sweep; + } + while(!done && m_num_vertices < 26); + } + + + + + //-------------------------------------------------------------------- + void bezier_arc_svg::init(double x0, double y0, + double rx, double ry, + double angle, + bool large_arc_flag, + bool sweep_flag, + double x2, double y2) + { + m_radii_ok = true; + + if(rx < 0.0) rx = -rx; + if(ry < 0.0) ry = -rx; + + // Calculate the middle point between + // the current and the final points + //------------------------ + double dx2 = (x0 - x2) / 2.0; + double dy2 = (y0 - y2) / 2.0; + + double cos_a = cos(angle); + double sin_a = sin(angle); + + // Calculate (x1, y1) + //------------------------ + double x1 = cos_a * dx2 + sin_a * dy2; + double y1 = -sin_a * dx2 + cos_a * dy2; + + // Ensure radii are large enough + //------------------------ + double prx = rx * rx; + double pry = ry * ry; + double px1 = x1 * x1; + double py1 = y1 * y1; + + // Check that radii are large enough + //------------------------ + double radii_check = px1/prx + py1/pry; + if(radii_check > 1.0) + { + rx = sqrt(radii_check) * rx; + ry = sqrt(radii_check) * ry; + prx = rx * rx; + pry = ry * ry; + if(radii_check > 10.0) m_radii_ok = false; + } + + // Calculate (cx1, cy1) + //------------------------ + double sign = (large_arc_flag == sweep_flag) ? -1.0 : 1.0; + double sq = (prx*pry - prx*py1 - pry*px1) / (prx*py1 + pry*px1); + double coef = sign * sqrt((sq < 0) ? 0 : sq); + double cx1 = coef * ((rx * y1) / ry); + double cy1 = coef * -((ry * x1) / rx); + + // + // Calculate (cx, cy) from (cx1, cy1) + //------------------------ + double sx2 = (x0 + x2) / 2.0; + double sy2 = (y0 + y2) / 2.0; + double cx = sx2 + (cos_a * cx1 - sin_a * cy1); + double cy = sy2 + (sin_a * cx1 + cos_a * cy1); + + // Calculate the start_angle (angle1) and the sweep_angle (dangle) + //------------------------ + double ux = (x1 - cx1) / rx; + double uy = (y1 - cy1) / ry; + double vx = (-x1 - cx1) / rx; + double vy = (-y1 - cy1) / ry; + double p, n; + + // Calculate the angle start + //------------------------ + n = sqrt(ux*ux + uy*uy); + p = ux; // (1 * ux) + (0 * uy) + sign = (uy < 0) ? -1.0 : 1.0; + double v = p / n; + if(v < -1.0) v = -1.0; + if(v > 1.0) v = 1.0; + double start_angle = sign * acos(v); + + // Calculate the sweep angle + //------------------------ + n = sqrt((ux*ux + uy*uy) * (vx*vx + vy*vy)); + p = ux * vx + uy * vy; + sign = (ux * vy - uy * vx < 0) ? -1.0 : 1.0; + v = p / n; + if(v < -1.0) v = -1.0; + if(v > 1.0) v = 1.0; + double sweep_angle = sign * acos(v); + if(!sweep_flag && sweep_angle > 0) + { + sweep_angle -= pi * 2.0; + } + else + if (sweep_flag && sweep_angle < 0) + { + sweep_angle += pi * 2.0; + } + + // We can now build and transform the resulting arc + //------------------------ + m_arc.init(0.0, 0.0, rx, ry, start_angle, sweep_angle); + trans_affine mtx = trans_affine_rotation(angle); + mtx *= trans_affine_translation(cx, cy); + + for(unsigned i = 2; i < m_arc.num_vertices()-2; i += 2) + { + mtx.transform(m_arc.vertices() + i, m_arc.vertices() + i + 1); + } + + // We must make sure that the starting and ending points + // exactly coincide with the initial (x0,y0) and (x2,y2) + m_arc.vertices()[0] = x0; + m_arc.vertices()[1] = y0; + if(m_arc.num_vertices() > 2) + { + m_arc.vertices()[m_arc.num_vertices() - 2] = x2; + m_arc.vertices()[m_arc.num_vertices() - 1] = y2; + } + } + + +} diff --git a/src/agg_svg/agg_curves.cpp b/src/agg_svg/agg_curves.cpp new file mode 100644 index 000000000..2f2d288e3 --- /dev/null +++ b/src/agg_svg/agg_curves.cpp @@ -0,0 +1,620 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#include <math.h> +#include <agg/agg_curves.h> +#include <agg/agg_math.h> + +namespace agg +{ + + //------------------------------------------------------------------------ + const double curve_distance_epsilon = 1e-30; + const double curve_collinearity_epsilon = 1e-30; + const double curve_angle_tolerance_epsilon = 0.01; + enum curve_recursion_limit_e { curve_recursion_limit = 32 }; + + + + //------------------------------------------------------------------------ + void curve3_inc::approximation_scale(double s) + { + m_scale = s; + } + + //------------------------------------------------------------------------ + double curve3_inc::approximation_scale() const + { + return m_scale; + } + + //------------------------------------------------------------------------ + void curve3_inc::init(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + m_start_x = x1; + m_start_y = y1; + m_end_x = x3; + m_end_y = y3; + + double dx1 = x2 - x1; + double dy1 = y2 - y1; + double dx2 = x3 - x2; + double dy2 = y3 - y2; + + double len = sqrt(dx1 * dx1 + dy1 * dy1) + sqrt(dx2 * dx2 + dy2 * dy2); + + m_num_steps = uround(len * 0.25 * m_scale); + + if(m_num_steps < 4) + { + m_num_steps = 4; + } + + double subdivide_step = 1.0 / m_num_steps; + double subdivide_step2 = subdivide_step * subdivide_step; + + double tmpx = (x1 - x2 * 2.0 + x3) * subdivide_step2; + double tmpy = (y1 - y2 * 2.0 + y3) * subdivide_step2; + + m_saved_fx = m_fx = x1; + m_saved_fy = m_fy = y1; + + m_saved_dfx = m_dfx = tmpx + (x2 - x1) * (2.0 * subdivide_step); + m_saved_dfy = m_dfy = tmpy + (y2 - y1) * (2.0 * subdivide_step); + + m_ddfx = tmpx * 2.0; + m_ddfy = tmpy * 2.0; + + m_step = m_num_steps; + } + + //------------------------------------------------------------------------ + void curve3_inc::rewind(unsigned) + { + if(m_num_steps == 0) + { + m_step = -1; + return; + } + m_step = m_num_steps; + m_fx = m_saved_fx; + m_fy = m_saved_fy; + m_dfx = m_saved_dfx; + m_dfy = m_saved_dfy; + } + + //------------------------------------------------------------------------ + unsigned curve3_inc::vertex(double* x, double* y) + { + if(m_step < 0) return path_cmd_stop; + if(m_step == m_num_steps) + { + *x = m_start_x; + *y = m_start_y; + --m_step; + return path_cmd_move_to; + } + if(m_step == 0) + { + *x = m_end_x; + *y = m_end_y; + --m_step; + return path_cmd_line_to; + } + m_fx += m_dfx; + m_fy += m_dfy; + m_dfx += m_ddfx; + m_dfy += m_ddfy; + *x = m_fx; + *y = m_fy; + --m_step; + return path_cmd_line_to; + } + + //------------------------------------------------------------------------ + void curve3_div::init(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + m_points.remove_all(); + m_distance_tolerance_square = 0.5 / m_approximation_scale; + m_distance_tolerance_square *= m_distance_tolerance_square; + bezier(x1, y1, x2, y2, x3, y3); + m_count = 0; + } + + //------------------------------------------------------------------------ + void curve3_div::recursive_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + unsigned level) + { + if(level > curve_recursion_limit) + { + return; + } + + // Calculate all the mid-points of the line segments + //---------------------- + double x12 = (x1 + x2) / 2; + double y12 = (y1 + y2) / 2; + double x23 = (x2 + x3) / 2; + double y23 = (y2 + y3) / 2; + double x123 = (x12 + x23) / 2; + double y123 = (y12 + y23) / 2; + + double dx = x3-x1; + double dy = y3-y1; + double d = fabs(((x2 - x3) * dy - (y2 - y3) * dx)); + double da; + + if(d > curve_collinearity_epsilon) + { + // Regular case + //----------------- + if(d * d <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + // If the curvature doesn't exceed the distance_tolerance value + // we tend to finish subdivisions. + //---------------------- + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.add(point_d(x123, y123)); + return; + } + + // Angle & Cusp Condition + //---------------------- + da = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); + if(da >= pi) da = 2*pi - da; + + if(da < m_angle_tolerance) + { + // Finally we can stop the recursion + //---------------------- + m_points.add(point_d(x123, y123)); + return; + } + } + } + else + { + // Collinear case + //------------------ + da = dx*dx + dy*dy; + if(da == 0) + { + d = calc_sq_distance(x1, y1, x2, y2); + } + else + { + d = ((x2 - x1)*dx + (y2 - y1)*dy) / da; + if(d > 0 && d < 1) + { + // Simple collinear case, 1---2---3 + // We can leave just two endpoints + return; + } + if(d <= 0) d = calc_sq_distance(x2, y2, x1, y1); + else if(d >= 1) d = calc_sq_distance(x2, y2, x3, y3); + else d = calc_sq_distance(x2, y2, x1 + d*dx, y1 + d*dy); + } + if(d < m_distance_tolerance_square) + { + m_points.add(point_d(x2, y2)); + return; + } + } + + // Continue subdivision + //---------------------- + recursive_bezier(x1, y1, x12, y12, x123, y123, level + 1); + recursive_bezier(x123, y123, x23, y23, x3, y3, level + 1); + } + + //------------------------------------------------------------------------ + void curve3_div::bezier(double x1, double y1, + double x2, double y2, + double x3, double y3) + { + m_points.add(point_d(x1, y1)); + recursive_bezier(x1, y1, x2, y2, x3, y3, 0); + m_points.add(point_d(x3, y3)); + } + + + + + + //------------------------------------------------------------------------ + void curve4_inc::approximation_scale(double s) + { + m_scale = s; + } + + //------------------------------------------------------------------------ + double curve4_inc::approximation_scale() const + { + return m_scale; + } + + //------------------------------------------------------------------------ + static double MSC60_fix_ICE(double v) { return v; } + + //------------------------------------------------------------------------ + void curve4_inc::init(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + m_start_x = x1; + m_start_y = y1; + m_end_x = x4; + m_end_y = y4; + + double dx1 = x2 - x1; + double dy1 = y2 - y1; + double dx2 = x3 - x2; + double dy2 = y3 - y2; + double dx3 = x4 - x3; + double dy3 = y4 - y3; + + double len = (sqrt(dx1 * dx1 + dy1 * dy1) + + sqrt(dx2 * dx2 + dy2 * dy2) + + sqrt(dx3 * dx3 + dy3 * dy3)) * 0.25 * m_scale; + +#if defined(_MSC_VER) && _MSC_VER <= 1200 + m_num_steps = uround(MSC60_fix_ICE(len)); +#else + m_num_steps = uround(len); +#endif + + if(m_num_steps < 4) + { + m_num_steps = 4; + } + + double subdivide_step = 1.0 / m_num_steps; + double subdivide_step2 = subdivide_step * subdivide_step; + double subdivide_step3 = subdivide_step * subdivide_step * subdivide_step; + + double pre1 = 3.0 * subdivide_step; + double pre2 = 3.0 * subdivide_step2; + double pre4 = 6.0 * subdivide_step2; + double pre5 = 6.0 * subdivide_step3; + + double tmp1x = x1 - x2 * 2.0 + x3; + double tmp1y = y1 - y2 * 2.0 + y3; + + double tmp2x = (x2 - x3) * 3.0 - x1 + x4; + double tmp2y = (y2 - y3) * 3.0 - y1 + y4; + + m_saved_fx = m_fx = x1; + m_saved_fy = m_fy = y1; + + m_saved_dfx = m_dfx = (x2 - x1) * pre1 + tmp1x * pre2 + tmp2x * subdivide_step3; + m_saved_dfy = m_dfy = (y2 - y1) * pre1 + tmp1y * pre2 + tmp2y * subdivide_step3; + + m_saved_ddfx = m_ddfx = tmp1x * pre4 + tmp2x * pre5; + m_saved_ddfy = m_ddfy = tmp1y * pre4 + tmp2y * pre5; + + m_dddfx = tmp2x * pre5; + m_dddfy = tmp2y * pre5; + + m_step = m_num_steps; + } + + //------------------------------------------------------------------------ + void curve4_inc::rewind(unsigned) + { + if(m_num_steps == 0) + { + m_step = -1; + return; + } + m_step = m_num_steps; + m_fx = m_saved_fx; + m_fy = m_saved_fy; + m_dfx = m_saved_dfx; + m_dfy = m_saved_dfy; + m_ddfx = m_saved_ddfx; + m_ddfy = m_saved_ddfy; + } + + //------------------------------------------------------------------------ + unsigned curve4_inc::vertex(double* x, double* y) + { + if(m_step < 0) return path_cmd_stop; + if(m_step == m_num_steps) + { + *x = m_start_x; + *y = m_start_y; + --m_step; + return path_cmd_move_to; + } + + if(m_step == 0) + { + *x = m_end_x; + *y = m_end_y; + --m_step; + return path_cmd_line_to; + } + + m_fx += m_dfx; + m_fy += m_dfy; + m_dfx += m_ddfx; + m_dfy += m_ddfy; + m_ddfx += m_dddfx; + m_ddfy += m_dddfy; + + *x = m_fx; + *y = m_fy; + --m_step; + return path_cmd_line_to; + } + + + + + //------------------------------------------------------------------------ + void curve4_div::init(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + m_points.remove_all(); + m_distance_tolerance_square = 0.5 / m_approximation_scale; + m_distance_tolerance_square *= m_distance_tolerance_square; + bezier(x1, y1, x2, y2, x3, y3, x4, y4); + m_count = 0; + } + + //------------------------------------------------------------------------ + void curve4_div::recursive_bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4, + unsigned level) + { + if(level > curve_recursion_limit) + { + return; + } + + // Calculate all the mid-points of the line segments + //---------------------- + double x12 = (x1 + x2) / 2; + double y12 = (y1 + y2) / 2; + double x23 = (x2 + x3) / 2; + double y23 = (y2 + y3) / 2; + double x34 = (x3 + x4) / 2; + double y34 = (y3 + y4) / 2; + double x123 = (x12 + x23) / 2; + double y123 = (y12 + y23) / 2; + double x234 = (x23 + x34) / 2; + double y234 = (y23 + y34) / 2; + double x1234 = (x123 + x234) / 2; + double y1234 = (y123 + y234) / 2; + + + // Try to approximate the full cubic curve by a single straight line + //------------------ + double dx = x4-x1; + double dy = y4-y1; + + double d2 = fabs(((x2 - x4) * dy - (y2 - y4) * dx)); + double d3 = fabs(((x3 - x4) * dy - (y3 - y4) * dx)); + double da1, da2, k; + + switch((int(d2 > curve_collinearity_epsilon) << 1) + + int(d3 > curve_collinearity_epsilon)) + { + case 0: + // All collinear OR p1==p4 + //---------------------- + k = dx*dx + dy*dy; + if(k == 0) + { + d2 = calc_sq_distance(x1, y1, x2, y2); + d3 = calc_sq_distance(x4, y4, x3, y3); + } + else + { + k = 1 / k; + da1 = x2 - x1; + da2 = y2 - y1; + d2 = k * (da1*dx + da2*dy); + da1 = x3 - x1; + da2 = y3 - y1; + d3 = k * (da1*dx + da2*dy); + if(d2 > 0 && d2 < 1 && d3 > 0 && d3 < 1) + { + // Simple collinear case, 1---2---3---4 + // We can leave just two endpoints + return; + } + if(d2 <= 0) d2 = calc_sq_distance(x2, y2, x1, y1); + else if(d2 >= 1) d2 = calc_sq_distance(x2, y2, x4, y4); + else d2 = calc_sq_distance(x2, y2, x1 + d2*dx, y1 + d2*dy); + + if(d3 <= 0) d3 = calc_sq_distance(x3, y3, x1, y1); + else if(d3 >= 1) d3 = calc_sq_distance(x3, y3, x4, y4); + else d3 = calc_sq_distance(x3, y3, x1 + d3*dx, y1 + d3*dy); + } + if(d2 > d3) + { + if(d2 < m_distance_tolerance_square) + { + m_points.add(point_d(x2, y2)); + return; + } + } + else + { + if(d3 < m_distance_tolerance_square) + { + m_points.add(point_d(x3, y3)); + return; + } + } + break; + + case 1: + // p1,p2,p4 are collinear, p3 is significant + //---------------------- + if(d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.add(point_d(x23, y23)); + return; + } + + // Angle Condition + //---------------------- + da1 = fabs(atan2(y4 - y3, x4 - x3) - atan2(y3 - y2, x3 - x2)); + if(da1 >= pi) da1 = 2*pi - da1; + + if(da1 < m_angle_tolerance) + { + m_points.add(point_d(x2, y2)); + m_points.add(point_d(x3, y3)); + return; + } + + if(m_cusp_limit != 0.0) + { + if(da1 > m_cusp_limit) + { + m_points.add(point_d(x3, y3)); + return; + } + } + } + break; + + case 2: + // p1,p3,p4 are collinear, p2 is significant + //---------------------- + if(d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.add(point_d(x23, y23)); + return; + } + + // Angle Condition + //---------------------- + da1 = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); + if(da1 >= pi) da1 = 2*pi - da1; + + if(da1 < m_angle_tolerance) + { + m_points.add(point_d(x2, y2)); + m_points.add(point_d(x3, y3)); + return; + } + + if(m_cusp_limit != 0.0) + { + if(da1 > m_cusp_limit) + { + m_points.add(point_d(x2, y2)); + return; + } + } + } + break; + + case 3: + // Regular case + //----------------- + if((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy)) + { + // If the curvature doesn't exceed the distance_tolerance value + // we tend to finish subdivisions. + //---------------------- + if(m_angle_tolerance < curve_angle_tolerance_epsilon) + { + m_points.add(point_d(x23, y23)); + return; + } + + // Angle & Cusp Condition + //---------------------- + k = atan2(y3 - y2, x3 - x2); + da1 = fabs(k - atan2(y2 - y1, x2 - x1)); + da2 = fabs(atan2(y4 - y3, x4 - x3) - k); + if(da1 >= pi) da1 = 2*pi - da1; + if(da2 >= pi) da2 = 2*pi - da2; + + if(da1 + da2 < m_angle_tolerance) + { + // Finally we can stop the recursion + //---------------------- + m_points.add(point_d(x23, y23)); + return; + } + + if(m_cusp_limit != 0.0) + { + if(da1 > m_cusp_limit) + { + m_points.add(point_d(x2, y2)); + return; + } + + if(da2 > m_cusp_limit) + { + m_points.add(point_d(x3, y3)); + return; + } + } + } + break; + } + + // Continue subdivision + //---------------------- + recursive_bezier(x1, y1, x12, y12, x123, y123, x1234, y1234, level + 1); + recursive_bezier(x1234, y1234, x234, y234, x34, y34, x4, y4, level + 1); + } + + //------------------------------------------------------------------------ + void curve4_div::bezier(double x1, double y1, + double x2, double y2, + double x3, double y3, + double x4, double y4) + { + m_points.add(point_d(x1, y1)); + recursive_bezier(x1, y1, x2, y2, x3, y3, x4, y4, 0); + m_points.add(point_d(x4, y4)); + } + +} + diff --git a/src/agg_svg/agg_svg_exception.h b/src/agg_svg/agg_svg_exception.h new file mode 100644 index 000000000..2a49b9938 --- /dev/null +++ b/src/agg_svg/agg_svg_exception.h @@ -0,0 +1,69 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG exception +// +//---------------------------------------------------------------------------- + +#ifndef AGG_SVG_EXCEPTION_INCLUDED +#define AGG_SVG_EXCEPTION_INCLUDED + +#include <stdio.h> +#include <string.h> +#include <stdarg.h> + +namespace agg +{ +namespace svg +{ + class exception + { + public: + ~exception() + { + delete [] m_msg; + } + + exception() : m_msg(0) {} + + exception(const char* fmt, ...) : + m_msg(0) + { + if(fmt) + { + m_msg = new char [4096]; + va_list arg; + va_start(arg, fmt); + vsprintf(m_msg, fmt, arg); + va_end(arg); + } + } + + exception(const exception& exc) : + m_msg(exc.m_msg ? new char[strlen(exc.m_msg) + 1] : 0) + { + if(m_msg) strcpy(m_msg, exc.m_msg); + } + + const char* msg() const { return m_msg; } + + private: + char* m_msg; + }; + +} +} + +#endif diff --git a/src/agg_svg/agg_svg_parser.cpp b/src/agg_svg/agg_svg_parser.cpp new file mode 100644 index 000000000..4eeac31db --- /dev/null +++ b/src/agg_svg/agg_svg_parser.cpp @@ -0,0 +1,886 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG parser. +// +//---------------------------------------------------------------------------- + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include "agg_svg_parser.h" +#include "expat.h" + +namespace agg +{ +namespace svg +{ + struct named_color + { + char name[22]; + int8u r, g, b, a; + }; + + named_color colors[] = + { + { "aliceblue",240,248,255, 255 }, + { "antiquewhite",250,235,215, 255 }, + { "aqua",0,255,255, 255 }, + { "aquamarine",127,255,212, 255 }, + { "azure",240,255,255, 255 }, + { "beige",245,245,220, 255 }, + { "bisque",255,228,196, 255 }, + { "black",0,0,0, 255 }, + { "blanchedalmond",255,235,205, 255 }, + { "blue",0,0,255, 255 }, + { "blueviolet",138,43,226, 255 }, + { "brown",165,42,42, 255 }, + { "burlywood",222,184,135, 255 }, + { "cadetblue",95,158,160, 255 }, + { "chartreuse",127,255,0, 255 }, + { "chocolate",210,105,30, 255 }, + { "coral",255,127,80, 255 }, + { "cornflowerblue",100,149,237, 255 }, + { "cornsilk",255,248,220, 255 }, + { "crimson",220,20,60, 255 }, + { "cyan",0,255,255, 255 }, + { "darkblue",0,0,139, 255 }, + { "darkcyan",0,139,139, 255 }, + { "darkgoldenrod",184,134,11, 255 }, + { "darkgray",169,169,169, 255 }, + { "darkgreen",0,100,0, 255 }, + { "darkgrey",169,169,169, 255 }, + { "darkkhaki",189,183,107, 255 }, + { "darkmagenta",139,0,139, 255 }, + { "darkolivegreen",85,107,47, 255 }, + { "darkorange",255,140,0, 255 }, + { "darkorchid",153,50,204, 255 }, + { "darkred",139,0,0, 255 }, + { "darksalmon",233,150,122, 255 }, + { "darkseagreen",143,188,143, 255 }, + { "darkslateblue",72,61,139, 255 }, + { "darkslategray",47,79,79, 255 }, + { "darkslategrey",47,79,79, 255 }, + { "darkturquoise",0,206,209, 255 }, + { "darkviolet",148,0,211, 255 }, + { "deeppink",255,20,147, 255 }, + { "deepskyblue",0,191,255, 255 }, + { "dimgray",105,105,105, 255 }, + { "dimgrey",105,105,105, 255 }, + { "dodgerblue",30,144,255, 255 }, + { "firebrick",178,34,34, 255 }, + { "floralwhite",255,250,240, 255 }, + { "forestgreen",34,139,34, 255 }, + { "fuchsia",255,0,255, 255 }, + { "gainsboro",220,220,220, 255 }, + { "ghostwhite",248,248,255, 255 }, + { "gold",255,215,0, 255 }, + { "goldenrod",218,165,32, 255 }, + { "gray",128,128,128, 255 }, + { "green",0,128,0, 255 }, + { "greenyellow",173,255,47, 255 }, + { "grey",128,128,128, 255 }, + { "honeydew",240,255,240, 255 }, + { "hotpink",255,105,180, 255 }, + { "indianred",205,92,92, 255 }, + { "indigo",75,0,130, 255 }, + { "ivory",255,255,240, 255 }, + { "khaki",240,230,140, 255 }, + { "lavender",230,230,250, 255 }, + { "lavenderblush",255,240,245, 255 }, + { "lawngreen",124,252,0, 255 }, + { "lemonchiffon",255,250,205, 255 }, + { "lightblue",173,216,230, 255 }, + { "lightcoral",240,128,128, 255 }, + { "lightcyan",224,255,255, 255 }, + { "lightgoldenrodyellow",250,250,210, 255 }, + { "lightgray",211,211,211, 255 }, + { "lightgreen",144,238,144, 255 }, + { "lightgrey",211,211,211, 255 }, + { "lightpink",255,182,193, 255 }, + { "lightsalmon",255,160,122, 255 }, + { "lightseagreen",32,178,170, 255 }, + { "lightskyblue",135,206,250, 255 }, + { "lightslategray",119,136,153, 255 }, + { "lightslategrey",119,136,153, 255 }, + { "lightsteelblue",176,196,222, 255 }, + { "lightyellow",255,255,224, 255 }, + { "lime",0,255,0, 255 }, + { "limegreen",50,205,50, 255 }, + { "linen",250,240,230, 255 }, + { "magenta",255,0,255, 255 }, + { "maroon",128,0,0, 255 }, + { "mediumaquamarine",102,205,170, 255 }, + { "mediumblue",0,0,205, 255 }, + { "mediumorchid",186,85,211, 255 }, + { "mediumpurple",147,112,219, 255 }, + { "mediumseagreen",60,179,113, 255 }, + { "mediumslateblue",123,104,238, 255 }, + { "mediumspringgreen",0,250,154, 255 }, + { "mediumturquoise",72,209,204, 255 }, + { "mediumvioletred",199,21,133, 255 }, + { "midnightblue",25,25,112, 255 }, + { "mintcream",245,255,250, 255 }, + { "mistyrose",255,228,225, 255 }, + { "moccasin",255,228,181, 255 }, + { "navajowhite",255,222,173, 255 }, + { "navy",0,0,128, 255 }, + { "oldlace",253,245,230, 255 }, + { "olive",128,128,0, 255 }, + { "olivedrab",107,142,35, 255 }, + { "orange",255,165,0, 255 }, + { "orangered",255,69,0, 255 }, + { "orchid",218,112,214, 255 }, + { "palegoldenrod",238,232,170, 255 }, + { "palegreen",152,251,152, 255 }, + { "paleturquoise",175,238,238, 255 }, + { "palevioletred",219,112,147, 255 }, + { "papayawhip",255,239,213, 255 }, + { "peachpuff",255,218,185, 255 }, + { "peru",205,133,63, 255 }, + { "pink",255,192,203, 255 }, + { "plum",221,160,221, 255 }, + { "powderblue",176,224,230, 255 }, + { "purple",128,0,128, 255 }, + { "red",255,0,0, 255 }, + { "rosybrown",188,143,143, 255 }, + { "royalblue",65,105,225, 255 }, + { "saddlebrown",139,69,19, 255 }, + { "salmon",250,128,114, 255 }, + { "sandybrown",244,164,96, 255 }, + { "seagreen",46,139,87, 255 }, + { "seashell",255,245,238, 255 }, + { "sienna",160,82,45, 255 }, + { "silver",192,192,192, 255 }, + { "skyblue",135,206,235, 255 }, + { "slateblue",106,90,205, 255 }, + { "slategray",112,128,144, 255 }, + { "slategrey",112,128,144, 255 }, + { "snow",255,250,250, 255 }, + { "springgreen",0,255,127, 255 }, + { "steelblue",70,130,180, 255 }, + { "tan",210,180,140, 255 }, + { "teal",0,128,128, 255 }, + { "thistle",216,191,216, 255 }, + { "tomato",255,99,71, 255 }, + { "turquoise",64,224,208, 255 }, + { "violet",238,130,238, 255 }, + { "wheat",245,222,179, 255 }, + { "white",255,255,255, 255 }, + { "whitesmoke",245,245,245, 255 }, + { "yellow",255,255,0, 255 }, + { "yellowgreen",154,205,50, 255 }, + { "zzzzzzzzzzz",0,0,0, 0 } + }; + + + //------------------------------------------------------------------------ + parser::~parser() + { + delete [] m_attr_value; + delete [] m_attr_name; + delete [] m_buf; + delete [] m_title; + } + + //------------------------------------------------------------------------ + parser::parser(path_renderer& path) : + m_path(path), + m_tokenizer(), + m_buf(new char[buf_size]), + m_title(new char[256]), + m_title_len(0), + m_title_flag(false), + m_path_flag(false), + m_attr_name(new char[128]), + m_attr_value(new char[1024]), + m_attr_name_len(127), + m_attr_value_len(1023) + { + m_title[0] = 0; + } + + //------------------------------------------------------------------------ + void parser::parse(const char* fname) + { + char msg[1024]; + XML_Parser p = XML_ParserCreate(NULL); + if(p == 0) + { + throw exception("Couldn't allocate memory for parser"); + } + + XML_SetUserData(p, this); + XML_SetElementHandler(p, start_element, end_element); + XML_SetCharacterDataHandler(p, content); + + FILE* fd = fopen(fname, "r"); + if(fd == 0) + { + sprintf(msg, "Couldn't open file %s", fname); + throw exception(msg); + } + + bool done = false; + do + { + size_t len = fread(m_buf, 1, buf_size, fd); + done = len < buf_size; + if(!XML_Parse(p, m_buf, len, done)) + { + sprintf(msg, + "%s at line %d\n", + XML_ErrorString(XML_GetErrorCode(p)), + XML_GetCurrentLineNumber(p)); + throw exception(msg); + } + } + while(!done); + fclose(fd); + XML_ParserFree(p); + + char* ts = m_title; + while(*ts) + { + if(*ts < ' ') *ts = ' '; + ++ts; + } + } + + + //------------------------------------------------------------------------ + void parser::start_element(void* data, const char* el, const char** attr) + { + parser& self = *(parser*)data; + + if(strcmp(el, "title") == 0) + { + self.m_title_flag = true; + } + else + if(strcmp(el, "g") == 0) + { + self.m_path.push_attr(); + self.parse_attr(attr); + } + else + if(strcmp(el, "path") == 0) + { + if(self.m_path_flag) + { + throw exception("start_element: Nested path"); + } + self.m_path.begin_path(); + self.parse_path(attr); + self.m_path.end_path(); + self.m_path_flag = true; + } + else + if(strcmp(el, "rect") == 0) + { + self.parse_rect(attr); + } + else + if(strcmp(el, "line") == 0) + { + self.parse_line(attr); + } + else + if(strcmp(el, "polyline") == 0) + { + self.parse_poly(attr, false); + } + else + if(strcmp(el, "polygon") == 0) + { + self.parse_poly(attr, true); + } + //else + //if(strcmp(el, "<OTHER_ELEMENTS>") == 0) + //{ + //} + // . . . + } + + + //------------------------------------------------------------------------ + void parser::end_element(void* data, const char* el) + { + parser& self = *(parser*)data; + + if(strcmp(el, "title") == 0) + { + self.m_title_flag = false; + } + else + if(strcmp(el, "g") == 0) + { + self.m_path.pop_attr(); + } + else + if(strcmp(el, "path") == 0) + { + self.m_path_flag = false; + } + //else + //if(strcmp(el, "<OTHER_ELEMENTS>") == 0) + //{ + //} + // . . . + } + + + //------------------------------------------------------------------------ + void parser::content(void* data, const char* s, int len) + { + parser& self = *(parser*)data; + + // m_title_flag signals that the <title> tag is being parsed now. + // The following code concatenates the pieces of content of the <title> tag. + if(self.m_title_flag) + { + if(len + self.m_title_len > 255) len = 255 - self.m_title_len; + if(len > 0) + { + memcpy(self.m_title + self.m_title_len, s, len); + self.m_title_len += len; + self.m_title[self.m_title_len] = 0; + } + } + } + + + //------------------------------------------------------------------------ + void parser::parse_attr(const char** attr) + { + int i; + for(i = 0; attr[i]; i += 2) + { + if(strcmp(attr[i], "style") == 0) + { + parse_style(attr[i + 1]); + } + else + { + parse_attr(attr[i], attr[i + 1]); + } + } + } + + //------------------------------------------------------------- + void parser::parse_path(const char** attr) + { + int i; + + for(i = 0; attr[i]; i += 2) + { + // The <path> tag can consist of the path itself ("d=") + // as well as of other parameters like "style=", "transform=", etc. + // In the last case we simply rely on the function of parsing + // attributes (see 'else' branch). + if(strcmp(attr[i], "d") == 0) + { + m_tokenizer.set_path_str(attr[i + 1]); + m_path.parse_path(m_tokenizer); + } + else + { + // Create a temporary single pair "name-value" in order + // to avoid multiple calls for the same attribute. + const char* tmp[4]; + tmp[0] = attr[i]; + tmp[1] = attr[i + 1]; + tmp[2] = 0; + tmp[3] = 0; + parse_attr(tmp); + } + } + } + + + //------------------------------------------------------------- + int cmp_color(const void* p1, const void* p2) + { + return strcmp(((named_color*)p1)->name, ((named_color*)p2)->name); + } + + //------------------------------------------------------------- + rgba8 parse_color(const char* str) + { + while(*str == ' ') ++str; + unsigned c = 0; + if(*str == '#') + { + sscanf(str + 1, "%x", &c); + return rgb8_packed(c); + } + else + { + named_color c; + unsigned len = strlen(str); + if(len > sizeof(c.name) - 1) + { + throw exception("parse_color: Invalid color name '%s'", str); + } + strcpy(c.name, str); + const void* p = bsearch(&c, + colors, + sizeof(colors) / sizeof(colors[0]), + sizeof(colors[0]), + cmp_color); + if(p == 0) + { + throw exception("parse_color: Invalid color name '%s'", str); + } + const named_color* pc = (const named_color*)p; + return rgba8(pc->r, pc->g, pc->b, pc->a); + } + } + + double parse_double(const char* str) + { + while(*str == ' ') ++str; + return atof(str); + } + + + + //------------------------------------------------------------- + bool parser::parse_attr(const char* name, const char* value) + { + if(strcmp(name, "style") == 0) + { + parse_style(value); + } + else + if(strcmp(name, "fill") == 0) + { + if(strcmp(value, "none") == 0) + { + m_path.fill_none(); + } + else + { + m_path.fill(parse_color(value)); + } + } + else + if(strcmp(name, "fill-opacity") == 0) + { + m_path.fill_opacity(parse_double(value)); + } + else + if(strcmp(name, "stroke") == 0) + { + if(strcmp(value, "none") == 0) + { + m_path.stroke_none(); + } + else + { + m_path.stroke(parse_color(value)); + } + } + else + if(strcmp(name, "stroke-width") == 0) + { + m_path.stroke_width(parse_double(value)); + } + else + if(strcmp(name, "stroke-linecap") == 0) + { + if(strcmp(value, "butt") == 0) m_path.line_cap(butt_cap); + else if(strcmp(value, "round") == 0) m_path.line_cap(round_cap); + else if(strcmp(value, "square") == 0) m_path.line_cap(square_cap); + } + else + if(strcmp(name, "stroke-linejoin") == 0) + { + if(strcmp(value, "miter") == 0) m_path.line_join(miter_join); + else if(strcmp(value, "round") == 0) m_path.line_join(round_join); + else if(strcmp(value, "bevel") == 0) m_path.line_join(bevel_join); + } + else + if(strcmp(name, "stroke-miterlimit") == 0) + { + m_path.miter_limit(parse_double(value)); + } + else + if(strcmp(name, "stroke-opacity") == 0) + { + m_path.stroke_opacity(parse_double(value)); + } + else + if(strcmp(name, "transform") == 0) + { + parse_transform(value); + } + //else + //if(strcmp(el, "<OTHER_ATTRIBUTES>") == 0) + //{ + //} + // . . . + else + { + return false; + } + return true; + } + + + + //------------------------------------------------------------- + void parser::copy_name(const char* start, const char* end) + { + unsigned len = unsigned(end - start); + if(m_attr_name_len == 0 || len > m_attr_name_len) + { + delete [] m_attr_name; + m_attr_name = new char[len + 1]; + m_attr_name_len = len; + } + if(len) memcpy(m_attr_name, start, len); + m_attr_name[len] = 0; + } + + + + //------------------------------------------------------------- + void parser::copy_value(const char* start, const char* end) + { + unsigned len = unsigned(end - start); + if(m_attr_value_len == 0 || len > m_attr_value_len) + { + delete [] m_attr_value; + m_attr_value = new char[len + 1]; + m_attr_value_len = len; + } + if(len) memcpy(m_attr_value, start, len); + m_attr_value[len] = 0; + } + + + //------------------------------------------------------------- + bool parser::parse_name_value(const char* nv_start, const char* nv_end) + { + const char* str = nv_start; + while(str < nv_end && *str != ':') ++str; + + const char* val = str; + + // Right Trim + while(str > nv_start && + (*str == ':' || isspace(*str))) --str; + ++str; + + copy_name(nv_start, str); + + while(val < nv_end && (*val == ':' || isspace(*val))) ++val; + + copy_value(val, nv_end); + return parse_attr(m_attr_name, m_attr_value); + } + + + + //------------------------------------------------------------- + void parser::parse_style(const char* str) + { + while(*str) + { + // Left Trim + while(*str && isspace(*str)) ++str; + const char* nv_start = str; + while(*str && *str != ';') ++str; + const char* nv_end = str; + + // Right Trim + while(nv_end > nv_start && + (*nv_end == ';' || isspace(*nv_end))) --nv_end; + ++nv_end; + + parse_name_value(nv_start, nv_end); + if(*str) ++str; + } + + } + + + //------------------------------------------------------------- + void parser::parse_rect(const char** attr) + { + int i; + double x = 0.0; + double y = 0.0; + double w = 0.0; + double h = 0.0; + + m_path.begin_path(); + for(i = 0; attr[i]; i += 2) + { + if(!parse_attr(attr[i], attr[i + 1])) + { + if(strcmp(attr[i], "x") == 0) x = parse_double(attr[i + 1]); + if(strcmp(attr[i], "y") == 0) y = parse_double(attr[i + 1]); + if(strcmp(attr[i], "width") == 0) w = parse_double(attr[i + 1]); + if(strcmp(attr[i], "height") == 0) h = parse_double(attr[i + 1]); + // rx - to be implemented + // ry - to be implemented + } + } + + + if(w != 0.0 && h != 0.0) + { + if(w < 0.0) throw exception("parse_rect: Invalid width: %f", w); + if(h < 0.0) throw exception("parse_rect: Invalid height: %f", h); + + m_path.move_to(x, y); + m_path.line_to(x + w, y); + m_path.line_to(x + w, y + h); + m_path.line_to(x, y + h); + m_path.close_subpath(); + } + m_path.end_path(); + } + + + //------------------------------------------------------------- + void parser::parse_line(const char** attr) + { + int i; + double x1 = 0.0; + double y1 = 0.0; + double x2 = 0.0; + double y2 = 0.0; + + m_path.begin_path(); + for(i = 0; attr[i]; i += 2) + { + if(!parse_attr(attr[i], attr[i + 1])) + { + if(strcmp(attr[i], "x1") == 0) x1 = parse_double(attr[i + 1]); + if(strcmp(attr[i], "y1") == 0) y1 = parse_double(attr[i + 1]); + if(strcmp(attr[i], "x2") == 0) x2 = parse_double(attr[i + 1]); + if(strcmp(attr[i], "y2") == 0) y2 = parse_double(attr[i + 1]); + } + } + + m_path.move_to(x1, y1); + m_path.line_to(x2, y2); + m_path.end_path(); + } + + + //------------------------------------------------------------- + void parser::parse_poly(const char** attr, bool close_flag) + { + int i; + double x = 0.0; + double y = 0.0; + + m_path.begin_path(); + for(i = 0; attr[i]; i += 2) + { + if(!parse_attr(attr[i], attr[i + 1])) + { + if(strcmp(attr[i], "points") == 0) + { + m_tokenizer.set_path_str(attr[i + 1]); + if(!m_tokenizer.next()) + { + throw exception("parse_poly: Too few coordinates"); + } + x = m_tokenizer.last_number(); + if(!m_tokenizer.next()) + { + throw exception("parse_poly: Too few coordinates"); + } + y = m_tokenizer.last_number(); + m_path.move_to(x, y); + while(m_tokenizer.next()) + { + x = m_tokenizer.last_number(); + if(!m_tokenizer.next()) + { + throw exception("parse_poly: Odd number of coordinates"); + } + y = m_tokenizer.last_number(); + m_path.line_to(x, y); + } + } + } + } + if(close_flag) + { + m_path.close_subpath(); + } + m_path.end_path(); + } + + //------------------------------------------------------------- + void parser::parse_transform(const char* str) + { + while(*str) + { + if(islower(*str)) + { + if(strncmp(str, "matrix", 6) == 0) str += parse_matrix(str); else + if(strncmp(str, "translate", 9) == 0) str += parse_translate(str); else + if(strncmp(str, "rotate", 6) == 0) str += parse_rotate(str); else + if(strncmp(str, "scale", 5) == 0) str += parse_scale(str); else + if(strncmp(str, "skewX", 5) == 0) str += parse_skew_x(str); else + if(strncmp(str, "skewY", 5) == 0) str += parse_skew_y(str); else + { + ++str; + } + } + else + { + ++str; + } + } + } + + + //------------------------------------------------------------- + static bool is_numeric(char c) + { + return strchr("0123456789+-.eE", c) != 0; + } + + //------------------------------------------------------------- + static unsigned parse_transform_args(const char* str, + double* args, + unsigned max_na, + unsigned* na) + { + *na = 0; + const char* ptr = str; + while(*ptr && *ptr != '(') ++ptr; + if(*ptr == 0) + { + throw exception("parse_transform_args: Invalid syntax"); + } + const char* end = ptr; + while(*end && *end != ')') ++end; + if(*end == 0) + { + throw exception("parse_transform_args: Invalid syntax"); + } + + while(ptr < end) + { + if(is_numeric(*ptr)) + { + if(*na >= max_na) + { + throw exception("parse_transform_args: Too many arguments"); + } + args[(*na)++] = atof(ptr); + while(ptr < end && is_numeric(*ptr)) ++ptr; + } + else + { + ++ptr; + } + } + return unsigned(end - str); + } + + //------------------------------------------------------------- + unsigned parser::parse_matrix(const char* str) + { + double args[6]; + unsigned na = 0; + unsigned len = parse_transform_args(str, args, 6, &na); + if(na != 6) + { + throw exception("parse_matrix: Invalid number of arguments"); + } + m_path.transform().premultiply(trans_affine(args[0], args[1], args[2], args[3], args[4], args[5])); + return len; + } + + //------------------------------------------------------------- + unsigned parser::parse_translate(const char* str) + { + double args[2]; + unsigned na = 0; + unsigned len = parse_transform_args(str, args, 2, &na); + if(na == 1) args[1] = 0.0; + m_path.transform().premultiply(trans_affine_translation(args[0], args[1])); + return len; + } + + //------------------------------------------------------------- + unsigned parser::parse_rotate(const char* str) + { + double args[3]; + unsigned na = 0; + unsigned len = parse_transform_args(str, args, 3, &na); + if(na == 1) + { + m_path.transform().premultiply(trans_affine_rotation(deg2rad(args[0]))); + } + else if(na == 3) + { + trans_affine t = trans_affine_translation(-args[1], -args[2]); + t *= trans_affine_rotation(deg2rad(args[0])); + t *= trans_affine_translation(args[1], args[2]); + m_path.transform().premultiply(t); + } + else + { + throw exception("parse_rotate: Invalid number of arguments"); + } + return len; + } + + //------------------------------------------------------------- + unsigned parser::parse_scale(const char* str) + { + double args[2]; + unsigned na = 0; + unsigned len = parse_transform_args(str, args, 2, &na); + if(na == 1) args[1] = args[0]; + m_path.transform().premultiply(trans_affine_scaling(args[0], args[1])); + return len; + } + + //------------------------------------------------------------- + unsigned parser::parse_skew_x(const char* str) + { + double arg; + unsigned na = 0; + unsigned len = parse_transform_args(str, &arg, 1, &na); + m_path.transform().premultiply(trans_affine_skewing(deg2rad(arg), 0.0)); + return len; + } + + //------------------------------------------------------------- + unsigned parser::parse_skew_y(const char* str) + { + double arg; + unsigned na = 0; + unsigned len = parse_transform_args(str, &arg, 1, &na); + m_path.transform().premultiply(trans_affine_skewing(0.0, deg2rad(arg))); + return len; + } + +} +} + + diff --git a/src/agg_svg/agg_svg_parser.h b/src/agg_svg/agg_svg_parser.h new file mode 100644 index 000000000..4d40936c7 --- /dev/null +++ b/src/agg_svg/agg_svg_parser.h @@ -0,0 +1,85 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG parser. +// +//---------------------------------------------------------------------------- + +#ifndef AGG_SVG_PARSER_INCLUDED +#define AGG_SVG_PARSER_INCLUDED + +#include "agg_svg_path_tokenizer.h" +#include "agg_svg_path_renderer.h" + +namespace agg +{ +namespace svg +{ + + class parser + { + enum buf_size_e { buf_size = BUFSIZ }; + public: + + ~parser(); + parser(path_renderer& path); + + void parse(const char* fname); + const char* title() const { return m_title; } + + private: + // XML event handlers + static void start_element(void* data, const char* el, const char** attr); + static void end_element(void* data, const char* el); + static void content(void* data, const char* s, int len); + + void parse_attr(const char** attr); + void parse_path(const char** attr); + void parse_poly(const char** attr, bool close_flag); + void parse_rect(const char** attr); + void parse_line(const char** attr); + void parse_style(const char* str); + void parse_transform(const char* str); + + unsigned parse_matrix(const char* str); + unsigned parse_translate(const char* str); + unsigned parse_rotate(const char* str); + unsigned parse_scale(const char* str); + unsigned parse_skew_x(const char* str); + unsigned parse_skew_y(const char* str); + + bool parse_attr(const char* name, const char* value); + bool parse_name_value(const char* nv_start, const char* nv_end); + void copy_name(const char* start, const char* end); + void copy_value(const char* start, const char* end); + + private: + path_renderer& m_path; + path_tokenizer m_tokenizer; + char* m_buf; + char* m_title; + unsigned m_title_len; + bool m_title_flag; + bool m_path_flag; + char* m_attr_name; + char* m_attr_value; + unsigned m_attr_name_len; + unsigned m_attr_value_len; + }; + +} +} + +#endif diff --git a/src/agg_svg/agg_svg_path_renderer.cpp b/src/agg_svg/agg_svg_path_renderer.cpp new file mode 100644 index 000000000..27c7b2e3a --- /dev/null +++ b/src/agg_svg/agg_svg_path_renderer.cpp @@ -0,0 +1,366 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG path renderer. +// +//---------------------------------------------------------------------------- + +#include <stdio.h> +#include "agg_svg_path_renderer.h" + +namespace agg +{ +namespace svg +{ + + //------------------------------------------------------------------------ + path_renderer::path_renderer() : + m_curved(m_storage), + m_curved_count(m_curved), + + m_curved_stroked(m_curved_count), + m_curved_stroked_trans(m_curved_stroked, m_transform), + + m_curved_trans(m_curved_count, m_transform), + m_curved_trans_contour(m_curved_trans) + { + m_curved_trans_contour.auto_detect_orientation(false); + } + + + //------------------------------------------------------------------------ + void path_renderer::remove_all() + { + m_storage.remove_all(); + m_attr_storage.remove_all(); + m_attr_stack.remove_all(); + m_transform.reset(); + } + + //------------------------------------------------------------------------ + void path_renderer::begin_path() + { + push_attr(); + unsigned idx = m_storage.start_new_path(); + m_attr_storage.add(path_attributes(cur_attr(), idx)); + } + + //------------------------------------------------------------------------ + void path_renderer::end_path() + { + if(m_attr_storage.size() == 0) + { + throw exception("end_path : The path was not begun"); + } + path_attributes attr = cur_attr(); + unsigned idx = m_attr_storage[m_attr_storage.size() - 1].index; + attr.index = idx; + m_attr_storage[m_attr_storage.size() - 1] = attr; + pop_attr(); + } + + //------------------------------------------------------------------------ + void path_renderer::move_to(double x, double y, bool rel) // M, m + { + if(rel) m_storage.rel_to_abs(&x, &y); + m_storage.move_to(x, y); + } + + //------------------------------------------------------------------------ + void path_renderer::line_to(double x, double y, bool rel) // L, l + { + if(rel) m_storage.rel_to_abs(&x, &y); + m_storage.line_to(x, y); + } + + //------------------------------------------------------------------------ + void path_renderer::hline_to(double x, bool rel) // H, h + { + double x2 = 0.0; + double y2 = 0.0; + if(m_storage.total_vertices()) + { + m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2); + if(rel) x += x2; + m_storage.line_to(x, y2); + } + } + + //------------------------------------------------------------------------ + void path_renderer::vline_to(double y, bool rel) // V, v + { + double x2 = 0.0; + double y2 = 0.0; + if(m_storage.total_vertices()) + { + m_storage.vertex(m_storage.total_vertices() - 1, &x2, &y2); + if(rel) y += y2; + m_storage.line_to(x2, y); + } + } + + //------------------------------------------------------------------------ + void path_renderer::curve3(double x1, double y1, // Q, q + double x, double y, bool rel) + { + if(rel) + { + m_storage.rel_to_abs(&x1, &y1); + m_storage.rel_to_abs(&x, &y); + } + m_storage.curve3(x1, y1, x, y); + } + + //------------------------------------------------------------------------ + void path_renderer::curve3(double x, double y, bool rel) // T, t + { +// throw exception("curve3(x, y) : NOT IMPLEMENTED YET"); + if(rel) + { + m_storage.curve3_rel(x, y); + } else + { + m_storage.curve3(x, y); + } + } + + //------------------------------------------------------------------------ + void path_renderer::curve4(double x1, double y1, // C, c + double x2, double y2, + double x, double y, bool rel) + { + if(rel) + { + m_storage.rel_to_abs(&x1, &y1); + m_storage.rel_to_abs(&x2, &y2); + m_storage.rel_to_abs(&x, &y); + } + m_storage.curve4(x1, y1, x2, y2, x, y); + } + + //------------------------------------------------------------------------ + void path_renderer::curve4(double x2, double y2, // S, s + double x, double y, bool rel) + { + //throw exception("curve4(x2, y2, x, y) : NOT IMPLEMENTED YET"); + if(rel) + { + m_storage.curve4_rel(x2, y2, x, y); + } else + { + m_storage.curve4(x2, y2, x, y); + } + } + + //------------------------------------------------------------------------ + void path_renderer::close_subpath() + { + m_storage.end_poly(path_flags_close); + } + + //------------------------------------------------------------------------ + path_attributes& path_renderer::cur_attr() + { + if(m_attr_stack.size() == 0) + { + throw exception("cur_attr : Attribute stack is empty"); + } + return m_attr_stack[m_attr_stack.size() - 1]; + } + + //------------------------------------------------------------------------ + void path_renderer::push_attr() + { + m_attr_stack.add(m_attr_stack.size() ? + m_attr_stack[m_attr_stack.size() - 1] : + path_attributes()); + } + + //------------------------------------------------------------------------ + void path_renderer::pop_attr() + { + if(m_attr_stack.size() == 0) + { + throw exception("pop_attr : Attribute stack is empty"); + } + m_attr_stack.remove_last(); + } + + //------------------------------------------------------------------------ + void path_renderer::fill(const rgba8& f) + { + path_attributes& attr = cur_attr(); + attr.fill_color = f; + attr.fill_flag = true; + } + + //------------------------------------------------------------------------ + void path_renderer::stroke(const rgba8& s) + { + path_attributes& attr = cur_attr(); + attr.stroke_color = s; + attr.stroke_flag = true; + } + + //------------------------------------------------------------------------ + void path_renderer::even_odd(bool flag) + { + cur_attr().even_odd_flag = flag; + } + + //------------------------------------------------------------------------ + void path_renderer::stroke_width(double w) + { + cur_attr().stroke_width = w; + } + + //------------------------------------------------------------------------ + void path_renderer::fill_none() + { + cur_attr().fill_flag = false; + } + + //------------------------------------------------------------------------ + void path_renderer::stroke_none() + { + cur_attr().stroke_flag = false; + } + + //------------------------------------------------------------------------ + void path_renderer::fill_opacity(double op) + { + cur_attr().fill_color.opacity(op); + } + + //------------------------------------------------------------------------ + void path_renderer::stroke_opacity(double op) + { + cur_attr().stroke_color.opacity(op); + } + + //------------------------------------------------------------------------ + void path_renderer::line_join(line_join_e join) + { + cur_attr().line_join = join; + } + + //------------------------------------------------------------------------ + void path_renderer::line_cap(line_cap_e cap) + { + cur_attr().line_cap = cap; + } + + //------------------------------------------------------------------------ + void path_renderer::miter_limit(double ml) + { + cur_attr().miter_limit = ml; + } + + //------------------------------------------------------------------------ + trans_affine& path_renderer::transform() + { + return cur_attr().transform; + } + + //------------------------------------------------------------------------ + void path_renderer::parse_path(path_tokenizer& tok) + { + while(tok.next()) + { + double arg[10]; + char cmd = tok.last_command(); + unsigned i; + switch(cmd) + { + case 'M': case 'm': + arg[0] = tok.last_number(); + arg[1] = tok.next(cmd); + move_to(arg[0], arg[1], cmd == 'm'); + break; + + case 'L': case 'l': + arg[0] = tok.last_number(); + arg[1] = tok.next(cmd); + line_to(arg[0], arg[1], cmd == 'l'); + break; + + case 'V': case 'v': + vline_to(tok.last_number(), cmd == 'v'); + break; + + case 'H': case 'h': + hline_to(tok.last_number(), cmd == 'h'); + break; + + case 'Q': case 'q': + arg[0] = tok.last_number(); + for(i = 1; i < 4; i++) + { + arg[i] = tok.next(cmd); + } + curve3(arg[0], arg[1], arg[2], arg[3], cmd == 'q'); + break; + + case 'T': case 't': + arg[0] = tok.last_number(); + arg[1] = tok.next(cmd); + curve3(arg[0], arg[1], cmd == 't'); + break; + + case 'C': case 'c': + arg[0] = tok.last_number(); + for(i = 1; i < 6; i++) + { + arg[i] = tok.next(cmd); + } + curve4(arg[0], arg[1], arg[2], arg[3], arg[4], arg[5], cmd == 'c'); + break; + + case 'S': case 's': + arg[0] = tok.last_number(); + for(i = 1; i < 4; i++) + { + arg[i] = tok.next(cmd); + } + curve4(arg[0], arg[1], arg[2], arg[3], cmd == 's'); + break; + + case 'A': case 'a': + arg[0] = tok.last_number(); + for (i = 1; i < 7; i++) + { + arg[i] = tok.next(cmd); + } +// curve3(arg[0], arg[1], arg[2], arg[3], cmd == 'q'); +// throw exception("parse_path: Command A: NOT IMPLEMENTED YET"); + break; + + case 'Z': case 'z': + close_subpath(); + break; + + default: + { + char buf[100]; + sprintf(buf, "parse_path: Invalid Command %c", cmd); + throw exception(buf); + } + } + } + } + +} +} + diff --git a/src/agg_svg/agg_svg_path_renderer.h b/src/agg_svg/agg_svg_path_renderer.h new file mode 100644 index 000000000..0f27066b5 --- /dev/null +++ b/src/agg_svg/agg_svg_path_renderer.h @@ -0,0 +1,321 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG path renderer. +// +//---------------------------------------------------------------------------- +#ifndef AGG_SVG_PATH_RENDERER_INCLUDED +#define AGG_SVG_PATH_RENDERER_INCLUDED + +#include <agg/agg_path_storage.h> +#include <agg/agg_conv_transform.h> +#include <agg/agg_conv_stroke.h> +#include <agg/agg_conv_contour.h> +#include <agg/agg_conv_curve.h> +#include <agg/agg_color_rgba.h> +#include <agg/agg_renderer_scanline.h> +#include <agg/agg_bounding_rect.h> +#include <agg/agg_rasterizer_scanline_aa.h> +#include "agg_svg_path_tokenizer.h" + +namespace agg +{ +namespace svg +{ + template<class VertexSource> class conv_count + { + public: + conv_count(VertexSource& vs) : m_source(&vs), m_count(0) {} + + void count(unsigned n) { m_count = n; } + unsigned count() const { return m_count; } + + void rewind(unsigned path_id) { m_source->rewind(path_id); } + unsigned vertex(double* x, double* y) + { + ++m_count; + return m_source->vertex(x, y); + } + + private: + VertexSource* m_source; + unsigned m_count; + }; + + + + + //============================================================================ + // Basic path attributes + struct path_attributes + { + unsigned index; + rgba8 fill_color; + rgba8 stroke_color; + bool fill_flag; + bool stroke_flag; + bool even_odd_flag; + line_join_e line_join; + line_cap_e line_cap; + double miter_limit; + double stroke_width; + trans_affine transform; + + // Empty constructor + path_attributes() : + index(0), + fill_color(rgba(0,0,0)), + stroke_color(rgba(0,0,0)), + fill_flag(true), + stroke_flag(false), + even_odd_flag(false), + line_join(miter_join), + line_cap(butt_cap), + miter_limit(4.0), + stroke_width(1.0), + transform() + { + } + + // Copy constructor + path_attributes(const path_attributes& attr) : + index(attr.index), + fill_color(attr.fill_color), + stroke_color(attr.stroke_color), + fill_flag(attr.fill_flag), + stroke_flag(attr.stroke_flag), + even_odd_flag(attr.even_odd_flag), + line_join(attr.line_join), + line_cap(attr.line_cap), + miter_limit(attr.miter_limit), + stroke_width(attr.stroke_width), + transform(attr.transform) + { + } + + // Copy constructor with new index value + path_attributes(const path_attributes& attr, unsigned idx) : + index(idx), + fill_color(attr.fill_color), + stroke_color(attr.stroke_color), + fill_flag(attr.fill_flag), + stroke_flag(attr.stroke_flag), + even_odd_flag(attr.even_odd_flag), + line_join(attr.line_join), + line_cap(attr.line_cap), + miter_limit(attr.miter_limit), + stroke_width(attr.stroke_width), + transform(attr.transform) + { + } + }; + + + //============================================================================ + // Path container and renderer. + class path_renderer + { + public: + typedef pod_bvector<path_attributes> attr_storage; + + typedef conv_curve<path_storage> curved; + typedef conv_count<curved> curved_count; + + typedef conv_stroke<curved_count> curved_stroked; + typedef conv_transform<curved_stroked> curved_stroked_trans; + + typedef conv_transform<curved_count> curved_trans; + typedef conv_contour<curved_trans> curved_trans_contour; + + path_renderer(); + + void remove_all(); + + // Use these functions as follows: + // begin_path() when the XML tag <path> comes ("start_element" handler) + // parse_path() on "d=" tag attribute + // end_path() when parsing of the entire tag is done. + void begin_path(); + void parse_path(path_tokenizer& tok); + void end_path(); + + // The following functions are essentially a "reflection" of + // the respective SVG path commands. + void move_to(double x, double y, bool rel=false); // M, m + void line_to(double x, double y, bool rel=false); // L, l + void hline_to(double x, bool rel=false); // H, h + void vline_to(double y, bool rel=false); // V, v + void curve3(double x1, double y1, // Q, q + double x, double y, bool rel=false); + void curve3(double x, double y, bool rel=false); // T, t + void curve4(double x1, double y1, // C, c + double x2, double y2, + double x, double y, bool rel=false); + void curve4(double x2, double y2, // S, s + double x, double y, bool rel=false); + void close_subpath(); // Z, z + +// template<class VertexSource> +// void add_path(VertexSource& vs, +// unsigned path_id = 0, +// bool solid_path = true) +// { +// m_storage.add_path(vs, path_id, solid_path); +// } + + + unsigned vertex_count() const { return m_curved_count.count(); } + + + // Call these functions on <g> tag (start_element, end_element respectively) + void push_attr(); + void pop_attr(); + + // Attribute setting functions. + void fill(const rgba8& f); + void stroke(const rgba8& s); + void even_odd(bool flag); + void stroke_width(double w); + void fill_none(); + void stroke_none(); + void fill_opacity(double op); + void stroke_opacity(double op); + void line_join(line_join_e join); + void line_cap(line_cap_e cap); + void miter_limit(double ml); + trans_affine& transform(); + + // Make all polygons CCW-oriented + void arrange_orientations() + { + m_storage.arrange_orientations_all_paths(path_flags_ccw); + } + + // Expand all polygons + void expand(double value) + { + m_curved_trans_contour.width(value); + } + + unsigned operator [](unsigned idx) + { + m_transform = m_attr_storage[idx].transform; + return m_attr_storage[idx].index; + } + + void bounding_rect(double* x1, double* y1, double* x2, double* y2) + { + agg::conv_transform<agg::path_storage> trans(m_storage, m_transform); + agg::bounding_rect(trans, *this, 0, m_attr_storage.size(), x1, y1, x2, y2); + } + + // Rendering. One can specify two additional parameters: + // trans_affine and opacity. They can be used to transform the whole + // image and/or to make it translucent. + template<class Rasterizer, class Scanline, class Renderer> + void render(Rasterizer& ras, + Scanline& sl, + Renderer& ren, + const trans_affine& mtx, + const rect_i& cb, + double opacity=1.0) + { + unsigned i; + + ras.clip_box(cb.x1, cb.y1, cb.x2, cb.y2); + m_curved_count.count(0); + + for(i = 0; i < m_attr_storage.size(); i++) + { + const path_attributes& attr = m_attr_storage[i]; + m_transform = attr.transform; + m_transform *= mtx; + double scl = m_transform.scale(); + //m_curved.approximation_method(curve_inc); + m_curved.approximation_scale(scl); + m_curved.angle_tolerance(0.0); + + rgba8 color; + + if(attr.fill_flag) + { + ras.reset(); + ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero); + if(fabs(m_curved_trans_contour.width()) < 0.0001) + { + ras.add_path(m_curved_trans, attr.index); + } + else + { + m_curved_trans_contour.miter_limit(attr.miter_limit); + ras.add_path(m_curved_trans_contour, attr.index); + } + + color = attr.fill_color; + color.opacity(color.opacity() * opacity); + ren.color(color); + agg::render_scanlines(ras, sl, ren); + } + + if(attr.stroke_flag) + { + m_curved_stroked.width(attr.stroke_width); + //m_curved_stroked.line_join((attr.line_join == miter_join) ? miter_join_round : attr.line_join); + m_curved_stroked.line_join(attr.line_join); + m_curved_stroked.line_cap(attr.line_cap); + m_curved_stroked.miter_limit(attr.miter_limit); + m_curved_stroked.inner_join(inner_round); + m_curved_stroked.approximation_scale(scl); + + // If the *visual* line width is considerable we + // turn on processing of curve cusps. + //--------------------- + if(attr.stroke_width * scl > 1.0) + { + m_curved.angle_tolerance(0.2); + } + ras.reset(); + ras.filling_rule(fill_non_zero); + ras.add_path(m_curved_stroked_trans, attr.index); + color = attr.stroke_color; + color.opacity(color.opacity() * opacity); + ren.color(color); + agg::render_scanlines(ras, sl, ren); + } + } + } + + private: + path_attributes& cur_attr(); + + path_storage m_storage; + attr_storage m_attr_storage; + attr_storage m_attr_stack; + trans_affine m_transform; + + curved m_curved; + curved_count m_curved_count; + + curved_stroked m_curved_stroked; + curved_stroked_trans m_curved_stroked_trans; + + curved_trans m_curved_trans; + curved_trans_contour m_curved_trans_contour; + }; + +} +} + +#endif diff --git a/src/agg_svg/agg_svg_path_tokenizer.cpp b/src/agg_svg/agg_svg_path_tokenizer.cpp new file mode 100644 index 000000000..bd49519bf --- /dev/null +++ b/src/agg_svg/agg_svg_path_tokenizer.cpp @@ -0,0 +1,151 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG path tokenizer. +// +//---------------------------------------------------------------------------- +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include "agg_svg_exception.h" +#include "agg_svg_path_tokenizer.h" + + +namespace agg +{ +namespace svg +{ + + //------------------------------------------------------------------------ + const char path_tokenizer::s_commands[] = "+-MmZzLlHhVvCcSsQqTtAaFfPp"; + const char path_tokenizer::s_numeric[] = ".Ee0123456789"; + const char path_tokenizer::s_separators[] = " ,\t\n\r"; + + //------------------------------------------------------------------------ + path_tokenizer::path_tokenizer() + : m_path(0), m_last_command(0), m_last_number(0.0) + { + init_char_mask(m_commands_mask, s_commands); + init_char_mask(m_numeric_mask, s_numeric); + init_char_mask(m_separators_mask, s_separators); + } + + + //------------------------------------------------------------------------ + void path_tokenizer::set_path_str(const char* str) + { + m_path = str; + m_last_command = 0; + m_last_number = 0.0; + } + + + //------------------------------------------------------------------------ + void path_tokenizer::init_char_mask(char* mask, const char* char_set) + { + memset(mask, 0, 256/8); + while(*char_set) + { + unsigned c = unsigned(*char_set++) & 0xFF; + mask[c >> 3] |= 1 << (c & 7); + } + } + + + //------------------------------------------------------------------------ + bool path_tokenizer::next() + { + if(m_path == 0) return false; + + // Skip all white spaces and other garbage + while(*m_path && !is_command(*m_path) && !is_numeric(*m_path)) + { + if(!is_separator(*m_path)) + { + char buf[100]; + sprintf(buf, "path_tokenizer::next : Invalid Character %c", *m_path); + throw exception(buf); + } + m_path++; + } + + if(*m_path == 0) return false; + + if(is_command(*m_path)) + { + // Check if the command is a numeric sign character + if(*m_path == '-' || *m_path == '+') + { + return parse_number(); + } + m_last_command = *m_path++; + while(*m_path && is_separator(*m_path)) m_path++; + if(*m_path == 0) return true; + } + return parse_number(); + } + + + + //------------------------------------------------------------------------ + double path_tokenizer::next(char cmd) + { + if(!next()) throw exception("parse_path: Unexpected end of path"); + if(last_command() != cmd) + { + char buf[100]; + sprintf(buf, "parse_path: Command %c: bad or missing parameters", cmd); + throw exception(buf); + } + return last_number(); + } + + + //------------------------------------------------------------------------ + bool path_tokenizer::parse_number() + { + char buf[256]; // Should be enough for any number + char* buf_ptr = buf; + + // Copy all sign characters + while(buf_ptr < buf+255 && *m_path == '-' || *m_path == '+') + { + *buf_ptr++ = *m_path++; + } + + // Copy all numeric characters + bool dot_seen = false; + while(buf_ptr < buf+255 && is_numeric(*m_path)) + { + char c = *m_path; + if (c == '.') { + if (dot_seen) + break; + dot_seen = true; + } + *buf_ptr++ = *m_path++; + } + *buf_ptr = 0; + m_last_number = atof(buf); + return true; + } + + +} //namespace svg +} //namespace agg + + + + diff --git a/src/agg_svg/agg_svg_path_tokenizer.h b/src/agg_svg/agg_svg_path_tokenizer.h new file mode 100644 index 000000000..591ec0e72 --- /dev/null +++ b/src/agg_svg/agg_svg_path_tokenizer.h @@ -0,0 +1,114 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.3 +// 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 +//---------------------------------------------------------------------------- +// +// SVG path tokenizer. +// +//---------------------------------------------------------------------------- +#ifndef AGG_SVG_PATH_TOKENIZER_INCLUDED +#define AGG_SVG_PATH_TOKENIZER_INCLUDED + +#include "agg_svg_exception.h" + +namespace agg +{ +namespace svg +{ + // SVG path tokenizer. + // Example: + // + // agg::svg::path_tokenizer tok; + // + // tok.set_str("M-122.304 84.285L-122.304 84.285 122.203 86.179 "); + // while(tok.next()) + // { + // printf("command='%c' number=%f\n", + // tok.last_command(), + // tok.last_number()); + // } + // + // The tokenizer does all the routine job of parsing the SVG paths. + // It doesn't recognize any graphical primitives, it even doesn't know + // anything about pairs of coordinates (X,Y). The purpose of this class + // is to tokenize the numeric values and commands. SVG paths can + // have single numeric values for Horizontal or Vertical line_to commands + // as well as more than two coordinates (4 or 6) for Bezier curves + // depending on the semantics of the command. + // The behaviour is as follows: + // + // Each call to next() returns true if there's new command or new numeric + // value or false when the path ends. How to interpret the result + // depends on the sematics of the command. For example, command "C" + // (cubic Bezier curve) implies 6 floating point numbers preceded by this + // command. If the command assumes no arguments (like z or Z) the + // the last_number() values won't change, that is, last_number() always + // returns the last recognized numeric value, so does last_command(). + //=============================================================== + class path_tokenizer + { + public: + path_tokenizer(); + + void set_path_str(const char* str); + bool next(); + + double next(char cmd); + + char last_command() const { return m_last_command; } + double last_number() const { return m_last_number; } + + + private: + static void init_char_mask(char* mask, const char* char_set); + + bool contains(const char* mask, unsigned c) const + { + return (mask[(c >> 3) & (256/8-1)] & (1 << (c & 7))) != 0; + } + + bool is_command(unsigned c) const + { + return contains(m_commands_mask, c); + } + + bool is_numeric(unsigned c) const + { + return contains(m_numeric_mask, c); + } + + bool is_separator(unsigned c) const + { + return contains(m_separators_mask, c); + } + + bool parse_number(); + + char m_separators_mask[256/8]; + char m_commands_mask[256/8]; + char m_numeric_mask[256/8]; + + const char* m_path; + double m_last_number; + char m_last_command; + + static const char s_commands[]; + static const char s_numeric[]; + static const char s_separators[]; + }; + +} //namespace svg +} //namespace agg + + +#endif diff --git a/src/agg_svg/agg_trans_affine.cpp b/src/agg_svg/agg_trans_affine.cpp new file mode 100644 index 000000000..151b1d728 --- /dev/null +++ b/src/agg_svg/agg_trans_affine.cpp @@ -0,0 +1,200 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#include <agg/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; + } + + +} + diff --git a/src/agg_svg/agg_vcgen_contour.cpp b/src/agg_svg/agg_vcgen_contour.cpp new file mode 100644 index 000000000..ecc087e94 --- /dev/null +++ b/src/agg_svg/agg_vcgen_contour.cpp @@ -0,0 +1,170 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#include <math.h> +#include <agg/agg_vcgen_contour.h> + +namespace agg +{ + + //------------------------------------------------------------------------ + vcgen_contour::vcgen_contour() : + m_stroker(), + m_width(1), + m_src_vertices(), + m_out_vertices(), + m_status(initial), + m_src_vertex(0), + m_closed(0), + m_orientation(0), + m_auto_detect(false) + { + } + + //------------------------------------------------------------------------ + void vcgen_contour::remove_all() + { + m_src_vertices.remove_all(); + m_closed = 0; + m_orientation = 0; + m_status = initial; + } + + //------------------------------------------------------------------------ + void vcgen_contour::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 + { + if(is_end_poly(cmd)) + { + m_closed = get_close_flag(cmd); + if(m_orientation == path_flags_none) + { + m_orientation = get_orientation(cmd); + } + } + } + } + } + + //------------------------------------------------------------------------ + void vcgen_contour::rewind(unsigned) + { + if(m_status == initial) + { + m_src_vertices.close(true); + if(m_auto_detect) + { + if(!is_oriented(m_orientation)) + { + m_orientation = (calc_polygon_area(m_src_vertices) > 0.0) ? + path_flags_ccw : + path_flags_cw; + } + } + if(is_oriented(m_orientation)) + { + m_stroker.width(is_ccw(m_orientation) ? m_width : -m_width); + } + } + m_status = ready; + m_src_vertex = 0; + } + + //------------------------------------------------------------------------ + unsigned vcgen_contour::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 = outline; + cmd = path_cmd_move_to; + m_src_vertex = 0; + m_out_vertex = 0; + + case outline: + if(m_src_vertex >= m_src_vertices.size()) + { + m_status = end_poly; + 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_status = out_vertices; + m_out_vertex = 0; + + case out_vertices: + if(m_out_vertex >= m_out_vertices.size()) + { + m_status = outline; + } + else + { + const point_d& c = m_out_vertices[m_out_vertex++]; + *x = c.x; + *y = c.y; + return cmd; + } + break; + + case end_poly: + if(!m_closed) return path_cmd_stop; + m_status = stop; + return path_cmd_end_poly | path_flags_close | path_flags_ccw; + + case stop: + return path_cmd_stop; + } + } + return cmd; + } + +} diff --git a/src/agg_svg/agg_vcgen_stroke.cpp b/src/agg_svg/agg_vcgen_stroke.cpp new file mode 100644 index 000000000..a8b378195 --- /dev/null +++ b/src/agg_svg/agg_vcgen_stroke.cpp @@ -0,0 +1,219 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry (AGG) - Version 2.5 +// A high quality rendering engine for C++ +// Copyright (C) 2002-2006 Maxim Shemanarev +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://antigrain.com +// +// AGG is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// AGG is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with AGG; if not, write to the Free Software +// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +// MA 02110-1301, USA. +//---------------------------------------------------------------------------- + +#include <math.h> +#include <agg/agg_vcgen_stroke.h> +#include <agg/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; + } + +} diff --git a/src/libslic3r/Rasterizer/Rasterizer.cpp b/src/libslic3r/Rasterizer/Rasterizer.cpp index 5961d9b78..bd8b54389 100644 --- a/src/libslic3r/Rasterizer/Rasterizer.cpp +++ b/src/libslic3r/Rasterizer/Rasterizer.cpp @@ -27,7 +27,7 @@ public: using TPixel = TPixelRenderer::color_type; using TRawBuffer = agg::rendering_buffer; - using TBuffer = std::vector<TPixelRenderer::pixel_type>; + using TBuffer = std::vector<TPixelRenderer::value_type>; using TRendererAA = agg::renderer_scanline_aa_solid<TRawRenderer>; @@ -36,6 +36,11 @@ public: using Origin = Raster::Origin; + enum + { + num_components = 1, + }; + private: Raster::Resolution m_resolution; Raster::PixelDim m_pxdim; @@ -58,7 +63,7 @@ public: m_buf(res.pixels()), m_rbuf(reinterpret_cast<TPixelRenderer::value_type*>(m_buf.data()), res.width_px, res.height_px, - int(res.width_px*TPixelRenderer::num_components)), + int(res.width_px*num_components)), m_pixfmt(m_rbuf), m_raw_renderer(m_pixfmt), m_renderer(m_raw_renderer), diff --git a/src/slic3r/CMakeLists.txt b/src/slic3r/CMakeLists.txt index 9d65a479f..f98819713 100644 --- a/src/slic3r/CMakeLists.txt +++ b/src/slic3r/CMakeLists.txt @@ -121,6 +121,8 @@ set(SLIC3R_GUI_SOURCES Utils/Bonjour.hpp Utils/PresetUpdater.cpp Utils/PresetUpdater.hpp + Utils/SVGImport.cpp + Utils/SVGImport.hpp Utils/Time.cpp Utils/Time.hpp Utils/HexFile.cpp @@ -133,7 +135,10 @@ endif () add_library(libslic3r_gui STATIC ${SLIC3R_GUI_SOURCES}) -target_link_libraries(libslic3r_gui libslic3r avrdude imgui) +target_compile_definitions(libslic3r_gui PUBLIC -DUSE_TBB ${PNG_DEFINITIONS}) +target_include_directories(libslic3r_gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${PNG_INCLUDE_DIRS}) +target_link_libraries(libslic3r_gui libslic3r avrdude imgui ${PNG_LIBRARIES} agg_svg) + if (SLIC3R_PCH AND NOT SLIC3R_SYNTAXONLY) add_precompiled_header(libslic3r_gui pchheader.hpp FORCEINCLUDE) endif () diff --git a/src/slic3r/GUI/MainFrame.cpp b/src/slic3r/GUI/MainFrame.cpp index 91574cda6..64d4f040b 100644 --- a/src/slic3r/GUI/MainFrame.cpp +++ b/src/slic3r/GUI/MainFrame.cpp @@ -27,6 +27,7 @@ #include <fstream> #include "GUI_App.hpp" +#include "Utils/SVGImport.hpp" namespace Slic3r { namespace GUI { @@ -35,6 +36,9 @@ MainFrame::MainFrame() : wxFrame(NULL, wxID_ANY, SLIC3R_BUILD, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, "mainframe"), m_printhost_queue_dlg(new PrintHostQueueDialog(this)) { + + Slic3r::Utils::vojtikuv_pokus(); + // Load the icon either from the exe, or from the ico file. #if _WIN32 { diff --git a/src/slic3r/Utils/SVGImport.cpp b/src/slic3r/Utils/SVGImport.cpp new file mode 100644 index 000000000..f0639f659 --- /dev/null +++ b/src/slic3r/Utils/SVGImport.cpp @@ -0,0 +1,98 @@ +#include "SVGImport.hpp" + +#include <agg/agg_basics.h> +#include <agg/agg_rendering_buffer.h> +#include <agg/agg_rasterizer_scanline_aa.h> +#include <agg/agg_scanline_p.h> +#include <agg/agg_renderer_scanline.h> +#include <agg/agg_pixfmt_rgba.h> +#include <agg_svg/agg_svg_parser.h> + +#include <png/writer.hpp> + +#include <boost/nowide/iostream.hpp> + +namespace Slic3r { namespace Utils { + +int vojtikuv_pokus() +{ + std::string fname = "D:\\temp\\svg_examples\\slicer_vnitrni-menu.svg"; + try + { + agg::svg::path_renderer path; + agg::svg::parser prsr(path); + prsr.parse(fname.c_str()); + path.arrange_orientations(); + double m_min_x; + double m_min_y; + double m_max_x; + double m_max_y; + path.bounding_rect(&m_min_x, &m_min_y, &m_max_x, &m_max_y); +// caption(p.title()); + + +// typedef agg::pixfmt_bgra32 pixfmt; + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::renderer_base<pixfmt> renderer_base; + typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid; + + unsigned int width_px = 1000; + unsigned int height_px = 1000; + std::vector<unsigned char> buffer(width_px * height_px * 4, 0); + agg::rendering_buffer rbuf(reinterpret_cast<pixfmt::value_type*>(buffer.data()), width_px, height_px, int(width_px * 4)); + pixfmt pixf(rbuf); + renderer_base rb(pixf); + renderer_solid ren(rb); + + rb.clear(agg::rgba(1,1,1)); + + agg::rasterizer_scanline_aa<> ras; + agg::scanline_p8 sl; + agg::trans_affine mtx; + + ras.gamma(agg::gamma_power(1.)); + mtx *= agg::trans_affine_translation(- m_min_x, - m_min_y); + mtx *= agg::trans_affine_scaling(double(width_px) / (m_max_x - m_min_x), double(height_px) / (m_max_y - m_min_y)); + + path.expand(1.); + path.render(ras, sl, ren, mtx, rb.clip_box(), 1.0); + +// ren.color(agg::rgba(0,0,0)); + ren.color(agg::rgba(1,1,1)); + agg::render_scanlines(ras, sl, ren); + + + + + + + try { + boost::nowide::ofstream c; + c.open("d:\\temp\\rasterized.png", std::ios::out | std::ios::binary | std::ios::trunc); + png::writer<std::ostream> wr(c); + wr.set_bit_depth(8); + wr.set_color_type(png::color_type_rgb_alpha); + wr.set_width(width_px); + wr.set_height(height_px); + wr.set_compression_type(png::compression_type_default); + wr.write_info(); + auto ptr = reinterpret_cast<png::byte*>(buffer.data()); + unsigned stride = 4 * width_px; + for(unsigned r = 0; r < height_px; ++ r, ptr += stride) + wr.write_row(ptr); + wr.write_end_info(); + c.close(); + } + catch (std::exception &ex) { + printf("Hu!"); + } + } + catch(agg::svg::exception& e) + { +// app.message(e.msg()); + } + + return 0; +} + +} } // namespace Slic3r::Utils diff --git a/src/slic3r/Utils/SVGImport.hpp b/src/slic3r/Utils/SVGImport.hpp new file mode 100644 index 000000000..9dedb2431 --- /dev/null +++ b/src/slic3r/Utils/SVGImport.hpp @@ -0,0 +1,12 @@ +#ifndef slic3r_Utils_SVGImport_hpp_ +#define slic3r_Utils_SVGImport_hpp_ + +namespace Slic3r { +namespace Utils { + +int vojtikuv_pokus(); + +}; // namespace Utils +}; // namespace Slic3r + +#endif /* slic3r_Utils_SVGImport_hpp_ */