From 15ae7c17948acf36a44e0a74cfc2e1cda66c5e5d Mon Sep 17 00:00:00 2001 From: Jean-Mathieu Deschenes Date: Tue, 8 Aug 2017 11:17:12 -0400 Subject: [PATCH 1/4] Upgrade to the same AGG version as Matplotlib * Now using the same version of AGG as matplotlib * Removed unittest skips that were hampered by a bug with the old agg version * Some small changes to the unit test as the rendering changed * Adapted function `void transform_image_interpolate` to make it compile * Changed signature of `agg24::rendering_buffer* graphics_context_base::rendering_buffer_ptr()` to `agg24::rendering_buffer& graphics_context_base::rendering_buffer()` --- enable/tests/primitives/test_image.py | 4 - kiva/agg/agg-24/include/agg_alpha_mask_u8.h | 8 +- kiva/agg/agg-24/include/agg_array.h | 36 +- kiva/agg/agg-24/include/agg_basics.h | 84 +- kiva/agg/agg-24/include/agg_blur.h | 1503 ++++++++ kiva/agg/agg-24/include/agg_color_gray.h | 971 ++++- kiva/agg/agg-24/include/agg_color_rgba.h | 1169 ++++-- kiva/agg/agg-24/include/agg_config.h | 20 +- .../agg-24/include/agg_conv_adaptor_vcgen.h | 2 +- .../agg-24/include/agg_conv_adaptor_vpgen.h | 2 +- .../agg-24/include/agg_conv_close_polygon.h | 2 +- kiva/agg/agg-24/include/agg_conv_curve.h | 10 +- kiva/agg/agg-24/include/agg_conv_gpc.h | 432 +++ kiva/agg/agg-24/include/agg_conv_transform.h | 6 +- .../agg-24/include/agg_conv_unclose_polygon.h | 2 +- kiva/agg/agg-24/include/agg_curves.h | 2 - .../agg-24/include/agg_font_cache_manager.h | 6 + .../agg-24/include/agg_font_cache_manager2.h | 311 ++ kiva/agg/agg-24/include/agg_gamma_functions.h | 9 + kiva/agg/agg-24/include/agg_gamma_lut.h | 184 + kiva/agg/agg-24/include/agg_gradient_lut.h | 244 ++ kiva/agg/agg-24/include/agg_gsv_text.h | 4 +- kiva/agg/agg-24/include/agg_image_accessors.h | 30 +- kiva/agg/agg-24/include/agg_math.h | 78 +- kiva/agg/agg-24/include/agg_math_stroke.h | 229 +- kiva/agg/agg-24/include/agg_path_storage.h | 96 +- .../agg-24/include/agg_pattern_filters_rgba.h | 11 +- .../agg-24/include/agg_pixfmt_amask_adaptor.h | 20 +- kiva/agg/agg-24/include/agg_pixfmt_base.h | 97 + kiva/agg/agg-24/include/agg_pixfmt_gray.h | 503 ++- kiva/agg/agg-24/include/agg_pixfmt_rgb.h | 723 ++-- .../agg-24/include/agg_pixfmt_rgb_packed.h | 113 +- kiva/agg/agg-24/include/agg_pixfmt_rgba.h | 3167 +++++++++-------- .../agg-24/include/agg_pixfmt_transposer.h | 157 + .../agg-24/include/agg_rasterizer_cells_aa.h | 125 +- .../include/agg_rasterizer_compound_aa.h | 230 +- .../agg-24/include/agg_rasterizer_outline.h | 2 +- .../include/agg_rasterizer_outline_aa.h | 2 +- .../include/agg_rasterizer_scanline_aa.h | 63 +- .../agg_rasterizer_scanline_aa_nogamma.h | 482 +++ kiva/agg/agg-24/include/agg_renderer_base.h | 183 +- .../agg/agg-24/include/agg_renderer_markers.h | 1 - kiva/agg/agg-24/include/agg_renderer_mclip.h | 2 +- .../agg-24/include/agg_renderer_outline_aa.h | 38 +- .../include/agg_renderer_outline_image.h | 57 +- .../agg-24/include/agg_renderer_primitives.h | 2 +- .../agg-24/include/agg_renderer_scanline.h | 213 +- .../agg/agg-24/include/agg_rendering_buffer.h | 177 +- .../include/agg_rendering_buffer_dynarow.h | 7 +- .../agg-24/include/agg_scanline_storage_aa.h | 12 +- .../agg-24/include/agg_scanline_storage_bin.h | 20 +- kiva/agg/agg-24/include/agg_scanline_u.h | 12 +- .../agg-24/include/agg_span_gouraud_rgba.h | 16 +- kiva/agg/agg-24/include/agg_span_gradient.h | 174 +- .../agg-24/include/agg_span_gradient_alpha.h | 8 +- .../include/agg_span_gradient_contour.h | 362 ++ .../agg-24/include/agg_span_gradient_image.h | 188 + .../agg-24/include/agg_span_image_filter.h | 64 +- .../include/agg_span_image_filter_gray.h | 138 +- .../include/agg_span_image_filter_rgb.h | 182 +- .../include/agg_span_image_filter_rgba.h | 149 +- .../include/agg_span_interpolator_adaptor.h | 14 +- .../include/agg_span_interpolator_linear.h | 14 +- .../include/agg_span_interpolator_trans.h | 6 +- .../agg-24/include/agg_span_pattern_rgba.h | 2 +- kiva/agg/agg-24/include/agg_trans_affine.h | 255 +- kiva/agg/agg-24/include/agg_trans_lens.h | 79 - .../agg-24/include/agg_trans_perspective.h | 747 +++- .../agg-24/include/agg_trans_warp_magnifier.h | 5 + .../include/platform/agg_platform_support.h | 23 +- kiva/agg/agg-24/include/util/agg_color_conv.h | 44 + .../agg-24/include/util/agg_color_conv_rgb8.h | 25 +- kiva/agg/agg-24/src/agg_curves.cpp | 118 +- kiva/agg/agg-24/src/agg_gsv_text.cpp | 17 +- kiva/agg/agg-24/src/agg_sqrt_tables.cpp | 4 +- kiva/agg/agg-24/src/agg_trans_affine.cpp | 105 +- .../agg-24/src/agg_trans_warp_magnifier.cpp | 28 +- kiva/agg/src/kiva_graphics_context.h | 20 +- kiva/agg/src/kiva_graphics_context_base.cpp | 4 +- kiva/agg/src/kiva_graphics_context_base.h | 2 +- kiva/agg/tests/affine_matrix_test_case.py | 2 +- kiva/agg/tests/join_stroke_path_test_case.py | 6 +- kiva/agg/tests/stroke_path_test_case.py | 6 +- kiva/tests/agg/image_test_case.py | 1 - kiva/tests/test_graphics_context.py | 2 - setup.py | 1 + 86 files changed, 10986 insertions(+), 3688 deletions(-) create mode 100644 kiva/agg/agg-24/include/agg_blur.h create mode 100644 kiva/agg/agg-24/include/agg_conv_gpc.h create mode 100644 kiva/agg/agg-24/include/agg_font_cache_manager2.h create mode 100644 kiva/agg/agg-24/include/agg_gradient_lut.h create mode 100644 kiva/agg/agg-24/include/agg_pixfmt_base.h create mode 100644 kiva/agg/agg-24/include/agg_pixfmt_transposer.h create mode 100644 kiva/agg/agg-24/include/agg_rasterizer_scanline_aa_nogamma.h create mode 100644 kiva/agg/agg-24/include/agg_span_gradient_contour.h create mode 100644 kiva/agg/agg-24/include/agg_span_gradient_image.h delete mode 100644 kiva/agg/agg-24/include/agg_trans_lens.h diff --git a/enable/tests/primitives/test_image.py b/enable/tests/primitives/test_image.py index 61af7bf35..4617ce7ba 100644 --- a/enable/tests/primitives/test_image.py +++ b/enable/tests/primitives/test_image.py @@ -113,7 +113,6 @@ def test_image_gc_32(self): image_gc = self.image_32._image assert_array_equal(image_gc.bmp_array, self.data) - @unittest.skipIf(six.PY3, reason="Crashes on python 3. See GH #95.") def test_draw_24(self): gc = GraphicsContext((256, 128), pix_format='rgb24') self.image_24.draw(gc) @@ -127,8 +126,6 @@ def test_draw_24(self): self.image_24.draw(gc2) assert_array_equal(gc2.bmp_array[..., :3], self.data[..., :3]) - - @unittest.skipIf(six.PY3, reason="Crashes on python 3. See GH #95.") def test_draw_32(self): gc = GraphicsContext((256, 128), pix_format='rgba32') self.image_32.draw(gc) @@ -140,7 +137,6 @@ def test_draw_32(self): white_image = np.ones(shape=(256, 128, 4), dtype='uint8')*255 self.assertFalse(np.array_equal(white_image, gc.bmp_array)) - @unittest.skipIf(six.PY3, reason="Crashes on python 3. See GH #95.") def test_draw_stretched(self): gc = GraphicsContext((256, 256), pix_format='rgba32') self.image_32.bounds = [128, 258] diff --git a/kiva/agg/agg-24/include/agg_alpha_mask_u8.h b/kiva/agg/agg-24/include/agg_alpha_mask_u8.h index 31c332986..97e5ab01a 100644 --- a/kiva/agg/agg-24/include/agg_alpha_mask_u8.h +++ b/kiva/agg/agg-24/include/agg_alpha_mask_u8.h @@ -57,7 +57,7 @@ namespace agg24 }; alpha_mask_u8() : m_rbuf(0) {} - alpha_mask_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} + explicit alpha_mask_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; } @@ -70,7 +70,7 @@ namespace agg24 { if(x >= 0 && y >= 0 && x < (int)m_rbuf->width() && - y <= (int)m_rbuf->height()) + y < (int)m_rbuf->height()) { return (cover_type)m_mask_function.calculate( m_rbuf->row_ptr(y) + x * Step + Offset); @@ -83,7 +83,7 @@ namespace agg24 { if(x >= 0 && y >= 0 && x < (int)m_rbuf->width() && - y <= (int)m_rbuf->height()) + y < (int)m_rbuf->height()) { return (cover_type)((cover_full + val * m_mask_function.calculate( @@ -361,7 +361,7 @@ namespace agg24 }; amask_no_clip_u8() : m_rbuf(0) {} - amask_no_clip_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} + explicit amask_no_clip_u8(rendering_buffer& rbuf) : m_rbuf(&rbuf) {} void attach(rendering_buffer& rbuf) { m_rbuf = &rbuf; } diff --git a/kiva/agg/agg-24/include/agg_array.h b/kiva/agg/agg-24/include/agg_array.h index 5d91d8b35..cf31e2d7c 100644 --- a/kiva/agg/agg-24/include/agg_array.h +++ b/kiva/agg/agg-24/include/agg_array.h @@ -1044,7 +1044,6 @@ namespace agg24 return j; } - //--------------------------------------------------------invert_container template void invert_container(Array& arr) { @@ -1056,7 +1055,6 @@ namespace agg24 } } - //------------------------------------------------------binary_search_pos template unsigned binary_search_pos(const Array& arr, const Value& val, Less less) @@ -1082,6 +1080,40 @@ namespace agg24 return end; } + //----------------------------------------------------------range_adaptor + template class range_adaptor + { + public: + typedef typename Array::value_type value_type; + + range_adaptor(Array& array, unsigned start, unsigned size) : + m_array(array), m_start(start), m_size(size) + {} + + unsigned size() const { return m_size; } + const value_type& operator [] (unsigned i) const { return m_array[m_start + i]; } + value_type& operator [] (unsigned i) { return m_array[m_start + i]; } + const value_type& at(unsigned i) const { return m_array[m_start + i]; } + value_type& at(unsigned i) { return m_array[m_start + i]; } + value_type value_at(unsigned i) const { return m_array[m_start + i]; } + + private: + Array& m_array; + unsigned m_start; + unsigned m_size; + }; + + //---------------------------------------------------------------int_less + inline bool int_less(int a, int b) { return a < b; } + + //------------------------------------------------------------int_greater + inline bool int_greater(int a, int b) { return a > b; } + + //----------------------------------------------------------unsigned_less + inline bool unsigned_less(unsigned a, unsigned b) { return a < b; } + + //-------------------------------------------------------unsigned_greater + inline bool unsigned_greater(unsigned a, unsigned b) { return a > b; } } #endif diff --git a/kiva/agg/agg-24/include/agg_basics.h b/kiva/agg/agg-24/include/agg_basics.h index 183e4dc15..e536ea2c0 100644 --- a/kiva/agg/agg-24/include/agg_basics.h +++ b/kiva/agg/agg-24/include/agg_basics.h @@ -19,6 +19,7 @@ #include #include "agg_config.h" +//---------------------------------------------------------AGG_CUSTOM_ALLOCATOR #ifdef AGG_CUSTOM_ALLOCATOR #include "agg_allocator.h" #else @@ -129,21 +130,31 @@ namespace agg24 #pragma warning(disable : 4035) //Disable warning "no return value" AGG_INLINE int iround(double v) //-------iround { + int t; __asm fld qword ptr [v] - __asm fistp dword ptr [ebp-8] - __asm mov eax, dword ptr [ebp-8] + __asm fistp dword ptr [t] + __asm mov eax, dword ptr [t] } AGG_INLINE unsigned uround(double v) //-------uround { + unsigned t; __asm fld qword ptr [v] - __asm fistp dword ptr [ebp-8] - __asm mov eax, dword ptr [ebp-8] + __asm fistp dword ptr [t] + __asm mov eax, dword ptr [t] } #pragma warning(pop) + AGG_INLINE int ifloor(double v) + { + return int(floor(v)); + } AGG_INLINE unsigned ufloor(double v) //-------ufloor { return unsigned(floor(v)); } + AGG_INLINE int iceil(double v) + { + return int(ceil(v)); + } AGG_INLINE unsigned uceil(double v) //--------uceil { return unsigned(ceil(v)); @@ -157,10 +168,18 @@ namespace agg24 { 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)); @@ -174,10 +193,19 @@ namespace agg24 { 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)); @@ -226,7 +254,7 @@ namespace agg24 { poly_subpixel_shift = 8, //----poly_subpixel_shift poly_subpixel_scale = 1< struct rect_base { + typedef T value_type; typedef rect_base self_type; - T x1; - T y1; - T x2; - T y2; + T x1, y1, x2, y2; rect_base() {} rect_base(T x1_, T y1_, T x2_, T y2_) : x1(x1_), y1(y1_), x2(x2_), y2(y2_) {} + void init(T x1_, T y1_, T x2_, T y2_) + { + x1 = x1_; y1 = y1_; x2 = x2_; y2 = y2_; + } + const self_type& normalize() { T t; @@ -285,6 +316,17 @@ namespace agg24 { return x1 <= x2 && y1 <= y2; } + + bool hit_test(T x, T y) const + { + return (x >= x1 && x <= x2 && y >= y1 && y <= y2); + } + + bool overlaps(const self_type& r) const + { + return !(r.x1 > x2 || r.x2 < x1 + || r.y1 > y2 || r.y2 < y1); + } }; //-----------------------------------------------------intersect_rectangles @@ -487,6 +529,30 @@ namespace agg24 typedef vertex_base vertex_f; //-----vertex_f typedef vertex_base vertex_d; //-----vertex_d + //----------------------------------------------------------------row_info + template struct row_info + { + int x1, x2; + T* ptr; + row_info() {} + row_info(int x1_, int x2_, T* ptr_) : x1(x1_), x2(x2_), ptr(ptr_) {} + }; + + //----------------------------------------------------------const_row_info + template struct const_row_info + { + int x1, x2; + const T* ptr; + const_row_info() {} + const_row_info(int x1_, int x2_, const T* ptr_) : + x1(x1_), x2(x2_), ptr(ptr_) {} + }; + + //------------------------------------------------------------is_equal_eps + template inline bool is_equal_eps(T v1, T v2, T epsilon) + { + return fabs(v1 - v2) <= double(epsilon); + } } diff --git a/kiva/agg/agg-24/include/agg_blur.h b/kiva/agg/agg-24/include/agg_blur.h new file mode 100644 index 000000000..3b84e00c7 --- /dev/null +++ b/kiva/agg/agg-24/include/agg_blur.h @@ -0,0 +1,1503 @@ +//---------------------------------------------------------------------------- +// 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 +//---------------------------------------------------------------------------- +// +// The Stack Blur Algorithm was invented by Mario Klingemann, +// mario@quasimondo.com and described here: +// http://incubator.quasimondo.com/processing/fast_blur_deluxe.php +// (search phrase "Stackblur: Fast But Goodlooking"). +// The major improvement is that there's no more division table +// that was very expensive to create for large blur radii. Insted, +// for 8-bit per channel and radius not exceeding 254 the division is +// replaced by multiplication and shift. +// +//---------------------------------------------------------------------------- + +#ifndef AGG_BLUR_INCLUDED +#define AGG_BLUR_INCLUDED + +#include "agg_array.h" +#include "agg_pixfmt_base.h" +#include "agg_pixfmt_transposer.h" + +namespace agg24 +{ + + template struct stack_blur_tables + { + static int16u const g_stack_blur8_mul[255]; + static int8u const g_stack_blur8_shr[255]; + }; + + //------------------------------------------------------------------------ + template + int16u const stack_blur_tables::g_stack_blur8_mul[255] = + { + 512,512,456,512,328,456,335,512,405,328,271,456,388,335,292,512, + 454,405,364,328,298,271,496,456,420,388,360,335,312,292,273,512, + 482,454,428,405,383,364,345,328,312,298,284,271,259,496,475,456, + 437,420,404,388,374,360,347,335,323,312,302,292,282,273,265,512, + 497,482,468,454,441,428,417,405,394,383,373,364,354,345,337,328, + 320,312,305,298,291,284,278,271,265,259,507,496,485,475,465,456, + 446,437,428,420,412,404,396,388,381,374,367,360,354,347,341,335, + 329,323,318,312,307,302,297,292,287,282,278,273,269,265,261,512, + 505,497,489,482,475,468,461,454,447,441,435,428,422,417,411,405, + 399,394,389,383,378,373,368,364,359,354,350,345,341,337,332,328, + 324,320,316,312,309,305,301,298,294,291,287,284,281,278,274,271, + 268,265,262,259,257,507,501,496,491,485,480,475,470,465,460,456, + 451,446,442,437,433,428,424,420,416,412,408,404,400,396,392,388, + 385,381,377,374,370,367,363,360,357,354,350,347,344,341,338,335, + 332,329,326,323,320,318,315,312,310,307,304,302,299,297,294,292, + 289,287,285,282,280,278,275,273,271,269,267,265,263,261,259 + }; + + //------------------------------------------------------------------------ + template + int8u const stack_blur_tables::g_stack_blur8_shr[255] = + { + 9, 11, 12, 13, 13, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 17, + 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, + 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 20, 20, 20, + 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, + 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 + }; + + + + //==============================================================stack_blur + template class stack_blur + { + public: + typedef ColorT color_type; + typedef CalculatorT calculator_type; + + //-------------------------------------------------------------------- + template void blur_x(Img& img, unsigned radius) + { + if(radius < 1) return; + + unsigned x, y, xp, i; + unsigned stack_ptr; + unsigned stack_start; + + color_type pix; + color_type* stack_pix; + calculator_type sum; + calculator_type sum_in; + calculator_type sum_out; + + unsigned w = img.width(); + unsigned h = img.height(); + unsigned wm = w - 1; + unsigned div = radius * 2 + 1; + + unsigned div_sum = (radius + 1) * (radius + 1); + unsigned mul_sum = 0; + unsigned shr_sum = 0; + unsigned max_val = color_type::base_mask; + + if(max_val <= 255 && radius < 255) + { + mul_sum = stack_blur_tables::g_stack_blur8_mul[radius]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[radius]; + } + + m_buf.allocate(w, 128); + m_stack.allocate(div, 32); + + for(y = 0; y < h; y++) + { + sum.clear(); + sum_in.clear(); + sum_out.clear(); + + pix = img.pixel(0, y); + for(i = 0; i <= radius; i++) + { + m_stack[i] = pix; + sum.add(pix, i + 1); + sum_out.add(pix); + } + for(i = 1; i <= radius; i++) + { + pix = img.pixel((i > wm) ? wm : i, y); + m_stack[i + radius] = pix; + sum.add(pix, radius + 1 - i); + sum_in.add(pix); + } + + stack_ptr = radius; + for(x = 0; x < w; x++) + { + if(mul_sum) sum.calc_pix(m_buf[x], mul_sum, shr_sum); + else sum.calc_pix(m_buf[x], div_sum); + + sum.sub(sum_out); + + stack_start = stack_ptr + div - radius; + if(stack_start >= div) stack_start -= div; + stack_pix = &m_stack[stack_start]; + + sum_out.sub(*stack_pix); + + xp = x + radius + 1; + if(xp > wm) xp = wm; + pix = img.pixel(xp, y); + + *stack_pix = pix; + + sum_in.add(pix); + sum.add(sum_in); + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix = &m_stack[stack_ptr]; + + sum_out.add(*stack_pix); + sum_in.sub(*stack_pix); + } + img.copy_color_hspan(0, y, w, &m_buf[0]); + } + } + + //-------------------------------------------------------------------- + template void blur_y(Img& img, unsigned radius) + { + pixfmt_transposer img2(img); + blur_x(img2, radius); + } + + //-------------------------------------------------------------------- + template void blur(Img& img, unsigned radius) + { + blur_x(img, radius); + pixfmt_transposer img2(img); + blur_x(img2, radius); + } + + private: + pod_vector m_buf; + pod_vector m_stack; + }; + + //====================================================stack_blur_calc_rgba + template struct stack_blur_calc_rgba + { + typedef T value_type; + value_type r,g,b,a; + + AGG_INLINE void clear() + { + r = g = b = a = 0; + } + + template AGG_INLINE void add(const ArgT& v) + { + r += v.r; + g += v.g; + b += v.b; + a += v.a; + } + + template AGG_INLINE void add(const ArgT& v, unsigned k) + { + r += v.r * k; + g += v.g * k; + b += v.b * k; + a += v.a * k; + } + + template AGG_INLINE void sub(const ArgT& v) + { + r -= v.r; + g -= v.g; + b -= v.b; + a -= v.a; + } + + template AGG_INLINE void calc_pix(ArgT& v, unsigned div) + { + typedef typename ArgT::value_type value_type; + v.r = value_type(r / div); + v.g = value_type(g / div); + v.b = value_type(b / div); + v.a = value_type(a / div); + } + + template + AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) + { + typedef typename ArgT::value_type value_type; + v.r = value_type((r * mul) >> shr); + v.g = value_type((g * mul) >> shr); + v.b = value_type((b * mul) >> shr); + v.a = value_type((a * mul) >> shr); + } + }; + + + //=====================================================stack_blur_calc_rgb + template struct stack_blur_calc_rgb + { + typedef T value_type; + value_type r,g,b; + + AGG_INLINE void clear() + { + r = g = b = 0; + } + + template AGG_INLINE void add(const ArgT& v) + { + r += v.r; + g += v.g; + b += v.b; + } + + template AGG_INLINE void add(const ArgT& v, unsigned k) + { + r += v.r * k; + g += v.g * k; + b += v.b * k; + } + + template AGG_INLINE void sub(const ArgT& v) + { + r -= v.r; + g -= v.g; + b -= v.b; + } + + template AGG_INLINE void calc_pix(ArgT& v, unsigned div) + { + typedef typename ArgT::value_type value_type; + v.r = value_type(r / div); + v.g = value_type(g / div); + v.b = value_type(b / div); + } + + template + AGG_INLINE void calc_pix(ArgT& v, unsigned mul, unsigned shr) + { + typedef typename ArgT::value_type value_type; + v.r = value_type((r * mul) >> shr); + v.g = value_type((g * mul) >> shr); + v.b = value_type((b * mul) >> shr); + } + }; + + + //====================================================stack_blur_calc_gray + template struct stack_blur_calc_gray + { + typedef T value_type; + value_type v; + + AGG_INLINE void clear() + { + v = 0; + } + + template AGG_INLINE void add(const ArgT& a) + { + v += a.v; + } + + template AGG_INLINE void add(const ArgT& a, unsigned k) + { + v += a.v * k; + } + + template AGG_INLINE void sub(const ArgT& a) + { + v -= a.v; + } + + template AGG_INLINE void calc_pix(ArgT& a, unsigned div) + { + typedef typename ArgT::value_type value_type; + a.v = value_type(v / div); + } + + template + AGG_INLINE void calc_pix(ArgT& a, unsigned mul, unsigned shr) + { + typedef typename ArgT::value_type value_type; + a.v = value_type((v * mul) >> shr); + } + }; + + + + //========================================================stack_blur_gray8 + template + void stack_blur_gray8(Img& img, unsigned rx, unsigned ry) + { + unsigned x, y, xp, yp, i; + unsigned stack_ptr; + unsigned stack_start; + + const int8u* src_pix_ptr; + int8u* dst_pix_ptr; + unsigned pix; + unsigned stack_pix; + unsigned sum; + unsigned sum_in; + unsigned sum_out; + + unsigned w = img.width(); + unsigned h = img.height(); + unsigned wm = w - 1; + unsigned hm = h - 1; + + unsigned div; + unsigned mul_sum; + unsigned shr_sum; + + pod_vector stack; + + if(rx > 0) + { + if(rx > 254) rx = 254; + div = rx * 2 + 1; + mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; + stack.allocate(div); + + for(y = 0; y < h; y++) + { + sum = sum_in = sum_out = 0; + + src_pix_ptr = img.pix_ptr(0, y); + pix = *src_pix_ptr; + for(i = 0; i <= rx; i++) + { + stack[i] = pix; + sum += pix * (i + 1); + sum_out += pix; + } + for(i = 1; i <= rx; i++) + { + if(i <= wm) src_pix_ptr += Img::pix_width; + pix = *src_pix_ptr; + stack[i + rx] = pix; + sum += pix * (rx + 1 - i); + sum_in += pix; + } + + stack_ptr = rx; + xp = rx; + if(xp > wm) xp = wm; + src_pix_ptr = img.pix_ptr(xp, y); + dst_pix_ptr = img.pix_ptr(0, y); + for(x = 0; x < w; x++) + { + *dst_pix_ptr = (sum * mul_sum) >> shr_sum; + dst_pix_ptr += Img::pix_width; + + sum -= sum_out; + + stack_start = stack_ptr + div - rx; + if(stack_start >= div) stack_start -= div; + sum_out -= stack[stack_start]; + + if(xp < wm) + { + src_pix_ptr += Img::pix_width; + pix = *src_pix_ptr; + ++xp; + } + + stack[stack_start] = pix; + + sum_in += pix; + sum += sum_in; + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix = stack[stack_ptr]; + + sum_out += stack_pix; + sum_in -= stack_pix; + } + } + } + + if(ry > 0) + { + if(ry > 254) ry = 254; + div = ry * 2 + 1; + mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; + stack.allocate(div); + + int stride = img.stride(); + for(x = 0; x < w; x++) + { + sum = sum_in = sum_out = 0; + + src_pix_ptr = img.pix_ptr(x, 0); + pix = *src_pix_ptr; + for(i = 0; i <= ry; i++) + { + stack[i] = pix; + sum += pix * (i + 1); + sum_out += pix; + } + for(i = 1; i <= ry; i++) + { + if(i <= hm) src_pix_ptr += stride; + pix = *src_pix_ptr; + stack[i + ry] = pix; + sum += pix * (ry + 1 - i); + sum_in += pix; + } + + stack_ptr = ry; + yp = ry; + if(yp > hm) yp = hm; + src_pix_ptr = img.pix_ptr(x, yp); + dst_pix_ptr = img.pix_ptr(x, 0); + for(y = 0; y < h; y++) + { + *dst_pix_ptr = (sum * mul_sum) >> shr_sum; + dst_pix_ptr += stride; + + sum -= sum_out; + + stack_start = stack_ptr + div - ry; + if(stack_start >= div) stack_start -= div; + sum_out -= stack[stack_start]; + + if(yp < hm) + { + src_pix_ptr += stride; + pix = *src_pix_ptr; + ++yp; + } + + stack[stack_start] = pix; + + sum_in += pix; + sum += sum_in; + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix = stack[stack_ptr]; + + sum_out += stack_pix; + sum_in -= stack_pix; + } + } + } + } + + + + //========================================================stack_blur_rgb24 + template + void stack_blur_rgb24(Img& img, unsigned rx, unsigned ry) + { + typedef typename Img::color_type color_type; + typedef typename Img::order_type order_type; + enum order_e + { + R = order_type::R, + G = order_type::G, + B = order_type::B + }; + + unsigned x, y, xp, yp, i; + unsigned stack_ptr; + unsigned stack_start; + + const int8u* src_pix_ptr; + int8u* dst_pix_ptr; + color_type* stack_pix_ptr; + + unsigned sum_r; + unsigned sum_g; + unsigned sum_b; + unsigned sum_in_r; + unsigned sum_in_g; + unsigned sum_in_b; + unsigned sum_out_r; + unsigned sum_out_g; + unsigned sum_out_b; + + unsigned w = img.width(); + unsigned h = img.height(); + unsigned wm = w - 1; + unsigned hm = h - 1; + + unsigned div; + unsigned mul_sum; + unsigned shr_sum; + + pod_vector stack; + + if(rx > 0) + { + if(rx > 254) rx = 254; + div = rx * 2 + 1; + mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; + stack.allocate(div); + + for(y = 0; y < h; y++) + { + sum_r = + sum_g = + sum_b = + sum_in_r = + sum_in_g = + sum_in_b = + sum_out_r = + sum_out_g = + sum_out_b = 0; + + src_pix_ptr = img.pix_ptr(0, y); + for(i = 0; i <= rx; i++) + { + stack_pix_ptr = &stack[i]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + sum_r += src_pix_ptr[R] * (i + 1); + sum_g += src_pix_ptr[G] * (i + 1); + sum_b += src_pix_ptr[B] * (i + 1); + sum_out_r += src_pix_ptr[R]; + sum_out_g += src_pix_ptr[G]; + sum_out_b += src_pix_ptr[B]; + } + for(i = 1; i <= rx; i++) + { + if(i <= wm) src_pix_ptr += Img::pix_width; + stack_pix_ptr = &stack[i + rx]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + sum_r += src_pix_ptr[R] * (rx + 1 - i); + sum_g += src_pix_ptr[G] * (rx + 1 - i); + sum_b += src_pix_ptr[B] * (rx + 1 - i); + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + } + + stack_ptr = rx; + xp = rx; + if(xp > wm) xp = wm; + src_pix_ptr = img.pix_ptr(xp, y); + dst_pix_ptr = img.pix_ptr(0, y); + for(x = 0; x < w; x++) + { + dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; + dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; + dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; + dst_pix_ptr += Img::pix_width; + + sum_r -= sum_out_r; + sum_g -= sum_out_g; + sum_b -= sum_out_b; + + stack_start = stack_ptr + div - rx; + if(stack_start >= div) stack_start -= div; + stack_pix_ptr = &stack[stack_start]; + + sum_out_r -= stack_pix_ptr->r; + sum_out_g -= stack_pix_ptr->g; + sum_out_b -= stack_pix_ptr->b; + + if(xp < wm) + { + src_pix_ptr += Img::pix_width; + ++xp; + } + + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + sum_r += sum_in_r; + sum_g += sum_in_g; + sum_b += sum_in_b; + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix_ptr = &stack[stack_ptr]; + + sum_out_r += stack_pix_ptr->r; + sum_out_g += stack_pix_ptr->g; + sum_out_b += stack_pix_ptr->b; + sum_in_r -= stack_pix_ptr->r; + sum_in_g -= stack_pix_ptr->g; + sum_in_b -= stack_pix_ptr->b; + } + } + } + + if(ry > 0) + { + if(ry > 254) ry = 254; + div = ry * 2 + 1; + mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; + stack.allocate(div); + + int stride = img.stride(); + for(x = 0; x < w; x++) + { + sum_r = + sum_g = + sum_b = + sum_in_r = + sum_in_g = + sum_in_b = + sum_out_r = + sum_out_g = + sum_out_b = 0; + + src_pix_ptr = img.pix_ptr(x, 0); + for(i = 0; i <= ry; i++) + { + stack_pix_ptr = &stack[i]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + sum_r += src_pix_ptr[R] * (i + 1); + sum_g += src_pix_ptr[G] * (i + 1); + sum_b += src_pix_ptr[B] * (i + 1); + sum_out_r += src_pix_ptr[R]; + sum_out_g += src_pix_ptr[G]; + sum_out_b += src_pix_ptr[B]; + } + for(i = 1; i <= ry; i++) + { + if(i <= hm) src_pix_ptr += stride; + stack_pix_ptr = &stack[i + ry]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + sum_r += src_pix_ptr[R] * (ry + 1 - i); + sum_g += src_pix_ptr[G] * (ry + 1 - i); + sum_b += src_pix_ptr[B] * (ry + 1 - i); + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + } + + stack_ptr = ry; + yp = ry; + if(yp > hm) yp = hm; + src_pix_ptr = img.pix_ptr(x, yp); + dst_pix_ptr = img.pix_ptr(x, 0); + for(y = 0; y < h; y++) + { + dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; + dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; + dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; + dst_pix_ptr += stride; + + sum_r -= sum_out_r; + sum_g -= sum_out_g; + sum_b -= sum_out_b; + + stack_start = stack_ptr + div - ry; + if(stack_start >= div) stack_start -= div; + + stack_pix_ptr = &stack[stack_start]; + sum_out_r -= stack_pix_ptr->r; + sum_out_g -= stack_pix_ptr->g; + sum_out_b -= stack_pix_ptr->b; + + if(yp < hm) + { + src_pix_ptr += stride; + ++yp; + } + + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + sum_r += sum_in_r; + sum_g += sum_in_g; + sum_b += sum_in_b; + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix_ptr = &stack[stack_ptr]; + + sum_out_r += stack_pix_ptr->r; + sum_out_g += stack_pix_ptr->g; + sum_out_b += stack_pix_ptr->b; + sum_in_r -= stack_pix_ptr->r; + sum_in_g -= stack_pix_ptr->g; + sum_in_b -= stack_pix_ptr->b; + } + } + } + } + + + + //=======================================================stack_blur_rgba32 + template + void stack_blur_rgba32(Img& img, unsigned rx, unsigned ry) + { + typedef typename Img::color_type color_type; + typedef typename Img::order_type order_type; + enum order_e + { + R = order_type::R, + G = order_type::G, + B = order_type::B, + A = order_type::A + }; + + unsigned x, y, xp, yp, i; + unsigned stack_ptr; + unsigned stack_start; + + const int8u* src_pix_ptr; + int8u* dst_pix_ptr; + color_type* stack_pix_ptr; + + unsigned sum_r; + unsigned sum_g; + unsigned sum_b; + unsigned sum_a; + unsigned sum_in_r; + unsigned sum_in_g; + unsigned sum_in_b; + unsigned sum_in_a; + unsigned sum_out_r; + unsigned sum_out_g; + unsigned sum_out_b; + unsigned sum_out_a; + + unsigned w = img.width(); + unsigned h = img.height(); + unsigned wm = w - 1; + unsigned hm = h - 1; + + unsigned div; + unsigned mul_sum; + unsigned shr_sum; + + pod_vector stack; + + if(rx > 0) + { + if(rx > 254) rx = 254; + div = rx * 2 + 1; + mul_sum = stack_blur_tables::g_stack_blur8_mul[rx]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[rx]; + stack.allocate(div); + + for(y = 0; y < h; y++) + { + sum_r = + sum_g = + sum_b = + sum_a = + sum_in_r = + sum_in_g = + sum_in_b = + sum_in_a = + sum_out_r = + sum_out_g = + sum_out_b = + sum_out_a = 0; + + src_pix_ptr = img.pix_ptr(0, y); + for(i = 0; i <= rx; i++) + { + stack_pix_ptr = &stack[i]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + stack_pix_ptr->a = src_pix_ptr[A]; + sum_r += src_pix_ptr[R] * (i + 1); + sum_g += src_pix_ptr[G] * (i + 1); + sum_b += src_pix_ptr[B] * (i + 1); + sum_a += src_pix_ptr[A] * (i + 1); + sum_out_r += src_pix_ptr[R]; + sum_out_g += src_pix_ptr[G]; + sum_out_b += src_pix_ptr[B]; + sum_out_a += src_pix_ptr[A]; + } + for(i = 1; i <= rx; i++) + { + if(i <= wm) src_pix_ptr += Img::pix_width; + stack_pix_ptr = &stack[i + rx]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + stack_pix_ptr->a = src_pix_ptr[A]; + sum_r += src_pix_ptr[R] * (rx + 1 - i); + sum_g += src_pix_ptr[G] * (rx + 1 - i); + sum_b += src_pix_ptr[B] * (rx + 1 - i); + sum_a += src_pix_ptr[A] * (rx + 1 - i); + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + sum_in_a += src_pix_ptr[A]; + } + + stack_ptr = rx; + xp = rx; + if(xp > wm) xp = wm; + src_pix_ptr = img.pix_ptr(xp, y); + dst_pix_ptr = img.pix_ptr(0, y); + for(x = 0; x < w; x++) + { + dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; + dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; + dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; + dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; + dst_pix_ptr += Img::pix_width; + + sum_r -= sum_out_r; + sum_g -= sum_out_g; + sum_b -= sum_out_b; + sum_a -= sum_out_a; + + stack_start = stack_ptr + div - rx; + if(stack_start >= div) stack_start -= div; + stack_pix_ptr = &stack[stack_start]; + + sum_out_r -= stack_pix_ptr->r; + sum_out_g -= stack_pix_ptr->g; + sum_out_b -= stack_pix_ptr->b; + sum_out_a -= stack_pix_ptr->a; + + if(xp < wm) + { + src_pix_ptr += Img::pix_width; + ++xp; + } + + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + stack_pix_ptr->a = src_pix_ptr[A]; + + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + sum_in_a += src_pix_ptr[A]; + sum_r += sum_in_r; + sum_g += sum_in_g; + sum_b += sum_in_b; + sum_a += sum_in_a; + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix_ptr = &stack[stack_ptr]; + + sum_out_r += stack_pix_ptr->r; + sum_out_g += stack_pix_ptr->g; + sum_out_b += stack_pix_ptr->b; + sum_out_a += stack_pix_ptr->a; + sum_in_r -= stack_pix_ptr->r; + sum_in_g -= stack_pix_ptr->g; + sum_in_b -= stack_pix_ptr->b; + sum_in_a -= stack_pix_ptr->a; + } + } + } + + if(ry > 0) + { + if(ry > 254) ry = 254; + div = ry * 2 + 1; + mul_sum = stack_blur_tables::g_stack_blur8_mul[ry]; + shr_sum = stack_blur_tables::g_stack_blur8_shr[ry]; + stack.allocate(div); + + int stride = img.stride(); + for(x = 0; x < w; x++) + { + sum_r = + sum_g = + sum_b = + sum_a = + sum_in_r = + sum_in_g = + sum_in_b = + sum_in_a = + sum_out_r = + sum_out_g = + sum_out_b = + sum_out_a = 0; + + src_pix_ptr = img.pix_ptr(x, 0); + for(i = 0; i <= ry; i++) + { + stack_pix_ptr = &stack[i]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + stack_pix_ptr->a = src_pix_ptr[A]; + sum_r += src_pix_ptr[R] * (i + 1); + sum_g += src_pix_ptr[G] * (i + 1); + sum_b += src_pix_ptr[B] * (i + 1); + sum_a += src_pix_ptr[A] * (i + 1); + sum_out_r += src_pix_ptr[R]; + sum_out_g += src_pix_ptr[G]; + sum_out_b += src_pix_ptr[B]; + sum_out_a += src_pix_ptr[A]; + } + for(i = 1; i <= ry; i++) + { + if(i <= hm) src_pix_ptr += stride; + stack_pix_ptr = &stack[i + ry]; + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + stack_pix_ptr->a = src_pix_ptr[A]; + sum_r += src_pix_ptr[R] * (ry + 1 - i); + sum_g += src_pix_ptr[G] * (ry + 1 - i); + sum_b += src_pix_ptr[B] * (ry + 1 - i); + sum_a += src_pix_ptr[A] * (ry + 1 - i); + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + sum_in_a += src_pix_ptr[A]; + } + + stack_ptr = ry; + yp = ry; + if(yp > hm) yp = hm; + src_pix_ptr = img.pix_ptr(x, yp); + dst_pix_ptr = img.pix_ptr(x, 0); + for(y = 0; y < h; y++) + { + dst_pix_ptr[R] = (sum_r * mul_sum) >> shr_sum; + dst_pix_ptr[G] = (sum_g * mul_sum) >> shr_sum; + dst_pix_ptr[B] = (sum_b * mul_sum) >> shr_sum; + dst_pix_ptr[A] = (sum_a * mul_sum) >> shr_sum; + dst_pix_ptr += stride; + + sum_r -= sum_out_r; + sum_g -= sum_out_g; + sum_b -= sum_out_b; + sum_a -= sum_out_a; + + stack_start = stack_ptr + div - ry; + if(stack_start >= div) stack_start -= div; + + stack_pix_ptr = &stack[stack_start]; + sum_out_r -= stack_pix_ptr->r; + sum_out_g -= stack_pix_ptr->g; + sum_out_b -= stack_pix_ptr->b; + sum_out_a -= stack_pix_ptr->a; + + if(yp < hm) + { + src_pix_ptr += stride; + ++yp; + } + + stack_pix_ptr->r = src_pix_ptr[R]; + stack_pix_ptr->g = src_pix_ptr[G]; + stack_pix_ptr->b = src_pix_ptr[B]; + stack_pix_ptr->a = src_pix_ptr[A]; + + sum_in_r += src_pix_ptr[R]; + sum_in_g += src_pix_ptr[G]; + sum_in_b += src_pix_ptr[B]; + sum_in_a += src_pix_ptr[A]; + sum_r += sum_in_r; + sum_g += sum_in_g; + sum_b += sum_in_b; + sum_a += sum_in_a; + + ++stack_ptr; + if(stack_ptr >= div) stack_ptr = 0; + stack_pix_ptr = &stack[stack_ptr]; + + sum_out_r += stack_pix_ptr->r; + sum_out_g += stack_pix_ptr->g; + sum_out_b += stack_pix_ptr->b; + sum_out_a += stack_pix_ptr->a; + sum_in_r -= stack_pix_ptr->r; + sum_in_g -= stack_pix_ptr->g; + sum_in_b -= stack_pix_ptr->b; + sum_in_a -= stack_pix_ptr->a; + } + } + } + } + + + + //===========================================================recursive_blur + template class recursive_blur + { + public: + typedef ColorT color_type; + typedef CalculatorT calculator_type; + typedef typename color_type::value_type value_type; + typedef typename calculator_type::value_type calc_type; + + //-------------------------------------------------------------------- + template void blur_x(Img& img, double radius) + { + if(radius < 0.62) return; + if(img.width() < 3) return; + + calc_type s = calc_type(radius * 0.5); + calc_type q = calc_type((s < 2.5) ? + 3.97156 - 4.14554 * sqrt(1 - 0.26891 * s) : + 0.98711 * s - 0.96330); + + calc_type q2 = calc_type(q * q); + calc_type q3 = calc_type(q2 * q); + + calc_type b0 = calc_type(1.0 / (1.578250 + + 2.444130 * q + + 1.428100 * q2 + + 0.422205 * q3)); + + calc_type b1 = calc_type( 2.44413 * q + + 2.85619 * q2 + + 1.26661 * q3); + + calc_type b2 = calc_type(-1.42810 * q2 + + -1.26661 * q3); + + calc_type b3 = calc_type(0.422205 * q3); + + calc_type b = calc_type(1 - (b1 + b2 + b3) * b0); + + b1 *= b0; + b2 *= b0; + b3 *= b0; + + int w = img.width(); + int h = img.height(); + int wm = w-1; + int x, y; + + m_sum1.allocate(w); + m_sum2.allocate(w); + m_buf.allocate(w); + + for(y = 0; y < h; y++) + { + calculator_type c; + c.from_pix(img.pixel(0, y)); + m_sum1[0].calc(b, b1, b2, b3, c, c, c, c); + c.from_pix(img.pixel(1, y)); + m_sum1[1].calc(b, b1, b2, b3, c, m_sum1[0], m_sum1[0], m_sum1[0]); + c.from_pix(img.pixel(2, y)); + m_sum1[2].calc(b, b1, b2, b3, c, m_sum1[1], m_sum1[0], m_sum1[0]); + + for(x = 3; x < w; ++x) + { + c.from_pix(img.pixel(x, y)); + m_sum1[x].calc(b, b1, b2, b3, c, m_sum1[x-1], m_sum1[x-2], m_sum1[x-3]); + } + + m_sum2[wm ].calc(b, b1, b2, b3, m_sum1[wm ], m_sum1[wm ], m_sum1[wm], m_sum1[wm]); + m_sum2[wm-1].calc(b, b1, b2, b3, m_sum1[wm-1], m_sum2[wm ], m_sum2[wm], m_sum2[wm]); + m_sum2[wm-2].calc(b, b1, b2, b3, m_sum1[wm-2], m_sum2[wm-1], m_sum2[wm], m_sum2[wm]); + m_sum2[wm ].to_pix(m_buf[wm ]); + m_sum2[wm-1].to_pix(m_buf[wm-1]); + m_sum2[wm-2].to_pix(m_buf[wm-2]); + + for(x = wm-3; x >= 0; --x) + { + m_sum2[x].calc(b, b1, b2, b3, m_sum1[x], m_sum2[x+1], m_sum2[x+2], m_sum2[x+3]); + m_sum2[x].to_pix(m_buf[x]); + } + img.copy_color_hspan(0, y, w, &m_buf[0]); + } + } + + //-------------------------------------------------------------------- + template void blur_y(Img& img, double radius) + { + pixfmt_transposer img2(img); + blur_x(img2, radius); + } + + //-------------------------------------------------------------------- + template void blur(Img& img, double radius) + { + blur_x(img, radius); + pixfmt_transposer img2(img); + blur_x(img2, radius); + } + + private: + agg24::pod_vector m_sum1; + agg24::pod_vector m_sum2; + agg24::pod_vector m_buf; + }; + + + //=================================================recursive_blur_calc_rgba + template struct recursive_blur_calc_rgba + { + typedef T value_type; + typedef recursive_blur_calc_rgba self_type; + + value_type r,g,b,a; + + template + AGG_INLINE void from_pix(const ColorT& c) + { + r = c.r; + g = c.g; + b = c.b; + a = c.a; + } + + AGG_INLINE void calc(value_type b1, + value_type b2, + value_type b3, + value_type b4, + const self_type& c1, + const self_type& c2, + const self_type& c3, + const self_type& c4) + { + r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; + g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; + b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; + a = b1*c1.a + b2*c2.a + b3*c3.a + b4*c4.a; + } + + template + AGG_INLINE void to_pix(ColorT& c) const + { + typedef typename ColorT::value_type cv_type; + c.r = cv_type(r); + c.g = cv_type(g); + c.b = cv_type(b); + c.a = cv_type(a); + } + }; + + + //=================================================recursive_blur_calc_rgb + template struct recursive_blur_calc_rgb + { + typedef T value_type; + typedef recursive_blur_calc_rgb self_type; + + value_type r,g,b; + + template + AGG_INLINE void from_pix(const ColorT& c) + { + r = c.r; + g = c.g; + b = c.b; + } + + AGG_INLINE void calc(value_type b1, + value_type b2, + value_type b3, + value_type b4, + const self_type& c1, + const self_type& c2, + const self_type& c3, + const self_type& c4) + { + r = b1*c1.r + b2*c2.r + b3*c3.r + b4*c4.r; + g = b1*c1.g + b2*c2.g + b3*c3.g + b4*c4.g; + b = b1*c1.b + b2*c2.b + b3*c3.b + b4*c4.b; + } + + template + AGG_INLINE void to_pix(ColorT& c) const + { + typedef typename ColorT::value_type cv_type; + c.r = cv_type(r); + c.g = cv_type(g); + c.b = cv_type(b); + } + }; + + + //================================================recursive_blur_calc_gray + template struct recursive_blur_calc_gray + { + typedef T value_type; + typedef recursive_blur_calc_gray self_type; + + value_type v; + + template + AGG_INLINE void from_pix(const ColorT& c) + { + v = c.v; + } + + AGG_INLINE void calc(value_type b1, + value_type b2, + value_type b3, + value_type b4, + const self_type& c1, + const self_type& c2, + const self_type& c3, + const self_type& c4) + { + v = b1*c1.v + b2*c2.v + b3*c3.v + b4*c4.v; + } + + template + AGG_INLINE void to_pix(ColorT& c) const + { + typedef typename ColorT::value_type cv_type; + c.v = cv_type(v); + } + }; + + //================================================slight_blur + // Special-purpose filter for applying a Gaussian blur with a radius small enough + // that the blur only affects adjacent pixels. A Gaussian curve with a standard + // deviation of r/2 is used, as per the HTML/CSS spec. At 3 standard deviations, + // the contribution drops to less than 0.005, i.e. less than half a percent, + // therefore the radius can be at least 1.33 before errors become significant. + // This filter is useful for smoothing artifacts caused by detail rendered + // at the pixel scale, e.g. single-pixel lines. Note that the filter should + // only be used with premultiplied pixel formats (or those without alpha). + // See the "line_thickness" example for a demonstration. + template + class slight_blur + { + public: + typedef typename PixFmt::pixel_type pixel_type; + typedef typename PixFmt::value_type value_type; + typedef typename PixFmt::order_type order_type; + + slight_blur(double r = 1.33) + { + radius(r); + } + + void radius(double r) + { + if (r > 0) + { + // Sample the gaussian curve at 0 and r/2 standard deviations. + // At 3 standard deviations, the response is < 0.005. + double pi = 3.14159; + double n = 2 / r; + m_g0 = 1 / sqrt(2 * pi); + m_g1 = m_g0 * exp(-n * n); + + // Normalize. + double sum = m_g0 + 2 * m_g1; + m_g0 /= sum; + m_g1 /= sum; + } + else + { + m_g0 = 1; + m_g1 = 0; + } + } + + void blur(PixFmt& img, rect_i bounds) + { + // Make sure we stay within the image area. + bounds.clip(rect_i(0, 0, img.width() - 1, img.height() - 1)); + + int w = bounds.x2 - bounds.x1 + 1; + int h = bounds.y2 - bounds.y1 + 1; + + if (w < 3 || h < 3) return; + + // Allocate 3 rows of buffer space. + m_buf.allocate(w * 3); + + // Set up row pointers + pixel_type * begin = &m_buf[0]; + pixel_type * r0 = begin; + pixel_type * r1 = r0 + w; + pixel_type * r2 = r1 + w; + pixel_type * end = r2 + w; + + // Horizontally blur the first two input rows. + calc_row(img, bounds.x1, bounds.y1, w, r0); + memcpy(r1, r0, w * sizeof(pixel_type)); + + for (int y = 0; ; ) + { + // Get pointer to first pixel. + pixel_type* p = img.pix_value_ptr(bounds.x1, bounds.y1 + y, bounds.x1 + w); + + // Horizontally blur the row below. + if (y + 1 < h) + { + calc_row(img, bounds.x1, bounds.y1 + y + 1, w, r2); + } + else + { + memcpy(r2, r1, w * sizeof(pixel_type)); // duplicate bottom row + } + + // Combine blurred rows into destination. + for (int x = 0; x < w; ++x) + { + calc_pixel(*r0++, *r1++, *r2++, *p++); + } + + if (++y >= h) break; + + // Wrap bottom row pointer around to top of buffer. + if (r2 == end) r2 = begin; + else if (r1 == end) r1 = begin; + else if (r0 == end) r0 = begin; + } + } + + private: + void calc_row(PixFmt& img, int x, int y, int w, pixel_type* row) + { + const int wm = w - 1; + + pixel_type* p = img.pix_value_ptr(x, y, w); + + pixel_type c[3]; + pixel_type* p0 = c; + pixel_type* p1 = c + 1; + pixel_type* p2 = c + 2; + pixel_type* end = c + 3; + *p0 = *p1 = *p; + + for (int x = 0; x < wm; ++x) + { + *p2 = *(p = p->next()); + + calc_pixel(*p0++, *p1++, *p2++, *row++); + + if (p0 == end) p0 = c; + else if (p1 == end) p1 = c; + else if (p2 == end) p2 = c; + } + + calc_pixel(*p0, *p1, *p1, *row); + } + + void calc_pixel( + pixel_type const & c1, + pixel_type const & c2, + pixel_type const & c3, + pixel_type & x) + { + calc_pixel(c1, c2, c3, x, PixFmt::pixfmt_category()); + } + + void calc_pixel( + pixel_type const & c1, + pixel_type const & c2, + pixel_type const & c3, + pixel_type & x, + pixfmt_gray_tag) + { + x.c[0] = calc_value(c1.c[0], c2.c[0], c3.c[0]); + } + + void calc_pixel( + pixel_type const & c1, + pixel_type const & c2, + pixel_type const & c3, + pixel_type & x, + pixfmt_rgb_tag) + { + enum { R = order_type::R, G = order_type::G, B = order_type::B }; + x.c[R] = calc_value(c1.c[R], c2.c[R], c3.c[R]); + x.c[G] = calc_value(c1.c[G], c2.c[G], c3.c[G]); + x.c[B] = calc_value(c1.c[B], c2.c[B], c3.c[B]); + } + + void calc_pixel( + pixel_type const & c1, + pixel_type const & c2, + pixel_type const & c3, + pixel_type & x, + pixfmt_rgba_tag) + { + enum { R = order_type::R, G = order_type::G, B = order_type::B, A = order_type::A }; + x.c[R] = calc_value(c1.c[R], c2.c[R], c3.c[R]); + x.c[G] = calc_value(c1.c[G], c2.c[G], c3.c[G]); + x.c[B] = calc_value(c1.c[B], c2.c[B], c3.c[B]); + x.c[A] = calc_value(c1.c[A], c2.c[A], c3.c[A]); + } + + value_type calc_value(value_type v1, value_type v2, value_type v3) + { + return value_type(m_g1 * v1 + m_g0 * v2 + m_g1 * v3); + } + + double m_g0, m_g1; + pod_vector m_buf; + }; + + // Helper functions for applying blur to a surface without having to create an intermediate object. + + template + void apply_slight_blur(PixFmt& img, const rect_i& bounds, double r = 1) + { + if (r > 0) slight_blur(r).blur(img, bounds); + } + + template + void apply_slight_blur(PixFmt& img, double r = 1) + { + if (r > 0) slight_blur(r).blur(img, rect_i(0, 0, img.width() - 1, img.height() - 1)); + } + + template + void apply_slight_blur(renderer_base& img, const rect_i& bounds, double r = 1) + { + if (r > 0) slight_blur(r).blur(img.ren(), bounds); + } + + template + void apply_slight_blur(renderer_base& img, double r = 1) + { + if (r > 0) slight_blur(r).blur(img.ren(), img.clip_box()); + } +} + + + + +#endif diff --git a/kiva/agg/agg-24/include/agg_color_gray.h b/kiva/agg/agg-24/include/agg_color_gray.h index a3b1bf363..072b4be90 100644 --- a/kiva/agg/agg-24/include/agg_color_gray.h +++ b/kiva/agg/agg-24/include/agg_color_gray.h @@ -2,8 +2,8 @@ // 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. +// 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. // @@ -13,12 +13,12 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for high precision colors has been sponsored by +// 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. -// +// //---------------------------------------------------------------------------- // // color types gray8, gray16 @@ -35,7 +35,8 @@ namespace agg24 { //===================================================================gray8 - struct gray8 + template + struct gray8T { typedef int8u value_type; typedef int32u calc_type; @@ -44,111 +45,329 @@ namespace agg24 { base_shift = 8, base_scale = 1 << base_shift, - base_mask = base_scale - 1 + base_mask = base_scale - 1, + base_MSB = 1 << (base_shift - 1) }; - typedef gray8 self_type; + typedef gray8T 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& dst, const gray8T& src) + { + dst.v = sRGB_conv::rgb_from_sRGB(src.v); + dst.a = src.a; + } + + static void convert(gray8T& dst, const gray8T& src) + { + dst.v = sRGB_conv::rgb_to_sRGB(src.v); + dst.a = src.a; + } + + static void convert(gray8T& dst, const rgba8& src) + { + dst.v = luminance(src); + dst.a = src.a; + } + + static void convert(gray8T& dst, const srgba8& src) + { + // The RGB weights are only valid for linear values. + convert(dst, rgba8(src)); + } + + static void convert(gray8T& dst, const rgba8& src) + { + dst.v = sRGB_conv::rgb_to_sRGB(luminance(src)); + dst.a = src.a; + } + + static void convert(gray8T& dst, const srgba8& src) + { + // The RGB weights are only valid for linear values. + convert(dst, rgba8(src)); + } + //-------------------------------------------------------------------- - gray8() {} + gray8T() {} //-------------------------------------------------------------------- - gray8(unsigned v_, unsigned a_=base_mask) : + explicit gray8T(unsigned v_, unsigned a_ = base_mask) : v(int8u(v_)), a(int8u(a_)) {} //-------------------------------------------------------------------- - gray8(const self_type& c, unsigned a_) : + gray8T(const self_type& c, unsigned a_) : v(c.v), a(value_type(a_)) {} //-------------------------------------------------------------------- - 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))) {} + gray8T(const rgba& c) : + v(luminance(c)), + a(value_type(uround(c.a * base_mask))) {} //-------------------------------------------------------------------- - 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 + gray8T(const gray8T& c) + { + convert(*this, c); + } //-------------------------------------------------------------------- - gray8(const rgba8& c) : - v((c.r*77 + c.g*150 + c.b*29) >> 8), - a(c.a) {} + template + gray8T(const rgba8T& c) + { + convert(*this, c); + } //-------------------------------------------------------------------- - gray8(const rgba8& c, unsigned a_) : - v((c.r*77 + c.g*150 + c.b*29) >> 8), - a(a_) {} + template + T convert_from_sRGB() const + { + typename T::value_type y = sRGB_conv::rgb_from_sRGB(v); + return T(y, y, y, sRGB_conv::alpha_from_sRGB(a)); + } + + template + T convert_to_sRGB() const + { + typename T::value_type y = sRGB_conv::rgb_to_sRGB(v); + return T(y, y, y, sRGB_conv::alpha_to_sRGB(a)); + } //-------------------------------------------------------------------- - void clear() + rgba8 make_rgba8(const linear&) const { - v = a = 0; + return rgba8(v, v, v, a); + } + + rgba8 make_rgba8(const sRGB&) const + { + return convert_from_sRGB(); + } + + operator rgba8() const + { + return make_rgba8(Colorspace()); } //-------------------------------------------------------------------- - const self_type& transparent() + srgba8 make_srgba8(const linear&) const { - a = 0; - return *this; + return convert_to_sRGB(); + } + + 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(); + } + + operator rgba16() const + { + return make_rgba16(Colorspace()); } //-------------------------------------------------------------------- - void opacity(double a_) + rgba32 make_rgba32(const linear&) const { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); + 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(); + } + + operator rgba32() const + { + return make_rgba32(Colorspace()); } //-------------------------------------------------------------------- - double opacity() const + static AGG_INLINE double to_double(value_type a) { - return double(a) / double(base_mask); + 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; + } //-------------------------------------------------------------------- - const self_type& premultiply() + // Fixed-point multiply, exact over int8u. + static AGG_INLINE value_type multiply(value_type a, value_type b) { - if(a == base_mask) return *this; - if(a == 0) + 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) { - v = 0; - return *this; + return 0; } - v = value_type((calc_type(v) * a) >> base_shift); + else if (a >= b) + { + return base_mask; + } + else return value_type((a * base_mask + (b >> 1)) / b); + } + + //-------------------------------------------------------------------- + template + static AGG_INLINE T downscale(T a) + { + return a >> base_shift; + } + + //-------------------------------------------------------------------- + template + 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() + { + v = a = 0; + return *this; + } + + //-------------------------------------------------------------------- + self_type& transparent() + { + a = 0; return *this; } //-------------------------------------------------------------------- - const self_type& premultiply(unsigned a_) + 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)); + return *this; + } + + //-------------------------------------------------------------------- + double opacity() const + { + return double(a) / double(base_mask); + } + + //-------------------------------------------------------------------- + self_type& premultiply() { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) + if (a < base_mask) { - v = a = 0; - return *this; + if (a == 0) v = 0; + else v = multiply(v, a); } - 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() + self_type& demultiply() { - if(a == base_mask) return *this; - if(a == 0) + if (a < base_mask) { - v = 0; - return *this; + 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_); + } } - calc_type v_ = (calc_type(v) * base_mask) / a; - v = value_type((v_ > base_mask) ? base_mask : v_); return *this; } @@ -157,8 +376,8 @@ namespace agg24 { self_type ret; calc_type ik = uround(k * base_scale); - 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)); + ret.v = lerp(v, c.v, ik); + ret.a = lerp(a, c.a, ik); return ret; } @@ -166,59 +385,34 @@ namespace agg24 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; 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; + cv = v + c.v; + ca = a + c.a; } } else { - 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; + cv = v + mult_cover(c.v, cover); + ca = a + mult_cover(c.a, cover); } + 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); } }; - - //-------------------------------------------------------------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(); - } - - + typedef gray8T gray8; + typedef gray8T sgray8; //==================================================================gray16 @@ -231,18 +425,46 @@ namespace agg24 { base_shift = 16, base_scale = 1 << base_shift, - base_mask = base_scale - 1 + base_mask = base_scale - 1, + base_MSB = 1 << (base_shift - 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() {} //-------------------------------------------------------------------- - gray16(unsigned v_, unsigned a_=base_mask) : + explicit gray16(unsigned v_, unsigned a_ = base_mask) : v(int16u(v_)), a(int16u(a_)) {} //-------------------------------------------------------------------- @@ -251,91 +473,231 @@ namespace agg24 //-------------------------------------------------------------------- gray16(const rgba& c) : - v((value_type)uround((0.299*c.r + 0.587*c.g + 0.114*c.b) * double(base_mask))), + v(luminance(c)), 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)), + 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) : - v(c.r*77 + c.g*150 + c.b*29), + 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 rgba8& c, unsigned a_) : - v(c.r*77 + c.g*150 + c.b*29), - a((value_type(a_) << 8) | c.a) {} + gray16(const sgray8& c) : + v(sRGB_conv::rgb_from_sRGB(c.v)), + a(sRGB_conv::alpha_from_sRGB(c.a)) {} //-------------------------------------------------------------------- - void clear() + operator rgba8() const { - v = a = 0; + return rgba8(v >> 8, v >> 8, v >> 8, a >> 8); } //-------------------------------------------------------------------- - const self_type& transparent() + operator srgba8() const { - a = 0; - return *this; + value_type y = sRGB_conv::rgb_to_sRGB(v); + return srgba8(y, y, y, sRGB_conv::alpha_to_sRGB(a)); } //-------------------------------------------------------------------- - void opacity(double 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 { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); + return gray8(v >> 8, a >> 8); } //-------------------------------------------------------------------- - double opacity() const + operator sgray8() const { - return double(a) / double(base_mask); + return sgray8( + sRGB_conv::rgb_to_sRGB(v), + sRGB_conv::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; + } //-------------------------------------------------------------------- - const self_type& premultiply() + static AGG_INLINE value_type full_value() { - if(a == base_mask) return *this; - if(a == 0) + 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) { - v = 0; - return *this; + return base_mask; } - v = value_type((calc_type(v) * a) >> base_shift); + else return value_type((a * base_mask + (b >> 1)) / b); + } + + //-------------------------------------------------------------------- + template + static AGG_INLINE T downscale(T a) + { + return a >> base_shift; + } + + //-------------------------------------------------------------------- + template + 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() + { + v = a = 0; + return *this; + } + + //-------------------------------------------------------------------- + self_type& transparent() + { + a = 0; return *this; } //-------------------------------------------------------------------- - const self_type& premultiply(unsigned a_) + 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)); + return *this; + } + + //-------------------------------------------------------------------- + double opacity() const { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) + return double(a) / double(base_mask); + } + + + //-------------------------------------------------------------------- + self_type& premultiply() + { + if (a < base_mask) { - v = a = 0; - return *this; + if(a == 0) v = 0; + else v = multiply(v, a); } - 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() + self_type& demultiply() { - if(a == base_mask) return *this; - if(a == 0) + if (a < base_mask) { - v = 0; - return *this; + if (a == 0) + { + v = 0; + } + else + { + calc_type v_ = (calc_type(v) * base_mask) / a; + v = value_type((v_ > base_mask) ? base_mask : v_); + } } - calc_type v_ = (calc_type(v) * base_mask) / a; - v = value_type((v_ > base_mask) ? base_mask : v_); return *this; } @@ -344,8 +706,8 @@ namespace agg24 { self_type ret; calc_type ik = uround(k * base_scale); - 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)); + ret.v = lerp(v, c.v, ik); + ret.a = lerp(a, c.a, ik); return ret; } @@ -353,25 +715,26 @@ namespace agg24 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; 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; + cv = v + c.v; + ca = a + c.a; } } else { - 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; + cv = v + mult_cover(c.v, cover); + ca = a + mult_cover(c.a, cover); } + 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); } //-------------------------------------------------------------------- @@ -379,33 +742,303 @@ namespace agg24 }; - //------------------------------------------------------------gray16_pre - inline gray16 gray16_pre(unsigned v, unsigned a = gray16::base_mask) + //===================================================================gray32 + struct gray32 { - 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(); - } + 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::rgb_from_sRGB(c.v)), + a(sRGB_conv::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::rgb_to_sRGB(v), + sRGB_conv::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::rgb_to_sRGB(v); + return srgba8(y, y, y, sRGB_conv::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 + static AGG_INLINE T downscale(T a) + { + return a; + } + + //-------------------------------------------------------------------- + template + 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; + } + + + //-------------------------------------------------------------------- + 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/kiva/agg/agg-24/include/agg_color_rgba.h b/kiva/agg/agg-24/include/agg_color_rgba.h index 775f0ee25..02343f1d1 100644 --- a/kiva/agg/agg-24/include/agg_color_rgba.h +++ b/kiva/agg/agg-24/include/agg_color_rgba.h @@ -2,19 +2,19 @@ // 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. +// 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. // //---------------------------------------------------------------------------- // -// Adaptation for high precision colors has been sponsored by +// 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. -// +// //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com @@ -26,17 +26,22 @@ #include #include "agg_basics.h" +#include "agg_gamma_lut.h" namespace agg24 { - // Supported byte orders for RGB and RGBA pixel formats + // Supported component orders for RGB and RGBA pixel formats //======================================================================= - 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 + 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 {}; //====================================================================rgba struct rgba @@ -59,24 +64,25 @@ namespace agg24 rgba(const rgba& c, double a_) : r(c.r), g(c.g), b(c.b), a(a_) {} //-------------------------------------------------------------------- - void clear() + rgba& clear() { r = g = b = a = 0; + return *this; } //-------------------------------------------------------------------- - const rgba& transparent() + rgba& transparent() { - a = 0.0; + a = 0; return *this; } //-------------------------------------------------------------------- - const rgba& opacity(double a_) + rgba& opacity(double a_) { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = a_; + if (a_ < 0) a = 0; + else if (a_ > 1) a = 1; + else a = a_; return *this; } @@ -87,7 +93,7 @@ namespace agg24 } //-------------------------------------------------------------------- - const rgba& premultiply() + rgba& premultiply() { r *= a; g *= a; @@ -96,33 +102,37 @@ namespace agg24 } //-------------------------------------------------------------------- - const rgba& premultiply(double a_) + rgba& premultiply(double a_) { - if(a <= 0.0 || a_ <= 0.0) + if (a <= 0 || a_ <= 0) + { + r = g = b = a = 0; + } + else { - r = g = b = a = 0.0; - return *this; + a_ /= a; + r *= a_; + g *= a_; + b *= a_; + a = a_; } - a_ /= a; - r *= a_; - g *= a_; - b *= a_; - a = a_; return *this; } //-------------------------------------------------------------------- - const rgba& demultiply() + rgba& demultiply() { - if(a == 0) + if (a == 0) { r = g = b = 0; - return *this; } - double a_ = 1.0 / a; - r *= a_; - g *= a_; - b *= a_; + else + { + double a_ = 1.0 / a; + r *= a_; + g *= a_; + b *= a_; + } return *this; } @@ -138,12 +148,30 @@ namespace agg24 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) { @@ -152,18 +180,14 @@ namespace agg24 }; - //----------------------------------------------------------------rgba_pre - inline rgba rgba_pre(double r, double g, double b, double a=1.0) - { - return rgba(r, g, b, a).premultiply(); - } - inline rgba rgba_pre(const rgba& c) + inline rgba operator+(const rgba& a, const rgba& b) { - return rgba(c).premultiply(); + return rgba(a) += b; } - inline rgba rgba_pre(const rgba& c, double a) + + inline rgba operator*(const rgba& a, double b) { - return rgba(c, a).premultiply(); + return rgba(a) *= b; } //------------------------------------------------------------------------ @@ -171,44 +195,39 @@ namespace agg24 { 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); @@ -216,11 +235,15 @@ namespace agg24 return t; } + inline rgba rgba_pre(double r, double g, double b, double a) + { + return rgba(r, g, b, a).premultiply(); + } - //===================================================================rgba8 - struct rgba8 + template + struct rgba8T { typedef int8u value_type; typedef int32u calc_type; @@ -229,9 +252,10 @@ namespace agg24 { base_shift = 8, base_scale = 1 << base_shift, - base_mask = base_scale - 1 + base_mask = base_scale - 1, + base_MSB = 1 << (base_shift - 1) }; - typedef rgba8 self_type; + typedef rgba8T self_type; value_type r; @@ -239,53 +263,218 @@ namespace agg24 value_type b; value_type a; + static void convert(rgba8T& dst, const rgba8T& src) + { + dst.r = sRGB_conv::rgb_from_sRGB(src.r); + dst.g = sRGB_conv::rgb_from_sRGB(src.g); + dst.b = sRGB_conv::rgb_from_sRGB(src.b); + dst.a = src.a; + } + + static void convert(rgba8T& dst, const rgba8T& src) + { + dst.r = sRGB_conv::rgb_to_sRGB(src.r); + dst.g = sRGB_conv::rgb_to_sRGB(src.g); + dst.b = sRGB_conv::rgb_to_sRGB(src.b); + dst.a = src.a; + } + + static void convert(rgba8T& 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& dst, const rgba& src) + { + // Use the "float" table. + dst.r = sRGB_conv::rgb_to_sRGB(float(src.r)); + dst.g = sRGB_conv::rgb_to_sRGB(float(src.g)); + dst.b = sRGB_conv::rgb_to_sRGB(float(src.b)); + dst.a = sRGB_conv::alpha_to_sRGB(float(src.a)); + } + + static void convert(rgba& dst, const rgba8T& 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& src) + { + // Use the "float" table. + dst.r = sRGB_conv::rgb_from_sRGB(src.r); + dst.g = sRGB_conv::rgb_from_sRGB(src.g); + dst.b = sRGB_conv::rgb_from_sRGB(src.b); + dst.a = sRGB_conv::alpha_from_sRGB(src.a); + } + //-------------------------------------------------------------------- - rgba8() {} + rgba8T() {} //-------------------------------------------------------------------- - rgba8(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : - r(value_type(r_)), - g(value_type(g_)), - b(value_type(b_)), + rgba8T(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_)) {} //-------------------------------------------------------------------- - 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 rgba& c) + { + convert(*this, c); + } //-------------------------------------------------------------------- - rgba8(const self_type& c, unsigned a_) : + rgba8T(const self_type& c, unsigned a_) : r(c.r), g(c.g), b(c.b), a(value_type(a_)) {} //-------------------------------------------------------------------- - 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))) {} + template + rgba8T(const rgba8T& c) + { + convert(*this, c); + } + + //-------------------------------------------------------------------- + operator rgba() const + { + rgba c; + convert(c, *this); + return c; + } + + //-------------------------------------------------------------------- + static AGG_INLINE double to_double(value_type a) + { + return double(a) / base_mask; + } //-------------------------------------------------------------------- - void clear() + 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 + static AGG_INLINE T downscale(T a) + { + return a >> base_shift; + } + + //-------------------------------------------------------------------- + template + 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() { r = g = b = a = 0; + return *this; } - + //-------------------------------------------------------------------- - const self_type& transparent() + self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- - const self_type& opacity(double a_) + self_type& opacity(double a_) { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); + if (a_ < 0) a = 0; + else if (a_ > 1) a = 1; + else a = (value_type)uround(a_ * double(base_mask)); return *this; } @@ -296,54 +485,66 @@ namespace agg24 } //-------------------------------------------------------------------- - AGG_INLINE const self_type& premultiply() + AGG_INLINE self_type& premultiply() { - if(a == base_mask) return *this; - if(a == 0) + if (a != base_mask) { - r = g = b = 0; - return *this; + if (a == 0) + { + r = g = b = 0; + } + else + { + r = multiply(r, a); + g = multiply(g, a); + b = multiply(b, a); + } } - 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 const self_type& premultiply(unsigned a_) + AGG_INLINE self_type& premultiply(unsigned a_) { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) + if (a != base_mask || a_ < base_mask) { - r = g = b = a = 0; - return *this; + 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_); + } } - 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 const self_type& demultiply() + AGG_INLINE self_type& demultiply() { - if(a == base_mask) return *this; - if(a == 0) + if (a < base_mask) { - r = g = b = 0; - return *this; + 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_); + } } - 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; } @@ -351,11 +552,11 @@ namespace agg24 AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; - 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)); + 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); return ret; } @@ -363,31 +564,32 @@ namespace agg24 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; 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; + cr = r + c.r; + cg = g + c.g; + cb = b + c.b; + ca = a + c.a; } } else { - 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; + 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); } + 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); } //-------------------------------------------------------------------- @@ -418,57 +620,45 @@ namespace agg24 } }; - - //-------------------------------------------------------------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(); - } + typedef rgba8T rgba8; + typedef rgba8T srgba8; - //-----------------------------------------------------------rgb8_packed + //-------------------------------------------------------------rgb8_packed inline rgba8 rgb8_packed(unsigned v) { return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF); } - //-----------------------------------------------------------bgr8_packed + //-------------------------------------------------------------bgr8_packed inline rgba8 bgr8_packed(unsigned v) { return rgba8(v & 0xFF, (v >> 8) & 0xFF, (v >> 16) & 0xFF); } - //----------------------------------------------------------argb8_packed + //------------------------------------------------------------argb8_packed inline rgba8 argb8_packed(unsigned v) { return rgba8((v >> 16) & 0xFF, (v >> 8) & 0xFF, v & 0xFF, v >> 24); } + //---------------------------------------------------------rgba8_gamma_dir + template + rgba8 rgba8_gamma_dir(rgba8 c, const GammaLUT& gamma) + { + return rgba8(gamma.dir(c.r), gamma.dir(c.g), gamma.dir(c.b), c.a); + } + //---------------------------------------------------------rgba8_gamma_inv + template + rgba8 rgba8_gamma_inv(rgba8 c, const GammaLUT& gamma) + { + return rgba8(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); + } - - - - //=================================================================rgba16 + //==================================================================rgba16 struct rgba16 { typedef int16u value_type; @@ -478,7 +668,8 @@ namespace agg24 { base_shift = 16, base_scale = 1 << base_shift, - base_mask = base_scale - 1 + base_mask = base_scale - 1, + base_MSB = 1 << (base_shift - 1) }; typedef rgba16 self_type; @@ -492,9 +683,9 @@ namespace agg24 //-------------------------------------------------------------------- rgba16(unsigned r_, unsigned g_, unsigned b_, unsigned a_=base_mask) : - r(value_type(r_)), - g(value_type(g_)), - b(value_type(b_)), + r(value_type(r_)), + g(value_type(g_)), + b(value_type(b_)), a(value_type(a_)) {} //-------------------------------------------------------------------- @@ -503,51 +694,179 @@ namespace agg24 //-------------------------------------------------------------------- rgba16(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))), + 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))) {} - //-------------------------------------------------------------------- - 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)), - g(value_type((value_type(c.g) << 8) | c.g)), - b(value_type((value_type(c.b) << 8) | c.b)), + 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((value_type(c.a) << 8) | 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)) {} + rgba16(const srgba8& c) : + r(sRGB_conv::rgb_from_sRGB(c.r)), + g(sRGB_conv::rgb_from_sRGB(c.g)), + b(sRGB_conv::rgb_from_sRGB(c.b)), + a(sRGB_conv::alpha_from_sRGB(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::rgb_to_sRGB(r), + sRGB_conv::rgb_to_sRGB(g), + sRGB_conv::rgb_to_sRGB(b), + sRGB_conv::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 + static AGG_INLINE T downscale(T a) + { + return a >> base_shift; + } + + //-------------------------------------------------------------------- + template + 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)); + } //-------------------------------------------------------------------- - void clear() + self_type& clear() { r = g = b = a = 0; + return *this; } - + //-------------------------------------------------------------------- - const self_type& transparent() + self_type& transparent() { a = 0; return *this; } //-------------------------------------------------------------------- - AGG_INLINE const self_type& opacity(double a_) + AGG_INLINE self_type& opacity(double a_) { - if(a_ < 0.0) a_ = 0.0; - if(a_ > 1.0) a_ = 1.0; - a = (value_type)uround(a_ * double(base_mask)); + if (a_ < 0) a = 0; + if (a_ > 1) a = 1; + a = value_type(uround(a_ * double(base_mask))); return *this; } @@ -558,54 +877,66 @@ namespace agg24 } //-------------------------------------------------------------------- - AGG_INLINE const self_type& premultiply() + AGG_INLINE self_type& premultiply() { - if(a == base_mask) return *this; - if(a == 0) + if (a != base_mask) { - r = g = b = 0; - return *this; + if (a == 0) + { + r = g = b = 0; + } + else + { + r = multiply(r, a); + g = multiply(g, a); + b = multiply(b, a); + } } - 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 const self_type& premultiply(unsigned a_) + AGG_INLINE self_type& premultiply(unsigned a_) { - if(a == base_mask && a_ >= base_mask) return *this; - if(a == 0 || a_ == 0) + if (a < base_mask || a_ < base_mask) { - r = g = b = a = 0; - return *this; + 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_); + } } - 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 const self_type& demultiply() + AGG_INLINE self_type& demultiply() { - if(a == base_mask) return *this; - if(a == 0) + if (a < base_mask) { - r = g = b = 0; - return *this; + 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_); + } } - 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; } @@ -613,11 +944,11 @@ namespace agg24 AGG_INLINE self_type gradient(const self_type& c, double k) const { self_type ret; - 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)); + 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); return ret; } @@ -625,31 +956,32 @@ namespace agg24 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; 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; + cr = r + c.r; + cg = g + c.g; + cb = b + c.b; + ca = a + c.a; } } else { - 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; + 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); } + 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); } //-------------------------------------------------------------------- @@ -681,34 +1013,339 @@ namespace agg24 }; - - //--------------------------------------------------------------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) + //------------------------------------------------------rgba16_gamma_dir + template + rgba16 rgba16_gamma_dir(rgba16 c, const GammaLUT& gamma) { - return rgba16(c).premultiply(); + return rgba16(gamma.dir(c.r), gamma.dir(c.g), gamma.dir(c.b), c.a); } - inline rgba16 rgba16_pre(const rgba& c, double a) - { - return rgba16(c,a).premultiply(); - } - inline rgba16 rgba16_pre(const rgba8& c) + + //------------------------------------------------------rgba16_gamma_inv + template + rgba16 rgba16_gamma_inv(rgba16 c, const GammaLUT& gamma) { - return rgba16(c).premultiply(); + return rgba16(gamma.inv(c.r), gamma.inv(c.g), gamma.inv(c.b), c.a); } - inline rgba16 rgba16_pre(const rgba8& c, unsigned a) + + //====================================================================rgba32 + struct rgba32 { - return rgba16(c,a).premultiply(); - } + 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::rgb_from_sRGB(c.r)), + g(sRGB_conv::rgb_from_sRGB(c.g)), + b(sRGB_conv::rgb_from_sRGB(c.b)), + a(sRGB_conv::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::rgb_to_sRGB(r), + sRGB_conv::rgb_to_sRGB(g), + sRGB_conv::rgb_to_sRGB(b), + sRGB_conv::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 + static AGG_INLINE T downscale(T a) + { + return a; + } + + //-------------------------------------------------------------------- + template + 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 + AGG_INLINE void apply_gamma_dir(const GammaLUT& gamma) + { + r = gamma.dir(r); + g = gamma.dir(g); + b = gamma.dir(b); + } + + //-------------------------------------------------------------------- + template + 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/kiva/agg/agg-24/include/agg_config.h b/kiva/agg/agg-24/include/agg_config.h index 5c699a22d..9df70bfdd 100644 --- a/kiva/agg/agg-24/include/agg_config.h +++ b/kiva/agg/agg-24/include/agg_config.h @@ -1,7 +1,10 @@ #ifndef AGG_CONFIG_INCLUDED #define AGG_CONFIG_INCLUDED -// This file can be used to redefine the default basic types such as: +// This file can be used to redefine certain data types. + +//--------------------------------------- +// 1. Default basic types such as: // // AGG_INT8 // AGG_INT8U @@ -23,4 +26,19 @@ // but it won't result any crash and the rest of the library will remain // fully functional. + +//--------------------------------------- +// 2. Default rendering_buffer type. Can be: +// +// Provides faster access for massive pixel operations, +// such as blur, image filtering: +// #define AGG_RENDERING_BUFFER row_ptr_cache +// +// Provides cheaper creation and destruction (no mem allocs): +// #define AGG_RENDERING_BUFFER row_accessor +// +// You can still use both of them simultaneously in your applications +// This #define is used only for default rendering_buffer type, +// in short hand typedefs like pixfmt_rgba32. + #endif diff --git a/kiva/agg/agg-24/include/agg_conv_adaptor_vcgen.h b/kiva/agg/agg-24/include/agg_conv_adaptor_vcgen.h index 7d2b9674c..4e684cefd 100644 --- a/kiva/agg/agg-24/include/agg_conv_adaptor_vcgen.h +++ b/kiva/agg/agg-24/include/agg_conv_adaptor_vcgen.h @@ -45,7 +45,7 @@ namespace agg24 }; public: - conv_adaptor_vcgen(VertexSource& source) : + explicit conv_adaptor_vcgen(VertexSource& source) : m_source(&source), m_status(initial) {} diff --git a/kiva/agg/agg-24/include/agg_conv_adaptor_vpgen.h b/kiva/agg/agg-24/include/agg_conv_adaptor_vpgen.h index 13978051b..cc5c838df 100644 --- a/kiva/agg/agg-24/include/agg_conv_adaptor_vpgen.h +++ b/kiva/agg/agg-24/include/agg_conv_adaptor_vpgen.h @@ -25,7 +25,7 @@ namespace agg24 template class conv_adaptor_vpgen { public: - conv_adaptor_vpgen(VertexSource& source) : m_source(&source) {} + explicit conv_adaptor_vpgen(VertexSource& source) : m_source(&source) {} void attach(VertexSource& source) { m_source = &source; } VPGen& vpgen() { return m_vpgen; } diff --git a/kiva/agg/agg-24/include/agg_conv_close_polygon.h b/kiva/agg/agg-24/include/agg_conv_close_polygon.h index 6690536f0..a33da5a7f 100644 --- a/kiva/agg/agg-24/include/agg_conv_close_polygon.h +++ b/kiva/agg/agg-24/include/agg_conv_close_polygon.h @@ -25,7 +25,7 @@ namespace agg24 template class conv_close_polygon { public: - conv_close_polygon(VertexSource& vs) : m_source(&vs) {} + explicit conv_close_polygon(VertexSource& vs) : m_source(&vs) {} void attach(VertexSource& source) { m_source = &source; } void rewind(unsigned path_id); diff --git a/kiva/agg/agg-24/include/agg_conv_curve.h b/kiva/agg/agg-24/include/agg_conv_curve.h index 37d959539..7957a3c8d 100644 --- a/kiva/agg/agg-24/include/agg_conv_curve.h +++ b/kiva/agg/agg-24/include/agg_conv_curve.h @@ -60,7 +60,7 @@ namespace agg24 typedef Curve4 curve4_type; typedef conv_curve self_type; - conv_curve(VertexSource& source) : + 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; } @@ -154,10 +154,10 @@ namespace agg24 return path_cmd_line_to; } - double ct2_x = 0.0; - double ct2_y = 0.0; - double end_x = 0.0; - double end_y = 0.0; + double ct2_x; + double ct2_y; + double end_x; + double end_y; unsigned cmd = m_source->vertex(x, y); switch(cmd) diff --git a/kiva/agg/agg-24/include/agg_conv_gpc.h b/kiva/agg/agg-24/include/agg_conv_gpc.h new file mode 100644 index 000000000..ab80df26a --- /dev/null +++ b/kiva/agg/agg-24/include/agg_conv_gpc.h @@ -0,0 +1,432 @@ +//---------------------------------------------------------------------------- +// 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 +//---------------------------------------------------------------------------- +// +// General Polygon Clipper based on the GPC library by Alan Murta +// Union, Intersection, XOR, A-B, B-A +// Contact the author if you intend to use it in commercial applications! +// http://www.cs.man.ac.uk/aig/staff/alan/software/ +// Alan Murta (email: gpc@cs.man.ac.uk) +// +//---------------------------------------------------------------------------- + +#ifndef AGG_CONV_GPC_INCLUDED +#define AGG_CONV_GPC_INCLUDED + +#include +#include "agg_basics.h" +#include "agg_array.h" + +extern "C" +{ +#include "gpc.h" +} + +namespace agg24 +{ + enum gpc_op_e + { + gpc_or, + gpc_and, + gpc_xor, + gpc_a_minus_b, + gpc_b_minus_a + }; + + + //================================================================conv_gpc + template class conv_gpc + { + enum status + { + status_move_to, + status_line_to, + status_stop + }; + + struct contour_header_type + { + int num_vertices; + int hole_flag; + gpc_vertex* vertices; + }; + + typedef pod_bvector vertex_array_type; + typedef pod_bvector contour_header_array_type; + + + public: + typedef VSA source_a_type; + typedef VSB source_b_type; + typedef conv_gpc self_type; + + ~conv_gpc() + { + free_gpc_data(); + } + + conv_gpc(source_a_type& a, source_b_type& b, gpc_op_e op = gpc_or) : + m_src_a(&a), + m_src_b(&b), + m_status(status_move_to), + m_vertex(-1), + m_contour(-1), + m_operation(op) + { + memset(&m_poly_a, 0, sizeof(m_poly_a)); + memset(&m_poly_b, 0, sizeof(m_poly_b)); + memset(&m_result, 0, sizeof(m_result)); + } + + void attach1(VSA& source) { m_src_a = &source; } + void attach2(VSB& source) { m_src_b = &source; } + + void operation(gpc_op_e v) { m_operation = v; } + + // Vertex Source Interface + void rewind(unsigned path_id); + unsigned vertex(double* x, double* y); + + private: + conv_gpc(const conv_gpc&); + const conv_gpc& operator = (const conv_gpc&); + + //-------------------------------------------------------------------- + void free_polygon(gpc_polygon& p); + void free_result(); + void free_gpc_data(); + void start_contour(); + void add_vertex(double x, double y); + void end_contour(unsigned orientation); + void make_polygon(gpc_polygon& p); + void start_extracting(); + bool next_contour(); + bool next_vertex(double* x, double* y); + + + //-------------------------------------------------------------------- + template void add(VS& src, gpc_polygon& p) + { + unsigned cmd; + double x, y; + double start_x = 0.0; + double start_y = 0.0; + bool line_to = false; + unsigned orientation = 0; + + m_contour_accumulator.remove_all(); + + while(!is_stop(cmd = src.vertex(&x, &y))) + { + if(is_vertex(cmd)) + { + if(is_move_to(cmd)) + { + if(line_to) + { + end_contour(orientation); + orientation = 0; + } + start_contour(); + start_x = x; + start_y = y; + } + add_vertex(x, y); + line_to = true; + } + else + { + if(is_end_poly(cmd)) + { + orientation = get_orientation(cmd); + if(line_to && is_closed(cmd)) + { + add_vertex(start_x, start_y); + } + } + } + } + if(line_to) + { + end_contour(orientation); + } + make_polygon(p); + } + + + private: + //-------------------------------------------------------------------- + source_a_type* m_src_a; + source_b_type* m_src_b; + status m_status; + int m_vertex; + int m_contour; + gpc_op_e m_operation; + vertex_array_type m_vertex_accumulator; + contour_header_array_type m_contour_accumulator; + gpc_polygon m_poly_a; + gpc_polygon m_poly_b; + gpc_polygon m_result; + }; + + + + + + //------------------------------------------------------------------------ + template + void conv_gpc::free_polygon(gpc_polygon& p) + { + int i; + for(i = 0; i < p.num_contours; i++) + { + pod_allocator::deallocate(p.contour[i].vertex, + p.contour[i].num_vertices); + } + pod_allocator::deallocate(p.contour, p.num_contours); + memset(&p, 0, sizeof(gpc_polygon)); + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::free_result() + { + if(m_result.contour) + { + gpc_free_polygon(&m_result); + } + memset(&m_result, 0, sizeof(m_result)); + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::free_gpc_data() + { + free_polygon(m_poly_a); + free_polygon(m_poly_b); + free_result(); + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::start_contour() + { + contour_header_type h; + memset(&h, 0, sizeof(h)); + m_contour_accumulator.add(h); + m_vertex_accumulator.remove_all(); + } + + + //------------------------------------------------------------------------ + template + inline void conv_gpc::add_vertex(double x, double y) + { + gpc_vertex v; + v.x = x; + v.y = y; + m_vertex_accumulator.add(v); + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::end_contour(unsigned orientation) + { + if(m_contour_accumulator.size()) + { + if(m_vertex_accumulator.size() > 2) + { + contour_header_type& h = + m_contour_accumulator[m_contour_accumulator.size() - 1]; + + h.num_vertices = m_vertex_accumulator.size(); + h.hole_flag = 0; + + // TO DO: Clarify the "holes" + //if(is_cw(orientation)) h.hole_flag = 1; + + h.vertices = pod_allocator::allocate(h.num_vertices); + gpc_vertex* d = h.vertices; + int i; + for(i = 0; i < h.num_vertices; i++) + { + const gpc_vertex& s = m_vertex_accumulator[i]; + d->x = s.x; + d->y = s.y; + ++d; + } + } + else + { + m_vertex_accumulator.remove_last(); + } + } + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::make_polygon(gpc_polygon& p) + { + free_polygon(p); + if(m_contour_accumulator.size()) + { + p.num_contours = m_contour_accumulator.size(); + + p.hole = 0; + p.contour = pod_allocator::allocate(p.num_contours); + + int i; + gpc_vertex_list* pv = p.contour; + for(i = 0; i < p.num_contours; i++) + { + const contour_header_type& h = m_contour_accumulator[i]; + pv->num_vertices = h.num_vertices; + pv->vertex = h.vertices; + ++pv; + } + } + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::start_extracting() + { + m_status = status_move_to; + m_contour = -1; + m_vertex = -1; + } + + + //------------------------------------------------------------------------ + template + bool conv_gpc::next_contour() + { + if(++m_contour < m_result.num_contours) + { + m_vertex = -1; + return true; + } + return false; + } + + + //------------------------------------------------------------------------ + template + inline bool conv_gpc::next_vertex(double* x, double* y) + { + const gpc_vertex_list& vlist = m_result.contour[m_contour]; + if(++m_vertex < vlist.num_vertices) + { + const gpc_vertex& v = vlist.vertex[m_vertex]; + *x = v.x; + *y = v.y; + return true; + } + return false; + } + + + //------------------------------------------------------------------------ + template + void conv_gpc::rewind(unsigned path_id) + { + free_result(); + m_src_a->rewind(path_id); + m_src_b->rewind(path_id); + add(*m_src_a, m_poly_a); + add(*m_src_b, m_poly_b); + switch(m_operation) + { + case gpc_or: + gpc_polygon_clip(GPC_UNION, + &m_poly_a, + &m_poly_b, + &m_result); + break; + + case gpc_and: + gpc_polygon_clip(GPC_INT, + &m_poly_a, + &m_poly_b, + &m_result); + break; + + case gpc_xor: + gpc_polygon_clip(GPC_XOR, + &m_poly_a, + &m_poly_b, + &m_result); + break; + + case gpc_a_minus_b: + gpc_polygon_clip(GPC_DIFF, + &m_poly_a, + &m_poly_b, + &m_result); + break; + + case gpc_b_minus_a: + gpc_polygon_clip(GPC_DIFF, + &m_poly_b, + &m_poly_a, + &m_result); + break; + } + start_extracting(); + } + + + //------------------------------------------------------------------------ + template + unsigned conv_gpc::vertex(double* x, double* y) + { + if(m_status == status_move_to) + { + if(next_contour()) + { + if(next_vertex(x, y)) + { + m_status = status_line_to; + return path_cmd_move_to; + } + m_status = status_stop; + return path_cmd_end_poly | path_flags_close; + } + } + else + { + if(next_vertex(x, y)) + { + return path_cmd_line_to; + } + else + { + m_status = status_move_to; + } + return path_cmd_end_poly | path_flags_close; + } + return path_cmd_stop; + } + + +} + + +#endif diff --git a/kiva/agg/agg-24/include/agg_conv_transform.h b/kiva/agg/agg-24/include/agg_conv_transform.h index 64fddcd8b..3cc4c0a1d 100644 --- a/kiva/agg/agg-24/include/agg_conv_transform.h +++ b/kiva/agg/agg-24/include/agg_conv_transform.h @@ -29,7 +29,7 @@ namespace agg24 template class conv_transform { public: - conv_transform(VertexSource& source, const Transformer& tr) : + conv_transform(VertexSource& source, Transformer& tr) : m_source(&source), m_trans(&tr) {} void attach(VertexSource& source) { m_source = &source; } @@ -48,7 +48,7 @@ namespace agg24 return cmd; } - void transformer(const Transformer& tr) + void transformer(Transformer& tr) { m_trans = &tr; } @@ -59,7 +59,7 @@ namespace agg24 operator = (const conv_transform&); VertexSource* m_source; - const Transformer* m_trans; + Transformer* m_trans; }; diff --git a/kiva/agg/agg-24/include/agg_conv_unclose_polygon.h b/kiva/agg/agg-24/include/agg_conv_unclose_polygon.h index 46b3a2720..203e3008e 100644 --- a/kiva/agg/agg-24/include/agg_conv_unclose_polygon.h +++ b/kiva/agg/agg-24/include/agg_conv_unclose_polygon.h @@ -24,7 +24,7 @@ namespace agg24 template class conv_unclose_polygon { public: - conv_unclose_polygon(VertexSource& vs) : m_source(&vs) {} + explicit conv_unclose_polygon(VertexSource& vs) : m_source(&vs) {} void attach(VertexSource& source) { m_source = &source; } void rewind(unsigned path_id) diff --git a/kiva/agg/agg-24/include/agg_curves.h b/kiva/agg/agg-24/include/agg_curves.h index 105d49283..a55a9a35d 100644 --- a/kiva/agg/agg-24/include/agg_curves.h +++ b/kiva/agg/agg-24/include/agg_curves.h @@ -152,7 +152,6 @@ namespace agg24 double m_approximation_scale; double m_distance_tolerance_square; - double m_distance_tolerance_manhattan; double m_angle_tolerance; unsigned m_count; pod_bvector m_points; @@ -464,7 +463,6 @@ namespace agg24 double m_approximation_scale; double m_distance_tolerance_square; - double m_distance_tolerance_manhattan; double m_angle_tolerance; double m_cusp_limit; unsigned m_count; diff --git a/kiva/agg/agg-24/include/agg_font_cache_manager.h b/kiva/agg/agg-24/include/agg_font_cache_manager.h index b6acc4744..ba33b37c1 100644 --- a/kiva/agg/agg-24/include/agg_font_cache_manager.h +++ b/kiva/agg/agg-24/include/agg_font_cache_manager.h @@ -275,6 +275,12 @@ namespace agg24 m_last_glyph(0) {} + //-------------------------------------------------------------------- + void reset_last_glyph() + { + m_prev_glyph = m_last_glyph = 0; + } + //-------------------------------------------------------------------- const glyph_cache* glyph(unsigned glyph_code) { diff --git a/kiva/agg/agg-24/include/agg_font_cache_manager2.h b/kiva/agg/agg-24/include/agg_font_cache_manager2.h new file mode 100644 index 000000000..2a89d7e3f --- /dev/null +++ b/kiva/agg/agg-24/include/agg_font_cache_manager2.h @@ -0,0 +1,311 @@ +//---------------------------------------------------------------------------- +// 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_FONT_CACHE_MANAGER2_INCLUDED +#define AGG_FONT_CACHE_MANAGER2_INCLUDED + +#include +#include +#include +#include "agg_array.h" + +namespace agg24 { + +namespace fman { + //---------------------------------------------------------glyph_data_type + enum glyph_data_type + { + glyph_data_invalid = 0, + glyph_data_mono = 1, + glyph_data_gray8 = 2, + glyph_data_outline = 3 + }; + + + //-------------------------------------------------------------cached_glyph + struct cached_glyph + { + void * cached_font; + unsigned glyph_code; + unsigned glyph_index; + int8u* data; + unsigned data_size; + glyph_data_type data_type; + rect_i bounds; + double advance_x; + double advance_y; + }; + + + //--------------------------------------------------------------cached_glyphs + class cached_glyphs + { + public: + enum block_size_e { block_size = 16384-16 }; + + //-------------------------------------------------------------------- + cached_glyphs() + : m_allocator(block_size) + { memset(m_glyphs, 0, sizeof(m_glyphs)); } + + //-------------------------------------------------------------------- + const cached_glyph* find_glyph(unsigned glyph_code) const + { + unsigned msb = (glyph_code >> 8) & 0xFF; + if(m_glyphs[msb]) + { + return m_glyphs[msb][glyph_code & 0xFF]; + } + return 0; + } + + //-------------------------------------------------------------------- + cached_glyph* cache_glyph( + void * cached_font, + unsigned glyph_code, + unsigned glyph_index, + unsigned data_size, + glyph_data_type data_type, + const rect_i& bounds, + double advance_x, + double advance_y) + { + unsigned msb = (glyph_code >> 8) & 0xFF; + if(m_glyphs[msb] == 0) + { + m_glyphs[msb] = + (cached_glyph**)m_allocator.allocate(sizeof(cached_glyph*) * 256, + sizeof(cached_glyph*)); + memset(m_glyphs[msb], 0, sizeof(cached_glyph*) * 256); + } + + unsigned lsb = glyph_code & 0xFF; + if(m_glyphs[msb][lsb]) return 0; // Already exists, do not overwrite + + cached_glyph* glyph = + (cached_glyph*)m_allocator.allocate(sizeof(cached_glyph), + sizeof(double)); + + glyph->cached_font = cached_font; + glyph->glyph_code = glyph_code; + glyph->glyph_index = glyph_index; + glyph->data = m_allocator.allocate(data_size); + glyph->data_size = data_size; + glyph->data_type = data_type; + glyph->bounds = bounds; + glyph->advance_x = advance_x; + glyph->advance_y = advance_y; + return m_glyphs[msb][lsb] = glyph; + } + + private: + block_allocator m_allocator; + cached_glyph** m_glyphs[256]; + }; + + + + //------------------------------------------------------------------------ + enum glyph_rendering + { + glyph_ren_native_mono, + glyph_ren_native_gray8, + glyph_ren_outline, + glyph_ren_agg_mono, + glyph_ren_agg_gray8 + }; + + + + + //------------------------------------------------------font_cache_manager + template class font_cache_manager + { + public: + typedef FontEngine font_engine_type; + typedef font_cache_manager self_type; + typedef typename font_engine_type::path_adaptor_type path_adaptor_type; + typedef typename font_engine_type::gray8_adaptor_type gray8_adaptor_type; + typedef typename gray8_adaptor_type::embedded_scanline gray8_scanline_type; + typedef typename font_engine_type::mono_adaptor_type mono_adaptor_type; + typedef typename mono_adaptor_type::embedded_scanline mono_scanline_type; + + struct cached_font + { + cached_font( + font_engine_type& engine, + typename FontEngine::loaded_face *face, + double height, + double width, + bool hinting, + glyph_rendering rendering ) + : m_engine( engine ) + , m_face( face ) + , m_height( height ) + , m_width( width ) + , m_hinting( hinting ) + , m_rendering( rendering ) + { + select_face(); + m_face_height=m_face->height(); + m_face_width=m_face->width(); + m_face_ascent=m_face->ascent(); + m_face_descent=m_face->descent(); + m_face_ascent_b=m_face->ascent_b(); + m_face_descent_b=m_face->descent_b(); + } + + double height() const + { + return m_face_height; + } + + double width() const + { + return m_face_width; + } + + double ascent() const + { + return m_face_ascent; + } + + double descent() const + { + return m_face_descent; + } + + double ascent_b() const + { + return m_face_ascent_b; + } + + double descent_b() const + { + return m_face_descent_b; + } + + bool add_kerning( const cached_glyph *first, const cached_glyph *second, double* x, double* y) + { + if( !first || !second ) + return false; + select_face(); + return m_face->add_kerning( + first->glyph_index, second->glyph_index, x, y ); + } + + void select_face() + { + m_face->select_instance( m_height, m_width, m_hinting, m_rendering ); + } + + const cached_glyph *get_glyph(unsigned cp) + { + const cached_glyph *glyph=m_glyphs.find_glyph(cp); + if( glyph==0 ) + { + typename FontEngine::prepared_glyph prepared; + select_face(); + bool success=m_face->prepare_glyph(cp, &prepared); + if( success ) + { + glyph=m_glyphs.cache_glyph( + this, + prepared.glyph_code, + prepared.glyph_index, + prepared.data_size, + prepared.data_type, + prepared.bounds, + prepared.advance_x, + prepared.advance_y ); + assert( glyph!=0 ); + m_face->write_glyph_to(&prepared,glyph->data); + } + } + return glyph; + } + + font_engine_type& m_engine; + typename FontEngine::loaded_face *m_face; + double m_height; + double m_width; + bool m_hinting; + glyph_rendering m_rendering; + double m_face_height; + double m_face_width; + double m_face_ascent; + double m_face_descent; + double m_face_ascent_b; + double m_face_descent_b; + cached_glyphs m_glyphs; + }; + + //-------------------------------------------------------------------- + font_cache_manager(font_engine_type& engine, unsigned max_fonts=32) + :m_engine(engine) + { } + + //-------------------------------------------------------------------- + void init_embedded_adaptors(const cached_glyph* gl, + double x, double y, + double scale=1.0) + { + if(gl) + { + switch(gl->data_type) + { + default: return; + case glyph_data_mono: + m_mono_adaptor.init(gl->data, gl->data_size, x, y); + break; + + case glyph_data_gray8: + m_gray8_adaptor.init(gl->data, gl->data_size, x, y); + break; + + case glyph_data_outline: + m_path_adaptor.init(gl->data, gl->data_size, x, y, scale); + break; + } + } + } + + + //-------------------------------------------------------------------- + path_adaptor_type& path_adaptor() { return m_path_adaptor; } + gray8_adaptor_type& gray8_adaptor() { return m_gray8_adaptor; } + gray8_scanline_type& gray8_scanline() { return m_gray8_scanline; } + mono_adaptor_type& mono_adaptor() { return m_mono_adaptor; } + mono_scanline_type& mono_scanline() { return m_mono_scanline; } + + + private: + //-------------------------------------------------------------------- + font_cache_manager(const self_type&); + const self_type& operator = (const self_type&); + + font_engine_type& m_engine; + path_adaptor_type m_path_adaptor; + gray8_adaptor_type m_gray8_adaptor; + gray8_scanline_type m_gray8_scanline; + mono_adaptor_type m_mono_adaptor; + mono_scanline_type m_mono_scanline; + }; + +} +} + +#endif + diff --git a/kiva/agg/agg-24/include/agg_gamma_functions.h b/kiva/agg/agg-24/include/agg_gamma_functions.h index 643460bf0..c85f40192 100644 --- a/kiva/agg/agg-24/include/agg_gamma_functions.h +++ b/kiva/agg/agg-24/include/agg_gamma_functions.h @@ -115,6 +115,15 @@ namespace agg24 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/kiva/agg/agg-24/include/agg_gamma_lut.h b/kiva/agg/agg-24/include/agg_gamma_lut.h index bf4976861..a793dd3a9 100644 --- a/kiva/agg/agg-24/include/agg_gamma_lut.h +++ b/kiva/agg/agg-24/include/agg_gamma_lut.h @@ -18,6 +18,7 @@ #include #include "agg_basics.h" +#include "agg_gamma_functions.h" namespace agg24 { @@ -116,6 +117,189 @@ namespace agg24 HiResT* m_dir_gamma; LoResT* m_inv_gamma; }; + + // + // sRGB support classes + // + + // Optimized sRGB lookup table. The direct conversion (sRGB to linear) + // is a straightforward lookup. The inverse conversion (linear to sRGB) + // is implemented using binary search. + template + class sRGB_lut_base + { + public: + LinearType dir(int8u v) const + { + return m_dir_table[v]; + } + + int8u inv(LinearType v) const + { + // Unrolled binary search. + int8u x = 0; + if (v > m_inv_table[128]) x = 128; + if (v > m_inv_table[x + 64]) x += 64; + if (v > m_inv_table[x + 32]) x += 32; + if (v > m_inv_table[x + 16]) x += 16; + if (v > m_inv_table[x + 8]) x += 8; + if (v > m_inv_table[x + 4]) x += 4; + if (v > m_inv_table[x + 2]) x += 2; + if (v > m_inv_table[x + 1]) x += 1; + return x; + } + + protected: + LinearType m_dir_table[256]; + LinearType m_inv_table[256]; + + // Only derived classes may instantiate. + sRGB_lut_base() + { + } + }; + + // sRGB_lut - implements sRGB conversion for the various types. + // Base template is undefined, specializations are provided below. + template + class sRGB_lut; + + template<> + class sRGB_lut : public sRGB_lut_base + { + public: + sRGB_lut() + { + // Generate lookup tables. + m_dir_table[0] = 0; + m_inv_table[0] = 0; + for (unsigned i = 1; i <= 255; ++i) + { + // Floating-point RGB is in range [0,1]. + m_dir_table[i] = float(sRGB_to_linear(i / 255.0)); + m_inv_table[i] = float(sRGB_to_linear((i - 0.5) / 255.0)); + } + } + }; + + template<> + class sRGB_lut : public sRGB_lut_base + { + public: + sRGB_lut() + { + // Generate lookup tables. + m_dir_table[0] = 0; + m_inv_table[0] = 0; + for (unsigned i = 1; i <= 255; ++i) + { + // 16-bit RGB is in range [0,65535]. + m_dir_table[i] = uround(65535.0 * sRGB_to_linear(i / 255.0)); + m_inv_table[i] = uround(65535.0 * sRGB_to_linear((i - 0.5) / 255.0)); + } + } + }; + + template<> + class sRGB_lut : public sRGB_lut_base + { + public: + sRGB_lut() + { + // Generate lookup tables. + m_dir_table[0] = 0; + m_inv_table[0] = 0; + for (unsigned i = 1; i <= 255; ++i) + { + // 8-bit RGB is handled with simple bidirectional lookup tables. + 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 inv(int8u v) const + { + // In this case, the inverse transform is a simple lookup. + return m_inv_table[v]; + } + }; + + // Common base class for sRGB_conv objects. Defines an internal + // sRGB_lut object so that users don't have to. + template + 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 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 + sRGB_lut sRGB_conv_base::lut; + + // Wrapper for sRGB-linear conversion. + // Base template is undefined, specializations are provided below. + template + class sRGB_conv; + + template<> + class sRGB_conv : public sRGB_conv_base + { + public: + static float alpha_from_sRGB(int8u x) + { + return float(x / 255.0); + } + + static int8u alpha_to_sRGB(float x) + { + if (x <= 0) return 0; + else if (x >= 1) return 255; + else return int8u(0.5 + x * 255); + } + }; + + template<> + class sRGB_conv : public sRGB_conv_base + { + 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 : public sRGB_conv_base + { + public: + static int8u alpha_from_sRGB(int8u x) + { + return x; + } + + static int8u alpha_to_sRGB(int8u x) + { + return x; + } + }; } #endif diff --git a/kiva/agg/agg-24/include/agg_gradient_lut.h b/kiva/agg/agg-24/include/agg_gradient_lut.h new file mode 100644 index 000000000..3e9deab6c --- /dev/null +++ b/kiva/agg/agg-24/include/agg_gradient_lut.h @@ -0,0 +1,244 @@ +//---------------------------------------------------------------------------- +// 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_GRADIENT_LUT_INCLUDED +#define AGG_GRADIENT_LUT_INCLUDED + +#include "agg_array.h" +#include "agg_dda_line.h" +#include "agg_color_rgba.h" +#include "agg_color_gray.h" + +namespace agg24 +{ + + //======================================================color_interpolator + template struct color_interpolator + { + public: + typedef ColorT color_type; + + color_interpolator(const color_type& c1, + const color_type& c2, + unsigned len) : + m_c1(c1), + m_c2(c2), + m_len(len), + m_count(0) + {} + + void operator ++ () + { + ++m_count; + } + + color_type color() const + { + return m_c1.gradient(m_c2, double(m_count) / m_len); + } + + private: + color_type m_c1; + color_type m_c2; + unsigned m_len; + unsigned m_count; + }; + + //======================================================================== + // Fast specialization for rgba8 + template<> struct color_interpolator + { + public: + typedef rgba8 color_type; + + color_interpolator(const color_type& c1, + const color_type& c2, + unsigned len) : + r(c1.r, c2.r, len), + g(c1.g, c2.g, len), + b(c1.b, c2.b, len), + a(c1.a, c2.a, len) + {} + + void operator ++ () + { + ++r; ++g; ++b; ++a; + } + + color_type color() const + { + return color_type(r.y(), g.y(), b.y(), a.y()); + } + + private: + agg24::dda_line_interpolator<14> r, g, b, a; + }; + + //======================================================================== + // Fast specialization for gray8 + template<> struct color_interpolator + { + public: + typedef gray8 color_type; + + color_interpolator(const color_type& c1, + const color_type& c2, + unsigned len) : + v(c1.v, c2.v, len), + a(c1.a, c2.a, len) + {} + + void operator ++ () + { + ++v; ++a; + } + + color_type color() const + { + return color_type(v.y(), a.y()); + } + + private: + agg24::dda_line_interpolator<14> v,a; + }; + + //============================================================gradient_lut + template class gradient_lut + { + public: + typedef ColorInterpolator interpolator_type; + typedef typename interpolator_type::color_type color_type; + enum { color_lut_size = ColorLutSize }; + + //-------------------------------------------------------------------- + gradient_lut() : m_color_lut(color_lut_size) {} + + // Build Gradient Lut + // First, call remove_all(), then add_color() at least twice, + // then build_lut(). Argument "offset" in add_color must be + // in range [0...1] and defines a color stop as it is described + // in SVG specification, section Gradients and Patterns. + // The simplest linear gradient is: + // gradient_lut.add_color(0.0, start_color); + // gradient_lut.add_color(1.0, end_color); + //-------------------------------------------------------------------- + void remove_all(); + void add_color(double offset, const color_type& color); + void build_lut(); + + // Size-index Interface. This class can be used directly as the + // ColorF in span_gradient. All it needs is two access methods + // size() and operator []. + //-------------------------------------------------------------------- + static unsigned size() + { + return color_lut_size; + } + const color_type& operator [] (unsigned i) const + { + return m_color_lut[i]; + } + + private: + //-------------------------------------------------------------------- + struct color_point + { + double offset; + color_type color; + + color_point() {} + color_point(double off, const color_type& c) : + offset(off), color(c) + { + if(offset < 0.0) offset = 0.0; + if(offset > 1.0) offset = 1.0; + } + }; + typedef agg24::pod_bvector color_profile_type; + typedef agg24::pod_array color_lut_type; + + static bool offset_less(const color_point& a, const color_point& b) + { + return a.offset < b.offset; + } + static bool offset_equal(const color_point& a, const color_point& b) + { + return a.offset == b.offset; + } + + //-------------------------------------------------------------------- + color_profile_type m_color_profile; + color_lut_type m_color_lut; + }; + + + + //------------------------------------------------------------------------ + template + void gradient_lut::remove_all() + { + m_color_profile.remove_all(); + } + + //------------------------------------------------------------------------ + template + void gradient_lut::add_color(double offset, const color_type& color) + { + m_color_profile.add(color_point(offset, color)); + } + + //------------------------------------------------------------------------ + template + void gradient_lut::build_lut() + { + quick_sort(m_color_profile, offset_less); + m_color_profile.cut_at(remove_duplicates(m_color_profile, offset_equal)); + if(m_color_profile.size() >= 2) + { + unsigned i; + unsigned start = uround(m_color_profile[0].offset * color_lut_size); + unsigned end; + color_type c = m_color_profile[0].color; + for(i = 0; i < start; i++) + { + m_color_lut[i] = c; + } + for(i = 1; i < m_color_profile.size(); i++) + { + end = uround(m_color_profile[i].offset * color_lut_size); + interpolator_type ci(m_color_profile[i-1].color, + m_color_profile[i ].color, + end - start + 1); + while(start < end) + { + m_color_lut[start] = ci.color(); + ++ci; + ++start; + } + } + c = m_color_profile.last().color; + for(; end < m_color_lut.size(); end++) + { + m_color_lut[end] = c; + } + } + } +} + + + + +#endif diff --git a/kiva/agg/agg-24/include/agg_gsv_text.h b/kiva/agg/agg-24/include/agg_gsv_text.h index 04297fba8..b4f12ff98 100644 --- a/kiva/agg/agg-24/include/agg_gsv_text.h +++ b/kiva/agg/agg-24/include/agg_gsv_text.h @@ -54,6 +54,8 @@ namespace agg24 void start_point(double x, double y); void text(const char* text); + double text_width(); + void rewind(unsigned path_id); unsigned vertex(double* x, double* y); @@ -110,7 +112,7 @@ namespace agg24 template class gsv_text_outline { public: - gsv_text_outline(gsv_text& text, const Transformer& trans) : + gsv_text_outline(gsv_text& text, Transformer& trans) : m_polyline(text), m_trans(m_polyline, trans) { diff --git a/kiva/agg/agg-24/include/agg_image_accessors.h b/kiva/agg/agg-24/include/agg_image_accessors.h index b84b5b2dd..dba9f3391 100644 --- a/kiva/agg/agg-24/include/agg_image_accessors.h +++ b/kiva/agg/agg-24/include/agg_image_accessors.h @@ -32,13 +32,14 @@ namespace agg24 enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_clip() {} - image_accessor_clip(const pixfmt_type& pixf, const color_type& bk) : + explicit image_accessor_clip(pixfmt_type& pixf, + const color_type& bk) : m_pixf(&pixf) { pixfmt_type::make_pix(m_bk_buf, bk); } - void attach(const pixfmt_type& pixf) + void attach(pixfmt_type& pixf) { m_pixf = &pixf; } @@ -64,9 +65,8 @@ namespace agg24 { m_x = m_x0 = x; m_y = y; - // comparison between signed and unsigned if(y >= 0 && y < (int)m_pixf->height() && - x >= 0 && (int)(x+len) <= (int)m_pixf->width()) + x >= 0 && x+(int)len <= (int)m_pixf->width()) { return m_pix_ptr = m_pixf->pix_ptr(x, y); } @@ -96,7 +96,7 @@ namespace agg24 private: const pixfmt_type* m_pixf; - int8u m_bk_buf[4]; + int8u m_bk_buf[pix_width]; int m_x, m_x0, m_y; const int8u* m_pix_ptr; }; @@ -115,9 +115,11 @@ namespace agg24 enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_no_clip() {} - image_accessor_no_clip(const pixfmt_type& pixf) : m_pixf(&pixf) {} + explicit image_accessor_no_clip(pixfmt_type& pixf) : + m_pixf(&pixf) + {} - void attach(const pixfmt_type& pixf) + void attach(pixfmt_type& pixf) { m_pixf = &pixf; } @@ -160,9 +162,11 @@ namespace agg24 enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_clone() {} - image_accessor_clone(const pixfmt_type& pixf) : m_pixf(&pixf) {} + explicit image_accessor_clone(pixfmt_type& pixf) : + m_pixf(&pixf) + {} - void attach(const pixfmt_type& pixf) + void attach(pixfmt_type& pixf) { m_pixf = &pixf; } @@ -234,13 +238,13 @@ namespace agg24 enum pix_width_e { pix_width = pixfmt_type::pix_width }; image_accessor_wrap() {} - image_accessor_wrap(const pixfmt_type& pixf) : + explicit image_accessor_wrap(pixfmt_type& pixf) : m_pixf(&pixf), m_wrap_x(pixf.width()), m_wrap_y(pixf.height()) {} - void attach(const pixfmt_type& pixf) + void attach(pixfmt_type& pixf) { m_pixf = &pixf; } @@ -248,7 +252,7 @@ namespace agg24 AGG_INLINE const int8u* span(int x, int y, unsigned) { m_x = x; - m_row_ptr = m_pixf->row_ptr(m_wrap_y(y)); + m_row_ptr = m_pixf->pix_ptr(0, m_wrap_y(y)); return m_row_ptr + m_wrap_x(x) * pix_width; } @@ -260,7 +264,7 @@ namespace agg24 AGG_INLINE const int8u* next_y() { - m_row_ptr = m_pixf->row_ptr(++m_wrap_y); + m_row_ptr = m_pixf->pix_ptr(0, ++m_wrap_y); return m_row_ptr + m_wrap_x(m_x) * pix_width; } diff --git a/kiva/agg/agg-24/include/agg_math.h b/kiva/agg/agg-24/include/agg_math.h index afe01c3c1..42aa63bb7 100644 --- a/kiva/agg/agg-24/include/agg_math.h +++ b/kiva/agg/agg-24/include/agg_math.h @@ -41,7 +41,6 @@ namespace agg24 return (x - x2) * (y2 - y1) - (y - y2) * (x2 - x1); } - //--------------------------------------------------------point_in_triangle AGG_INLINE bool point_in_triangle(double x1, double y1, double x2, double y2, @@ -54,7 +53,6 @@ namespace agg24 return cp1 == cp2 && cp2 == cp3 && cp3 == cp1; } - //-----------------------------------------------------------calc_distance AGG_INLINE double calc_distance(double x1, double y1, double x2, double y2) { @@ -63,6 +61,13 @@ namespace agg24 return sqrt(dx * dx + dy * dy); } + //--------------------------------------------------------calc_sq_distance + AGG_INLINE double calc_sq_distance(double x1, double y1, double x2, double y2) + { + double dx = x2-x1; + double dy = y2-y1; + return dx * dx + dy * dy; + } //------------------------------------------------calc_line_point_distance AGG_INLINE double calc_line_point_distance(double x1, double y1, @@ -79,6 +84,53 @@ namespace agg24 return ((x - x2) * dy - (y - y2) * dx) / d; } + //-------------------------------------------------------calc_line_point_u + AGG_INLINE double calc_segment_point_u(double x1, double y1, + double x2, double y2, + double x, double y) + { + double dx = x2 - x1; + double dy = y2 - y1; + + if(dx == 0 && dy == 0) + { + return 0; + } + + double pdx = x - x1; + double pdy = y - y1; + + return (pdx * dx + pdy * dy) / (dx * dx + dy * dy); + } + + //---------------------------------------------calc_line_point_sq_distance + AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, + double x2, double y2, + double x, double y, + double u) + { + if(u <= 0) + { + return calc_sq_distance(x, y, x1, y1); + } + else + if(u >= 1) + { + return calc_sq_distance(x, y, x2, y2); + } + return calc_sq_distance(x, y, x1 + u * (x2 - x1), y1 + u * (y2 - y1)); + } + + //---------------------------------------------calc_line_point_sq_distance + AGG_INLINE double calc_segment_point_sq_distance(double x1, double y1, + double x2, double y2, + double x, double y) + { + return + calc_segment_point_sq_distance( + x1, y1, x2, y2, x, y, + calc_segment_point_u(x1, y1, x2, y2, x, y)); + } //-------------------------------------------------------calc_intersection AGG_INLINE bool calc_intersection(double ax, double ay, double bx, double by, @@ -94,7 +146,6 @@ namespace agg24 return true; } - //-----------------------------------------------------intersection_exists AGG_INLINE bool intersection_exists(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) @@ -122,7 +173,6 @@ namespace agg24 //return ua >= 0.0 && ua <= 1.0 && ub >= 0.0 && ub <= 1.0; } - //--------------------------------------------------------calc_orthogonal AGG_INLINE void calc_orthogonal(double thickness, double x1, double y1, @@ -132,11 +182,10 @@ namespace agg24 double dx = x2 - x1; double dy = y2 - y1; double d = sqrt(dx*dx + dy*dy); - *x = thickness * dy / d; - *y = thickness * dx / d; + *x = thickness * dy / d; + *y = -thickness * dx / d; } - //--------------------------------------------------------dilate_triangle AGG_INLINE void dilate_triangle(double x1, double y1, double x2, double y2, @@ -161,12 +210,12 @@ namespace agg24 calc_orthogonal(d, x2, y2, x3, y3, &dx2, &dy2); calc_orthogonal(d, x3, y3, x1, y1, &dx3, &dy3); } - *x++ = x1 + dx1; *y++ = y1 - dy1; - *x++ = x2 + dx1; *y++ = y2 - dy1; - *x++ = x2 + dx2; *y++ = y2 - dy2; - *x++ = x3 + dx2; *y++ = y3 - dy2; - *x++ = x3 + dx3; *y++ = y3 - dy3; - *x++ = x1 + dx3; *y++ = y1 - dy3; + *x++ = x1 + dx1; *y++ = y1 + dy1; + *x++ = x2 + dx1; *y++ = y2 + dy1; + *x++ = x2 + dx2; *y++ = y2 + dy2; + *x++ = x3 + dx2; *y++ = y3 + dy2; + *x++ = x3 + dx3; *y++ = y3 + dy3; + *x++ = x1 + dx3; *y++ = y1 + dy3; } //------------------------------------------------------calc_triangle_area @@ -177,7 +226,6 @@ namespace agg24 return (x1*y2 - x2*y1 + x2*y3 - x3*y2 + x3*y1 - x1*y3) * 0.5; } - //-------------------------------------------------------calc_polygon_area template double calc_polygon_area(const Storage& st) { @@ -274,7 +322,7 @@ namespace agg24 } } - //This is calculation sqrt itself. + //This code calculates the sqrt. bit -= 9; if(bit > 0) { diff --git a/kiva/agg/agg-24/include/agg_math_stroke.h b/kiva/agg/agg-24/include/agg_math_stroke.h index 7d09287d5..1353e2b6c 100644 --- a/kiva/agg/agg-24/include/agg_math_stroke.h +++ b/kiva/agg/agg-24/include/agg_math_stroke.h @@ -80,12 +80,12 @@ namespace agg24 double inner_miter_limit() const { return m_inner_miter_limit; } double approximation_scale() const { return m_approx_scale; } - void calc_cap(VertexConsumer& out_vertices, + void calc_cap(VertexConsumer& vc, const vertex_dist& v0, const vertex_dist& v1, double len); - void calc_join(VertexConsumer& out_vertices, + void calc_join(VertexConsumer& vc, const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, @@ -93,22 +93,29 @@ namespace agg24 double len2); private: - void calc_arc(VertexConsumer& out_vertices, + 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& out_vertices, + 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 ml); + 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; @@ -122,6 +129,7 @@ namespace agg24 template math_stroke::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), @@ -146,6 +154,7 @@ namespace agg24 m_width_abs = m_width; m_width_sign = 1; } + m_width_eps = m_width / 1024.0; } //----------------------------------------------------------------------- @@ -156,7 +165,7 @@ namespace agg24 //----------------------------------------------------------------------- template - void math_stroke::calc_arc(VC& out_vertices, + void math_stroke::calc_arc(VC& vc, double x, double y, double dx1, double dy1, double dx2, double dy2) @@ -168,7 +177,7 @@ namespace agg24 da = acos(m_width_abs / (m_width_abs + 0.125 / m_approx_scale)) * 2; - out_vertices.add(coord_type(x + dx1, y + dy1)); + add_vertex(vc, x + dx1, y + dy1); if(m_width_sign > 0) { if(a1 > a2) a2 += 2 * pi; @@ -177,8 +186,7 @@ namespace agg24 a1 += da; for(i = 0; i < n; i++) { - out_vertices.add(coord_type(x + cos(a1) * m_width, - y + sin(a1) * m_width)); + add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width); a1 += da; } } @@ -190,28 +198,31 @@ namespace agg24 a1 -= da; for(i = 0; i < n; i++) { - out_vertices.add(coord_type(x + cos(a1) * m_width, - y + sin(a1) * m_width)); + add_vertex(vc, x + cos(a1) * m_width, y + sin(a1) * m_width); a1 -= da; } } - out_vertices.add(coord_type(x + dx2, y + dy2)); + add_vertex(vc, x + dx2, y + dy2); } //----------------------------------------------------------------------- template - void math_stroke::calc_miter(VC& out_vertices, + void math_stroke::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 ml) + double mlimit, + double dbevel) { - double xi = v1.x; - double yi = v1.y; + 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, @@ -221,15 +232,15 @@ namespace agg24 { // Calculation of the intersection succeeded //--------------------- - double d1 = calc_distance(v1.x, v1.y, xi, yi); - double lim = m_width_abs * ml; - if(d1 <= lim) + di = calc_distance(v1.x, v1.y, xi, yi); + if(di <= lim) { // Inside the miter limit //--------------------- - out_vertices.add(coord_type(xi, yi)); + add_vertex(vc, xi, yi); miter_limit_exceeded = false; } + intersection_failed = false; } else { @@ -243,13 +254,13 @@ namespace agg24 //---------------- double x2 = v1.x + dx1; double y2 = v1.y - dy1; - if(((x2 - v0.x)*dy1 - (v0.y - y2)*dx1 < 0.0) != - ((x2 - v2.x)*dy1 - (v2.y - y2)*dx1 < 0.0)) + 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) //----------------- - out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); + add_vertex(vc, v1.x + dx1, v1.y - dy1); miter_limit_exceeded = false; } } @@ -265,22 +276,37 @@ namespace agg24 // we use a simple bevel join instead of // "smart" bevel //------------------- - out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); - out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); + 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(out_vertices, v1.x, v1.y, dx1, -dy1, dx2, -dy2); + calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2); break; default: // If no miter-revert, calculate new dx1, dy1, dx2, dy2 //---------------- - ml *= m_width_sign; - out_vertices.add(coord_type(v1.x + dx1 + dy1 * ml, - v1.y - dy1 + dx1 * ml)); - out_vertices.add(coord_type(v1.x + dx2 - dy2 * ml, - v1.y - dy2 - dx2 * ml)); + 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; } } @@ -288,12 +314,12 @@ namespace agg24 //--------------------------------------------------------stroke_calc_cap template - void math_stroke::calc_cap(VC& out_vertices, + void math_stroke::calc_cap(VC& vc, const vertex_dist& v0, const vertex_dist& v1, double len) { - out_vertices.remove_all(); + vc.remove_all(); double dx1 = (v1.y - v0.y) / len; double dy1 = (v1.x - v0.x) / len; @@ -310,8 +336,8 @@ namespace agg24 dx2 = dy1 * m_width_sign; dy2 = dx1 * m_width_sign; } - out_vertices.add(coord_type(v0.x - dx1 - dx2, v0.y + dy1 - dy2)); - out_vertices.add(coord_type(v0.x + dx1 - dx2, v0.y - dy1 - dy2)); + add_vertex(vc, v0.x - dx1 - dx2, v0.y + dy1 - dy2); + add_vertex(vc, v0.x + dx1 - dx2, v0.y - dy1 - dy2); } else { @@ -321,15 +347,15 @@ namespace agg24 int n = int(pi / da); da = pi / (n + 1); - out_vertices.add(coord_type(v0.x - dx1, v0.y + dy1)); + 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++) { - out_vertices.add(coord_type(v0.x + cos(a1) * m_width, - v0.y + sin(a1) * m_width)); + add_vertex(vc, v0.x + cos(a1) * m_width, + v0.y + sin(a1) * m_width); a1 += da; } } @@ -339,81 +365,81 @@ namespace agg24 a1 -= da; for(i = 0; i < n; i++) { - out_vertices.add(coord_type(v0.x + cos(a1) * m_width, - v0.y + sin(a1) * m_width)); + add_vertex(vc, v0.x + cos(a1) * m_width, + v0.y + sin(a1) * m_width); a1 -= da; } } - out_vertices.add(coord_type(v0.x + dx1, v0.y - dy1)); + add_vertex(vc, v0.x + dx1, v0.y - dy1); } } //----------------------------------------------------------------------- template - void math_stroke::calc_join(VC& out_vertices, + void math_stroke::calc_join(VC& vc, const vertex_dist& v0, const vertex_dist& v1, const vertex_dist& v2, double len1, double len2) { - double dx1, dy1, dx2, dy2; - double d; - - dx1 = m_width * (v1.y - v0.y) / len1; - dy1 = m_width * (v1.x - v0.x) / len1; - - dx2 = m_width * (v2.y - v1.y) / len2; - dy2 = m_width * (v2.x - v1.x) / 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; - out_vertices.remove_all(); + 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 - out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); - out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); + add_vertex(vc, v1.x + dx1, v1.y - dy1); + add_vertex(vc, v1.x + dx2, v1.y - dy2); break; case inner_miter: - calc_miter(out_vertices, + calc_miter(vc, v0, v1, v2, dx1, dy1, dx2, dy2, miter_join_revert, - m_inner_miter_limit); + 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) { - d = (dx1-dx2) * (dx1-dx2) + (dy1-dy2) * (dy1-dy2); - if(d < len1 * len1 && d < len2 * len2) + calc_miter(vc, + v0, v1, v2, dx1, dy1, dx2, dy2, + miter_join_revert, + limit, 0); + } + else + { + if(m_inner_join == inner_jag) { - calc_miter(out_vertices, - v0, v1, v2, dx1, dy1, dx2, dy2, - miter_join_revert, - m_inner_miter_limit); + 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 { - if(m_inner_join == inner_jag) - { - out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); - out_vertices.add(coord_type(v1.x, v1.y )); - out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); - } - else - { - out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); - out_vertices.add(coord_type(v1.x, v1.y )); - calc_arc(out_vertices, v1.x, v1.y, dx2, -dy2, dx1, -dy1); - out_vertices.add(coord_type(v1.x, v1.y )); - out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); - } + 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; @@ -423,11 +449,18 @@ namespace agg24 { // Outer join //--------------- - line_join_e lj = m_line_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 collonear segments. If there's no + // 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. // @@ -436,40 +469,50 @@ namespace agg24 // 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 switch - // to the miter join. + // 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. One can safely comment - // out this "if". + // the same as in round joins and caps. You can safely comment + // out this entire "if". //------------------- - double dx = (dx1 + dx2) / 2; - double dy = (dy1 + dy2) / 2; - d = m_width_abs - sqrt(dx * dx + dy * dy); - if(d < 0.0625 / m_approx_scale) + if(m_approx_scale * (m_width_abs - dbevel) < m_width_eps) { - lj = miter_join; + 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(lj) + switch(m_line_join) { case miter_join: case miter_join_revert: case miter_join_round: - calc_miter(out_vertices, + calc_miter(vc, v0, v1, v2, dx1, dy1, dx2, dy2, - lj, - m_miter_limit); + m_line_join, + m_miter_limit, + dbevel); break; case round_join: - calc_arc(out_vertices, v1.x, v1.y, dx1, -dy1, dx2, -dy2); + calc_arc(vc, v1.x, v1.y, dx1, -dy1, dx2, -dy2); break; default: // Bevel join - out_vertices.add(coord_type(v1.x + dx1, v1.y - dy1)); - out_vertices.add(coord_type(v1.x + dx2, v1.y - dy2)); + add_vertex(vc, v1.x + dx1, v1.y - dy1); + add_vertex(vc, v1.x + dx2, v1.y - dy2); break; } } diff --git a/kiva/agg/agg-24/include/agg_path_storage.h b/kiva/agg/agg-24/include/agg_path_storage.h index ae76f1f91..5b8dfe95b 100644 --- a/kiva/agg/agg-24/include/agg_path_storage.h +++ b/kiva/agg/agg-24/include/agg_path_storage.h @@ -490,14 +490,14 @@ namespace agg24 m_stop(false) {} - poly_container_reverse_adaptor(const Container& data, bool closed) : + poly_container_reverse_adaptor(Container& data, bool closed) : m_container(&data), m_index(-1), m_closed(closed), m_stop(false) {} - void init(const Container& data, bool closed) + void init(Container& data, bool closed) { m_container = &data; m_index = m_container->size() - 1; @@ -531,7 +531,7 @@ namespace agg24 } private: - const Container* m_container; + Container* m_container; int m_index; bool m_closed; bool m_stop; @@ -769,7 +769,7 @@ namespace agg24 while(!is_stop(cmd = vs.vertex(&x, &y))) { m_vertices.add_vertex(x, y, is_move_to(cmd) ? - path_cmd_line_to : + unsigned(path_cmd_line_to) : cmd); } } @@ -795,6 +795,46 @@ namespace agg24 join_path(poly); } + //-------------------------------------------------------------------- + void translate(double dx, double dy, unsigned path_id=0); + void translate_all_paths(double dx, double dy); + + //-------------------------------------------------------------------- + template + void transform(const Trans& trans, unsigned path_id=0) + { + unsigned num_ver = m_vertices.total_vertices(); + for(; path_id < num_ver; path_id++) + { + double x, y; + unsigned cmd = m_vertices.vertex(path_id, &x, &y); + if(is_stop(cmd)) break; + if(is_vertex(cmd)) + { + trans.transform(&x, &y); + m_vertices.modify_vertex(path_id, x, y); + } + } + } + + //-------------------------------------------------------------------- + template + void transform_all_paths(const Trans& trans) + { + unsigned idx; + unsigned num_ver = m_vertices.total_vertices(); + for(idx = 0; idx < num_ver; idx++) + { + double x, y; + if(is_vertex(m_vertices.vertex(idx, &x, &y))) + { + trans.transform(&x, &y); + m_vertices.modify_vertex(idx, x, y); + } + } + } + + private: unsigned perceive_polygon_orientation(unsigned start, unsigned end); @@ -1170,7 +1210,6 @@ namespace agg24 return m_vertices.vertex(m_iterator++, x, y); } - //------------------------------------------------------------------------ template unsigned path_base::perceive_polygon_orientation(unsigned start, @@ -1191,7 +1230,6 @@ namespace agg24 return (area < 0.0) ? path_flags_cw : path_flags_ccw; } - //------------------------------------------------------------------------ template void path_base::invert_polygon(unsigned start, unsigned end) @@ -1235,10 +1273,7 @@ namespace agg24 while(end < m_vertices.total_vertices() && !is_next_poly(m_vertices.command(end))) ++end; - if(end - start > 2) - { - invert_polygon(start, end); - } + invert_polygon(start, end); } //------------------------------------------------------------------------ @@ -1279,7 +1314,6 @@ namespace agg24 return end; } - //------------------------------------------------------------------------ template unsigned path_base::arrange_orientations(unsigned start, @@ -1300,7 +1334,6 @@ namespace agg24 return start; } - //------------------------------------------------------------------------ template void path_base::arrange_orientations_all_paths(path_flags_e orientation) @@ -1315,7 +1348,6 @@ namespace agg24 } } - //------------------------------------------------------------------------ template void path_base::flip_x(double x1, double x2) @@ -1332,7 +1364,6 @@ namespace agg24 } } - //------------------------------------------------------------------------ template void path_base::flip_y(double y1, double y2) @@ -1349,9 +1380,42 @@ namespace agg24 } } + //------------------------------------------------------------------------ + template + void path_base::translate(double dx, double dy, unsigned path_id) + { + unsigned num_ver = m_vertices.total_vertices(); + for(; path_id < num_ver; path_id++) + { + double x, y; + unsigned cmd = m_vertices.vertex(path_id, &x, &y); + if(is_stop(cmd)) break; + if(is_vertex(cmd)) + { + x += dx; + y += dy; + m_vertices.modify_vertex(path_id, x, y); + } + } + } - - + //------------------------------------------------------------------------ + template + void path_base::translate_all_paths(double dx, double dy) + { + unsigned idx; + unsigned num_ver = m_vertices.total_vertices(); + for(idx = 0; idx < num_ver; idx++) + { + double x, y; + if(is_vertex(m_vertices.vertex(idx, &x, &y))) + { + x += dx; + y += dy; + m_vertices.modify_vertex(idx, x, y); + } + } + } //-----------------------------------------------------vertex_stl_storage template class vertex_stl_storage diff --git a/kiva/agg/agg-24/include/agg_pattern_filters_rgba.h b/kiva/agg/agg-24/include/agg_pattern_filters_rgba.h index 1ff9906d4..ad1042e0d 100644 --- a/kiva/agg/agg-24/include/agg_pattern_filters_rgba.h +++ b/kiva/agg/agg-24/include/agg_pattern_filters_rgba.h @@ -67,7 +67,7 @@ namespace agg24 color_type* p, int x, int y) { calc_type r, g, b, a; - r = g = b = a = line_subpixel_scale * line_subpixel_scale / 2; + r = g = b = a = 0; calc_type weight; int x_lr = x >> line_subpixel_shift; @@ -108,15 +108,16 @@ namespace agg24 b += weight * ptr->b; a += weight * ptr->a; - p->r = (value_type)(r >> line_subpixel_shift * 2); - p->g = (value_type)(g >> line_subpixel_shift * 2); - p->b = (value_type)(b >> line_subpixel_shift * 2); - p->a = (value_type)(a >> line_subpixel_shift * 2); + p->r = (value_type)color_type::downshift(r, line_subpixel_shift * 2); + p->g = (value_type)color_type::downshift(g, line_subpixel_shift * 2); + p->b = (value_type)color_type::downshift(b, line_subpixel_shift * 2); + p->a = (value_type)color_type::downshift(a, line_subpixel_shift * 2); } }; typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba8; typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba16; + typedef pattern_filter_bilinear_rgba pattern_filter_bilinear_rgba32; } #endif diff --git a/kiva/agg/agg-24/include/agg_pixfmt_amask_adaptor.h b/kiva/agg/agg-24/include/agg_pixfmt_amask_adaptor.h index 268a55d4c..1213c9651 100644 --- a/kiva/agg/agg-24/include/agg_pixfmt_amask_adaptor.h +++ b/kiva/agg/agg-24/include/agg_pixfmt_amask_adaptor.h @@ -59,12 +59,19 @@ namespace agg24 public: - pixfmt_amask_adaptor(pixfmt_type& pixf, const amask_type& mask) : + pixfmt_amask_adaptor(pixfmt_type& pixf, amask_type& mask) : m_pixf(&pixf), m_mask(&mask), m_span() {} - void attach_pixfmt(pixfmt_type& pixf) { m_pixf = &pixf; } - void attach_alpha_mask(const amask_type& mask) { m_mask = &mask; } + void attach_pixfmt(pixfmt_type& pixf) { m_pixf = &pixf; } + void attach_alpha_mask(amask_type& mask) { m_mask = &mask; } + + //-------------------------------------------------------------------- + template + bool attach_pixfmt(PixFmt2& pixf, int x1, int y1, int x2, int y2) + { + return m_pixf->attach(pixf, x1, y1, x2, y2); + } //-------------------------------------------------------------------- unsigned width() const { return m_pixf->width(); } @@ -172,6 +179,13 @@ namespace agg24 m_pixf->blend_color_hspan(x, y, len, colors, &m_span[0], cover_full); } + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, unsigned len, const color_type* colors) + { + realloc_span(len); + m_mask->fill_vspan(x, y, &m_span[0], len); + m_pixf->blend_color_vspan(x, y, len, colors, &m_span[0], cover_full); + } //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, diff --git a/kiva/agg/agg-24/include/agg_pixfmt_base.h b/kiva/agg/agg-24/include/agg_pixfmt_base.h new file mode 100644 index 000000000..3f6945648 --- /dev/null +++ b/kiva/agg/agg-24/include/agg_pixfmt_base.h @@ -0,0 +1,97 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +#ifndef AGG_PIXFMT_BASE_INCLUDED +#define AGG_PIXFMT_BASE_INCLUDED + +#include "agg_basics.h" +#include "agg_color_gray.h" +#include "agg_color_rgba.h" + +namespace agg24 +{ + struct pixfmt_gray_tag + { + }; + + struct pixfmt_rgb_tag + { + }; + + struct pixfmt_rgba_tag + { + }; + + //--------------------------------------------------------------blender_base + template + 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/kiva/agg/agg-24/include/agg_pixfmt_gray.h b/kiva/agg/agg-24/include/agg_pixfmt_gray.h index a8f0388e0..fd961d6ea 100644 --- a/kiva/agg/agg-24/include/agg_pixfmt_gray.h +++ b/kiva/agg/agg-24/include/agg_pixfmt_gray.h @@ -25,8 +25,7 @@ #define AGG_PIXFMT_GRAY_INCLUDED #include -#include "agg_basics.h" -#include "agg_color_gray.h" +#include "agg_pixfmt_base.h" #include "agg_rendering_buffer.h" namespace agg24 @@ -38,12 +37,22 @@ namespace agg24 typedef ColorT color_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 }; + typedef typename color_type::long_type long_type; - static AGG_INLINE void blend_pix(value_type* p, unsigned cv, - unsigned alpha, unsigned cover=0) + // 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) + { + 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 = (value_type)((((cv - calc_type(*p)) * alpha) + (calc_type(*p) << base_shift)) >> base_shift); + *p = color_type::lerp(*p, cv, alpha); } }; @@ -54,20 +63,21 @@ namespace agg24 typedef ColorT color_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 }; + typedef typename color_type::long_type long_type; - static AGG_INLINE void blend_pix(value_type* p, unsigned cv, - unsigned alpha, unsigned cover) + // 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) { - alpha = color_type::base_mask - alpha; - cover = (cover + 1) << (base_shift - 8); - *p = (value_type)((*p * alpha + cv * cover) >> base_shift); + blend_pix(p, color_type::mult_cover(cv, cover), color_type::mult_cover(alpha, cover)); } - static AGG_INLINE void blend_pix(value_type* p, unsigned cv, - unsigned alpha) + static AGG_INLINE void blend_pix(value_type* p, + value_type cv, value_type alpha) { - *p = (value_type)(((*p * (color_type::base_mask - alpha)) >> base_shift) + cv); + *p = color_type::prelerp(*p, cv, alpha); } }; @@ -112,10 +122,11 @@ namespace agg24 //=================================================pixfmt_alpha_blend_gray - template + template 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; @@ -123,122 +134,239 @@ namespace agg24 typedef int order_type; // A fake one typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; - enum base_scale_e + enum + { + num_components = 1, + pix_width = sizeof(value_type) * Step, + pix_step = Step, + pix_offset = Offset, + }; + struct pixel_type { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(value_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); + } }; private: //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c, - unsigned cover) + AGG_INLINE void blend_pix(pixel_type* p, + value_type v, value_type a, + 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.a) + if (!c.is_transparent()) { - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { - *p = c.v; + p->set(c); } else { - Blender::blend_pix(p, c.v, alpha, cover); + blend_pix(p, c, cover); } } } - - static AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c) + //-------------------------------------------------------------------- + AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) { - if (c.a) + if (!c.is_transparent()) { - if(c.a == base_mask) + if (c.is_opaque()) { - *p = c.v; + p->set(c); } else { - Blender::blend_pix(p, c.v, c.a); + blend_pix(p, c); } } } - public: //-------------------------------------------------------------------- - pixfmt_alpha_blend_gray(rbuf_type& rb) : + explicit pixfmt_alpha_blend_gray(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } + //-------------------------------------------------------------------- + + template + 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(); } //-------------------------------------------------------------------- - const int8u* row_ptr(int y) const + 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) { - return m_rbuf->row_ptr(y); + 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); } //-------------------------------------------------------------------- - const int8u* pix_ptr(int x, int y) const + AGG_INLINE static void write_plain_color(void* p, color_type c) { - return m_rbuf->row_ptr(y) + x * pix_width; + // Grayscale formats are implicitly premultiplied. + c.premultiply(); + pix_value_ptr(p)->set(c); } //-------------------------------------------------------------------- - row_data row(int y) const + AGG_INLINE static color_type read_plain_color(const void* p) { - return m_rbuf->row(y); + return pix_value_ptr(p)->get(); } //-------------------------------------------------------------------- AGG_INLINE static void make_pix(int8u* p, const color_type& c) { - *(value_type*)p = c.v; + ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { - value_type* p = (value_type*)m_rbuf->row(y) + x * Step + Offset; - return color_type(*p); + if (const pixel_type* p = pix_value_ptr(x, y)) + { + return p->get(); + } + return color_type::no_color(); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { - *((value_type*)m_rbuf->row_ptr(x, y, 1) + x * Step + Offset) = c.v; + pix_value_ptr(x, y, 1)->set(c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { - copy_or_blend_pix((value_type*) - m_rbuf->row_ptr(x, y, 1) + x * Step + Offset, - c, - cover); + copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); } - //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; - + pixel_type* p = pix_value_ptr(x, y, len); do { - *p = c.v; - p += Step; + p->set(c); + p = p->next(); } while(--len); } @@ -251,12 +379,9 @@ namespace agg24 { do { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - *p = c.v; + pix_value_ptr(x, y++, 1)->set(c); } - while(--len); + while (--len); } @@ -266,29 +391,27 @@ namespace agg24 const color_type& c, int8u cover) { - if (c.a) + if (!c.is_transparent()) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + pixel_type* p = pix_value_ptr(x, y, len); - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { do { - *p = c.v; - p += Step; + p->set(c); + p = p->next(); } - while(--len); + while (--len); } else { do { - Blender::blend_pix(p, c.v, alpha, cover); - p += Step; + blend_pix(p, c, cover); + p = p->next(); } - while(--len); + while (--len); } } } @@ -300,31 +423,23 @@ namespace agg24 const color_type& c, int8u cover) { - if (c.a) + if (!c.is_transparent()) { - value_type* p; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - *p = c.v; + pix_value_ptr(x, y++, 1)->set(c); } - while(--len); + while (--len); } else { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - Blender::blend_pix(p, c.v, alpha, cover); + blend_pix(pix_value_ptr(x, y++, 1), c, cover); } - while(--len); + while (--len); } } } @@ -336,26 +451,24 @@ namespace agg24 const color_type& c, const int8u* covers) { - if (c.a) + if (!c.is_transparent()) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + pixel_type* p = pix_value_ptr(x, y, len); do { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && *covers == cover_mask) { - *p = c.v; + p->set(c); } else { - Blender::blend_pix(p, c.v, alpha, *covers); + blend_pix(p, c, *covers); } - p += Step; + p = p->next(); ++covers; } - while(--len); + while (--len); } } @@ -366,26 +479,23 @@ namespace agg24 const color_type& c, const int8u* covers) { - if (c.a) + if (!c.is_transparent()) { do { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; + pixel_type* p = pix_value_ptr(x, y++, 1); - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - if(alpha == base_mask) + if (c.is_opaque() && *covers == cover_mask) { - *p = c.v; + p->set(c); } else { - Blender::blend_pix(p, c.v, alpha, *covers); + blend_pix(p, c, *covers); } ++covers; } - while(--len); + while (--len); } } @@ -395,18 +505,29 @@ namespace agg24 unsigned len, const color_type* colors) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + pixel_type* p = pix_value_ptr(x, y, len); do { - *p++ = colors->v; - ++colors; + p->set(*colors++); + p = p->next(); } - while(--len); + while (--len); } + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + pix_value_ptr(x, y++, 1)->set(*colors++); + } + while (--len); + } + //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, @@ -415,51 +536,41 @@ namespace agg24 const int8u* covers, int8u cover) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x * Step + Offset; + pixel_type* p = pix_value_ptr(x, y, len); - if(covers) + if (covers) { do { copy_or_blend_pix(p, *colors++, *covers++); - p += Step; + p = p->next(); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { do { - if(colors->a == base_mask) - { - *p = colors->v; - } - else - { - copy_or_blend_pix(p, *colors); - } - p += Step; - ++colors; + copy_or_blend_pix(p, *colors++); + p = p->next(); } - while(--len); + while (--len); } else { do { copy_or_blend_pix(p, *colors++, cover); - p += Step; + p = p->next(); } - while(--len); + while (--len); } } } - //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, @@ -467,49 +578,31 @@ namespace agg24 const int8u* covers, int8u cover) { - value_type* p; - if(covers) + if (covers) { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - copy_or_blend_pix(p, *colors++, *covers++); + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { do { - 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; + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } - while(--len); + while (--len); } else { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x * Step + Offset; - - copy_or_blend_pix(p, *colors++, cover); + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } - while(--len); + while (--len); } } } @@ -518,22 +611,19 @@ namespace agg24 template 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; - - value_type* p = (value_type*) - m_rbuf->row_ptr(r.x1, y, len) + r.x1 * Step + Offset; - + pixel_type* p = pix_value_ptr(r.x1, y, len); do { - f(p); - p += Step; + f(p->c); + p = p->next(); } - while(--len); + while (--len); } } } @@ -557,8 +647,7 @@ namespace agg24 int xsrc, int ysrc, unsigned len) { - const int8u* p = from.row_ptr(ysrc); - if(p) + if (const int8u* p = from.row_ptr(ysrc)) { memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, @@ -566,19 +655,83 @@ namespace agg24 } } + //-------------------------------------------------------------------- + // Blend from single color, using grayscale surface as alpha channel. + template + void blend_from_color(const SrcPixelFormatRenderer& from, + const color_type& color, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + typedef typename SrcPixelFormatRenderer::color_type src_color_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + + do + { + copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + + //-------------------------------------------------------------------- + // Blend from color table, using grayscale surface as indexes into table. + // Obviously, this only works for integer value types. + template + void blend_from_lut(const SrcPixelFormatRenderer& from, + const color_type* color_lut, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + + do + { + copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + private: rbuf_type* m_rbuf; }; - typedef blender_gray blender_gray8; - typedef blender_gray_pre blender_gray8_pre; - typedef blender_gray blender_gray16; + typedef blender_gray blender_gray8; + typedef blender_gray blender_sgray8; + typedef blender_gray blender_gray16; + typedef blender_gray blender_gray32; + + typedef blender_gray_pre blender_gray8_pre; + typedef blender_gray_pre blender_sgray8_pre; typedef blender_gray_pre blender_gray16_pre; + typedef blender_gray_pre blender_gray32_pre; + + typedef pixfmt_alpha_blend_gray pixfmt_gray8; + typedef pixfmt_alpha_blend_gray pixfmt_sgray8; + typedef pixfmt_alpha_blend_gray pixfmt_gray16; + typedef pixfmt_alpha_blend_gray pixfmt_gray32; - typedef pixfmt_alpha_blend_gray pixfmt_gray8; //----pixfmt_gray8 - typedef pixfmt_alpha_blend_gray pixfmt_gray8_pre; //----pixfmt_gray8_pre - typedef pixfmt_alpha_blend_gray pixfmt_gray16; //----pixfmt_gray16 - typedef pixfmt_alpha_blend_gray pixfmt_gray16_pre; //----pixfmt_gray16_pre + typedef pixfmt_alpha_blend_gray pixfmt_gray8_pre; + typedef pixfmt_alpha_blend_gray pixfmt_sgray8_pre; + typedef pixfmt_alpha_blend_gray pixfmt_gray16_pre; + typedef pixfmt_alpha_blend_gray pixfmt_gray32_pre; } #endif diff --git a/kiva/agg/agg-24/include/agg_pixfmt_rgb.h b/kiva/agg/agg-24/include/agg_pixfmt_rgb.h index 1d9914eaa..17c1fbf33 100644 --- a/kiva/agg/agg-24/include/agg_pixfmt_rgb.h +++ b/kiva/agg/agg-24/include/agg_pixfmt_rgb.h @@ -25,8 +25,7 @@ #define AGG_PIXFMT_RGB_INCLUDED #include -#include "agg_basics.h" -#include "agg_color_rgba.h" +#include "agg_pixfmt_base.h" #include "agg_rendering_buffer.h" namespace agg24 @@ -74,66 +73,73 @@ namespace agg24 //=========================================================blender_rgb - template struct blender_rgb + template + 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; - enum base_scale_e { base_shift = color_type::base_shift }; + typedef typename color_type::long_type long_type; + + // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's + // compositing function. Since the render buffer is opaque we skip the + // initial premultiply and final demultiply. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) + value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { - 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); + blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); } - }; + //-------------------------------------------------------------------- + static AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type alpha) + { + p[Order::R] = color_type::lerp(p[Order::R], cr, alpha); + p[Order::G] = color_type::lerp(p[Order::G], cg, alpha); + p[Order::B] = color_type::lerp(p[Order::B], cb, alpha); + } + }; //======================================================blender_rgb_pre - template struct blender_rgb_pre + template + 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; - enum base_scale_e { base_shift = color_type::base_shift }; + typedef typename color_type::long_type long_type; + + // Blend pixels using the premultiplied form of Alvy-Ray Smith's + // compositing function. //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) + value_type cr, value_type cg, value_type cb, value_type alpha, cover_type 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); + blend_pix(p, + color_type::mult_cover(cr, cover), + color_type::mult_cover(cg, cover), + color_type::mult_cover(cb, cover), + color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha) + value_type cr, value_type cg, value_type cb, value_type 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::R] = color_type::prelerp(p[Order::R], cr, alpha); + p[Order::G] = color_type::prelerp(p[Order::G], cg, alpha); + p[Order::B] = color_type::prelerp(p[Order::B], cb, alpha); } - }; - - //===================================================blender_rgb_gamma - template class blender_rgb_gamma + template + class blender_rgb_gamma : public blender_base { public: typedef ColorT color_type; @@ -141,7 +147,7 @@ namespace agg24 typedef Gamma gamma_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 }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- blender_rgb_gamma() : m_gamma(0) {} @@ -149,16 +155,21 @@ namespace agg24 //-------------------------------------------------------------------- AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) + value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) + { + blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type alpha) { calc_type r = m_gamma->dir(p[Order::R]); calc_type g = m_gamma->dir(p[Order::G]); calc_type b = m_gamma->dir(p[Order::B]); - p[Order::R] = m_gamma->inv((((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); + p[Order::R] = m_gamma->inv(color_type::downscale((m_gamma->dir(cr) - r) * alpha) + r); + p[Order::G] = m_gamma->inv(color_type::downscale((m_gamma->dir(cg) - g) * alpha) + g); + p[Order::B] = m_gamma->inv(color_type::downscale((m_gamma->dir(cb) - b) * alpha) + b); } private: @@ -166,146 +177,263 @@ namespace agg24 }; - - //==================================================pixfmt_alpha_blend_rgb - template class pixfmt_alpha_blend_rgb + template + class pixfmt_alpha_blend_rgb { public: + typedef pixfmt_rgb_tag pixfmt_category; typedef RenBuf rbuf_type; - typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; + typedef typename rbuf_type::row_data row_data; typedef typename blender_type::color_type color_type; typedef typename blender_type::order_type order_type; typedef typename color_type::value_type value_type; typedef typename color_type::calc_type calc_type; - enum base_scale_e + enum { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(value_type) * 3 + num_components = 3, + pix_step = Step, + pix_offset = Offset, + pix_width = sizeof(value_type) * pix_step + }; + struct pixel_type + { + value_type c[num_components]; + + void set(value_type r, value_type g, value_type b) + { + c[order_type::R] = r; + c[order_type::G] = g; + c[order_type::B] = b; + } + + void set(const color_type& color) + { + set(color.r, color.g, color.b); + } + + void get(value_type& r, value_type& g, value_type& b) const + { + r = c[order_type::R]; + g = c[order_type::G]; + b = c[order_type::B]; + } + + color_type get() const + { + return color_type( + c[order_type::R], + c[order_type::G], + c[order_type::B]); + } + + pixel_type* next() + { + return (pixel_type*)(c + pix_step); + } + + const pixel_type* next() const + { + return (const pixel_type*)(c + pix_step); + } + + pixel_type* advance(int n) + { + return (pixel_type*)(c + n * pix_step); + } + + const pixel_type* advance(int n) const + { + return (const pixel_type*)(c + n * pix_step); + } }; private: //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c, - unsigned cover) + AGG_INLINE void blend_pix(pixel_type* p, + value_type r, value_type g, value_type b, value_type a, + unsigned cover) + { + m_blender.blend_pix(p->c, r, g, b, a, cover); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_pix(pixel_type* p, + value_type r, value_type g, value_type b, value_type a) { - if (c.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()) { - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; + p->set(c); } else { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); + blend_pix(p, c, cover); } } } //-------------------------------------------------------------------- - AGG_INLINE void copy_or_blend_pix(value_type* p, - const color_type& c) + AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) { - if (c.a) + if (!c.is_transparent()) { - if(c.a == base_mask) + if (c.is_opaque()) { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; + p->set(c); } else { - m_blender.blend_pix(p, c.r, c.g, c.b, c.a); + blend_pix(p, c); } } } - public: //-------------------------------------------------------------------- - pixfmt_alpha_blend_rgb(rbuf_type& rb) : + explicit pixfmt_alpha_blend_rgb(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } + //-------------------------------------------------------------------- + template + bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) + { + rect_i r(x1, y1, x2, y2); + if (r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) + { + int stride = pixf.stride(); + m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), + (r.x2 - r.x1) + 1, + (r.y2 - r.y1) + 1, + stride); + return true; + } + return false; + } + //-------------------------------------------------------------------- Blender& blender() { return m_blender; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } + AGG_INLINE int stride() const { return m_rbuf->stride(); } + + //-------------------------------------------------------------------- + AGG_INLINE int8u* row_ptr(int y) { return m_rbuf->row_ptr(y); } + AGG_INLINE const int8u* row_ptr(int y) const { return m_rbuf->row_ptr(y); } + AGG_INLINE row_data row(int y) const { return m_rbuf->row(y); } //-------------------------------------------------------------------- - const int8u* row_ptr(int y) const + AGG_INLINE int8u* pix_ptr(int x, int y) + { + return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); + } + + AGG_INLINE const int8u* pix_ptr(int x, int y) const + { + return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step + pix_offset); + } + + // Return pointer to pixel value, forcing row to be allocated. + AGG_INLINE pixel_type* pix_value_ptr(int x, int y, unsigned len) + { + return (pixel_type*)(m_rbuf->row_ptr(x, y, len) + sizeof(value_type) * (x * pix_step + pix_offset)); + } + + // Return pointer to pixel value, or null if row not allocated. + AGG_INLINE const pixel_type* pix_value_ptr(int x, int y) const + { + int8u* p = m_rbuf->row_ptr(y); + return p ? (pixel_type*)(p + sizeof(value_type) * (x * pix_step + pix_offset)) : 0; + } + + // Get pixel pointer from raw buffer pointer. + AGG_INLINE static pixel_type* pix_value_ptr(void* p) + { + return (pixel_type*)((value_type*)p + pix_offset); + } + + // Get pixel pointer from raw buffer pointer. + AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { - return m_rbuf->row_ptr(y); + return (const pixel_type*)((const value_type*)p + pix_offset); } //-------------------------------------------------------------------- - const int8u* pix_ptr(int x, int y) const + AGG_INLINE static void write_plain_color(void* p, color_type c) { - return m_rbuf->row_ptr(y) + x * pix_width; + // RGB formats are implicitly premultiplied. + c.premultiply(); + pix_value_ptr(p)->set(c); } //-------------------------------------------------------------------- - row_data row(int y) const + AGG_INLINE static color_type read_plain_color(const void* p) { - return m_rbuf->row(y); + return pix_value_ptr(p)->get(); } //-------------------------------------------------------------------- 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; + ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { - 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]); + if (const pixel_type* p = pix_value_ptr(x, y)) + { + return p->get(); + } + return color_type::no_color(); } //-------------------------------------------------------------------- AGG_INLINE void copy_pixel(int x, int y, const color_type& c) { - 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; + pix_value_ptr(x, y, 1)->set(c); } //-------------------------------------------------------------------- AGG_INLINE void blend_pixel(int x, int y, const color_type& c, int8u cover) { - copy_or_blend_pix((value_type*)m_rbuf->row_ptr(x, y, 1) + x + x + x, c, cover); + copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); } - //-------------------------------------------------------------------- AGG_INLINE void copy_hline(int x, int y, unsigned len, const color_type& c) { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + x + x + x; + pixel_type* p = pix_value_ptr(x, y, len); do { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p += 3; + p->set(c); + p = p->next(); } while(--len); } @@ -318,47 +446,38 @@ namespace agg24 { do { - 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; + pix_value_ptr(x, y++, 1)->set(c); } - while(--len); + while (--len); } - //-------------------------------------------------------------------- void blend_hline(int x, int y, unsigned len, const color_type& c, int8u cover) { - if (c.a) + if (!c.is_transparent()) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; + pixel_type* p = pix_value_ptr(x, y, len); - calc_type alpha = (calc_type(c.a) * (calc_type(cover) + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { do { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; - p += 3; + p->set(c); + p = p->next(); } - while(--len); + while (--len); } else { do { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, cover); - p += 3; + blend_pix(p, c, cover); + p = p->next(); } - while(--len); + while (--len); } } } @@ -370,66 +489,51 @@ namespace agg24 const color_type& c, int8u cover) { - if (c.a) + if (!c.is_transparent()) { - value_type* p; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { do { - 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; + pix_value_ptr(x, y++, 1)->set(c); } - while(--len); + while (--len); } else { do { - 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); + blend_pix(pix_value_ptr(x, y++, 1), c, cover); } - while(--len); + while (--len); } } } - //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { - if (c.a) + if (!c.is_transparent()) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; + pixel_type* p = pix_value_ptr(x, y, len); do { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && *covers == cover_mask) { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; + p->set(c); } else { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); + blend_pix(p, c, *covers); } - p += 3; + p = p->next(); ++covers; } - while(--len); + while (--len); } } @@ -440,51 +544,54 @@ namespace agg24 const color_type& c, const int8u* covers) { - if (c.a) + if (!c.is_transparent()) { do { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; + pixel_type* p = pix_value_ptr(x, y++, 1); - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && *covers == cover_mask) { - p[order_type::R] = c.r; - p[order_type::G] = c.g; - p[order_type::B] = c.b; + p->set(c); } else { - m_blender.blend_pix(p, c.r, c.g, c.b, alpha, *covers); + blend_pix(p, c, *covers); } ++covers; } - while(--len); + 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 + x + x; + pixel_type* p = pix_value_ptr(x, y, len); do { - p[order_type::R] = colors->r; - p[order_type::G] = colors->g; - p[order_type::B] = colors->b; - ++colors; - p += 3; + p->set(*colors++); + p = p->next(); } - while(--len); + while (--len); } + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + pix_value_ptr(x, y++, 1)->set(*colors++); + } + while (--len); + } + //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, @@ -492,43 +599,40 @@ namespace agg24 const int8u* covers, int8u cover) { - value_type* p = (value_type*) - m_rbuf->row_ptr(x, y, len) + x + x + x; + pixel_type* p = pix_value_ptr(x, y, len); - if(covers) + if (covers) { do { copy_or_blend_pix(p, *colors++, *covers++); - p += 3; + p = p->next(); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { do { copy_or_blend_pix(p, *colors++); - p += 3; + p = p->next(); } - while(--len); + while (--len); } else { do { copy_or_blend_pix(p, *colors++, cover); - p += 3; + p = p->next(); } - while(--len); + while (--len); } } } - - //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, unsigned len, @@ -536,41 +640,31 @@ namespace agg24 const int8u* covers, int8u cover) { - value_type* p; - if(covers) + if (covers) { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - copy_or_blend_pix(p, *colors++, *covers++); + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - copy_or_blend_pix(p, *colors++); + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } - while(--len); + while (--len); } else { do { - p = (value_type*) - m_rbuf->row_ptr(x, y++, 1) + x + x + x; - - copy_or_blend_pix(p, *colors++, cover); + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } - while(--len); + while (--len); } } } @@ -578,21 +672,19 @@ namespace agg24 //-------------------------------------------------------------------- template void for_each_pixel(Function f) { - unsigned y; - for(y = 0; y < height(); ++y) + for (unsigned 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; - value_type* p = (value_type*) - m_rbuf->row_ptr(r.x1, y, len) + r.x1 * 3; + pixel_type* p = pix_value_ptr(r.x1, y, len); do { - f(p); - p += 3; + f(p->c); + p = p->next(); } - while(--len); + while (--len); } } } @@ -616,8 +708,7 @@ namespace agg24 int xsrc, int ysrc, unsigned len) { - const int8u* p = from.row_ptr(ysrc); - if(p) + if (const int8u* p = from.row_ptr(ysrc)) { memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, p + xsrc * pix_width, @@ -625,8 +716,8 @@ namespace agg24 } } - //-------------------------------------------------------------------- + // Blend from an RGBA surface. template void blend_from(const SrcPixelFormatRenderer& from, int xdst, int ydst, @@ -634,54 +725,115 @@ namespace agg24 unsigned len, int8u cover) { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; typedef typename SrcPixelFormatRenderer::order_type src_order; - const value_type* psrc = (const value_type*)from.row_ptr(ysrc); - if(psrc) + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { - psrc += xsrc * 4; - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst * 3; + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - if(cover == 255) + if (cover == cover_mask) { do { - value_type alpha = psrc[src_order::A]; - if(alpha) + value_type alpha = psrc->c[src_order::A]; + if (alpha <= color_type::empty_value()) { - if(alpha == base_mask) + if (alpha >= color_type::full_value()) { - pdst[order_type::R] = psrc[src_order::R]; - pdst[order_type::G] = psrc[src_order::G]; - pdst[order_type::B] = psrc[src_order::B]; + pdst->c[order_type::R] = psrc->c[src_order::R]; + pdst->c[order_type::G] = psrc->c[src_order::G]; + pdst->c[order_type::B] = psrc->c[src_order::B]; } else { - m_blender.blend_pix(pdst, - psrc[src_order::R], - psrc[src_order::G], - psrc[src_order::B], - alpha); + blend_pix(pdst, + psrc->c[src_order::R], + psrc->c[src_order::G], + psrc->c[src_order::B], + alpha); } } - psrc += 4; - pdst += 3; + psrc = psrc->next(); + pdst = pdst->next(); } while(--len); } else { - color_type color; do { - 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; + copy_or_blend_pix(pdst, psrc->get(), cover); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + } + + //-------------------------------------------------------------------- + // Blend from single color, using grayscale surface as alpha channel. + template + void blend_from_color(const SrcPixelFormatRenderer& from, + const color_type& color, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + typedef typename SrcPixelFormatRenderer::color_type src_color_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + + do + { + copy_or_blend_pix(pdst, color, src_color_type::scale_cover(cover, psrc->c[0])); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + + //-------------------------------------------------------------------- + // Blend from color table, using grayscale surface as indexes into table. + // Obviously, this only works for integer value types. + template + void blend_from_lut(const SrcPixelFormatRenderer& from, + const color_type* color_lut, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + + if (cover == cover_mask) + { + do + { + const color_type& color = color_lut[psrc->c[0]]; + blend_pix(pdst, color); + psrc = psrc->next(); + pdst = pdst->next(); + } + while(--len); + } + else + { + do + { + copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); + psrc = psrc->next(); + pdst = pdst->next(); } while(--len); } @@ -693,23 +845,97 @@ namespace agg24 Blender m_blender; }; - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb24; //----pixfmt_rgb24 - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr24; //----pixfmt_bgr24 - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb48; //----pixfmt_rgb48 - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr48; //----pixfmt_bgr48 + //----------------------------------------------------------------------- + typedef blender_rgb blender_rgb24; + typedef blender_rgb blender_bgr24; + typedef blender_rgb blender_srgb24; + typedef blender_rgb blender_sbgr24; + typedef blender_rgb blender_rgb48; + typedef blender_rgb blender_bgr48; + typedef blender_rgb blender_rgb96; + typedef blender_rgb blender_bgr96; + + typedef blender_rgb_pre blender_rgb24_pre; + typedef blender_rgb_pre blender_bgr24_pre; + typedef blender_rgb_pre blender_srgb24_pre; + typedef blender_rgb_pre blender_sbgr24_pre; + typedef blender_rgb_pre blender_rgb48_pre; + typedef blender_rgb_pre blender_bgr48_pre; + typedef blender_rgb_pre blender_rgb96_pre; + typedef blender_rgb_pre blender_bgr96_pre; + + typedef pixfmt_alpha_blend_rgb pixfmt_rgb24; + typedef pixfmt_alpha_blend_rgb pixfmt_bgr24; + typedef pixfmt_alpha_blend_rgb pixfmt_srgb24; + typedef pixfmt_alpha_blend_rgb pixfmt_sbgr24; + typedef pixfmt_alpha_blend_rgb pixfmt_rgb48; + typedef pixfmt_alpha_blend_rgb pixfmt_bgr48; + typedef pixfmt_alpha_blend_rgb pixfmt_rgb96; + typedef pixfmt_alpha_blend_rgb pixfmt_bgr96; + + typedef pixfmt_alpha_blend_rgb pixfmt_rgb24_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_bgr24_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_srgb24_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_sbgr24_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_rgb48_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_bgr48_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_rgb96_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_bgr96_pre; + + typedef pixfmt_alpha_blend_rgb pixfmt_rgbx32; + typedef pixfmt_alpha_blend_rgb pixfmt_xrgb32; + typedef pixfmt_alpha_blend_rgb pixfmt_xbgr32; + typedef pixfmt_alpha_blend_rgb pixfmt_bgrx32; + typedef pixfmt_alpha_blend_rgb pixfmt_srgbx32; + typedef pixfmt_alpha_blend_rgb pixfmt_sxrgb32; + typedef pixfmt_alpha_blend_rgb pixfmt_sxbgr32; + typedef pixfmt_alpha_blend_rgb pixfmt_sbgrx32; + typedef pixfmt_alpha_blend_rgb pixfmt_rgbx64; + typedef pixfmt_alpha_blend_rgb pixfmt_xrgb64; + typedef pixfmt_alpha_blend_rgb pixfmt_xbgr64; + typedef pixfmt_alpha_blend_rgb pixfmt_bgrx64; + typedef pixfmt_alpha_blend_rgb pixfmt_rgbx128; + typedef pixfmt_alpha_blend_rgb pixfmt_xrgb128; + typedef pixfmt_alpha_blend_rgb pixfmt_xbgr128; + typedef pixfmt_alpha_blend_rgb pixfmt_bgrx128; + + typedef pixfmt_alpha_blend_rgb pixfmt_rgbx32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_xrgb32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_xbgr32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_bgrx32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_srgbx32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_sxrgb32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_sxbgr32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_sbgrx32_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_rgbx64_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_xrgb64_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_xbgr64_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_bgrx64_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_rgbx128_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_xrgb128_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_xbgr128_pre; + typedef pixfmt_alpha_blend_rgb pixfmt_bgrx128_pre; - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb24_pre; //----pixfmt_rgb24_pre - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr24_pre; //----pixfmt_bgr24_pre - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_rgb48_pre; //----pixfmt_rgb48_pre - typedef pixfmt_alpha_blend_rgb, rendering_buffer> pixfmt_bgr48_pre; //----pixfmt_bgr48_pre //-----------------------------------------------------pixfmt_rgb24_gamma template class pixfmt_rgb24_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> + public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_rgb24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + { + this->blender().gamma(g); + } + }; + + //-----------------------------------------------------pixfmt_srgb24_gamma + template class pixfmt_srgb24_gamma : + public pixfmt_alpha_blend_rgb, rendering_buffer, 3> + { + public: + pixfmt_srgb24_gamma(rendering_buffer& rb, const Gamma& g) : + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } @@ -717,11 +943,23 @@ namespace agg24 //-----------------------------------------------------pixfmt_bgr24_gamma template class pixfmt_bgr24_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> + public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_bgr24_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) + { + this->blender().gamma(g); + } + }; + + //-----------------------------------------------------pixfmt_sbgr24_gamma + template class pixfmt_sbgr24_gamma : + public pixfmt_alpha_blend_rgb, rendering_buffer, 3> + { + public: + pixfmt_sbgr24_gamma(rendering_buffer& rb, const Gamma& g) : + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } @@ -729,11 +967,11 @@ namespace agg24 //-----------------------------------------------------pixfmt_rgb48_gamma template class pixfmt_rgb48_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> + public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_rgb48_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } @@ -741,17 +979,16 @@ namespace agg24 //-----------------------------------------------------pixfmt_bgr48_gamma template class pixfmt_bgr48_gamma : - public pixfmt_alpha_blend_rgb, rendering_buffer> + public pixfmt_alpha_blend_rgb, rendering_buffer, 3> { public: pixfmt_bgr48_gamma(rendering_buffer& rb, const Gamma& g) : - pixfmt_alpha_blend_rgb, rendering_buffer>(rb) + pixfmt_alpha_blend_rgb, rendering_buffer, 3>(rb) { this->blender().gamma(g); } }; - } #endif diff --git a/kiva/agg/agg-24/include/agg_pixfmt_rgb_packed.h b/kiva/agg/agg-24/include/agg_pixfmt_rgb_packed.h index edd6a0599..1b2fddc30 100644 --- a/kiva/agg/agg-24/include/agg_pixfmt_rgb_packed.h +++ b/kiva/agg/agg-24/include/agg_pixfmt_rgb_packed.h @@ -805,7 +805,7 @@ namespace agg24 base_shift = color_type::base_shift, base_scale = color_type::base_scale, base_mask = color_type::base_mask, - pix_width = sizeof(pixel_type) + pix_width = sizeof(pixel_type), }; private: @@ -828,30 +828,47 @@ namespace agg24 public: //-------------------------------------------------------------------- - pixfmt_alpha_blend_rgb_packed(rbuf_type& rb) : m_rbuf(&rb) {} + explicit pixfmt_alpha_blend_rgb_packed(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } + + //-------------------------------------------------------------------- + template + bool attach(PixFmt& pixf, int x1, int y1, int x2, int y2) + { + rect_i r(x1, y1, x2, y2); + if(r.clip(rect_i(0, 0, pixf.width()-1, pixf.height()-1))) + { + int stride = pixf.stride(); + m_rbuf->attach(pixf.pix_ptr(r.x1, stride < 0 ? r.y2 : r.y1), + (r.x2 - r.x1) + 1, + (r.y2 - r.y1) + 1, + stride); + return true; + } + return false; + } + Blender& blender() { return m_blender; } //-------------------------------------------------------------------- AGG_INLINE unsigned width() const { return m_rbuf->width(); } AGG_INLINE unsigned height() const { return m_rbuf->height(); } + AGG_INLINE int stride() const { return m_rbuf->stride(); } //-------------------------------------------------------------------- - const int8u* row_ptr(int y) const - { - return m_rbuf->row_ptr(y); - } + 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); } //-------------------------------------------------------------------- - const int8u* pix_ptr(int x, int y) const + AGG_INLINE int8u* pix_ptr(int x, int y) { return m_rbuf->row_ptr(y) + x * pix_width; } - //-------------------------------------------------------------------- - row_data row(int y) const + AGG_INLINE const int8u* pix_ptr(int x, int y) const { - return m_rbuf->row(y); + return m_rbuf->row_ptr(y) + x * pix_width; } //-------------------------------------------------------------------- @@ -1013,6 +1030,20 @@ namespace agg24 while(--len); } + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + pixel_type* p = (pixel_type*)m_rbuf->row_ptr(x, y++, 1) + x; + *p = m_blender.make_pix(colors->r, colors->g, colors->b); + ++colors; + } + while(--len); + } + //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, unsigned len, @@ -1103,6 +1134,68 @@ namespace agg24 } } + //-------------------------------------------------------------------- + template + 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; + typedef typename SrcPixelFormatRenderer::color_type src_color_type; + const src_value_type* psrc = (src_value_type*)from.row_ptr(ysrc); + if(psrc) + { + psrc += xsrc * SrcPixelFormatRenderer::pix_step + SrcPixelFormatRenderer::pix_offset; + pixel_type* pdst = + (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; + + do + { + m_blender.blend_pix(pdst, + color.r, color.g, color.b, color.a, + cover); + psrc += SrcPixelFormatRenderer::pix_step; + ++pdst; + } + while(--len); + } + } + + //-------------------------------------------------------------------- + template + 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) + { + psrc += xsrc * SrcPixelFormatRenderer::pix_step + SrcPixelFormatRenderer::pix_offset; + pixel_type* pdst = + (pixel_type*)m_rbuf->row_ptr(xdst, ydst, len) + xdst; + + do + { + const color_type& color = color_lut[*psrc]; + m_blender.blend_pix(pdst, + color.r, color.g, color.b, color.a, + cover); + psrc += SrcPixelFormatRenderer::pix_step; + ++pdst; + } + while(--len); + } + } + + + private: rbuf_type* m_rbuf; Blender m_blender; diff --git a/kiva/agg/agg-24/include/agg_pixfmt_rgba.h b/kiva/agg/agg-24/include/agg_pixfmt_rgba.h index 916476483..6cb741bea 100644 --- a/kiva/agg/agg-24/include/agg_pixfmt_rgba.h +++ b/kiva/agg/agg-24/include/agg_pixfmt_rgba.h @@ -26,63 +26,57 @@ #include #include -#include "agg_basics.h" -#include "agg_color_rgba.h" +#include "agg_pixfmt_base.h" #include "agg_rendering_buffer.h" namespace agg24 { + template inline T sd_min(T a, T b) { return (a < b) ? a : b; } + template inline T sd_max(T a, T b) { return (a > b) ? a : b; } + + inline rgba & clip(rgba & c) + { + if (c.a > 1) c.a = 1; else if (c.a < 0) c.a = 0; + if (c.r > c.a) c.r = c.a; else if (c.r < 0) c.r = 0; + if (c.g > c.a) c.g = c.a; else if (c.g < 0) c.g = 0; + if (c.b > c.a) c.b = c.a; else if (c.b < 0) c.b = 0; + return c; + } //=========================================================multiplier_rgba - template struct multiplier_rgba + template + struct multiplier_rgba { - typedef typename ColorT::value_type value_type; - typedef typename ColorT::calc_type calc_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_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); - } + value_type a = p[Order::A]; + p[Order::R] = color_type::multiply(p[Order::R], a); + p[Order::G] = color_type::multiply(p[Order::G], a); + p[Order::B] = color_type::multiply(p[Order::B], a); } //-------------------------------------------------------------------- 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); - } + value_type a = p[Order::A]; + p[Order::R] = color_type::demultiply(p[Order::R], a); + p[Order::G] = color_type::demultiply(p[Order::G], a); + p[Order::B] = color_type::demultiply(p[Order::B], a); } }; //=====================================================apply_gamma_dir_rgba - template class apply_gamma_dir_rgba + template + class apply_gamma_dir_rgba { public: - typedef typename ColorT::value_type value_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_type; apply_gamma_dir_rgba(const GammaLut& gamma) : m_gamma(gamma) {} @@ -101,7 +95,8 @@ namespace agg24 template class apply_gamma_inv_rgba { public: - typedef typename ColorT::value_type value_type; + typedef ColorT color_type; + typedef typename color_type::value_type value_type; apply_gamma_inv_rgba(const GammaLut& gamma) : m_gamma(gamma) {} @@ -117,1112 +112,927 @@ namespace agg24 }; - - + template + struct conv_rgba_pre + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + //-------------------------------------------------------------------- + static AGG_INLINE void set_plain_color(value_type* p, color_type c) + { + c.premultiply(); + p[Order::R] = c.r; + p[Order::G] = c.g; + p[Order::B] = c.b; + p[Order::A] = c.a; + } + //-------------------------------------------------------------------- + static AGG_INLINE color_type get_plain_color(const value_type* p) + { + return color_type( + p[Order::R], + p[Order::G], + p[Order::B], + p[Order::A]).demultiply(); + } + }; + template + struct conv_rgba_plain + { + typedef ColorT color_type; + typedef Order order_type; + typedef typename color_type::value_type value_type; + //-------------------------------------------------------------------- + static AGG_INLINE void set_plain_color(value_type* p, color_type c) + { + p[Order::R] = c.r; + p[Order::G] = c.g; + p[Order::B] = c.b; + p[Order::A] = c.a; + } + //-------------------------------------------------------------------- + static AGG_INLINE color_type get_plain_color(const value_type* p) + { + return color_type( + p[Order::R], + p[Order::G], + p[Order::B], + p[Order::A]); + } + }; //=============================================================blender_rgba - template struct blender_rgba + // Blends "plain" (i.e. non-premultiplied) colors into a premultiplied buffer. + template + struct blender_rgba : conv_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 - }; + 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 in fact premultiplied + // we omit the initial premultiplication and final demultiplication. + + //-------------------------------------------------------------------- + static AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) + { + blend_pix(p, cr, cg, cb, color_type::mult_cover(alpha, cover)); + } //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) + static AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type alpha) { - 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)); + 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::A] = color_type::prelerp(p[Order::A], alpha, alpha); } }; - //=========================================================blender_rgba_pre - template struct blender_rgba_pre + + //========================================================blender_rgba_pre + // Blends premultiplied colors into a premultiplied buffer. + template + struct blender_rgba_pre : conv_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 - }; + typedef typename color_type::long_type long_type; + + // Blend pixels using the premultiplied form of Alvy-Ray Smith's + // compositing function. //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) + static AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type alpha, cover_type 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)); + blend_pix(p, + color_type::mult_cover(cr, cover), + color_type::mult_cover(cg, cover), + color_type::mult_cover(cb, cover), + color_type::mult_cover(alpha, cover)); } //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha) + static AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type 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)); + 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); + p[Order::A] = color_type::prelerp(p[Order::A], alpha, alpha); } }; //======================================================blender_rgba_plain - template struct blender_rgba_plain + // Blends "plain" (non-premultiplied) colors into a plain (non-premultiplied) buffer. + template + struct blender_rgba_plain : conv_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 }; + typedef typename color_type::long_type long_type; + + // Blend pixels using the non-premultiplied form of Alvy-Ray Smith's + // compositing function. //-------------------------------------------------------------------- - static AGG_INLINE void blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover=0) + static AGG_INLINE void blend_pix(value_type* p, + value_type cr, value_type cg, value_type cb, value_type alpha, cover_type cover) { - 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); + 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) + { + if (alpha > color_type::empty_value()) + { + calc_type a = p[Order::A]; + calc_type r = color_type::multiply(p[Order::R], a); + calc_type g = color_type::multiply(p[Order::G], a); + calc_type b = color_type::multiply(p[Order::B], a); + p[Order::R] = color_type::lerp(r, cr, alpha); + p[Order::G] = color_type::lerp(g, cg, alpha); + p[Order::B] = color_type::lerp(b, cb, alpha); + p[Order::A] = color_type::prelerp(a, alpha, alpha); + multiplier_rgba::demultiply(p); + } + } + }; + // SVG compositing operations. + // For specifications, see http://www.w3.org/TR/SVGCompositing/ //=========================================================comp_op_rgba_clear - template struct comp_op_rgba_clear + template + struct comp_op_rgba_clear : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; - static AGG_INLINE void blend_pix(value_type* p, - unsigned, unsigned, unsigned, unsigned, - unsigned cover) + // Dca' = 0 + // Da' = 0 + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + if (cover >= cover_full) { - 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); + p[0] = p[1] = p[2] = p[3] = color_type::empty_value(); } - else + else if (cover > cover_none) { - p[0] = p[1] = p[2] = p[3] = 0; + set(p, get(p, cover_full - cover)); } } }; //===========================================================comp_op_rgba_src - template struct comp_op_rgba_src + template + struct comp_op_rgba_src : blender_base { typedef ColorT color_type; - typedef Order order_type; typedef typename color_type::value_type value_type; + using blender_base::get; + using blender_base::set; - static AGG_INLINE void blend_pix(value_type* p, - unsigned sr, unsigned sg, unsigned sb, - unsigned sa, unsigned cover) + // Dca' = Sca + // Da' = Sa + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + if (cover >= cover_full) { - 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)); + set(p, r, g, b, a); } else { - p[Order::R] = sr; - p[Order::G] = sg; - p[Order::B] = sb; - p[Order::A] = sa; + rgba s = get(r, g, b, a, cover); + rgba d = get(p, cover_full - cover); + d.r += s.r; + d.g += s.g; + d.b += s.b; + d.a += s.a; + set(p, d); } } }; //===========================================================comp_op_rgba_dst - template struct comp_op_rgba_dst + template + struct comp_op_rgba_dst : blender_base { 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) + // Dca' = Dca.Sa + Dca.(1 - Sa) = Dca + // Da' = Da.Sa + Da.(1 - Sa) = Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { + // Well, that was easy! } }; //======================================================comp_op_rgba_src_over - template struct comp_op_rgba_src_over + template + struct comp_op_rgba_src_over : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; - // 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)); + // Dca' = Sca + Dca.(1 - Sa) = Dca + Sca - Dca.Sa + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { +#if 1 + blender_rgba_pre::blend_pix(p, r, g, b, a, cover); +#else + rgba s = get(r, g, b, a, cover); + rgba d = get(p); + d.r += s.r - d.r * s.a; + d.g += s.g - d.g * s.a; + d.b += s.b - d.b * s.a; + d.a += s.a - d.a * s.a; + set(p, d); +#endif } }; //======================================================comp_op_rgba_dst_over - template struct comp_op_rgba_dst_over + template + struct comp_op_rgba_dst_over : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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)); + // Da' = Sa + Da - Sa.Da = Da + Sa.(1 - Da) + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba s = get(r, g, b, a, cover); + rgba d = get(p); + double d1a = 1 - d.a; + d.r += s.r * d1a; + d.g += s.g * d1a; + d.b += s.b * d1a; + d.a += s.a * d1a; + set(p, d); } }; //======================================================comp_op_rgba_src_in - template struct comp_op_rgba_src_in + template + struct comp_op_rgba_src_in : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - calc_type da = p[Order::A]; - if(cover < 255) + double da = ColorT::to_double(p[Order::A]); + if (da > 0) { - 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); + rgba s = get(r, g, b, a, cover); + rgba d = get(p, cover_full - cover); + d.r += s.r * da; + d.g += s.g * da; + d.b += s.b * da; + d.a += s.a * da; + set(p, d); } } }; //======================================================comp_op_rgba_dst_in - template struct comp_op_rgba_dst_in + template + struct comp_op_rgba_dst_in : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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); + // Da' = Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + double sa = ColorT::to_double(a); + rgba d = get(p, cover_full - cover); + rgba d2 = get(p, cover); + d.r += d2.r * sa; + d.g += d2.g * sa; + d.b += d2.b * sa; + d.a += d2.a * sa; + set(p, d); } }; //======================================================comp_op_rgba_src_out - template struct comp_op_rgba_src_out + template + struct comp_op_rgba_src_out : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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); - } + // Da' = Sa.(1 - Da) + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba s = get(r, g, b, a, cover); + rgba d = get(p, cover_full - cover); + double d1a = 1 - ColorT::to_double(p[Order::A]); + d.r += s.r * d1a; + d.g += s.g * d1a; + d.b += s.b * d1a; + d.a += s.a * d1a; + set(p, d); } }; //======================================================comp_op_rgba_dst_out - template struct comp_op_rgba_dst_out + template + struct comp_op_rgba_dst_out : blender_base { 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); + using blender_base::get; + using blender_base::set; + + // Dca' = Dca.(1 - Sa) + // Da' = Da.(1 - Sa) + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba d = get(p, cover_full - cover); + rgba dc = get(p, cover); + double s1a = 1 - ColorT::to_double(a); + d.r += dc.r * s1a; + d.g += dc.g * s1a; + d.b += dc.b * s1a; + d.a += dc.a * s1a; + set(p, d); } }; //=====================================================comp_op_rgba_src_atop - template struct comp_op_rgba_src_atop + template + struct comp_op_rgba_src_atop : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type 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); + rgba s = get(r, g, b, a, cover); + rgba d = get(p); + double s1a = 1 - s.a; + d.r = s.r * d.a + d.r * s1a; + d.g = s.g * d.a + d.g * s1a; + d.b = s.b * d.a + d.g * s1a; + set(p, d); } }; //=====================================================comp_op_rgba_dst_atop - template struct comp_op_rgba_dst_atop + template + struct comp_op_rgba_dst_atop : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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; - } + // Da' = Sa + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba sc = get(r, g, b, a, cover); + rgba dc = get(p, cover); + rgba d = get(p, cover_full - cover); + double sa = ColorT::to_double(a); + double d1a = 1 - ColorT::to_double(p[Order::A]); + d.r += dc.r * sa + sc.r * d1a; + d.g += dc.g * sa + sc.g * d1a; + d.b += dc.b * sa + sc.b * d1a; + d.a += sc.a; + set(p, d); } }; //=========================================================comp_op_rgba_xor - template struct comp_op_rgba_xor + template + struct comp_op_rgba_xor : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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; - } - 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))); + // Da' = Sa + Da - 2.Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba s = get(r, g, b, a, cover); + rgba d = get(p); + double s1a = 1 - s.a; + double d1a = 1 - ColorT::to_double(p[Order::A]); + d.r = s.r * d1a + d.r * s1a; + d.g = s.g * d1a + d.g * s1a; + d.b = s.b * d1a + d.b * s1a; + d.a = s.a + d.a - 2 * s.a * d.a; + set(p, d); } }; //=========================================================comp_op_rgba_plus - template struct comp_op_rgba_plus + template + struct comp_op_rgba_plus : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + d.a = sd_min(d.a + s.a, 1.0); + d.r = sd_min(d.r + s.r, d.a); + d.g = sd_min(d.g + s.g, d.a); + d.b = sd_min(d.b + s.b, d.a); + set(p, clip(d)); } - 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) ? base_mask : dr; - p[Order::G] = (dg > base_mask) ? base_mask : dg; - p[Order::B] = (db > base_mask) ? base_mask : db; - p[Order::A] = (da > base_mask) ? base_mask : da; } }; //========================================================comp_op_rgba_minus - template struct comp_op_rgba_minus + // Note: not included in SVG spec. + template + struct comp_op_rgba_minus : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = 1 - (1 - Sa).(1 - Da) = Da + Sa - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + d.a += s.a - s.a * d.a; + d.r = sd_max(d.r - s.r, 0.0); + d.g = sd_max(d.g - s.g, 0.0); + d.b = sd_max(d.b - s.b, 0.0); + set(p, clip(d)); } - 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)(base_mask - (((base_mask - sa) * (base_mask - p[Order::A]) + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_multiply - template struct comp_op_rgba_multiply + template + struct comp_op_rgba_multiply : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + double s1a = 1 - s.a; + double d1a = 1 - d.a; + d.r = s.r * d.r + s.r * d1a + d.r * s1a; + d.g = s.g * d.g + s.g * d1a + d.g * s1a; + d.b = s.b * d.b + s.b * d1a + d.b * s1a; + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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 struct comp_op_rgba_screen + template + struct comp_op_rgba_screen : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + d.r += s.r - s.r * d.r; + d.g += s.g - s.g * d.g; + d.b += s.b - s.b * d.b; + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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 struct comp_op_rgba_overlay + template + struct comp_op_rgba_overlay : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; - // if 2.Dca < Da + // 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) + static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) + { + return (2 * dca <= da) ? + 2 * sca * dca + sca * d1a + dca * s1a : + sada - 2 * (da - dca) * (sa - sca) + sca * d1a + dca * s1a; + } + + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + double d1a = 1 - d.a; + double s1a = 1 - s.a; + double sada = s.a * d.a; + d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); + d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); + d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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_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_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_shift); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; - - template inline T sd_min(T a, T b) { return (a < b) ? a : b; } - template inline T sd_max(T a, T b) { return (a > b) ? a : b; } - //=====================================================comp_op_rgba_darken - template struct comp_op_rgba_darken + template + struct comp_op_rgba_darken : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + double d1a = 1 - d.a; + double s1a = 1 - s.a; + d.r = sd_min(s.r * d.a, d.r * s.a) + s.r * d1a + d.r * s1a; + d.g = sd_min(s.g * d.a, d.g * s.a) + s.g * d1a + d.g * s1a; + d.b = sd_min(s.b * d.a, d.b * s.a) + s.b * d1a + d.b * s1a; + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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_shift); - p[Order::G] = (value_type)((sd_min(sg * da, dg * sa) + sg * d1a + dg * s1a) >> base_shift); - p[Order::B] = (value_type)((sd_min(sb * da, db * sa) + sb * d1a + db * s1a) >> base_shift); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_lighten - template struct comp_op_rgba_lighten + template + struct comp_op_rgba_lighten : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + double d1a = 1 - d.a; + double s1a = 1 - s.a; + d.r = sd_max(s.r * d.a, d.r * s.a) + s.r * d1a + d.r * s1a; + d.g = sd_max(s.g * d.a, d.g * s.a) + s.g * d1a + d.g * s1a; + d.b = sd_max(s.b * d.a, d.b * s.a) + s.b * d1a + d.b * s1a; + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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_shift); - p[Order::G] = (value_type)((sd_max(sg * da, dg * sa) + sg * d1a + dg * s1a) >> base_shift); - p[Order::B] = (value_type)((sd_max(sb * da, db * sa) + sb * d1a + db * s1a) >> base_shift); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_color_dodge - template struct comp_op_rgba_color_dodge + template + struct comp_op_rgba_color_dodge : blender_base { 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) + using blender_base::get; + using blender_base::set; + + // if Sca == Sa and Dca == 0 + // Dca' = Sca.(1 - Da) + Dca.(1 - Sa) = Sca.(1 - Da) + // otherwise if Sca == Sa + // Dca' = Sa.Da + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise if Sca < Sa + // Dca' = Sa.Da.min(1, Dca/Da.Sa/(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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { - if(cover < 255) + if (sca < sa) return sada * sd_min(1.0, (dca / da) * sa / (sa - sca)) + sca * d1a + dca * s1a; + if (dca > 0) return sada + sca * d1a + dca * s1a; + return sca * d1a; + } + + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + if (d.a > 0) + { + double sada = s.a * d.a; + double s1a = 1 - s.a; + double d1a = 1 - d.a; + d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); + d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); + d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); + d.a += s.a - s.a * d.a; + set(p, clip(d)); + } + else set(p, s); } - 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_shift : - drsa / (base_mask - (sr << base_shift) / sa) + ((sr * d1a + dr * s1a) >> base_shift)); - - p[Order::G] = (value_type)((sgda + dgsa >= sada) ? - (sada + sg * d1a + dg * s1a) >> base_shift : - dgsa / (base_mask - (sg << base_shift) / sa) + ((sg * d1a + dg * s1a) >> base_shift)); - - p[Order::B] = (value_type)((sbda + dbsa >= sada) ? - (sada + sb * d1a + db * s1a) >> base_shift : - dbsa / (base_mask - (sb << base_shift) / sa) + ((sb * d1a + db * s1a) >> base_shift)); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_color_burn - template struct comp_op_rgba_color_burn + template + struct comp_op_rgba_color_burn : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; - // 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 Sca == 0 and Dca == Da + // Dca' = Sa.Da + Dca.(1 - Sa) + // otherwise if Sca == 0 + // Dca' = Dca.(1 - Sa) + // otherwise if Sca > 0 + // Dca' = Sa.Da.(1 - min(1, (1 - Dca/Da).Sa/Sca)) + Sca.(1 - Da) + Dca.(1 - Sa) + static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { - if(cover < 255) + if (sca > 0) return sada * (1 - sd_min(1.0, (1 - dca / da) * sa / sca)) + sca * d1a + dca * s1a; + if (dca > da) return sada + dca * s1a; + return dca * s1a; + } + + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + if (d.a > 0) + { + double sada = s.a * d.a; + double s1a = 1 - s.a; + double d1a = 1 - d.a; + d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); + d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); + d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); + d.a += s.a - sada; + set(p, clip(d)); + } + else set(p, s); } - 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_shift); - - p[Order::G] = (value_type)(((sgda + dgsa <= sada) ? - sg * d1a + dg * s1a : - sa * (sgda + dgsa - sada) / sg + sg * d1a + dg * s1a) >> base_shift); - - p[Order::B] = (value_type)(((sbda + dbsa <= sada) ? - sb * d1a + db * s1a : - sa * (sbda + dbsa - sada) / sb + sb * d1a + db * s1a) >> base_shift); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_hard_light - template struct comp_op_rgba_hard_light + template + struct comp_op_rgba_hard_light : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) { - if(cover < 255) + return (2 * sca < sa) ? + 2 * sca * dca + sca * d1a + dca * s1a : + sada - 2 * (da - dca) * (sa - sca) + sca * d1a + dca * s1a; + } + + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + double d1a = 1 - d.a; + double s1a = 1 - s.a; + double sada = s.a * d.a; + d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); + d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); + d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); + d.a += s.a - sada; + set(p, clip(d)); } - 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_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_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_shift); - - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_soft_light - template struct comp_op_rgba_soft_light + template + struct comp_op_rgba_soft_light : blender_base { 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 + using blender_base::get; + using blender_base::set; + + // if 2.Sca <= Sa + // Dca' = Dca.Sa - (Sa.Da - 2.Sca.Da).Dca.Sa.(Sa.Da - Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise if 2.Sca > Sa and 4.Dca <= Da + // Dca' = Dca.Sa + (2.Sca.Da - Sa.Da).((((16.Dsa.Sa - 12).Dsa.Sa + 4).Dsa.Da) - Dsa.Da) + Sca.(1 - Da) + Dca.(1 - Sa) + // otherwise if 2.Sca > Sa and 4.Dca > Da + // Dca' = Dca.Sa + (2.Sca.Da - Sa.Da).((Dca.Sa)^0.5 - Dca.Sa) + Sca.(1 - Da) + Dca.(1 - Sa) + // + // Da' = Sa + Da - Sa.Da + static AGG_INLINE double calc(double dca, double sca, double da, double sa, double sada, double d1a, double s1a) + { + double dcasa = dca * sa; + if (2 * sca <= sa) return dcasa - (sada - 2 * sca * da) * dcasa * (sada - dcasa) + sca * d1a + dca * s1a; + if (4 * dca <= da) return dcasa + (2 * sca * da - sada) * ((((16 * dcasa - 12) * dcasa + 4) * dca * da) - dca * da) + sca * d1a + dca * s1a; + return dcasa + (2 * sca * da - sada) * (sqrt(dcasa) - dcasa) + sca * d1a + dca * s1a; + } - static AGG_INLINE void blend_pix(value_type* p, - unsigned r, unsigned g, unsigned b, - unsigned a, unsigned cover) + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type 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); - 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) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - a = (a * cover + 255) >> 8; + rgba d = get(p); + if (d.a > 0) + { + double sada = s.a * d.a; + double s1a = 1 - s.a; + double d1a = 1 - d.a; + d.r = calc(d.r, s.r, d.a, s.a, sada, d1a, s1a); + d.g = calc(d.g, s.g, d.a, s.a, sada, d1a, s1a); + d.b = calc(d.b, s.b, d.a, s.a, sada, d1a, s1a); + d.a += s.a - sada; + set(p, clip(d)); + } + else set(p, s); } - - 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 struct comp_op_rgba_difference + template + struct comp_op_rgba_difference : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + d.r += s.r - 2 * sd_min(s.r * d.a, d.r * s.a); + d.g += s.g - 2 * sd_min(s.g * d.a, d.g * s.a); + d.b += s.b - 2 * sd_min(s.b * d.a, d.b * s.a); + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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_shift)); - p[Order::G] = (value_type)(sg + dg - ((2 * sd_min(sg*da, dg*sa)) >> base_shift)); - p[Order::B] = (value_type)(sb + db - ((2 * sd_min(sb*da, db*sa)) >> base_shift)); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; //=====================================================comp_op_rgba_exclusion - template struct comp_op_rgba_exclusion + template + struct comp_op_rgba_exclusion : blender_base { 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 - }; + using blender_base::get; + using blender_base::set; // 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) + // Da' = Sa + Da - Sa.Da + static AGG_INLINE void blend_pix(value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - if(cover < 255) + rgba s = get(r, g, b, a, cover); + if (s.a > 0) { - sr = (sr * cover + 255) >> 8; - sg = (sg * cover + 255) >> 8; - sb = (sb * cover + 255) >> 8; - sa = (sa * cover + 255) >> 8; + rgba d = get(p); + double d1a = 1 - d.a; + double s1a = 1 - s.a; + d.r = (s.r * d.a + d.r * s.a - 2 * s.r * d.r) + s.r * d1a + d.r * s1a; + d.g = (s.g * d.a + d.g * s.a - 2 * s.g * d.g) + s.g * d1a + d.g * s1a; + d.b = (s.b * d.a + d.b * s.a - 2 * s.b * d.b) + s.b * d1a + d.b * s1a; + d.a += s.a - s.a * d.a; + set(p, clip(d)); } - 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_shift); - p[Order::G] = (value_type)((sg*da + dg*sa - 2*sg*dg + sg*d1a + dg*s1a) >> base_shift); - p[Order::B] = (value_type)((sb*da + db*sa - 2*sb*db + sb*d1a + db*s1a) >> base_shift); - p[Order::A] = (value_type)(sa + da - ((sa * da + base_mask) >> base_shift)); } }; +#if 0 //=====================================================comp_op_rgba_contrast template struct comp_op_rgba_contrast { @@ -1232,17 +1042,17 @@ namespace agg24 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, + static AGG_INLINE void blend_pix(value_type* p, + unsigned sr, unsigned sg, unsigned sb, unsigned sa, unsigned cover) { - if(cover < 255) + if (cover < 255) { sr = (sr * cover + 255) >> 8; sg = (sg * cover + 255) >> 8; @@ -1256,9 +1066,9 @@ namespace agg24 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); + 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; @@ -1270,33 +1080,104 @@ namespace agg24 } }; + //=====================================================comp_op_rgba_invert + template 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 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)); + } + } + }; +#endif //======================================================comp_op_table_rgba template 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); + typedef typename ColorT::calc_type calc_type; + typedef void (*comp_op_func_type)(value_type* p, + value_type cr, + value_type cg, + value_type cb, + value_type ca, + cover_type cover); static comp_op_func_type g_comp_op_func[]; }; //==========================================================g_comp_op_func - template + template typename comp_op_table_rgba::comp_op_func_type - comp_op_table_rgba::g_comp_op_func[] = + comp_op_table_rgba::g_comp_op_func[] = { comp_op_rgba_clear ::blend_pix, comp_op_rgba_src ::blend_pix, @@ -1311,7 +1192,7 @@ namespace agg24 comp_op_rgba_dst_atop ::blend_pix, comp_op_rgba_xor ::blend_pix, comp_op_rgba_plus ::blend_pix, - comp_op_rgba_minus ::blend_pix, + //comp_op_rgba_minus ::blend_pix, comp_op_rgba_multiply ::blend_pix, comp_op_rgba_screen ::blend_pix, comp_op_rgba_overlay ::blend_pix, @@ -1323,7 +1204,9 @@ namespace agg24 comp_op_rgba_soft_light ::blend_pix, comp_op_rgba_difference ::blend_pix, comp_op_rgba_exclusion ::blend_pix, - comp_op_rgba_contrast ::blend_pix, + //comp_op_rgba_contrast ::blend_pix, + //comp_op_rgba_invert ::blend_pix, + //comp_op_rgba_invert_rgb ::blend_pix, 0 }; @@ -1344,7 +1227,7 @@ namespace agg24 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_minus, //----comp_op_minus comp_op_multiply, //----comp_op_multiply comp_op_screen, //----comp_op_screen comp_op_overlay, //----comp_op_overlay @@ -1356,7 +1239,9 @@ namespace agg24 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_contrast, //----comp_op_contrast + //comp_op_invert, //----comp_op_invert + //comp_op_invert_rgb, //----comp_op_invert_rgb end_of_comp_op_e }; @@ -1368,335 +1253,465 @@ namespace agg24 //====================================================comp_op_adaptor_rgba - template struct comp_op_adaptor_rgba + template + struct comp_op_adaptor_rgba { - typedef Order order_type; 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 - }; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - comp_op_table_rgba::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_table_rgba::g_comp_op_func[op](p, + color_type::multiply(r, a), + color_type::multiply(g, a), + color_type::multiply(b, a), + a, cover); } }; //=========================================comp_op_adaptor_clip_to_dst_rgba - template struct comp_op_adaptor_clip_to_dst_rgba + template + struct comp_op_adaptor_clip_to_dst_rgba { - typedef Order order_type; 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 - }; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; - 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::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); + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + r = color_type::multiply(r, a); + g = color_type::multiply(g, a); + b = color_type::multiply(b, a); + value_type da = p[Order::A]; + comp_op_table_rgba::g_comp_op_func[op](p, + color_type::multiply(r, da), + color_type::multiply(g, da), + color_type::multiply(b, da), + color_type::multiply(a, da), cover); } }; //================================================comp_op_adaptor_rgba_pre - template struct comp_op_adaptor_rgba_pre + template + struct comp_op_adaptor_rgba_pre { - typedef Order order_type; 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 - }; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - comp_op_table_rgba::g_comp_op_func[op](p, cr, cg, cb, ca, cover); + comp_op_table_rgba::g_comp_op_func[op](p, r, g, b, a, cover); } }; //=====================================comp_op_adaptor_clip_to_dst_rgba_pre - template struct comp_op_adaptor_clip_to_dst_rgba_pre + template + struct comp_op_adaptor_clip_to_dst_rgba_pre { - typedef Order order_type; 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 - }; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + value_type da = p[Order::A]; + comp_op_table_rgba::g_comp_op_func[op](p, + color_type::multiply(r, da), + color_type::multiply(g, da), + color_type::multiply(b, da), + color_type::multiply(a, da), cover); + } + }; + + //====================================================comp_op_adaptor_rgba_plain + template + struct comp_op_adaptor_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; + typedef typename color_type::long_type long_type; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + multiplier_rgba::premultiply(p); + comp_op_adaptor_rgba::blend_pix(op, p, r, g, b, a, cover); + multiplier_rgba::demultiply(p); + } + }; - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) + //=========================================comp_op_adaptor_clip_to_dst_rgba_plain + template + struct comp_op_adaptor_clip_to_dst_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; + typedef typename color_type::long_type long_type; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) { - unsigned da = p[Order::A]; - comp_op_table_rgba::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); + multiplier_rgba::premultiply(p); + comp_op_adaptor_clip_to_dst_rgba::blend_pix(op, p, r, g, b, a, cover); + multiplier_rgba::demultiply(p); } }; //=======================================================comp_adaptor_rgba - template struct comp_adaptor_rgba + template + struct comp_adaptor_rgba { - typedef typename BlenderPre::order_type order_type; typedef typename BlenderPre::color_type color_type; + typedef typename BlenderPre::order_type 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 - }; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type 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); + BlenderPre::blend_pix(p, + color_type::multiply(r, a), + color_type::multiply(g, a), + color_type::multiply(b, a), + a, cover); } }; //==========================================comp_adaptor_clip_to_dst_rgba - template struct comp_adaptor_clip_to_dst_rgba + template + struct comp_adaptor_clip_to_dst_rgba { + typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type 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; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + r = color_type::multiply(r, a); + g = color_type::multiply(g, a); + b = color_type::multiply(b, a); + value_type da = p[order_type::A]; + BlenderPre::blend_pix(p, + color_type::multiply(r, da), + color_type::multiply(g, da), + color_type::multiply(b, da), + color_type::multiply(a, da), cover); + } + }; + + //=======================================================comp_adaptor_rgba_pre + template + struct comp_adaptor_rgba_pre + { typedef typename BlenderPre::color_type color_type; + typedef typename BlenderPre::order_type 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 - }; + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type 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); + BlenderPre::blend_pix(p, r, g, b, a, cover); } }; //======================================comp_adaptor_clip_to_dst_rgba_pre - template struct comp_adaptor_clip_to_dst_rgba_pre + template + struct comp_adaptor_clip_to_dst_rgba_pre + { + typedef typename BlenderPre::color_type color_type; + typedef typename BlenderPre::order_type 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; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + unsigned da = p[order_type::A]; + BlenderPre::blend_pix(p, + color_type::multiply(r, da), + color_type::multiply(g, da), + color_type::multiply(b, da), + color_type::multiply(a, da), + cover); + } + }; + + //=======================================================comp_adaptor_rgba_plain + template + struct comp_adaptor_rgba_plain { + typedef typename BlenderPre::color_type color_type; typedef typename BlenderPre::order_type 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; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + multiplier_rgba::premultiply(p); + comp_adaptor_rgba::blend_pix(op, p, r, g, b, a, cover); + multiplier_rgba::demultiply(p); + } + }; + + //==========================================comp_adaptor_clip_to_dst_rgba_plain + template + struct comp_adaptor_clip_to_dst_rgba_plain + { typedef typename BlenderPre::color_type color_type; + typedef typename BlenderPre::order_type 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 + typedef typename color_type::calc_type calc_type; + typedef typename color_type::long_type long_type; + + static AGG_INLINE void blend_pix(unsigned op, value_type* p, + value_type r, value_type g, value_type b, value_type a, cover_type cover) + { + multiplier_rgba::premultiply(p); + comp_adaptor_clip_to_dst_rgba::blend_pix(op, p, r, g, b, a, cover); + multiplier_rgba::demultiply(p); + } + }; + + + //=================================================pixfmt_alpha_blend_rgba + template + class pixfmt_alpha_blend_rgba + { + public: + typedef pixfmt_rgba_tag pixfmt_category; + 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 + { + num_components = 4, + pix_step = 4, + 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, value_type a) + { + c[order_type::R] = r; + c[order_type::G] = g; + c[order_type::B] = b; + c[order_type::A] = a; + } + + void set(const color_type& color) + { + set(color.r, color.g, color.b, color.a); + } + + void get(value_type& r, value_type& g, value_type& b, value_type& a) const + { + r = c[order_type::R]; + g = c[order_type::G]; + b = c[order_type::B]; + a = c[order_type::A]; + } + + color_type get() const + { + return color_type( + c[order_type::R], + c[order_type::G], + c[order_type::B], + c[order_type::A]); + } + + 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); + } }; - static AGG_INLINE void blend_pix(unsigned op, value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned ca, - unsigned cover) + private: + //-------------------------------------------------------------------- + AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, 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); + m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover); } - }; - - - - - - //===============================================copy_or_blend_rgba_wrapper - template 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 + //-------------------------------------------------------------------- + AGG_INLINE void blend_pix(pixel_type* p, const color_type& c) { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask - }; + m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a); + } //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha) + AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover) { - if(alpha) + if (!c.is_transparent()) { - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_mask) { - p[order_type::R] = cr; - p[order_type::G] = cg; - p[order_type::B] = cb; - p[order_type::A] = base_mask; + p->set(c.r, c.g, c.b, c.a); } else { - Blender::blend_pix(p, cr, cg, cb, alpha); + m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a, cover); } } } //-------------------------------------------------------------------- - static AGG_INLINE void copy_or_blend_pix(value_type* p, - unsigned cr, unsigned cg, unsigned cb, - unsigned alpha, - unsigned cover) + AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c) { - if(cover == 255) - { - copy_or_blend_pix(p, cr, cg, cb, alpha); - } - else + if (!c.is_transparent()) { - if(alpha) + if (c.is_opaque()) { - 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); - } + p->set(c.r, c.g, c.b, c.a); + } + else + { + m_blender.blend_pix(p->c, c.r, c.g, c.b, c.a); } } } - }; - - - - - - //=================================================pixfmt_alpha_blend_rgba - template - 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 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) {} - pixfmt_alpha_blend_rgba(rbuf_type& rb) : m_rbuf(&rb) {} + explicit pixfmt_alpha_blend_rgba(rbuf_type& rb) : m_rbuf(&rb) {} void attach(rbuf_type& rb) { m_rbuf = &rb; } + //-------------------------------------------------------------------- + template + 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); } //-------------------------------------------------------------------- - const int8u* row_ptr(int y) const + AGG_INLINE int8u* pix_ptr(int x, int y) + { + return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); + } + + AGG_INLINE const int8u* pix_ptr(int x, int y) const + { + return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); + } + + // 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)); + } + + // 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)) : 0; + } + + // Get pixel pointer from raw buffer pointer. + AGG_INLINE static pixel_type* pix_value_ptr(void* p) + { + return (pixel_type*)p; + } + + // Get pixel pointer from raw buffer pointer. + AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { - return m_rbuf->row_ptr(y); + return (const pixel_type*)p; } //-------------------------------------------------------------------- - const int8u* pix_ptr(int x, int y) const + AGG_INLINE static void write_plain_color(void* p, color_type c) { - return m_rbuf->row_ptr(y) + x * pix_width; + blender_type::set_plain_color(pix_value_ptr(p)->c, c); } //-------------------------------------------------------------------- - row_data row(int y) const + AGG_INLINE static color_type read_plain_color(const void* p) { - return m_rbuf->row(y); + return blender_type::get_plain_color(pix_value_ptr(p)->c); } //-------------------------------------------------------------------- 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; + ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- AGG_INLINE color_type pixel(int x, int y) const { - const value_type* p = (const value_type*)m_rbuf->row_ptr(y); - if(p) + if (const pixel_type* p = pix_value_ptr(x, y)) { - p += x << 2; - return color_type(p[order_type::R], - p[order_type::G], - p[order_type::B], - p[order_type::A]); + return p->get(); } return color_type::no_color(); } @@ -1704,105 +1719,85 @@ namespace agg24 //-------------------------------------------------------------------- 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; + pix_value_ptr(x, y, 1)->set(c); } //-------------------------------------------------------------------- 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); + copy_or_blend_pix(pix_value_ptr(x, y, 1), c, cover); } - //-------------------------------------------------------------------- - AGG_INLINE void copy_hline(int x, int y, - unsigned len, + 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; + v.set(c); + pixel_type* p = pix_value_ptr(x, y, len); do { - *(pixel_type*)p = v; - p += 4; + *p = v; + p = p->next(); } - while(--len); + while (--len); } //-------------------------------------------------------------------- AGG_INLINE void copy_vline(int x, int y, - unsigned len, + 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; + v.set(c); do { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - *(pixel_type*)p = v; + *pix_value_ptr(x, y++, 1) = v; } - while(--len); + while (--len); } - //-------------------------------------------------------------------- void blend_hline(int x, int y, - unsigned len, + unsigned len, const color_type& c, int8u cover) { - if (c.a) + if (!c.is_transparent()) { - 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* p = pix_value_ptr(x, y, len); + if (c.is_opaque() && cover == cover_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; + v.set(c); do { - *(pixel_type*)p = v; - p += 4; + *p = v; + p = p->next(); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { do { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha); - p += 4; + blend_pix(p, c); + p = p->next(); } - while(--len); + while (--len); } else { do { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, cover); - p += 4; + blend_pix(p, c, cover); + p = p->next(); } - while(--len); + while (--len); } } } @@ -1811,47 +1806,39 @@ namespace agg24 //-------------------------------------------------------------------- void blend_vline(int x, int y, - unsigned len, + unsigned len, const color_type& c, int8u cover) { - if (c.a) + if (!c.is_transparent()) { - value_type* p; - calc_type alpha = (calc_type(c.a) * (cover + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && cover == cover_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; + v.set(c); do { - p = (value_type*)m_rbuf->row_ptr(x, y++, 1) + (x << 2); - *(pixel_type*)p = v; + *pix_value_ptr(x, y++, 1) = v; } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { 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); + blend_pix(pix_value_ptr(x, y++, 1), c, c.a); } - while(--len); + 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); + blend_pix(pix_value_ptr(x, y++, 1), c, cover); } - while(--len); + while (--len); } } } @@ -1860,196 +1847,155 @@ namespace agg24 //-------------------------------------------------------------------- void blend_solid_hspan(int x, int y, - unsigned len, + unsigned len, const color_type& c, const int8u* covers) { - if (c.a) + if (!c.is_transparent()) { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do + pixel_type* p = pix_value_ptr(x, y, len); + do { - calc_type alpha = (calc_type(c.a) * (calc_type(*covers) + 1)) >> 8; - if(alpha == base_mask) + if (c.is_opaque() && *covers == cover_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; + p->set(c); } else { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, *covers); + blend_pix(p, c, *covers); } - p += 4; + p = p->next(); ++covers; } - while(--len); + while (--len); } } //-------------------------------------------------------------------- void blend_solid_vspan(int x, int y, - unsigned len, + unsigned len, const color_type& c, const int8u* covers) { - if (c.a) + if (!c.is_transparent()) { - do + 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) + pixel_type* p = pix_value_ptr(x, y++, 1); + if (c.is_opaque() && *covers == cover_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; + p->set(c); } else { - blender_type::blend_pix(p, c.r, c.g, c.b, alpha, *covers); + blend_pix(p, c, *covers); } ++covers; } - while(--len); + while (--len); } } - //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors) { - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do + pixel_type* p = pix_value_ptr(x, y, len); + 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; + p->set(*colors++); + p = p->next(); } - while(--len); + while (--len); } + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + do + { + pix_value_ptr(x, y++, 1)->set(*colors++); + } + while (--len); + } + //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, - unsigned len, + 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) + pixel_type* p = pix_value_ptr(x, y, len); + if (covers) { - do + do { - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a, - *covers++); - p += 4; - ++colors; + copy_or_blend_pix(p, *colors++, *covers++); + p = p->next(); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { - do + do { - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a); - p += 4; - ++colors; + copy_or_blend_pix(p, *colors++); + p = p->next(); } - while(--len); + while (--len); } else { - do + do { - cob_type::copy_or_blend_pix(p, - colors->r, - colors->g, - colors->b, - colors->a, - cover); - p += 4; - ++colors; + copy_or_blend_pix(p, *colors++, cover); + p = p->next(); } - while(--len); + while (--len); } } } - - //-------------------------------------------------------------------- void blend_color_vspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors, const int8u* covers, int8u cover) { - value_type* p; - if(covers) + if (covers) { - do + 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; + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, *covers++); } - while(--len); + while (--len); } else { - if(cover == 255) + if (cover == cover_mask) { - do + 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; + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++); } - while(--len); + while (--len); } else { - do + 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; + copy_or_blend_pix(pix_value_ptr(x, y++, 1), *colors++, cover); } - while(--len); + while (--len); } } } @@ -2057,21 +2003,19 @@ namespace agg24 //-------------------------------------------------------------------- template void for_each_pixel(Function f) { - unsigned y; - for(y = 0; y < height(); ++y) + for (unsigned 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; - value_type* p = - (value_type*)m_rbuf->row_ptr(r.x1, y, len) + (r.x1 << 2); + pixel_type* p = pix_value_ptr(r.x1, y, len); do { - f(p); - p += 4; + f(p->c); + p = p->next(); } - while(--len); + while (--len); } } } @@ -2101,86 +2045,145 @@ namespace agg24 } //-------------------------------------------------------------------- - template void copy_from(const RenBuf2& from, + template 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) + if (const int8u* p = from.row_ptr(ysrc)) { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- + // Blend from another RGBA surface. template - void blend_from(const SrcPixelFormatRenderer& from, + 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) + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { - psrc += xsrc << 2; - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); - int incp = 4; - if(xdst > xsrc) + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + int srcinc = 1; + int dstinc = 1; + + if (xdst > xsrc) { - psrc += (len-1) << 2; - pdst += (len-1) << 2; - incp = -4; + psrc = psrc->advance(len - 1); + pdst = pdst->advance(len - 1); + srcinc = -1; + dstinc = -1; } - if(cover == 255) + if (cover == cover_mask) { - do + 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; + copy_or_blend_pix(pdst, psrc->get()); + psrc = psrc->advance(srcinc); + pdst = pdst->advance(dstinc); } - while(--len); + while (--len); } else { - do + 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; + copy_or_blend_pix(pdst, psrc->get(), cover); + psrc = psrc->advance(srcinc); + pdst = pdst->advance(dstinc); } - while(--len); + while (--len); } } } - private: - rbuf_type* m_rbuf; - }; + //-------------------------------------------------------------------- + // Combine single color with grayscale surface and blend. + template + void blend_from_color(const SrcPixelFormatRenderer& from, + const color_type& color, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + typedef typename SrcPixelFormatRenderer::color_type src_color_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + + do + { + copy_or_blend_pix(pdst, color, + src_color_type::scale_cover(cover, psrc->c[0])); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + + //-------------------------------------------------------------------- + // Blend from color table, using grayscale surface as indexes into table. + // Obviously, this only works for integer value types. + template + void blend_from_lut(const SrcPixelFormatRenderer& from, + const color_type* color_lut, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + if (cover == cover_mask) + { + do + { + copy_or_blend_pix(pdst, color_lut[psrc->c[0]]); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + else + { + do + { + copy_or_blend_pix(pdst, color_lut[psrc->c[0]], cover); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + } + private: + rbuf_type* m_rbuf; + Blender m_blender; + }; //================================================pixfmt_custom_blend_rgba template class pixfmt_custom_blend_rgba { public: + typedef pixfmt_rgba_tag pixfmt_category; typedef RenBuf rbuf_type; typedef typename rbuf_type::row_data row_data; typedef Blender blender_type; @@ -2188,232 +2191,330 @@ namespace agg24 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 + enum { - base_shift = color_type::base_shift, - base_scale = color_type::base_scale, - base_mask = color_type::base_mask, - pix_width = sizeof(value_type) * 4 + num_components = 4, + pix_step = 4, + 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, value_type a) + { + c[order_type::R] = r; + c[order_type::G] = g; + c[order_type::B] = b; + c[order_type::A] = a; + } + + void set(const color_type& color) + { + set(color.r, color.g, color.b, color.a); + } + + void get(value_type& r, value_type& g, value_type& b, value_type& a) const + { + r = c[order_type::R]; + g = c[order_type::G]; + b = c[order_type::B]; + a = c[order_type::A]; + } + + color_type get() const + { + return color_type( + c[order_type::R], + c[order_type::G], + c[order_type::B], + c[order_type::A]); + } + + pixel_type* next() + { + return (pixel_type*)(c + pix_step); + } + + const pixel_type* next() const + { + return (const pixel_type*)(c + pix_step); + } + + pixel_type* advance(int n) + { + return (pixel_type*)(c + n * pix_step); + } + + const pixel_type* advance(int n) const + { + return (const pixel_type*)(c + n * pix_step); + } }; + private: + //-------------------------------------------------------------------- + AGG_INLINE void blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full) + { + m_blender.blend_pix(m_comp_op, p->c, c.r, c.g, c.b, c.a, cover); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_or_blend_pix(pixel_type* p, const color_type& c, unsigned cover = cover_full) + { + if (!c.is_transparent()) + { + if (c.is_opaque() && cover == cover_mask) + { + p->set(c.r, c.g, c.b, c.a); + } + else + { + blend_pix(p, c, cover); + } + } + } + + public: //-------------------------------------------------------------------- pixfmt_custom_blend_rgba() : m_rbuf(0), m_comp_op(3) {} - pixfmt_custom_blend_rgba(rbuf_type& rb, unsigned 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; } //-------------------------------------------------------------------- - unsigned width() const { return m_rbuf->width(); } - unsigned height() const { return m_rbuf->height(); } + template + 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; + } //-------------------------------------------------------------------- void comp_op(unsigned op) { m_comp_op = op; } unsigned comp_op() const { return m_comp_op; } //-------------------------------------------------------------------- - const int8u* row_ptr(int y) const + 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); + return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); } - //-------------------------------------------------------------------- - const int8u* pix_ptr(int x, int y) const + AGG_INLINE const int8u* pix_ptr(int x, int y) const { - return m_rbuf->row_ptr(y) + x * pix_width; + return m_rbuf->row_ptr(y) + sizeof(value_type) * (x * pix_step); } - //-------------------------------------------------------------------- - row_data row(int y) const + // 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)); + } + + // 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)) : 0; + } + + // Get pixel pointer from raw buffer pointer. + AGG_INLINE static pixel_type* pix_value_ptr(void* p) + { + return (pixel_type*)p; + } + + // Get pixel pointer from raw buffer pointer. + AGG_INLINE static const pixel_type* pix_value_ptr(const void* p) { - return m_rbuf->row(y); + return (const pixel_type*)p; } //-------------------------------------------------------------------- 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; + ((pixel_type*)p)->set(c); } //-------------------------------------------------------------------- - color_type pixel(int x, int y) const + AGG_INLINE 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]); + if (const pixel_type* p = pix_value_ptr(x, y)) + { + return p->get(); + } + return color_type::no_color(); } //-------------------------------------------------------------------- - void copy_pixel(int x, int y, const color_type& c) + AGG_INLINE 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); + make_pix(pix_value_ptr(x, y, 1), c); } //-------------------------------------------------------------------- - void blend_pixel(int x, int y, const color_type& c, int8u cover) + AGG_INLINE 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); + blend_pix(pix_value_ptr(x, y, 1), c, cover); } //-------------------------------------------------------------------- - void copy_hline(int x, int y, unsigned len, const color_type& c) + 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; + v.set(c); + pixel_type* p = pix_value_ptr(x, y, len); do { - blender_type::blend_pix(m_comp_op, p, c.r, c.g, c.b, c.a, 255); - p += 4; + *p = v; + p = p->next(); } - while(--len); + while (--len); } + //-------------------------------------------------------------------- - void copy_vline(int x, int y, unsigned len, const color_type& c) + AGG_INLINE void copy_vline(int x, int y, + unsigned len, + const color_type& c) { + pixel_type v; + v.set(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); + *pix_value_ptr(x, y++, 1) = v; } - while(--len); + while (--len); } //-------------------------------------------------------------------- - void blend_hline(int x, int y, unsigned 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); + pixel_type* p = pix_value_ptr(x, y, len); do { - blender_type::blend_pix(m_comp_op, p, c.r, c.g, c.b, c.a, cover); - p += 4; + blend_pix(p, c, cover); + p = p->next(); } - while(--len); + while (--len); } //-------------------------------------------------------------------- - void blend_vline(int x, int y, unsigned 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); + blend_pix(pix_value_ptr(x, y++, 1), c, cover); } - while(--len); + while (--len); } //-------------------------------------------------------------------- - void blend_solid_hspan(int x, int y, unsigned 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 + pixel_type* p = pix_value_ptr(x, y, len); + + do { - blender_type::blend_pix(m_comp_op, - p, c.r, c.g, c.b, c.a, - *covers++); - p += 4; + blend_pix(p, c, *covers++); + p = p->next(); } - while(--len); + while (--len); } //-------------------------------------------------------------------- - void blend_solid_vspan(int x, int y, unsigned len, + void blend_solid_vspan(int x, int y, unsigned len, const color_type& c, const int8u* covers) { - do + 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++); + blend_pix(pix_value_ptr(x, y++, 1), c, *covers++); } - while(--len); + while (--len); } //-------------------------------------------------------------------- void copy_color_hspan(int x, int y, - unsigned len, + unsigned len, const color_type* colors) { + pixel_type* p = pix_value_ptr(x, y, len); + + do + { + p->set(*colors++); + p = p->next(); + } + while (--len); + } - value_type* p = (value_type*)m_rbuf->row_ptr(x, y, len) + (x << 2); - do + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + 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; + pix_value_ptr(x, y++, 1)->set(*colors++); } - while(--len); + while (--len); } //-------------------------------------------------------------------- - void blend_color_hspan(int x, int y, unsigned len, - const color_type* colors, + 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 + pixel_type* p = pix_value_ptr(x, y, len); + + do { - blender_type::blend_pix(m_comp_op, - p, - colors->r, - colors->g, - colors->b, - colors->a, - covers ? *covers++ : cover); - p += 4; - ++colors; + blend_pix(p, *colors++, covers ? *covers++ : cover); + p = p->next(); } - while(--len); + while (--len); } //-------------------------------------------------------------------- - void blend_color_vspan(int x, int y, unsigned len, - const color_type* colors, + void blend_color_vspan(int x, int y, unsigned len, + const color_type* colors, const int8u* covers, int8u cover) { - do + 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; + blend_pix(pix_value_ptr(x, y++, 1), *colors++, covers ? *covers++ : cover); } - while(--len); + while (--len); } @@ -2421,20 +2522,19 @@ namespace agg24 template 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; - value_type* p = - (value_type*)m_rbuf->row_ptr(r.x1, y, len) + (r.x1 << 2); + pixel_type* p = pix_value_ptr(r.x1, y, len); do { - f(p); - p += 4; + f(p->c); + p = p->next(); } - while(--len); + while (--len); } } } @@ -2464,122 +2564,239 @@ namespace agg24 } //-------------------------------------------------------------------- - template void copy_from(const RenBuf2& from, + template 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) + if (const int8u* p = from.row_ptr(ysrc)) { - memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, - p + xsrc * pix_width, + memmove(m_rbuf->row_ptr(xdst, ydst, len) + xdst * pix_width, + p + xsrc * pix_width, len * pix_width); } } //-------------------------------------------------------------------- - template - void blend_from(const SrcPixelFormatRenderer& from, + // Blend from another RGBA surface. + template + 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) + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) { - psrc += xsrc << 2; - value_type* pdst = - (value_type*)m_rbuf->row_ptr(xdst, ydst, len) + (xdst << 2); + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + int srcinc = 1; + int dstinc = 1; - int incp = 4; - if(xdst > xsrc) + if (xdst > xsrc) { - psrc += (len-1) << 2; - pdst += (len-1) << 2; - incp = -4; + psrc = psrc->advance(len - 1); + pdst = pdst->advance(len - 1); + srcinc = -1; + dstinc = -1; } - do + 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; + blend_pix(pdst, psrc->get(), cover); + psrc = psrc->advance(srcinc); + pdst = pdst->advance(dstinc); } - while(--len); + while (--len); } } - private: - rbuf_type* m_rbuf; - unsigned m_comp_op; - }; + //-------------------------------------------------------------------- + // Blend from single color, using grayscale surface as alpha channel. + template + void blend_from_color(const SrcPixelFormatRenderer& from, + const color_type& color, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; + typedef typename SrcPixelFormatRenderer::color_type src_color_type; + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); + do + { + blend_pix(pdst, color, + src_color_type::scale_cover(cover, psrc->c[0])); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } + //-------------------------------------------------------------------- + // Blend from color table, using grayscale surface as indexes into table. + // Obviously, this only works for integer value types. + template + void blend_from_lut(const SrcPixelFormatRenderer& from, + const color_type* color_lut, + int xdst, int ydst, + int xsrc, int ysrc, + unsigned len, + int8u cover) + { + typedef typename SrcPixelFormatRenderer::pixel_type src_pixel_type; - //----------------------------------------------------------------------- - typedef blender_rgba blender_rgba32; //----blender_rgba32 - typedef blender_rgba blender_argb32; //----blender_argb32 - typedef blender_rgba blender_abgr32; //----blender_abgr32 - typedef blender_rgba blender_bgra32; //----blender_bgra32 + if (const src_pixel_type* psrc = from.pix_value_ptr(xsrc, ysrc)) + { + pixel_type* pdst = pix_value_ptr(xdst, ydst, len); - typedef blender_rgba_pre blender_rgba32_pre; //----blender_rgba32_pre - typedef blender_rgba_pre blender_argb32_pre; //----blender_argb32_pre - typedef blender_rgba_pre blender_abgr32_pre; //----blender_abgr32_pre - typedef blender_rgba_pre blender_bgra32_pre; //----blender_bgra32_pre + do + { + blend_pix(pdst, color_lut[psrc->c[0]], cover); + psrc = psrc->next(); + pdst = pdst->next(); + } + while (--len); + } + } - typedef blender_rgba_plain blender_rgba32_plain; //----blender_rgba32_plain - typedef blender_rgba_plain blender_argb32_plain; //----blender_argb32_plain - typedef blender_rgba_plain blender_abgr32_plain; //----blender_abgr32_plain - typedef blender_rgba_plain blender_bgra32_plain; //----blender_bgra32_plain + private: + rbuf_type* m_rbuf; + Blender m_blender; + unsigned m_comp_op; + }; - typedef blender_rgba blender_rgba64; //----blender_rgba64 - typedef blender_rgba blender_argb64; //----blender_argb64 - typedef blender_rgba blender_abgr64; //----blender_abgr64 - typedef blender_rgba blender_bgra64; //----blender_bgra64 - typedef blender_rgba_pre blender_rgba64_pre; //----blender_rgba64_pre - typedef blender_rgba_pre blender_argb64_pre; //----blender_argb64_pre - typedef blender_rgba_pre blender_abgr64_pre; //----blender_abgr64_pre - typedef blender_rgba_pre blender_bgra64_pre; //----blender_bgra64_pre + //----------------------------------------------------------------------- + typedef blender_rgba blender_rgba32; + typedef blender_rgba blender_argb32; + typedef blender_rgba blender_abgr32; + typedef blender_rgba blender_bgra32; + + typedef blender_rgba blender_srgba32; + typedef blender_rgba blender_sargb32; + typedef blender_rgba blender_sabgr32; + typedef blender_rgba blender_sbgra32; + + typedef blender_rgba_pre blender_rgba32_pre; + typedef blender_rgba_pre blender_argb32_pre; + typedef blender_rgba_pre blender_abgr32_pre; + typedef blender_rgba_pre blender_bgra32_pre; + + typedef blender_rgba_pre blender_srgba32_pre; + typedef blender_rgba_pre blender_sargb32_pre; + typedef blender_rgba_pre blender_sabgr32_pre; + typedef blender_rgba_pre blender_sbgra32_pre; + + typedef blender_rgba_plain blender_rgba32_plain; + typedef blender_rgba_plain blender_argb32_plain; + typedef blender_rgba_plain blender_abgr32_plain; + typedef blender_rgba_plain blender_bgra32_plain; + + typedef blender_rgba_plain blender_srgba32_plain; + typedef blender_rgba_plain blender_sargb32_plain; + typedef blender_rgba_plain blender_sabgr32_plain; + typedef blender_rgba_plain blender_sbgra32_plain; + + typedef blender_rgba blender_rgba64; + typedef blender_rgba blender_argb64; + typedef blender_rgba blender_abgr64; + typedef blender_rgba blender_bgra64; + + typedef blender_rgba_pre blender_rgba64_pre; + typedef blender_rgba_pre blender_argb64_pre; + typedef blender_rgba_pre blender_abgr64_pre; + typedef blender_rgba_pre blender_bgra64_pre; + + typedef blender_rgba_plain blender_rgba64_plain; + typedef blender_rgba_plain blender_argb64_plain; + typedef blender_rgba_plain blender_abgr64_plain; + typedef blender_rgba_plain blender_bgra64_plain; + + typedef blender_rgba blender_rgba128; + typedef blender_rgba blender_argb128; + typedef blender_rgba blender_abgr128; + typedef blender_rgba blender_bgra128; + + typedef blender_rgba_pre blender_rgba128_pre; + typedef blender_rgba_pre blender_argb128_pre; + typedef blender_rgba_pre blender_abgr128_pre; + typedef blender_rgba_pre blender_bgra128_pre; + + typedef blender_rgba_plain blender_rgba128_plain; + typedef blender_rgba_plain blender_argb128_plain; + typedef blender_rgba_plain blender_abgr128_plain; + typedef blender_rgba_plain blender_bgra128_plain; //----------------------------------------------------------------------- - typedef int32u pixel32_type; - typedef pixfmt_alpha_blend_rgba pixfmt_rgba32; //----pixfmt_rgba32 - typedef pixfmt_alpha_blend_rgba pixfmt_argb32; //----pixfmt_argb32 - typedef pixfmt_alpha_blend_rgba pixfmt_abgr32; //----pixfmt_abgr32 - typedef pixfmt_alpha_blend_rgba pixfmt_bgra32; //----pixfmt_bgra32 - - typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_pre; //----pixfmt_rgba32_pre - typedef pixfmt_alpha_blend_rgba pixfmt_argb32_pre; //----pixfmt_argb32_pre - typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_pre; //----pixfmt_abgr32_pre - typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_pre; //----pixfmt_bgra32_pre - - typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_plain; //----pixfmt_rgba32_plain - typedef pixfmt_alpha_blend_rgba pixfmt_argb32_plain; //----pixfmt_argb32_plain - typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_plain; //----pixfmt_abgr32_plain - typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_plain; //----pixfmt_bgra32_plain - - struct pixel64_type { int16u c[4]; }; - typedef pixfmt_alpha_blend_rgba pixfmt_rgba64; //----pixfmt_rgba64 - typedef pixfmt_alpha_blend_rgba pixfmt_argb64; //----pixfmt_argb64 - typedef pixfmt_alpha_blend_rgba pixfmt_abgr64; //----pixfmt_abgr64 - typedef pixfmt_alpha_blend_rgba pixfmt_bgra64; //----pixfmt_bgra64 - - typedef pixfmt_alpha_blend_rgba pixfmt_rgba64_pre; //----pixfmt_rgba64_pre - typedef pixfmt_alpha_blend_rgba pixfmt_argb64_pre; //----pixfmt_argb64_pre - typedef pixfmt_alpha_blend_rgba pixfmt_abgr64_pre; //----pixfmt_abgr64_pre - typedef pixfmt_alpha_blend_rgba pixfmt_bgra64_pre; //----pixfmt_bgra64_pre + typedef pixfmt_alpha_blend_rgba pixfmt_rgba32; + typedef pixfmt_alpha_blend_rgba pixfmt_argb32; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr32; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra32; + + typedef pixfmt_alpha_blend_rgba pixfmt_srgba32; + typedef pixfmt_alpha_blend_rgba pixfmt_sargb32; + typedef pixfmt_alpha_blend_rgba pixfmt_sabgr32; + typedef pixfmt_alpha_blend_rgba pixfmt_sbgra32; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_argb32_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_pre; + + typedef pixfmt_alpha_blend_rgba pixfmt_srgba32_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_sargb32_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_sabgr32_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_sbgra32_pre; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba32_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_argb32_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr32_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra32_plain; + + typedef pixfmt_alpha_blend_rgba pixfmt_srgba32_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_sargb32_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_sabgr32_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_sbgra32_plain; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba64; + typedef pixfmt_alpha_blend_rgba pixfmt_argb64; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr64; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra64; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba64_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_argb64_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr64_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra64_pre; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba64_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_argb64_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr64_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra64_plain; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba128; + typedef pixfmt_alpha_blend_rgba pixfmt_argb128; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr128; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra128; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba128_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_argb128_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr128_pre; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra128_pre; + + typedef pixfmt_alpha_blend_rgba pixfmt_rgba128_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_argb128_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_abgr128_plain; + typedef pixfmt_alpha_blend_rgba pixfmt_bgra128_plain; + } #endif diff --git a/kiva/agg/agg-24/include/agg_pixfmt_transposer.h b/kiva/agg/agg-24/include/agg_pixfmt_transposer.h new file mode 100644 index 000000000..cf078ba6a --- /dev/null +++ b/kiva/agg/agg-24/include/agg_pixfmt_transposer.h @@ -0,0 +1,157 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- + +#ifndef AGG_PIXFMT_TRANSPOSER_INCLUDED +#define AGG_PIXFMT_TRANSPOSER_INCLUDED + +#include "agg_basics.h" + +namespace agg24 +{ + //=======================================================pixfmt_transposer + template class pixfmt_transposer + { + public: + typedef PixFmt pixfmt_type; + typedef typename pixfmt_type::color_type color_type; + typedef typename pixfmt_type::row_data row_data; + typedef typename color_type::value_type value_type; + typedef typename color_type::calc_type calc_type; + + //-------------------------------------------------------------------- + pixfmt_transposer() : m_pixf(0) {} + explicit pixfmt_transposer(pixfmt_type& pixf) : m_pixf(&pixf) {} + void attach(pixfmt_type& pixf) { m_pixf = &pixf; } + + //-------------------------------------------------------------------- + AGG_INLINE unsigned width() const { return m_pixf->height(); } + AGG_INLINE unsigned height() const { return m_pixf->width(); } + + //-------------------------------------------------------------------- + AGG_INLINE color_type pixel(int x, int y) const + { + return m_pixf->pixel(y, x); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_pixel(int x, int y, const color_type& c) + { + m_pixf->copy_pixel(y, x, c); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_pixel(int x, int y, + const color_type& c, + int8u cover) + { + m_pixf->blend_pixel(y, x, c, cover); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_hline(int x, int y, + unsigned len, + const color_type& c) + { + m_pixf->copy_vline(y, x, len, c); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_vline(int x, int y, + unsigned len, + const color_type& c) + { + m_pixf->copy_hline(y, x, len, c); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_hline(int x, int y, + unsigned len, + const color_type& c, + int8u cover) + { + m_pixf->blend_vline(y, x, len, c, cover); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_vline(int x, int y, + unsigned len, + const color_type& c, + int8u cover) + { + m_pixf->blend_hline(y, x, len, c, cover); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_solid_hspan(int x, int y, + unsigned len, + const color_type& c, + const int8u* covers) + { + m_pixf->blend_solid_vspan(y, x, len, c, covers); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_solid_vspan(int x, int y, + unsigned len, + const color_type& c, + const int8u* covers) + { + m_pixf->blend_solid_hspan(y, x, len, c, covers); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_color_hspan(int x, int y, + unsigned len, + const color_type* colors) + { + m_pixf->copy_color_vspan(y, x, len, colors); + } + + //-------------------------------------------------------------------- + AGG_INLINE void copy_color_vspan(int x, int y, + unsigned len, + const color_type* colors) + { + m_pixf->copy_color_hspan(y, x, len, colors); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_color_hspan(int x, int y, + unsigned len, + const color_type* colors, + const int8u* covers, + int8u cover) + { + m_pixf->blend_color_vspan(y, x, len, colors, covers, cover); + } + + //-------------------------------------------------------------------- + AGG_INLINE void blend_color_vspan(int x, int y, + unsigned len, + const color_type* colors, + const int8u* covers, + int8u cover) + { + m_pixf->blend_color_hspan(y, x, len, colors, covers, cover); + } + + private: + pixfmt_type* m_pixf; + }; +} + +#endif + + diff --git a/kiva/agg/agg-24/include/agg_rasterizer_cells_aa.h b/kiva/agg/agg-24/include/agg_rasterizer_cells_aa.h index c3797ecfe..71f216b51 100644 --- a/kiva/agg/agg-24/include/agg_rasterizer_cells_aa.h +++ b/kiva/agg/agg-24/include/agg_rasterizer_cells_aa.h @@ -2,15 +2,15 @@ // 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. +// 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 +// 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. // //---------------------------------------------------------------------------- @@ -19,16 +19,17 @@ // http://www.antigrain.com //---------------------------------------------------------------------------- // -// Adaptation for 32-bit screen coordinates has been sponsored by +// Adaptation for 32-bit screen coordinates has been sponsored by // Liberty Technology Systems, Inc., visit http://lib-sys.com // // Liberty Technology Systems, Inc. is the provider of // PostScript and PDF technology for software developers. -// +// //---------------------------------------------------------------------------- #ifndef AGG_RASTERIZER_CELLS_AA_INCLUDED #define AGG_RASTERIZER_CELLS_AA_INCLUDED +#include #include #include #include "agg_math.h" @@ -48,8 +49,7 @@ namespace agg24 cell_block_shift = 12, cell_block_size = 1 << cell_block_shift, cell_block_mask = cell_block_size - 1, - cell_block_pool = 256, - cell_block_limit = 1024 + cell_block_pool = 256 }; struct sorted_y @@ -63,7 +63,7 @@ namespace agg24 typedef rasterizer_cells_aa self_type; ~rasterizer_cells_aa(); - rasterizer_cells_aa(); + rasterizer_cells_aa(unsigned cell_block_limit=1024); void reset(); void style(const cell_type& style_cell); @@ -76,19 +76,19 @@ namespace agg24 void sort_cells(); - unsigned total_cells() const + unsigned total_cells() const { return m_num_cells; } - unsigned scanline_num_cells(unsigned y) const - { - return m_sorted_y[y - m_min_y].num; + unsigned scanline_num_cells(unsigned y) const + { + return m_sorted_y[y - m_min_y].num; } const cell_type* const* scanline_cells(unsigned y) const - { - return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; + { + return m_sorted_cells.data() + m_sorted_y[y - m_min_y].start; } bool sorted() const { return m_sorted; } @@ -101,12 +101,13 @@ namespace agg24 void add_curr_cell(); void render_hline(int ey, int x1, int y1, int x2, int y2); void allocate_block(); - + private: unsigned m_num_blocks; unsigned m_max_blocks; unsigned m_curr_block; unsigned m_num_cells; + unsigned m_cell_block_limit; cell_type** m_cells; cell_type* m_curr_cell_ptr; pod_vector m_sorted_cells; @@ -124,7 +125,7 @@ namespace agg24 //------------------------------------------------------------------------ - template + template rasterizer_cells_aa::~rasterizer_cells_aa() { if(m_num_blocks) @@ -140,12 +141,13 @@ namespace agg24 } //------------------------------------------------------------------------ - template - rasterizer_cells_aa::rasterizer_cells_aa() : + template + rasterizer_cells_aa::rasterizer_cells_aa(unsigned cell_block_limit) : m_num_blocks(0), m_max_blocks(0), m_curr_block(0), m_num_cells(0), + m_cell_block_limit(cell_block_limit), m_cells(0), m_curr_cell_ptr(0), m_sorted_cells(), @@ -161,10 +163,10 @@ namespace agg24 } //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::reset() { - m_num_cells = 0; + m_num_cells = 0; m_curr_block = 0; m_curr_cell.initial(); m_style_cell.initial(); @@ -176,14 +178,16 @@ namespace agg24 } //------------------------------------------------------------------------ - template + template AGG_INLINE void rasterizer_cells_aa::add_curr_cell() { if(m_curr_cell.area | m_curr_cell.cover) { if((m_num_cells & cell_block_mask) == 0) { - if(m_num_blocks >= cell_block_limit) return; + if(m_num_blocks >= m_cell_block_limit) { + throw std::overflow_error("Exceeded cell block limit"); + } allocate_block(); } *m_curr_cell_ptr++ = m_curr_cell; @@ -192,7 +196,7 @@ namespace agg24 } //------------------------------------------------------------------------ - template + template AGG_INLINE void rasterizer_cells_aa::set_curr_cell(int x, int y) { if(m_curr_cell.not_equal(x, y, m_style_cell)) @@ -207,9 +211,9 @@ namespace agg24 } //------------------------------------------------------------------------ - template - AGG_INLINE void rasterizer_cells_aa::render_hline(int ey, - int x1, int y1, + template + AGG_INLINE void rasterizer_cells_aa::render_hline(int ey, + int x1, int y1, int x2, int y2) { int ex1 = x1 >> poly_subpixel_shift; @@ -305,14 +309,14 @@ namespace agg24 } //------------------------------------------------------------------------ - template + template AGG_INLINE void rasterizer_cells_aa::style(const cell_type& style_cell) - { - m_style_cell.style(style_cell); + { + m_style_cell.style(style_cell); } //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::line(int x1, int y1, int x2, int y2) { enum dx_limit_e { dx_limit = 16384 << poly_subpixel_shift }; @@ -358,7 +362,7 @@ namespace agg24 //Vertical line - we have to calculate start and end cells, //and then - the common values of the area and coverage for - //all cells of the line. We know exactly there's only one + //all cells of the line. We know exactly there's only one //cell, so, we don't have to call render_hline(). incr = 1; if(dx == 0) @@ -463,15 +467,15 @@ namespace agg24 } //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::allocate_block() { if(m_curr_block >= m_num_blocks) { if(m_num_blocks >= m_max_blocks) { - cell_type** new_cells = - pod_allocator::allocate(m_max_blocks + + cell_type** new_cells = + pod_allocator::allocate(m_max_blocks + cell_block_pool); if(m_cells) @@ -483,7 +487,7 @@ namespace agg24 m_max_blocks += cell_block_pool; } - m_cells[m_num_blocks++] = + m_cells[m_num_blocks++] = pod_allocator::allocate(cell_block_size); } @@ -513,7 +517,7 @@ namespace agg24 void qsort_cells(Cell** start, unsigned num) { Cell** stack[80]; - Cell*** top; + Cell*** top; Cell** limit; Cell** base; @@ -538,7 +542,7 @@ namespace agg24 i = base + 1; j = limit - 1; - // now ensure that *i <= *base <= *j + // now ensure that *i <= *base <= *j if((*j)->x < (*i)->x) { swap_cells(i, j); @@ -619,7 +623,7 @@ namespace agg24 //------------------------------------------------------------------------ - template + template void rasterizer_cells_aa::sort_cells() { if(m_sorted) return; //Perform sort only the first time. @@ -636,15 +640,14 @@ namespace agg24 //for(unsigned nc = 0; nc < m_num_cells; nc++) //{ // cell_type* cell = m_cells[nc >> cell_block_shift] + (nc & cell_block_mask); -// if(cell->x < m_min_x || -// cell->y < m_min_y || -// cell->x > m_max_x || +// if(cell->x < m_min_x || +// cell->y < m_min_y || +// cell->x > m_max_x || // cell->y > m_max_y) // { // cell = cell; // Breakpoint here // } //} - // Allocate the array of cell pointers m_sorted_cells.allocate(m_num_cells, 16); @@ -655,27 +658,20 @@ namespace agg24 // 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 >> cell_block_shift; + unsigned nb = m_num_cells; unsigned i; - while(nb--) + while(nb) { cell_ptr = *block_ptr++; - i = cell_block_size; - while(i--) + i = (nb > cell_block_size) ? cell_block_size : nb; + nb -= i; + while(i--) { m_sorted_y[cell_ptr->y - m_min_y].start++; ++cell_ptr; } } - 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++) @@ -687,12 +683,13 @@ namespace agg24 // Fill the cell pointer array sorted by Y block_ptr = m_cells; - nb = m_num_cells >> cell_block_shift; - while(nb--) + nb = m_num_cells; + while(nb) { cell_ptr = *block_ptr++; - i = cell_block_size; - while(i--) + i = (nb > cell_block_size) ? cell_block_size : nb; + nb -= i; + while(i--) { sorted_y& curr_y = m_sorted_y[cell_ptr->y - m_min_y]; m_sorted_cells[curr_y.start + curr_y.num] = cell_ptr; @@ -700,16 +697,6 @@ namespace agg24 ++cell_ptr; } } - - 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/kiva/agg/agg-24/include/agg_rasterizer_compound_aa.h b/kiva/agg/agg-24/include/agg_rasterizer_compound_aa.h index e429a2d27..f1f658517 100644 --- a/kiva/agg/agg-24/include/agg_rasterizer_compound_aa.h +++ b/kiva/agg/agg-24/include/agg_rasterizer_compound_aa.h @@ -70,6 +70,15 @@ namespace agg24 }; + //===========================================================layer_order_e + enum layer_order_e + { + layer_unsorted, //------layer_unsorted + layer_direct, //------layer_direct + layer_inverse //------layer_inverse + }; + + //==================================================rasterizer_compound_aa template class rasterizer_compound_aa { @@ -86,8 +95,9 @@ namespace agg24 }; public: - typedef Clip clip_type; - typedef typename Clip::conv_type conv_type; + typedef Clip clip_type; + typedef typename Clip::conv_type conv_type; + typedef typename Clip::coord_type coord_type; enum aa_scale_e { @@ -99,17 +109,23 @@ namespace agg24 }; //-------------------------------------------------------------------- - rasterizer_compound_aa() : - m_outline(), + rasterizer_compound_aa(unsigned cell_block_limit=1024) : + m_outline(cell_block_limit), m_clipper(), m_filling_rule(fill_non_zero), + m_layer_order(layer_direct), m_styles(), // Active Styles m_ast(), // Active Style Table (unique values) m_asm(), // Active Style Mask m_cells(), + m_cover_buf(), m_min_style(0x7FFFFFFF), m_max_style(-0x7FFFFFFF), - m_scan_y(0x7FFFFFFF) + m_start_x(0), + m_start_y(0), + m_scan_y(0x7FFFFFFF), + m_sl_start(0), + m_sl_len(0) {} //-------------------------------------------------------------------- @@ -117,6 +133,7 @@ namespace agg24 void reset_clipping(); void clip_box(double x1, double y1, double x2, double y2); void filling_rule(filling_rule_e filling_rule); + void layer_order(layer_order_e order); //-------------------------------------------------------------------- void styles(int left, int right); @@ -158,8 +175,12 @@ namespace agg24 void sort(); bool rewind_scanlines(); unsigned sweep_styles(); + int scanline_start() const { return m_sl_start; } + unsigned scanline_length() const { return m_sl_len; } unsigned style(unsigned style_idx) const; + cover_type* allocate_cover_buffer(unsigned len); + //-------------------------------------------------------------------- bool navigate_scanline(int y); bool hit_test(int tx, int ty); @@ -191,8 +212,14 @@ namespace agg24 sl.reset_spans(); - if(style_idx < 0) style_idx = 0; - else style_idx++; + if(style_idx < 0) + { + style_idx = 0; + } + else + { + style_idx++; + } const style_info& st = m_styles[m_ast[style_idx]]; @@ -230,7 +257,6 @@ namespace agg24 if(sl.num_spans() == 0) return false; sl.finalize(scan_y); return true; - } private: @@ -246,14 +272,20 @@ namespace agg24 rasterizer_cells_aa m_outline; clip_type m_clipper; filling_rule_e m_filling_rule; + layer_order_e m_layer_order; pod_vector m_styles; // Active Styles pod_vector m_ast; // Active Style Table (unique values) pod_vector m_asm; // Active Style Mask pod_vector m_cells; - - int m_min_style; - int m_max_style; - int m_scan_y; + pod_vector m_cover_buf; + + int m_min_style; + int m_max_style; + coord_type m_start_x; + coord_type m_start_y; + int m_scan_y; + int m_sl_start; + unsigned m_sl_len; }; @@ -273,6 +305,8 @@ namespace agg24 m_min_style = 0x7FFFFFFF; m_max_style = -0x7FFFFFFF; m_scan_y = 0x7FFFFFFF; + m_sl_start = 0; + m_sl_len = 0; } //------------------------------------------------------------------------ @@ -282,6 +316,13 @@ namespace agg24 m_filling_rule = filling_rule; } + //------------------------------------------------------------------------ + template + void rasterizer_compound_aa::layer_order(layer_order_e order) + { + m_layer_order = order; + } + //------------------------------------------------------------------------ template void rasterizer_compound_aa::clip_box(double x1, double y1, @@ -320,7 +361,8 @@ namespace agg24 void rasterizer_compound_aa::move_to(int x, int y) { if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::downscale(x), conv_type::downscale(y)); + m_clipper.move_to(m_start_x = conv_type::downscale(x), + m_start_y = conv_type::downscale(y)); } //------------------------------------------------------------------------ @@ -337,7 +379,8 @@ namespace agg24 void rasterizer_compound_aa::move_to_d(double x, double y) { if(m_outline.sorted()) reset(); - m_clipper.move_to(conv_type::upscale(x), conv_type::upscale(y)); + m_clipper.move_to(m_start_x = conv_type::upscale(x), + m_start_y = conv_type::upscale(y)); } //------------------------------------------------------------------------ @@ -358,11 +401,14 @@ namespace agg24 move_to_d(x, y); } else + if(is_vertex(cmd)) { - if(is_vertex(cmd)) - { - line_to_d(x, y); - } + line_to_d(x, y); + } + else + if(is_close(cmd)) + { + m_clipper.line_to(m_outline, m_start_x, m_start_y); } } @@ -457,83 +503,96 @@ namespace agg24 m_asm.allocate((num_styles + 7) >> 3, 8); m_asm.zero(); - // Pre-add zero (for no-fill style, that is, -1). - // We need that to ensure that the "-1 style" would go first. - m_asm[0] |= 1; - m_ast.add(0); - style = &m_styles[0]; - style->start_cell = 0; - style->num_cells = 0; - style->last_x = -0x7FFFFFFF; - - while(num_cells--) - { - curr_cell = *cells++; - add_style(curr_cell->left); - add_style(curr_cell->right); - } - - // Convert the Y-histogram into the array of starting indexes - unsigned i; - unsigned start_cell = 0; - for(i = 0; i < m_ast.size(); i++) - { - style_info& st = m_styles[m_ast[i]]; - unsigned v = st.start_cell; - st.start_cell = start_cell; - start_cell += v; - } - - cells = m_outline.scanline_cells(m_scan_y); - num_cells = m_outline.scanline_num_cells(m_scan_y); - - while(num_cells--) + if(num_cells) { - curr_cell = *cells++; - style_id = (curr_cell->left < 0) ? 0 : - curr_cell->left - m_min_style + 1; - - style = &m_styles[style_id]; - if(curr_cell->x == style->last_x) + // Pre-add zero (for no-fill style, that is, -1). + // We need that to ensure that the "-1 style" would go first. + m_asm[0] |= 1; + m_ast.add(0); + style = &m_styles[0]; + style->start_cell = 0; + style->num_cells = 0; + style->last_x = -0x7FFFFFFF; + + m_sl_start = cells[0]->x; + m_sl_len = cells[num_cells-1]->x - m_sl_start + 1; + while(num_cells--) { - cell = &m_cells[style->start_cell + style->num_cells - 1]; - cell->area += curr_cell->area; - cell->cover += curr_cell->cover; + curr_cell = *cells++; + add_style(curr_cell->left); + add_style(curr_cell->right); } - else + + // Convert the Y-histogram into the array of starting indexes + unsigned i; + unsigned start_cell = 0; + for(i = 0; i < m_ast.size(); i++) { - cell = &m_cells[style->start_cell + style->num_cells]; - cell->x = curr_cell->x; - cell->area = curr_cell->area; - cell->cover = curr_cell->cover; - style->last_x = curr_cell->x; - style->num_cells++; + style_info& st = m_styles[m_ast[i]]; + unsigned v = st.start_cell; + st.start_cell = start_cell; + start_cell += v; } - style_id = (curr_cell->right < 0) ? 0 : - curr_cell->right - m_min_style + 1; + cells = m_outline.scanline_cells(m_scan_y); + num_cells = m_outline.scanline_num_cells(m_scan_y); - style = &m_styles[style_id]; - if(curr_cell->x == style->last_x) - { - cell = &m_cells[style->start_cell + style->num_cells - 1]; - cell->area -= curr_cell->area; - cell->cover -= curr_cell->cover; - } - else + while(num_cells--) { - cell = &m_cells[style->start_cell + style->num_cells]; - cell->x = curr_cell->x; - cell->area = -curr_cell->area; - cell->cover = -curr_cell->cover; - style->last_x = curr_cell->x; - style->num_cells++; + curr_cell = *cells++; + style_id = (curr_cell->left < 0) ? 0 : + curr_cell->left - m_min_style + 1; + + style = &m_styles[style_id]; + if(curr_cell->x == style->last_x) + { + cell = &m_cells[style->start_cell + style->num_cells - 1]; + cell->area += curr_cell->area; + cell->cover += curr_cell->cover; + } + else + { + cell = &m_cells[style->start_cell + style->num_cells]; + cell->x = curr_cell->x; + cell->area = curr_cell->area; + cell->cover = curr_cell->cover; + style->last_x = curr_cell->x; + style->num_cells++; + } + + style_id = (curr_cell->right < 0) ? 0 : + curr_cell->right - m_min_style + 1; + + style = &m_styles[style_id]; + if(curr_cell->x == style->last_x) + { + cell = &m_cells[style->start_cell + style->num_cells - 1]; + cell->area -= curr_cell->area; + cell->cover -= curr_cell->cover; + } + else + { + cell = &m_cells[style->start_cell + style->num_cells]; + cell->x = curr_cell->x; + cell->area = -curr_cell->area; + cell->cover = -curr_cell->cover; + style->last_x = curr_cell->x; + style->num_cells++; + } } } if(m_ast.size() > 1) break; ++m_scan_y; } ++m_scan_y; + + if(m_layer_order != layer_unsorted) + { + range_adaptor > ra(m_ast, 1, m_ast.size() - 1); + if(m_layer_order == layer_direct) quick_sort(ra, unsigned_greater); + else quick_sort(ra, unsigned_less); + } + return m_ast.size() - 1; } @@ -588,8 +647,13 @@ namespace agg24 return sl.hit(); } - - + //------------------------------------------------------------------------ + template + cover_type* rasterizer_compound_aa::allocate_cover_buffer(unsigned len) + { + m_cover_buf.allocate(len, 256); + return &m_cover_buf[0]; + } } diff --git a/kiva/agg/agg-24/include/agg_rasterizer_outline.h b/kiva/agg/agg-24/include/agg_rasterizer_outline.h index f0b6ff7f8..c12ad3955 100644 --- a/kiva/agg/agg-24/include/agg_rasterizer_outline.h +++ b/kiva/agg/agg-24/include/agg_rasterizer_outline.h @@ -23,7 +23,7 @@ namespace agg24 template class rasterizer_outline { public: - rasterizer_outline(Renderer& ren) : + explicit rasterizer_outline(Renderer& ren) : m_ren(&ren), m_start_x(0), m_start_y(0), diff --git a/kiva/agg/agg-24/include/agg_rasterizer_outline_aa.h b/kiva/agg/agg-24/include/agg_rasterizer_outline_aa.h index 1f602547e..5d5c63d16 100644 --- a/kiva/agg/agg-24/include/agg_rasterizer_outline_aa.h +++ b/kiva/agg/agg-24/include/agg_rasterizer_outline_aa.h @@ -85,7 +85,7 @@ namespace agg24 typedef line_aa_vertex vertex_type; typedef vertex_sequence vertex_storage_type; - rasterizer_outline_aa(Renderer& ren) : + explicit rasterizer_outline_aa(Renderer& ren) : m_ren(&ren), m_line_join(ren.accurate_join_only() ? outline_miter_accurate_join : diff --git a/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa.h b/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa.h index 9ef6717b9..5b25774b4 100644 --- a/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa.h +++ b/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa.h @@ -31,41 +31,12 @@ #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 agg24 { - - - //-----------------------------------------------------------------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 @@ -122,8 +93,8 @@ namespace agg24 }; //-------------------------------------------------------------------- - rasterizer_scanline_aa() : - m_outline(), + rasterizer_scanline_aa(unsigned cell_block_limit=1024) : + m_outline(cell_block_limit), m_clipper(), m_filling_rule(fill_non_zero), m_auto_close(true), @@ -136,9 +107,9 @@ namespace agg24 } //-------------------------------------------------------------------- - template - rasterizer_scanline_aa(const GammaF& gamma_function) : - m_outline(), + template + rasterizer_scanline_aa(const GammaF& gamma_function, unsigned cell_block_limit) : + m_outline(cell_block_limit), m_clipper(m_outline), m_filling_rule(fill_non_zero), m_auto_close(true), @@ -357,7 +328,7 @@ namespace agg24 template void rasterizer_scanline_aa::close_polygon() { - if(m_auto_close && m_status == status_line_to) + if(m_status == status_line_to) { m_clipper.line_to(m_outline, m_start_x, m_start_y); m_status = status_closed; @@ -369,7 +340,7 @@ namespace agg24 void rasterizer_scanline_aa::move_to(int x, int y) { if(m_outline.sorted()) reset(); - if(m_status == status_line_to) close_polygon(); + 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; @@ -390,7 +361,7 @@ namespace agg24 void rasterizer_scanline_aa::move_to_d(double x, double y) { if(m_outline.sorted()) reset(); - if(m_status == status_line_to) close_polygon(); + 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; @@ -415,11 +386,14 @@ namespace agg24 move_to_d(x, y); } else + if(is_vertex(cmd)) { - if(is_vertex(cmd)) - { - line_to_d(x, y); - } + line_to_d(x, y); + } + else + if(is_close(cmd)) + { + close_polygon(); } } @@ -452,6 +426,7 @@ namespace agg24 template void rasterizer_scanline_aa::sort() { + if(m_auto_close) close_polygon(); m_outline.sort_cells(); } @@ -459,7 +434,7 @@ namespace agg24 template AGG_INLINE bool rasterizer_scanline_aa::rewind_scanlines() { - close_polygon(); + if(m_auto_close) close_polygon(); m_outline.sort_cells(); if(m_outline.total_cells() == 0) { @@ -474,7 +449,7 @@ namespace agg24 template AGG_INLINE bool rasterizer_scanline_aa::navigate_scanline(int y) { - close_polygon(); + if(m_auto_close) close_polygon(); m_outline.sort_cells(); if(m_outline.total_cells() == 0 || y < m_outline.min_y() || diff --git a/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa_nogamma.h b/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa_nogamma.h new file mode 100644 index 000000000..cf5562557 --- /dev/null +++ b/kiva/agg/agg-24/include/agg_rasterizer_scanline_aa_nogamma.h @@ -0,0 +1,482 @@ +//---------------------------------------------------------------------------- +// Anti-Grain Geometry - Version 2.4 +// Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) +// +// Permission to copy, use, modify, sell and distribute this software +// is granted provided this copyright notice appears in all copies. +// This software is provided "as is" without express or implied +// warranty, and with no claim as to its suitability for any purpose. +// +//---------------------------------------------------------------------------- +// +// The author gratefully acknowleges the support of David Turner, +// Robert Wilhelm, and Werner Lemberg - the authors of the FreeType +// libray - in producing this work. See http://www.freetype.org for details. +// +//---------------------------------------------------------------------------- +// Contact: mcseem@antigrain.com +// mcseemagg@yahoo.com +// http://www.antigrain.com +//---------------------------------------------------------------------------- +// +// Adaptation for 32-bit screen coordinates has been sponsored by +// Liberty Technology Systems, Inc., visit http://lib-sys.com +// +// Liberty Technology Systems, Inc. is the provider of +// PostScript and PDF technology for software developers. +// +//---------------------------------------------------------------------------- +#ifndef AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED +#define AGG_RASTERIZER_SCANLINE_AA_NOGAMMA_INCLUDED + +#include "agg_rasterizer_cells_aa.h" +#include "agg_rasterizer_sl_clip.h" + + +namespace agg24 +{ + + + //-----------------------------------------------------------------cell_aa + // A pixel cell. There're no constructors defined and it was done + // intentionally in order to avoid extra overhead when allocating an + // array of cells. + struct cell_aa + { + int x; + int y; + int cover; + int area; + + void initial() + { + x = 0x7FFFFFFF; + y = 0x7FFFFFFF; + cover = 0; + area = 0; + } + + void style(const cell_aa&) {} + + int not_equal(int ex, int ey, const cell_aa&) const + { + return (ex - x) | (ey - y); + } + }; + + + //==================================================rasterizer_scanline_aa_nogamma + // Polygon rasterizer that is used to render filled polygons with + // high-quality Anti-Aliasing. Internally, by default, the class uses + // integer coordinates in format 24.8, i.e. 24 bits for integer part + // and 8 bits for fractional - see poly_subpixel_shift. This class can be + // used in the following way: + // + // 1. filling_rule(filling_rule_e ft) - optional. + // + // 2. gamma() - optional. + // + // 3. reset() + // + // 4. move_to(x, y) / line_to(x, y) - make the polygon. One can create + // more than one contour, but each contour must consist of at least 3 + // vertices, i.e. move_to(x1, y1); line_to(x2, y2); line_to(x3, y3); + // is the absolute minimum of vertices that define a triangle. + // The algorithm does not check either the number of vertices nor + // coincidence of their coordinates, but in the worst case it just + // won't draw anything. + // The orger of the vertices (clockwise or counterclockwise) + // is important when using the non-zero filling rule (fill_non_zero). + // In this case the vertex order of all the contours must be the same + // if you want your intersecting polygons to be without "holes". + // You actually can use different vertices order. If the contours do not + // intersect each other the order is not important anyway. If they do, + // contours with the same vertex order will be rendered without "holes" + // while the intersecting contours with different orders will have "holes". + // + // filling_rule() and gamma() can be called anytime before "sweeping". + //------------------------------------------------------------------------ + template class 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(unsigned cell_block_limit=1024) : + m_outline(cell_block_limit), + 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 + 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 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&); + const rasterizer_scanline_aa_nogamma& + operator = (const rasterizer_scanline_aa_nogamma&); + + private: + rasterizer_cells_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 + void rasterizer_scanline_aa_nogamma::reset() + { + m_outline.reset(); + m_status = status_initial; + } + + //------------------------------------------------------------------------ + template + void rasterizer_scanline_aa_nogamma::filling_rule(filling_rule_e filling_rule) + { + m_filling_rule = filling_rule; + } + + //------------------------------------------------------------------------ + template + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::reset_clipping() + { + reset(); + m_clipper.reset_clipping(); + } + + //------------------------------------------------------------------------ + template + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::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 + void rasterizer_scanline_aa_nogamma::sort() + { + if(m_auto_close) close_polygon(); + m_outline.sort_cells(); + } + + //------------------------------------------------------------------------ + template + AGG_INLINE bool rasterizer_scanline_aa_nogamma::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 + AGG_INLINE bool rasterizer_scanline_aa_nogamma::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 + bool rasterizer_scanline_aa_nogamma::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/kiva/agg/agg-24/include/agg_renderer_base.h b/kiva/agg/agg-24/include/agg_renderer_base.h index 0167e902c..ab13d8c90 100644 --- a/kiva/agg/agg-24/include/agg_renderer_base.h +++ b/kiva/agg/agg-24/include/agg_renderer_base.h @@ -36,7 +36,7 @@ namespace agg24 //-------------------------------------------------------------------- renderer_base() : m_ren(0), m_clip_box(1, 1, 0, 0) {} - renderer_base(pixfmt_type& ren) : + explicit renderer_base(pixfmt_type& ren) : m_ren(&ren), m_clip_box(0, 0, ren.width() - 1, ren.height() - 1) {} @@ -134,6 +134,19 @@ namespace agg24 } + //-------------------------------------------------------------------- + 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) { @@ -327,6 +340,30 @@ namespace agg24 m_ren->copy_color_hspan(x, y, len, colors); } + + //-------------------------------------------------------------------- + void copy_color_vspan(int x, int y, int len, const color_type* colors) + { + if(x > xmax()) return; + if(x < xmin()) return; + + if(y < ymin()) + { + int d = ymin() - y; + len -= d; + if(len <= 0) return; + colors += d; + y = ymin(); + } + if(y + len > ymax()) + { + len = ymax() - y + 1; + if(len <= 0) return; + } + m_ren->copy_color_vspan(x, y, len, colors); + } + + //-------------------------------------------------------------------- void blend_color_hspan(int x, int y, int len, const color_type* colors, @@ -539,6 +576,150 @@ namespace agg24 } } + //-------------------------------------------------------------------- + template + void blend_from_color(const SrcPixelFormatRenderer& src, + const color_type& color, + const rect_i* rect_src_ptr = 0, + int dx = 0, + int dy = 0, + cover_type cover = agg24::cover_full) + { + rect_i rsrc(0, 0, src.width(), src.height()); + if(rect_src_ptr) + { + rsrc.x1 = rect_src_ptr->x1; + rsrc.y1 = rect_src_ptr->y1; + rsrc.x2 = rect_src_ptr->x2 + 1; + rsrc.y2 = rect_src_ptr->y2 + 1; + } + + // Version with xdst, ydst (absolute positioning) + //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); + + // Version with dx, dy (relative positioning) + rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); + rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); + + if(rc.x2 > 0) + { + int incy = 1; + if(rdst.y1 > rsrc.y1) + { + rsrc.y1 += rc.y2 - 1; + rdst.y1 += rc.y2 - 1; + incy = -1; + } + while(rc.y2 > 0) + { + typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); + if(rw.ptr) + { + int x1src = rsrc.x1; + int x1dst = rdst.x1; + int len = rc.x2; + if(rw.x1 > x1src) + { + x1dst += rw.x1 - x1src; + len -= rw.x1 - x1src; + x1src = rw.x1; + } + if(len > 0) + { + if(x1src + len-1 > rw.x2) + { + len -= x1src + len - rw.x2 - 1; + } + if(len > 0) + { + m_ren->blend_from_color(src, + color, + x1dst, rdst.y1, + x1src, rsrc.y1, + len, + cover); + } + } + } + rdst.y1 += incy; + rsrc.y1 += incy; + --rc.y2; + } + } + } + + //-------------------------------------------------------------------- + template + void blend_from_lut(const SrcPixelFormatRenderer& src, + const color_type* color_lut, + const rect_i* rect_src_ptr = 0, + int dx = 0, + int dy = 0, + cover_type cover = agg24::cover_full) + { + rect_i rsrc(0, 0, src.width(), src.height()); + if(rect_src_ptr) + { + rsrc.x1 = rect_src_ptr->x1; + rsrc.y1 = rect_src_ptr->y1; + rsrc.x2 = rect_src_ptr->x2 + 1; + rsrc.y2 = rect_src_ptr->y2 + 1; + } + + // Version with xdst, ydst (absolute positioning) + //rect_i rdst(xdst, ydst, xdst + rsrc.x2 - rsrc.x1, ydst + rsrc.y2 - rsrc.y1); + + // Version with dx, dy (relative positioning) + rect_i rdst(rsrc.x1 + dx, rsrc.y1 + dy, rsrc.x2 + dx, rsrc.y2 + dy); + rect_i rc = clip_rect_area(rdst, rsrc, src.width(), src.height()); + + if(rc.x2 > 0) + { + int incy = 1; + if(rdst.y1 > rsrc.y1) + { + rsrc.y1 += rc.y2 - 1; + rdst.y1 += rc.y2 - 1; + incy = -1; + } + while(rc.y2 > 0) + { + typename SrcPixelFormatRenderer::row_data rw = src.row(rsrc.y1); + if(rw.ptr) + { + int x1src = rsrc.x1; + int x1dst = rdst.x1; + int len = rc.x2; + if(rw.x1 > x1src) + { + x1dst += rw.x1 - x1src; + len -= rw.x1 - x1src; + x1src = rw.x1; + } + if(len > 0) + { + if(x1src + len-1 > rw.x2) + { + len -= x1src + len - rw.x2 - 1; + } + if(len > 0) + { + m_ren->blend_from_lut(src, + color_lut, + x1dst, rdst.y1, + x1src, rsrc.y1, + len, + cover); + } + } + } + rdst.y1 += incy; + rsrc.y1 += incy; + --rc.y2; + } + } + } + private: pixfmt_type* m_ren; rect_i m_clip_box; diff --git a/kiva/agg/agg-24/include/agg_renderer_markers.h b/kiva/agg/agg-24/include/agg_renderer_markers.h index 5342e1651..1fa8f4526 100644 --- a/kiva/agg/agg-24/include/agg_renderer_markers.h +++ b/kiva/agg/agg-24/include/agg_renderer_markers.h @@ -572,7 +572,6 @@ namespace agg24 case marker_dash: dash(x, y, r); break; case marker_dot: dot(x, y, r); break; case marker_pixel: pixel(x, y, r); break; - case end_of_markers: break; } } diff --git a/kiva/agg/agg-24/include/agg_renderer_mclip.h b/kiva/agg/agg-24/include/agg_renderer_mclip.h index f1abcbdf8..4bfcff10c 100644 --- a/kiva/agg/agg-24/include/agg_renderer_mclip.h +++ b/kiva/agg/agg-24/include/agg_renderer_mclip.h @@ -37,7 +37,7 @@ namespace agg24 typedef renderer_base base_ren_type; //-------------------------------------------------------------------- - renderer_mclip(pixfmt_type& pixf) : + explicit renderer_mclip(pixfmt_type& pixf) : m_ren(pixf), m_curr_cb(0), m_bounds(m_ren.xmin(), m_ren.ymin(), m_ren.xmax(), m_ren.ymax()) diff --git a/kiva/agg/agg-24/include/agg_renderer_outline_aa.h b/kiva/agg/agg-24/include/agg_renderer_outline_aa.h index 7d8db4f41..4783fa4b6 100644 --- a/kiva/agg/agg-24/include/agg_renderer_outline_aa.h +++ b/kiva/agg/agg-24/include/agg_renderer_outline_aa.h @@ -474,7 +474,7 @@ namespace agg24 }; //--------------------------------------------------------------------- - line_interpolator_aa_base(renderer_type& ren, const line_parameters& lp) : + line_interpolator_aa_base(renderer_type& ren, line_parameters& lp) : m_lp(&lp), m_li(lp.vertical ? line_dbl_hr(lp.x2 - lp.x1) : line_dbl_hr(lp.y2 - lp.y1), @@ -550,7 +550,7 @@ namespace agg24 operator = (const line_interpolator_aa_base&); protected: - const line_parameters* m_lp; + line_parameters* m_lp; dda2_line_interpolator m_li; renderer_type& m_ren; int m_len; @@ -582,7 +582,7 @@ namespace agg24 typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- - line_interpolator_aa0(renderer_type& ren, const line_parameters& lp) : + line_interpolator_aa0(renderer_type& ren, line_parameters& lp) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, lp.x1 & ~line_subpixel_mask, lp.y1 & ~line_subpixel_mask) @@ -676,7 +676,7 @@ namespace agg24 typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- - line_interpolator_aa1(renderer_type& ren, const line_parameters& lp, + line_interpolator_aa1(renderer_type& ren, line_parameters& lp, int sx, int sy) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, @@ -887,7 +887,7 @@ namespace agg24 typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- - line_interpolator_aa2(renderer_type& ren, const line_parameters& lp, + line_interpolator_aa2(renderer_type& ren, line_parameters& lp, int ex, int ey) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, ex, ey, @@ -1036,7 +1036,7 @@ namespace agg24 typedef line_interpolator_aa_base base_type; //--------------------------------------------------------------------- - line_interpolator_aa3(renderer_type& ren, const line_parameters& lp, + line_interpolator_aa3(renderer_type& ren, line_parameters& lp, int sx, int sy, int ex, int ey) : line_interpolator_aa_base(ren, lp), m_di(lp.x1, lp.y1, lp.x2, lp.y2, sx, sy, ex, ey, @@ -1350,7 +1350,7 @@ namespace agg24 typedef typename base_ren_type::color_type color_type; //--------------------------------------------------------------------- - renderer_outline_aa(base_ren_type& ren, const line_profile_aa& prof) : + renderer_outline_aa(base_ren_type& ren, line_profile_aa& prof) : m_ren(&ren), m_profile(&prof), m_clip_box(0,0,0,0), @@ -1363,9 +1363,9 @@ namespace agg24 const color_type& color() const { return m_color; } //--------------------------------------------------------------------- - void profile(const line_profile_aa& prof) { m_profile = &prof; } - const line_profile_aa& profile() const { return *m_profile; } - const line_profile_aa& profile() { return *m_profile; } + void profile(line_profile_aa& prof) { m_profile = &prof; } + line_profile_aa& profile() const { return *m_profile; } + line_profile_aa& profile() { return *m_profile; } //--------------------------------------------------------------------- int subpixel_width() const { return m_profile->subpixel_width(); } @@ -1546,7 +1546,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line0_no_clip(const line_parameters& lp) + void line0_no_clip(line_parameters& lp) { if(lp.len > line_max_length) { @@ -1572,7 +1572,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line0(const line_parameters& lp) + void line0(line_parameters& lp) { if(m_clipping) { @@ -1602,7 +1602,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line1_no_clip(const line_parameters& lp, int sx, int sy) + void line1_no_clip(line_parameters& lp, int sx, int sy) { if(lp.len > line_max_length) { @@ -1627,7 +1627,7 @@ namespace agg24 //------------------------------------------------------------------------- - void line1(const line_parameters& lp, int sx, int sy) + void line1(line_parameters& lp, int sx, int sy) { if(m_clipping) { @@ -1670,7 +1670,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line2_no_clip(const line_parameters& lp, int ex, int ey) + void line2_no_clip(line_parameters& lp, int ex, int ey) { if(lp.len > line_max_length) { @@ -1694,7 +1694,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line2(const line_parameters& lp, int ex, int ey) + void line2(line_parameters& lp, int ex, int ey) { if(m_clipping) { @@ -1737,7 +1737,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line3_no_clip(const line_parameters& lp, + void line3_no_clip(line_parameters& lp, int sx, int sy, int ex, int ey) { if(lp.len > line_max_length) @@ -1765,7 +1765,7 @@ namespace agg24 } //------------------------------------------------------------------------- - void line3(const line_parameters& lp, + void line3(line_parameters& lp, int sx, int sy, int ex, int ey) { if(m_clipping) @@ -1824,7 +1824,7 @@ namespace agg24 private: base_ren_type* m_ren; - const line_profile_aa* m_profile; + line_profile_aa* m_profile; color_type m_color; rect_i m_clip_box; bool m_clipping; diff --git a/kiva/agg/agg-24/include/agg_renderer_outline_image.h b/kiva/agg/agg-24/include/agg_renderer_outline_image.h index d6253e02c..f1ca3ca36 100644 --- a/kiva/agg/agg-24/include/agg_renderer_outline_image.h +++ b/kiva/agg/agg-24/include/agg_renderer_outline_image.h @@ -34,7 +34,8 @@ namespace agg24 line_image_scale(const Source& src, double height) : m_source(src), m_height(height), - m_scale(src.height() / height) + m_scale(src.height() / height), + m_scale_inv(height / src.height()) { } @@ -43,13 +44,34 @@ namespace agg24 color_type pixel(int x, int y) const { - double src_y = (y + 0.5) * m_scale - 0.5; - int h = m_source.height() - 1; - int y1 = ufloor(src_y); - int y2 = y1 + 1; - color_type pix1 = (y1 < 0) ? color_type::no_color() : m_source.pixel(x, y1); - color_type pix2 = (y2 > h) ? color_type::no_color() : m_source.pixel(x, y2); - return pix1.gradient(pix2, src_y - y1); + if (m_scale < 1.0) + { + // Interpolate between nearest source pixels. + double src_y = (y + 0.5) * m_scale - 0.5; + int h = m_source.height() - 1; + int y1 = ifloor(src_y); + int y2 = y1 + 1; + rgba pix1 = (y1 < 0) ? rgba::no_color() : m_source.pixel(x, y1); + rgba pix2 = (y2 > h) ? rgba::no_color() : m_source.pixel(x, y2); + return pix1.gradient(pix2, src_y - y1); + } + else + { + // Average source pixels between y and y+1. + double src_y1 = (y + 0.5) * m_scale - 0.5; + double src_y2 = src_y1 + m_scale; + int h = m_source.height() - 1; + int y1 = ifloor(src_y1); + int y2 = ifloor(src_y2); + rgba c = rgba::no_color(); + if (y1 >= 0) c += rgba(m_source.pixel(x, y1)) *= y1 + 1 - src_y1; + while (++y1 < y2) + { + if (y1 <= h) c += m_source.pixel(x, y1); + } + if (y2 <= h) c += rgba(m_source.pixel(x, y2)) *= src_y2 - y2; + return c *= m_scale_inv; + } } private: @@ -59,6 +81,7 @@ namespace agg24 const Source& m_source; double m_height; double m_scale; + double m_scale_inv; }; @@ -71,7 +94,7 @@ namespace agg24 typedef typename filter_type::color_type color_type; //-------------------------------------------------------------------- - line_image_pattern(const Filter& filter) : + line_image_pattern(Filter& filter) : m_filter(&filter), m_dilation(filter.dilation() + 1), m_dilation_hr(m_dilation << line_subpixel_shift), @@ -87,7 +110,7 @@ namespace agg24 // Create //-------------------------------------------------------------------- template - line_image_pattern(const Filter& filter, const Source& src) : + line_image_pattern(Filter& filter, const Source& src) : m_filter(&filter), m_dilation(filter.dilation() + 1), m_dilation_hr(m_dilation << line_subpixel_shift), @@ -210,14 +233,14 @@ namespace agg24 typedef Filter filter_type; typedef typename filter_type::color_type color_type; typedef line_image_pattern base_type; - + //-------------------------------------------------------------------- - line_image_pattern_pow2(const Filter& filter) : + line_image_pattern_pow2(Filter& filter) : line_image_pattern(filter), m_mask(line_subpixel_mask) {} //-------------------------------------------------------------------- template - line_image_pattern_pow2(const Filter& filter, const Source& src) : + line_image_pattern_pow2(Filter& filter, const Source& src) : line_image_pattern(filter), m_mask(line_subpixel_mask) { create(src); @@ -816,7 +839,7 @@ namespace agg24 //--------------------------------------------------------------------- - renderer_outline_image(base_ren_type& ren, const pattern_type& patt) : + renderer_outline_image(base_ren_type& ren, pattern_type& patt) : m_ren(&ren), m_pattern(&patt), m_start(0), @@ -827,8 +850,8 @@ namespace agg24 void attach(base_ren_type& ren) { m_ren = &ren; } //--------------------------------------------------------------------- - void pattern(const pattern_type& p) { m_pattern = &p; } - const pattern_type& pattern() const { return *m_pattern; } + void pattern(pattern_type& p) { m_pattern = &p; } + pattern_type& pattern() const { return *m_pattern; } //--------------------------------------------------------------------- void reset_clipping() { m_clipping = false; } @@ -995,7 +1018,7 @@ namespace agg24 private: base_ren_type* m_ren; - const pattern_type* m_pattern; + pattern_type* m_pattern; int m_start; double m_scale_x; rect_i m_clip_box; diff --git a/kiva/agg/agg-24/include/agg_renderer_primitives.h b/kiva/agg/agg-24/include/agg_renderer_primitives.h index 9c02ef51d..8f2d67f79 100644 --- a/kiva/agg/agg-24/include/agg_renderer_primitives.h +++ b/kiva/agg/agg-24/include/agg_renderer_primitives.h @@ -35,7 +35,7 @@ namespace agg24 typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- - renderer_primitives(base_ren_type& ren) : + explicit renderer_primitives(base_ren_type& ren) : m_ren(&ren), m_fill_color(), m_line_color(), diff --git a/kiva/agg/agg-24/include/agg_renderer_scanline.h b/kiva/agg/agg-24/include/agg_renderer_scanline.h index fedc33f63..5465fc97d 100644 --- a/kiva/agg/agg-24/include/agg_renderer_scanline.h +++ b/kiva/agg/agg-24/include/agg_renderer_scanline.h @@ -111,7 +111,7 @@ namespace agg24 //-------------------------------------------------------------------- renderer_scanline_aa_solid() : m_ren(0) {} - renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {} + explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {} void attach(base_ren_type& ren) { m_ren = &ren; @@ -311,7 +311,7 @@ namespace agg24 //-------------------------------------------------------------------- renderer_scanline_bin_solid() : m_ren(0) {} - renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {} + explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {} void attach(base_ren_type& ren) { m_ren = &ren; @@ -473,9 +473,6 @@ namespace agg24 - - - //=============================================render_scanlines_compound templatecovers; do { - colors->add(c, *covers); + if(*covers == cover_full) + { + *colors = c; + } + else + { + colors->add(c, *covers); + } ++colors; ++covers; } @@ -616,7 +620,14 @@ namespace agg24 covers = span_aa->covers; do { - colors->add(*cspan, *covers); + if(*covers == cover_full) + { + *colors = *cspan; + } + else + { + colors->add(*cspan, *covers); + } ++cspan; ++colors; ++covers; @@ -644,11 +655,195 @@ namespace agg24 if(--num_spans == 0) break; ++span_bin; } + } // if(ras.sweep_scanline(sl_bin, -1)) + } // if(num_styles == 1) ... else + } // while((num_styles = ras.sweep_styles()) > 0) + } // if(ras.rewind_scanlines()) + } + //=======================================render_scanlines_compound_layered + template + void render_scanlines_compound_layered(Rasterizer& ras, + ScanlineAA& sl_aa, + BaseRenderer& ren, + SpanAllocator& alloc, + StyleHandler& sh) + { + if(ras.rewind_scanlines()) + { + int min_x = ras.min_x(); + int len = ras.max_x() - min_x + 2; + sl_aa.reset(min_x, ras.max_x()); + + typedef typename BaseRenderer::color_type color_type; + color_type* color_span = alloc.allocate(len * 2); + color_type* mix_buffer = color_span + len; + cover_type* cover_buffer = ras.allocate_cover_buffer(len); + unsigned num_spans; + + unsigned num_styles; + unsigned style; + bool solid; + while((num_styles = ras.sweep_styles()) > 0) + { + typename ScanlineAA::const_iterator span_aa; + if(num_styles == 1) + { + // Optimization for a single style. Happens often + //------------------------- + if(ras.sweep_scanline(sl_aa, 0)) + { + style = ras.style(0); + if(sh.is_solid(style)) + { + // Just solid fill + //----------------------- + render_scanline_aa_solid(sl_aa, ren, sh.color(style)); + } + else + { + // Arbitrary span generator + //----------------------- + span_aa = sl_aa.begin(); + num_spans = sl_aa.num_spans(); + for(;;) + { + len = span_aa->len; + sh.generate_span(color_span, + span_aa->x, + sl_aa.y(), + len, + style); + + ren.blend_color_hspan(span_aa->x, + sl_aa.y(), + span_aa->len, + color_span, + span_aa->covers); + if(--num_spans == 0) break; + ++span_aa; + } + } } } - } - } + else + { + int sl_start = ras.scanline_start(); + unsigned sl_len = ras.scanline_length(); + + if(sl_len) + { + memset(mix_buffer + sl_start - min_x, + 0, + sl_len * sizeof(color_type)); + + memset(cover_buffer + sl_start - min_x, + 0, + sl_len * sizeof(cover_type)); + + int sl_y = 0x7FFFFFFF; + unsigned i; + for(i = 0; i < num_styles; i++) + { + style = ras.style(i); + solid = sh.is_solid(style); + + if(ras.sweep_scanline(sl_aa, i)) + { + unsigned cover; + color_type* colors; + color_type* cspan; + cover_type* src_covers; + cover_type* dst_covers; + span_aa = sl_aa.begin(); + num_spans = sl_aa.num_spans(); + sl_y = sl_aa.y(); + if(solid) + { + // Just solid fill + //----------------------- + for(;;) + { + color_type c = sh.color(style); + len = span_aa->len; + colors = mix_buffer + span_aa->x - min_x; + src_covers = span_aa->covers; + dst_covers = cover_buffer + span_aa->x - min_x; + do + { + cover = *src_covers; + if(*dst_covers + cover > cover_full) + { + cover = cover_full - *dst_covers; + } + if(cover) + { + colors->add(c, cover); + *dst_covers += cover; + } + ++colors; + ++src_covers; + ++dst_covers; + } + while(--len); + if(--num_spans == 0) break; + ++span_aa; + } + } + else + { + // Arbitrary span generator + //----------------------- + for(;;) + { + len = span_aa->len; + colors = mix_buffer + span_aa->x - min_x; + cspan = color_span; + sh.generate_span(cspan, + span_aa->x, + sl_aa.y(), + len, + style); + src_covers = span_aa->covers; + dst_covers = cover_buffer + span_aa->x - min_x; + do + { + cover = *src_covers; + if(*dst_covers + cover > cover_full) + { + cover = cover_full - *dst_covers; + } + if(cover) + { + colors->add(*cspan, cover); + *dst_covers += cover; + } + ++cspan; + ++colors; + ++src_covers; + ++dst_covers; + } + while(--len); + if(--num_spans == 0) break; + ++span_aa; + } + } + } + } + ren.blend_color_hspan(sl_start, + sl_y, + sl_len, + mix_buffer + sl_start - min_x, + 0, + cover_full); + } //if(sl_len) + } //if(num_styles == 1) ... else + } //while((num_styles = ras.sweep_styles()) > 0) + } //if(ras.rewind_scanlines()) } diff --git a/kiva/agg/agg-24/include/agg_rendering_buffer.h b/kiva/agg/agg-24/include/agg_rendering_buffer.h index 989b1a222..d7ae97ed0 100644 --- a/kiva/agg/agg-24/include/agg_rendering_buffer.h +++ b/kiva/agg/agg-24/include/agg_rendering_buffer.h @@ -25,19 +25,124 @@ namespace agg24 { - //==========================================================row_ptr_cache - template class row_ptr_cache + //===========================================================row_accessor + template class row_accessor { public: + typedef const_row_info row_data; + + //------------------------------------------------------------------- + row_accessor() : + m_buf(0), + m_start(0), + m_width(0), + m_height(0), + m_stride(0) + { + } + + //-------------------------------------------------------------------- + row_accessor(T* buf, unsigned width, unsigned height, int stride) : + m_buf(0), + m_start(0), + m_width(0), + m_height(0), + m_stride(0) + { + attach(buf, width, height, stride); + } + + + //-------------------------------------------------------------------- + void attach(T* buf, unsigned width, unsigned height, int stride) + { + m_buf = m_start = buf; + m_width = width; + m_height = height; + m_stride = stride; + if(stride < 0) + { + m_start = m_buf - (AGG_INT64)(height - 1) * stride; + } + } + + //-------------------------------------------------------------------- + AGG_INLINE T* buf() { return m_buf; } + AGG_INLINE const T* buf() const { return m_buf; } + AGG_INLINE unsigned width() const { return m_width; } + AGG_INLINE unsigned height() const { return m_height; } + AGG_INLINE int stride() const { return m_stride; } + AGG_INLINE unsigned stride_abs() const + { + return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); + } + + //-------------------------------------------------------------------- + AGG_INLINE T* row_ptr(int, int y, unsigned) + { + return m_start + y * (AGG_INT64)m_stride; + } + AGG_INLINE T* row_ptr(int y) { return m_start + y * (AGG_INT64)m_stride; } + AGG_INLINE const T* row_ptr(int y) const { return m_start + y * (AGG_INT64)m_stride; } + AGG_INLINE row_data row (int y) const + { + return row_data(0, m_width-1, row_ptr(y)); + } + + //-------------------------------------------------------------------- + template + void copy_from(const RenBuf& src) + { + unsigned h = height(); + if(src.height() < h) h = src.height(); + + unsigned l = stride_abs(); + if(src.stride_abs() < l) l = src.stride_abs(); + + l *= sizeof(T); + + unsigned y; + unsigned w = width(); + for (y = 0; y < h; y++) + { + memcpy(row_ptr(0, y, w), src.row_ptr(y), l); + } + } + //-------------------------------------------------------------------- - struct row_data + void clear(T value) { - int x1, x2; - const int8u* ptr; - row_data() {} - row_data(int x1_, int x2_, const int8u* ptr_) : - x1(x1_), x2(x2_), ptr(ptr_) {} - }; + unsigned y; + unsigned w = width(); + unsigned stride = stride_abs(); + for(y = 0; y < height(); y++) + { + T* p = row_ptr(0, y, w); + unsigned x; + for(x = 0; x < stride; x++) + { + *p++ = value; + } + } + } + + private: + //-------------------------------------------------------------------- + T* m_buf; // Pointer to renrdering buffer + T* m_start; // Pointer to first pixel depending on stride + unsigned m_width; // Width in pixels + unsigned m_height; // Height in pixels + int m_stride; // Number of bytes per row. Can be < 0 + }; + + + + + //==========================================================row_ptr_cache + template class row_ptr_cache + { + public: + typedef const_row_info row_data; //------------------------------------------------------------------- row_ptr_cache() : @@ -76,7 +181,7 @@ namespace agg24 if(stride < 0) { - row_ptr = m_buf - int(height - 1) * (stride); + row_ptr = m_buf - (AGG_INT64)(height - 1) * stride; } T** rows = &m_rows[0]; @@ -89,21 +194,27 @@ namespace agg24 } //-------------------------------------------------------------------- - T* buf() { return m_buf; } - const T* buf() const { return m_buf; } - unsigned width() const { return m_width; } - unsigned height() const { return m_height; } - int stride() const { return m_stride; } - unsigned stride_abs() const + AGG_INLINE T* buf() { return m_buf; } + AGG_INLINE const T* buf() const { return m_buf; } + AGG_INLINE unsigned width() const { return m_width; } + AGG_INLINE unsigned height() const { return m_height; } + AGG_INLINE int stride() const { return m_stride; } + AGG_INLINE unsigned stride_abs() const { return (m_stride < 0) ? unsigned(-m_stride) : unsigned(m_stride); } //-------------------------------------------------------------------- - T* row_ptr(int, int y, unsigned) { return m_rows[y]; } - T* row_ptr(int y) { return m_rows[y]; } - const T* row_ptr(int y) const { return m_rows[y]; } - row_data row (int y) const { return row_data(0, m_width-1, m_rows[y]); } + AGG_INLINE T* row_ptr(int, int y, unsigned) + { + return m_rows[y]; + } + AGG_INLINE T* row_ptr(int y) { return m_rows[y]; } + AGG_INLINE const T* row_ptr(int y) const { return m_rows[y]; } + AGG_INLINE row_data row (int y) const + { + return row_data(0, m_width-1, m_rows[y]); + } //-------------------------------------------------------------------- T const* const* rows() const { return &m_rows[0]; } @@ -156,8 +267,32 @@ namespace agg24 + //========================================================rendering_buffer - typedef row_ptr_cache rendering_buffer; + // + // The definition of the main type for accessing the rows in the frame + // buffer. It provides functionality to navigate to the rows in a + // rectangular matrix, from top to bottom or from bottom to top depending + // on stride. + // + // row_accessor is cheap to create/destroy, but performs one multiplication + // when calling row_ptr(). + // + // row_ptr_cache creates an array of pointers to rows, so, the access + // via row_ptr() may be faster. But it requires memory allocation + // when creating. For example, on typical Intel Pentium hardware + // row_ptr_cache speeds span_image_filter_rgb_nn up to 10% + // + // It's used only in short hand typedefs like pixfmt_rgba32 and can be + // redefined in agg_config.h + // In real applications you can use both, depending on your needs + //------------------------------------------------------------------------ +#ifdef AGG_RENDERING_BUFFER + typedef AGG_RENDERING_BUFFER rendering_buffer; +#else +// typedef row_ptr_cache rendering_buffer; + typedef row_accessor rendering_buffer; +#endif } diff --git a/kiva/agg/agg-24/include/agg_rendering_buffer_dynarow.h b/kiva/agg/agg-24/include/agg_rendering_buffer_dynarow.h index cd4daf41d..16d9ffd54 100644 --- a/kiva/agg/agg-24/include/agg_rendering_buffer_dynarow.h +++ b/kiva/agg/agg-24/include/agg_rendering_buffer_dynarow.h @@ -35,12 +35,7 @@ namespace agg24 class rendering_buffer_dynarow { public: - //---------------------------------------------------------------------- - struct row_data - { - int x1, x2; - const int8u* ptr; - }; + typedef row_info row_data; //------------------------------------------------------------------- ~rendering_buffer_dynarow() diff --git a/kiva/agg/agg-24/include/agg_scanline_storage_aa.h b/kiva/agg/agg-24/include/agg_scanline_storage_aa.h index d835f6b33..a3861651c 100644 --- a/kiva/agg/agg-24/include/agg_scanline_storage_aa.h +++ b/kiva/agg/agg-24/include/agg_scanline_storage_aa.h @@ -198,7 +198,7 @@ namespace agg24 }; const_iterator() : m_storage(0) {} - const_iterator(const embedded_scanline& sl) : + const_iterator(embedded_scanline& sl) : m_storage(sl.m_storage), m_span_idx(sl.m_scanline.start_span) { @@ -223,7 +223,7 @@ namespace agg24 m_span.covers = m_storage->covers_by_index(s.covers_id); } - const scanline_storage_aa* m_storage; + scanline_storage_aa* m_storage; unsigned m_span_idx; span m_span; }; @@ -557,9 +557,9 @@ namespace agg24 }; const_iterator() : m_ptr(0) {} - const_iterator(const embedded_scanline& sl) : - m_ptr(sl.m_ptr), - m_dx(sl.m_dx) + const_iterator(const embedded_scanline* sl) : + m_ptr(sl->m_ptr), + m_dx(sl->m_dx) { init_span(); } @@ -613,7 +613,7 @@ namespace agg24 void reset(int, int) {} unsigned num_spans() const { return m_num_spans; } int y() const { return m_y; } - const_iterator begin() const { return const_iterator(*this); } + const_iterator begin() const { return const_iterator(this); } private: diff --git a/kiva/agg/agg-24/include/agg_scanline_storage_bin.h b/kiva/agg/agg-24/include/agg_scanline_storage_bin.h index 0e3fa34d4..6ac55326a 100644 --- a/kiva/agg/agg-24/include/agg_scanline_storage_bin.h +++ b/kiva/agg/agg-24/include/agg_scanline_storage_bin.h @@ -64,9 +64,9 @@ namespace agg24 { public: const_iterator() : m_storage(0) {} - const_iterator(const embedded_scanline& sl) : - m_storage(sl.m_storage), - m_span_idx(sl.m_scanline.start_span) + const_iterator(const embedded_scanline* sl) : + m_storage(sl->m_storage), + m_span_idx(sl->m_scanline.start_span) { m_span = m_storage->span_by_index(m_span_idx); } @@ -90,7 +90,7 @@ namespace agg24 //----------------------------------------------------------- - embedded_scanline(const scanline_storage_bin& storage) : + embedded_scanline(scanline_storage_bin& storage) : m_storage(&storage) { setup(0); @@ -100,7 +100,7 @@ namespace agg24 void reset(int, int) {} unsigned num_spans() const { return m_scanline.num_spans; } int y() const { return m_scanline.y; } - const_iterator begin() const { return const_iterator(*this); } + const_iterator begin() const { return const_iterator(this); } //----------------------------------------------------------- void setup(unsigned scanline_idx) @@ -110,7 +110,7 @@ namespace agg24 } private: - const scanline_storage_bin* m_storage; + scanline_storage_bin* m_storage; scanline_data m_scanline; unsigned m_scanline_idx; }; @@ -362,9 +362,9 @@ namespace agg24 }; const_iterator() : m_ptr(0) {} - const_iterator(const embedded_scanline& sl) : - m_ptr(sl.m_ptr), - m_dx(sl.m_dx) + const_iterator(const embedded_scanline* sl) : + m_ptr(sl->m_ptr), + m_dx(sl->m_dx) { m_span.x = read_int32() + m_dx; m_span.len = read_int32(); @@ -405,7 +405,7 @@ namespace agg24 void reset(int, int) {} unsigned num_spans() const { return m_num_spans; } int y() const { return m_y; } - const_iterator begin() const { return const_iterator(*this); } + const_iterator begin() const { return const_iterator(this); } private: diff --git a/kiva/agg/agg-24/include/agg_scanline_u.h b/kiva/agg/agg-24/include/agg_scanline_u.h index 282c902b5..df5208505 100644 --- a/kiva/agg/agg-24/include/agg_scanline_u.h +++ b/kiva/agg/agg-24/include/agg_scanline_u.h @@ -62,7 +62,7 @@ namespace agg24 // // scanline_u8::const_iterator span = sl.begin(); // - // unsigned char* row = m_rbuf->row(y); // The the address of the beginning + // unsigned char* row = m_rbuf->row(y); // The address of the beginning // // of the current row // // unsigned num_spans = sl.num_spans(); // Number of spans. It's guaranteed that @@ -252,7 +252,7 @@ namespace agg24 typedef base_type::coord_type coord_type; scanline_u8_am() : base_type(), m_alpha_mask(0) {} - scanline_u8_am(const AlphaMask& am) : base_type(), m_alpha_mask(&am) {} + scanline_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {} //-------------------------------------------------------------------- void finalize(int span_y) @@ -275,7 +275,7 @@ namespace agg24 } private: - const AlphaMask* m_alpha_mask; + AlphaMask* m_alpha_mask; }; @@ -458,14 +458,14 @@ namespace agg24 class scanline32_u8_am : public scanline32_u8 { public: - typedef scanline32_u8 base_type; + typedef scanline32_u8 base_type; typedef AlphaMask alpha_mask_type; typedef base_type::cover_type cover_type; typedef base_type::coord_type coord_type; scanline32_u8_am() : base_type(), m_alpha_mask(0) {} - scanline32_u8_am(const AlphaMask& am) : base_type(), m_alpha_mask(&am) {} + scanline32_u8_am(AlphaMask& am) : base_type(), m_alpha_mask(&am) {} //-------------------------------------------------------------------- void finalize(int span_y) @@ -488,7 +488,7 @@ namespace agg24 } private: - const AlphaMask* m_alpha_mask; + AlphaMask* m_alpha_mask; }; diff --git a/kiva/agg/agg-24/include/agg_span_gouraud_rgba.h b/kiva/agg/agg-24/include/agg_span_gouraud_rgba.h index 809f6ce38..21ed44042 100644 --- a/kiva/agg/agg-24/include/agg_span_gouraud_rgba.h +++ b/kiva/agg/agg-24/include/agg_span_gouraud_rgba.h @@ -198,10 +198,10 @@ namespace agg24 vg = g.y(); vb = b.y(); va = a.y(); - if(vr < 0) vr = 0; if(vr > lim) vr = lim; - if(vg < 0) vg = 0; if(vg > lim) vg = lim; - if(vb < 0) vb = 0; if(vb > lim) vb = lim; - if(va < 0) va = 0; if(va > lim) va = lim; + if(vr < 0) { vr = 0; }; if(vr > lim) { vr = lim; }; + if(vg < 0) { vg = 0; }; if(vg > lim) { vg = lim; }; + if(vb < 0) { vb = 0; }; if(vb > lim) { vb = lim; }; + if(va < 0) { va = 0; }; if(va > lim) { va = lim; }; span->r = (value_type)vr; span->g = (value_type)vg; span->b = (value_type)vb; @@ -245,10 +245,10 @@ namespace agg24 vg = g.y(); vb = b.y(); va = a.y(); - if(vr < 0) vr = 0; if(vr > lim) vr = lim; - if(vg < 0) vg = 0; if(vg > lim) vg = lim; - if(vb < 0) vb = 0; if(vb > lim) vb = lim; - if(va < 0) va = 0; if(va > lim) va = lim; + if(vr < 0) { vr = 0; }; if(vr > lim) { vr = lim; }; + if(vg < 0) { vg = 0; }; if(vg > lim) { vg = lim; }; + if(vb < 0) { vb = 0; }; if(vb > lim) { vb = lim; }; + if(va < 0) { va = 0; }; if(va > lim) { va = lim; }; span->r = (value_type)vr; span->g = (value_type)vg; span->b = (value_type)vb; diff --git a/kiva/agg/agg-24/include/agg_span_gradient.h b/kiva/agg/agg-24/include/agg_span_gradient.h index 32e05ea08..566ac0744 100644 --- a/kiva/agg/agg-24/include/agg_span_gradient.h +++ b/kiva/agg/agg-24/include/agg_span_gradient.h @@ -58,8 +58,8 @@ namespace agg24 //-------------------------------------------------------------------- span_gradient(interpolator_type& inter, - const GradientF& gradient_function, - const ColorF& color_function, + GradientF& gradient_function, + ColorF& color_function, double d1, double d2) : m_interpolator(&inter), m_gradient_function(&gradient_function), @@ -77,8 +77,8 @@ namespace agg24 //-------------------------------------------------------------------- void interpolator(interpolator_type& i) { m_interpolator = &i; } - void gradient_function(const GradientF& gf) { m_gradient_function = &gf; } - void color_function(const ColorF& cf) { m_color_function = &cf; } + void gradient_function(GradientF& gf) { m_gradient_function = &gf; } + void color_function(ColorF& cf) { m_color_function = &cf; } void d1(double v) { m_d1 = iround(v * gradient_subpixel_scale); } void d2(double v) { m_d2 = iround(v * gradient_subpixel_scale); } @@ -107,8 +107,8 @@ namespace agg24 private: interpolator_type* m_interpolator; - const GradientF* m_gradient_function; - const ColorF* m_color_function; + GradientF* m_gradient_function; + ColorF* m_color_function; int m_d1; int m_d2; }; @@ -125,12 +125,19 @@ namespace agg24 gradient_linear_color() {} gradient_linear_color(const color_type& c1, const color_type& c2, unsigned size = 256) : - m_c1(c1), m_c2(c2), m_size(size) {} + m_c1(c1), m_c2(c2), m_size(size) + // VFALCO 4/28/09 + ,m_mult(1/(double(size)-1)) + // VFALCO + {} unsigned size() const { return m_size; } color_type operator [] (unsigned v) const { - return m_c1.gradient(m_c2, double(v) / double(m_size - 1)); + // VFALCO 4/28/09 + //return m_c1.gradient(m_c2, double(v) / double(m_size - 1)); + return m_c1.gradient(m_c2, double(v) * m_mult ); + // VFALCO } void colors(const color_type& c1, const color_type& c2, unsigned size = 256) @@ -138,14 +145,24 @@ namespace agg24 m_c1 = c1; m_c2 = c2; m_size = size; + // VFALCO 4/28/09 + m_mult=1/(double(size)-1); + // VFALCO } color_type m_c1; color_type m_c2; unsigned m_size; + // VFALCO 4/28/09 + double m_mult; + // VFALCO }; + + + + //==========================================================gradient_circle class gradient_circle { @@ -168,7 +185,6 @@ namespace agg24 } }; - //========================================================gradient_radial_d class gradient_radial_d { @@ -179,25 +195,24 @@ namespace agg24 } }; - //====================================================gradient_radial_focus class gradient_radial_focus { public: //--------------------------------------------------------------------- gradient_radial_focus() : - m_radius(100 * gradient_subpixel_scale), - m_focus_x(0), - m_focus_y(0) + m_r(100 * gradient_subpixel_scale), + m_fx(0), + m_fy(0) { update_values(); } //--------------------------------------------------------------------- gradient_radial_focus(double r, double fx, double fy) : - m_radius (iround(r * gradient_subpixel_scale)), - m_focus_x(iround(fx * gradient_subpixel_scale)), - m_focus_y(iround(fy * gradient_subpixel_scale)) + m_r (iround(r * gradient_subpixel_scale)), + m_fx(iround(fx * gradient_subpixel_scale)), + m_fy(iround(fy * gradient_subpixel_scale)) { update_values(); } @@ -205,111 +220,62 @@ namespace agg24 //--------------------------------------------------------------------- void init(double r, double fx, double fy) { - m_radius = iround(r * gradient_subpixel_scale); - m_focus_x = iround(fx * gradient_subpixel_scale); - m_focus_y = iround(fy * gradient_subpixel_scale); + m_r = iround(r * gradient_subpixel_scale); + m_fx = iround(fx * gradient_subpixel_scale); + m_fy = iround(fy * gradient_subpixel_scale); update_values(); } //--------------------------------------------------------------------- - double radius() const { return double(m_radius) / gradient_subpixel_scale; } - double focus_x() const { return double(m_focus_x) / gradient_subpixel_scale; } - double focus_y() const { return double(m_focus_y) / gradient_subpixel_scale; } + double radius() const { return double(m_r) / gradient_subpixel_scale; } + double focus_x() const { return double(m_fx) / gradient_subpixel_scale; } + double focus_y() const { return double(m_fy) / gradient_subpixel_scale; } //--------------------------------------------------------------------- int calculate(int x, int y, int) const { - double solution_x; - double solution_y; - - // Special case to avoid divide by zero or very near zero - //--------------------------------- - if(x == iround(m_focus_x)) - { - solution_x = m_focus_x; - solution_y = 0.0; - solution_y += (y > m_focus_y) ? m_trivial : -m_trivial; - } - else - { - // Slope of the focus-current line - //------------------------------- - double slope = double(y - m_focus_y) / double(x - m_focus_x); - - // y-intercept of that same line - //-------------------------------- - double yint = double(y) - (slope * x); - - // Use the classical quadratic formula to calculate - // the intersection point - //-------------------------------- - double a = (slope * slope) + 1; - double b = 2 * slope * yint; - double c = yint * yint - m_radius2; - double det = sqrt((b * b) - (4.0 * a * c)); - solution_x = -b; - - // Choose the positive or negative root depending - // on where the X coord lies with respect to the focus. - solution_x += (x < m_focus_x) ? -det : det; - solution_x /= 2.0 * a; - - // Calculating of Y is trivial - solution_y = (slope * solution_x) + yint; - } - - // Calculate the percentage (0...1) of the current point along the - // focus-circumference line and return the normalized (0...d) value - //------------------------------- - solution_x -= double(m_focus_x); - solution_y -= double(m_focus_y); - double int_to_focus = solution_x * solution_x + solution_y * solution_y; - double cur_to_focus = double(x - m_focus_x) * double(x - m_focus_x) + - double(y - m_focus_y) * double(y - m_focus_y); - - return iround(sqrt(cur_to_focus / int_to_focus) * m_radius); + double dx = x - m_fx; + double dy = y - m_fy; + double d2 = dx * m_fy - dy * m_fx; + double d3 = m_r2 * (dx * dx + dy * dy) - d2 * d2; + return iround((dx * m_fx + dy * m_fy + sqrt(fabs(d3))) * m_mul); } private: //--------------------------------------------------------------------- void update_values() { - // For use in the quadratic equation - //------------------------------- - m_radius2 = double(m_radius) * double(m_radius); - - double dist = sqrt(double(m_focus_x) * double(m_focus_x) + - double(m_focus_y) * double(m_focus_y)); - - // Test if distance from focus to center is greater than the radius - // For the sake of assurance factor restrict the point to be - // no further than 99% of the radius. - //------------------------------- - double r = m_radius * 0.99; - if(dist > r) - { - // clamp focus to radius - // x = r cos theta, y = r sin theta - //------------------------ - double a = atan2(double(m_focus_y), double(m_focus_x)); - m_focus_x = iround(r * cos(a)); - m_focus_y = iround(r * sin(a)); + // Calculate the invariant values. In case the focal center + // lies exactly on the gradient circle the divisor degenerates + // into zero. In this case we just move the focal center by + // one subpixel unit possibly in the direction to the origin (0,0) + // and calculate the values again. + //------------------------- + m_r2 = double(m_r) * double(m_r); + m_fx2 = double(m_fx) * double(m_fx); + m_fy2 = double(m_fy) * double(m_fy); + double d = (m_r2 - (m_fx2 + m_fy2)); + if(d == 0) + { + if(m_fx) { if(m_fx < 0) ++m_fx; else --m_fx; } + if(m_fy) { if(m_fy < 0) ++m_fy; else --m_fy; } + m_fx2 = double(m_fx) * double(m_fx); + m_fy2 = double(m_fy) * double(m_fy); + d = (m_r2 - (m_fx2 + m_fy2)); } - - // Calculate the solution to be used in the case where x == focus_x - //------------------------------ - m_trivial = sqrt(m_radius2 - (m_focus_x * m_focus_x)); + m_mul = m_r / d; } - int m_radius; - int m_focus_x; - int m_focus_y; - double m_radius2; - double m_trivial; + int m_r; + int m_fx; + int m_fy; + double m_r2; + double m_fx2; + double m_fy2; + double m_mul; }; - //==============================================================gradient_x class gradient_x { @@ -325,7 +291,6 @@ namespace agg24 static int calculate(int, int y, int) { return y; } }; - //========================================================gradient_diamond class gradient_diamond { @@ -338,7 +303,6 @@ namespace agg24 } }; - //=============================================================gradient_xy class gradient_xy { @@ -349,7 +313,6 @@ namespace agg24 } }; - //========================================================gradient_sqrt_xy class gradient_sqrt_xy { @@ -360,7 +323,6 @@ namespace agg24 } }; - //==========================================================gradient_conic class gradient_conic { @@ -371,7 +333,6 @@ namespace agg24 } }; - //=================================================gradient_repeat_adaptor template class gradient_repeat_adaptor { @@ -390,7 +351,6 @@ namespace agg24 const GradientF* m_gradient; }; - //================================================gradient_reflect_adaptor template class gradient_reflect_adaptor { diff --git a/kiva/agg/agg-24/include/agg_span_gradient_alpha.h b/kiva/agg/agg-24/include/agg_span_gradient_alpha.h index 73cee98ab..24ea93c05 100644 --- a/kiva/agg/agg-24/include/agg_span_gradient_alpha.h +++ b/kiva/agg/agg-24/include/agg_span_gradient_alpha.h @@ -43,8 +43,8 @@ namespace agg24 //-------------------------------------------------------------------- span_gradient_alpha(interpolator_type& inter, - const GradientF& gradient_function, - const AlphaF& alpha_function, + GradientF& gradient_function, + AlphaF& alpha_function, double d1, double d2) : m_interpolator(&inter), m_gradient_function(&gradient_function), @@ -93,8 +93,8 @@ namespace agg24 private: interpolator_type* m_interpolator; - const GradientF* m_gradient_function; - const AlphaF* m_alpha_function; + GradientF* m_gradient_function; + AlphaF* m_alpha_function; int m_d1; int m_d2; }; diff --git a/kiva/agg/agg-24/include/agg_span_gradient_contour.h b/kiva/agg/agg-24/include/agg_span_gradient_contour.h new file mode 100644 index 000000000..62475da62 --- /dev/null +++ b/kiva/agg/agg-24/include/agg_span_gradient_contour.h @@ -0,0 +1,362 @@ +//---------------------------------------------------------------------------- +// AGG Contribution Pack - Gradients 1 (AGG CP - Gradients 1) +// http://milan.marusinec.sk/aggcp +// +// For Anti-Grain Geometry - Version 2.4 +// http://www.antigrain.org +// +// Contribution Created By: +// Milan Marusinec alias Milano +// milan@marusinec.sk +// Copyright (c) 2007-2008 +// +// 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. +// +// [History] ----------------------------------------------------------------- +// +// 02.02.2008-Milano: Ported from Object Pascal code of AggPas +// +#ifndef AGG_SPAN_GRADIENT_CONTOUR_INCLUDED +#define AGG_SPAN_GRADIENT_CONTOUR_INCLUDED + +#include "agg_basics.h" +#include "agg_trans_affine.h" +#include "agg_path_storage.h" +#include "agg_pixfmt_gray.h" +#include "agg_conv_transform.h" +#include "agg_conv_curve.h" +#include "agg_bounding_rect.h" +#include "agg_renderer_base.h" +#include "agg_renderer_primitives.h" +#include "agg_rasterizer_outline.h" +#include "agg_span_gradient.h" + +#define infinity 1E20 + +namespace agg24 +{ + + //==========================================================gradient_contour + class gradient_contour + { + private: + int8u* m_buffer; + int m_width; + int m_height; + int m_frame; + + double m_d1; + double m_d2; + + public: + gradient_contour() : + m_buffer(NULL), + m_width(0), + m_height(0), + m_frame(10), + m_d1(0), + m_d2(100) + { + } + + gradient_contour(double d1, double d2) : + m_buffer(NULL), + m_width(0), + m_height(0), + m_frame(10), + m_d1(d1), + m_d2(d2) + { + } + + ~gradient_contour() + { + if (m_buffer) + { + delete [] m_buffer; + } + } + + int8u* contour_create(path_storage* ps ); + + int contour_width() { return m_width; } + int contour_height() { return m_height; } + + void d1(double d ) { m_d1 = d; } + void d2(double d ) { m_d2 = d; } + + void frame(int f ) { m_frame = f; } + int frame() { return m_frame; } + + int calculate(int x, int y, int d) const + { + if (m_buffer) + { + int px = x >> agg24::gradient_subpixel_shift; + int py = y >> agg24::gradient_subpixel_shift; + + px %= m_width; + + if (px < 0) + { + px += m_width; + } + + py %= m_height; + + if (py < 0 ) + { + py += m_height; + } + + return iround(m_buffer[py * m_width + px ] * (m_d2 / 256 ) + m_d1 ) << gradient_subpixel_shift; + + } + else + { + return 0; + } + } + + }; + + static AGG_INLINE int square(int x ) { return x * x; } + + // DT algorithm by: Pedro Felzenszwalb + void dt(float* spanf, float* spang, float* spanr, int* spann ,int length ) + { + int k = 0; + float s; + + spann[0 ] = 0; + spang[0 ] = float(-infinity ); + spang[1 ] = float(+infinity ); + + for (int q = 1; q <= length - 1; q++) + { + s = ((spanf[q ] + square(q ) ) - (spanf[spann[k ] ] + square(spann[k ] ) ) ) / (2 * q - 2 * spann[k ] ); + + while (s <= spang[k ]) + { + k--; + s = ((spanf[q ] + square(q ) ) - (spanf[spann[k ] ] + square(spann[k ] ) ) ) / (2 * q - 2 * spann[k ] ); + } + + k++; + spann[k ] = q; + spang[k ] = s; + spang[k + 1 ] = float(+infinity); + + } + + k = 0; + + for (int q = 0; q <= length - 1; q++) + { + while (spang[k + 1 ] < q ) + { + k++; + } + + spanr[q ] = square(q - spann[k ] ) + spanf[spann[k ] ]; + } + } + + // DT algorithm by: Pedro Felzenszwalb + int8u* gradient_contour::contour_create(path_storage* ps ) + { + int8u* result = NULL; + + if (ps) + { + // I. Render Black And White NonAA Stroke of the Path + // Path Bounding Box + Some Frame Space Around [configurable] + agg24::conv_curve conv(*ps); + + double x1, y1, x2, y2; + + if (agg24::bounding_rect_single(conv ,0 ,&x1 ,&y1 ,&x2 ,&y2 )) + { + // Create BW Rendering Surface + int width = int(ceil(x2 - x1 ) ) + m_frame * 2 + 1; + int height = int(ceil(y2 - y1 ) ) + m_frame * 2 + 1; + + int8u* buffer = new int8u[width * height]; + + if (buffer) + { + memset(buffer ,255 ,width * height ); + + // Setup VG Engine & Render + agg24::rendering_buffer rb; + rb.attach(buffer ,width ,height ,width ); + + agg24::pixfmt_gray8 pf(rb); + agg24::renderer_base renb(pf ); + + agg24::renderer_primitives > prim(renb ); + agg24::rasterizer_outline > > ras(prim ); + + agg24::trans_affine mtx; + mtx *= agg24::trans_affine_translation(-x1 + m_frame, -y1 + m_frame ); + + agg24::conv_transform > trans(conv ,mtx ); + + prim.line_color(agg24::rgba8(0 ,0 ,0 ,255 ) ); + ras.add_path(trans ); + + // II. Distance Transform + // Create Float Buffer + 0 vs infinity (1e20) assignment + float* image = new float[width * height]; + + if (image) + { + for (int y = 0, l = 0; y < height; y++ ) + { + for (int x = 0; x < width; x++, l++ ) + { + if (buffer[l ] == 0) + { + image[l ] = 0.0; + } + else + { + image[l ] = float(infinity ); + } + } + + } + + // DT of 2d + // SubBuff max width,height + int length = width; + + if (height > length) + { + length = height; + } + + float* spanf = new float[length]; + float* spang = new float[length + 1]; + float* spanr = new float[length]; + int* spann = new int[length]; + + if ((spanf) && (spang) && (spanr) && (spann)) + { + // Transform along columns + for (int x = 0; x < width; x++ ) + { + for (int y = 0; y < height; y++ ) + { + spanf[y] = image[y * width + x]; + } + + // DT of 1d + dt(spanf ,spang ,spanr ,spann ,height ); + + for (int y = 0; y < height; y++ ) + { + image[y * width + x] = spanr[y]; + } + } + + // Transform along rows + for (int y = 0; y < height; y++ ) + { + for (int x = 0; x < width; x++ ) + { + spanf[x] = image[y * width + x]; + } + + // DT of 1d + dt(spanf ,spang ,spanr ,spann ,width ); + + for (int x = 0; x < width; x++ ) + { + image[y * width + x] = spanr[x]; + } + } + + // Take Square Roots, Min & Max + float min = sqrt(image[0] ); + float max = min; + + for (int y = 0, l = 0; y < height; y++ ) + { + for (int x = 0; x < width; x++, l++ ) + { + image[l] = sqrt(image[l]); + + if (min > image[l]) + { + min = image[l]; + } + + if (max < image[l]) + { + max = image[l]; + } + + } + } + + // III. Convert To Grayscale + if (min == max) + { + memset(buffer ,0 ,width * height ); + } + else + { + float scale = 255 / (max - min ); + + for (int y = 0, l = 0; y < height; y++ ) + { + for (int x = 0; x < width; x++ ,l++ ) + { + buffer[l] = int8u(int((image[l] - min ) * scale )); + } + } + } + + // OK + if (m_buffer) + { + delete [] m_buffer; + } + + m_buffer = buffer; + m_width = width; + m_height = height; + + buffer = NULL; + result = m_buffer; + + } + + if (spanf) { delete [] spanf; } + if (spang) { delete [] spang; } + if (spanr) { delete [] spanr; } + if (spann) { delete [] spann; } + + delete [] image; + + } + } + + if (buffer) + { + delete [] buffer; + } + + } + + } + return result; + } + +} + +#endif diff --git a/kiva/agg/agg-24/include/agg_span_gradient_image.h b/kiva/agg/agg-24/include/agg_span_gradient_image.h new file mode 100644 index 000000000..a0e588c65 --- /dev/null +++ b/kiva/agg/agg-24/include/agg_span_gradient_image.h @@ -0,0 +1,188 @@ +//---------------------------------------------------------------------------- +// AGG Contribution Pack - Gradients 1 (AGG CP - Gradients 1) +// http://milan.marusinec.sk/aggcp +// +// For Anti-Grain Geometry - Version 2.4 +// http://www.antigrain.org +// +// Contribution Created By: +// Milan Marusinec alias Milano +// milan@marusinec.sk +// Copyright (c) 2007-2008 +// +// 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. +// +// [History] ----------------------------------------------------------------- +// +// 03.02.2008-Milano: Ported from Object Pascal code of AggPas +// +#ifndef AGG_SPAN_GRADIENT_IMAGE_INCLUDED +#define AGG_SPAN_GRADIENT_IMAGE_INCLUDED + +#include "agg_basics.h" +#include "agg_span_gradient.h" +#include "agg_color_rgba.h" +#include "agg_rendering_buffer.h" +#include "agg_pixfmt_rgba.h" + +namespace agg24 +{ + + //==========================================================one_color_function + template class one_color_function + { + public: + typedef ColorT color_type; + + color_type m_color; + + one_color_function() : + m_color() + { + } + + static unsigned size() { return 1; } + + const color_type& operator [] (unsigned i) const + { + return m_color; + } + + color_type* operator [] (unsigned i) + { + return &m_color; + } + }; + + //==========================================================gradient_image + template class gradient_image + { + private: + //------------ fields + typedef ColorT color_type; + typedef agg24::pixfmt_rgba32 pixfmt_type; + + agg24::rgba8* m_buffer; + + int m_alocdx; + int m_alocdy; + int m_width; + int m_height; + + color_type* m_color; + + one_color_function m_color_function; + + public: + gradient_image() : + m_color_function(), + m_buffer(NULL), + m_alocdx(0), + m_alocdy(0), + m_width(0), + m_height(0) + { + m_color = m_color_function[0 ]; + } + + ~gradient_image() + { + if (m_buffer) { delete [] m_buffer; } + } + + void* image_create(int width, int height ) + { + void* result = NULL; + + if (width > m_alocdx || height > m_alocdy) + { + if (m_buffer) { delete [] m_buffer; } + + m_buffer = NULL; + m_buffer = new agg24::rgba8[width * height]; + + if (m_buffer) + { + m_alocdx = width; + m_alocdy = height; + } + else + { + m_alocdx = 0; + m_alocdy = 0; + }; + }; + + if (m_buffer) + { + m_width = width; + m_height = height; + + for (int rows = 0; rows < height; rows++) + { + agg24::rgba8* row = &m_buffer[rows * m_alocdx ]; + memset(row ,0 ,m_width * 4 ); + }; + + result = m_buffer; + }; + return result; + } + + void* image_buffer() { return m_buffer; } + int image_width() { return m_width; } + int image_height() { return m_height; } + int image_stride() { return m_alocdx * 4; } + + int calculate(int x, int y, int d) const + { + if (m_buffer) + { + int px = x >> agg24::gradient_subpixel_shift; + int py = y >> agg24::gradient_subpixel_shift; + + px %= m_width; + + if (px < 0) + { + px += m_width; + } + + py %= m_height; + + if (py < 0 ) + { + py += m_height; + } + + rgba8* pixel = &m_buffer[py * m_alocdx + px ]; + + m_color->r = pixel->r; + m_color->g = pixel->g; + m_color->b = pixel->b; + m_color->a = pixel->a; + + } + else + { + m_color->r = 0; + m_color->g = 0; + m_color->b = 0; + m_color->a = 0; + } + return 0; + } + + const one_color_function& color_function() const + { + return m_color_function; + } + + }; + +} + +#endif diff --git a/kiva/agg/agg-24/include/agg_span_image_filter.h b/kiva/agg/agg-24/include/agg_span_image_filter.h index 6093f96e3..e0e28c6dd 100644 --- a/kiva/agg/agg-24/include/agg_span_image_filter.h +++ b/kiva/agg/agg-24/include/agg_span_image_filter.h @@ -37,7 +37,7 @@ namespace agg24 span_image_filter() {} span_image_filter(source_type& src, interpolator_type& interpolator, - const image_filter_lut* filter) : + image_filter_lut* filter) : m_src(&src), m_interpolator(&interpolator), m_filter(filter), @@ -59,7 +59,7 @@ namespace agg24 //-------------------------------------------------------------------- void interpolator(interpolator_type& v) { m_interpolator = &v; } - void filter(const image_filter_lut& v) { m_filter = &v; } + void filter(image_filter_lut& v) { m_filter = &v; } void filter_offset(double dx, double dy) { m_dx_dbl = dx; @@ -79,7 +79,7 @@ namespace agg24 private: source_type* m_src; interpolator_type* m_interpolator; - const image_filter_lut* m_filter; + image_filter_lut* m_filter; double m_dx_dbl; double m_dy_dbl; unsigned m_dx_int; @@ -109,7 +109,7 @@ namespace agg24 //-------------------------------------------------------------------- span_image_resample_affine(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter), m_scale_limit(200.0), m_blur_x(1.0), @@ -136,33 +136,29 @@ namespace agg24 base_type::interpolator().transformer().scaling_abs(&scale_x, &scale_y); - m_rx = image_subpixel_scale; - m_ry = image_subpixel_scale; - m_rx_inv = image_subpixel_scale; - m_ry_inv = image_subpixel_scale; - - scale_x *= m_blur_x; - scale_y *= m_blur_y; - if(scale_x * scale_y > m_scale_limit) { scale_x = scale_x * m_scale_limit / (scale_x * scale_y); scale_y = scale_y * m_scale_limit / (scale_x * scale_y); } - if(scale_x > 1.0001) - { - if(scale_x > m_scale_limit) scale_x = m_scale_limit; - m_rx = uround( scale_x * double(image_subpixel_scale)); - m_rx_inv = uround(1.0/scale_x * double(image_subpixel_scale)); - } + if(scale_x < 1) scale_x = 1; + if(scale_y < 1) scale_y = 1; - if(scale_y > 1.0001) - { - if(scale_y > m_scale_limit) scale_y = m_scale_limit; - m_ry = uround( scale_y * double(image_subpixel_scale)); - m_ry_inv = uround(1.0/scale_y * double(image_subpixel_scale)); - } + if(scale_x > m_scale_limit) scale_x = m_scale_limit; + if(scale_y > m_scale_limit) scale_y = m_scale_limit; + + scale_x *= m_blur_x; + scale_y *= m_blur_y; + + if(scale_x < 1) scale_x = 1; + if(scale_y < 1) scale_y = 1; + + m_rx = uround( scale_x * double(image_subpixel_scale)); + m_rx_inv = uround(1.0/scale_x * double(image_subpixel_scale)); + + m_ry = uround( scale_y * double(image_subpixel_scale)); + m_ry_inv = uround(1.0/scale_y * double(image_subpixel_scale)); } protected: @@ -199,7 +195,7 @@ namespace agg24 //-------------------------------------------------------------------- span_image_resample(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter), m_scale_limit(20), m_blur_x(image_subpixel_scale), @@ -219,6 +215,24 @@ namespace agg24 m_blur_y = uround(v * double(image_subpixel_scale)); } protected: + AGG_INLINE void adjust_scale(int* rx, int* ry) + { + if(*rx < image_subpixel_scale) *rx = image_subpixel_scale; + if(*ry < image_subpixel_scale) *ry = image_subpixel_scale; + if(*rx > image_subpixel_scale * m_scale_limit) + { + *rx = image_subpixel_scale * m_scale_limit; + } + if(*ry > image_subpixel_scale * m_scale_limit) + { + *ry = image_subpixel_scale * m_scale_limit; + } + *rx = (*rx * m_blur_x) >> image_subpixel_shift; + *ry = (*ry * m_blur_y) >> image_subpixel_shift; + if(*rx < image_subpixel_scale) *rx = image_subpixel_scale; + if(*ry < image_subpixel_scale) *ry = image_subpixel_scale; + } + int m_scale_limit; int m_blur_x; int m_blur_y; diff --git a/kiva/agg/agg-24/include/agg_span_image_filter_gray.h b/kiva/agg/agg-24/include/agg_span_image_filter_gray.h index c2ad0886d..a47d282cc 100644 --- a/kiva/agg/agg-24/include/agg_span_image_filter_gray.h +++ b/kiva/agg/agg-24/include/agg_span_image_filter_gray.h @@ -43,11 +43,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_nn() {} @@ -68,7 +64,7 @@ namespace agg24 base_type::source().span(x >> image_subpixel_shift, y >> image_subpixel_shift, 1); - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); @@ -89,11 +85,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_bilinear() {} @@ -108,7 +100,7 @@ namespace agg24 { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg; + long_type fg; const value_type *fg_ptr; do { @@ -123,7 +115,7 @@ namespace agg24 int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; - fg = image_subpixel_scale * image_subpixel_scale / 2; + fg = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -140,8 +132,8 @@ namespace agg24 fg_ptr = (const value_type*)base_type::source().next_x(); fg += *fg_ptr * x_hr * y_hr; - span->v = value_type(fg >> (image_subpixel_shift * 2)); - span->a = base_mask; + span->v = color_type::downshift(fg, image_subpixel_shift * 2); + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -162,11 +154,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_bilinear_clip() {} @@ -184,8 +172,8 @@ namespace agg24 { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg; - calc_type src_alpha; + long_type fg; + long_type src_alpha; value_type back_v = m_back_color.v; value_type back_a = m_back_color.a; @@ -210,7 +198,7 @@ namespace agg24 if(x_lr >= 0 && y_lr >= 0 && x_lr < maxx && y_lr < maxy) { - fg = image_subpixel_scale * image_subpixel_scale / 2; + fg = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -225,8 +213,8 @@ namespace agg24 fg += *fg_ptr++ * (image_subpixel_scale - x_hr) * y_hr; fg += *fg_ptr++ * x_hr * y_hr; - fg >>= image_subpixel_shift * 2; - src_alpha = base_mask; + fg = color_type::downshift(fg, image_subpixel_shift * 2); + src_alpha = color_type::full_value(); } else { @@ -239,8 +227,7 @@ namespace agg24 } else { - fg = - src_alpha = image_subpixel_scale * image_subpixel_scale / 2; + fg = src_alpha = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -252,7 +239,7 @@ namespace agg24 { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -268,7 +255,7 @@ namespace agg24 { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -285,7 +272,7 @@ namespace agg24 { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -301,7 +288,7 @@ namespace agg24 { fg += weight * *((const value_type*)base_type::source().row_ptr(y_lr) + x_lr); - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -309,8 +296,8 @@ namespace agg24 src_alpha += back_a * weight; } - fg >>= image_subpixel_shift * 2; - src_alpha >>= image_subpixel_shift * 2; + fg = color_type::downshift(fg, image_subpixel_shift * 2); + src_alpha = color_type::downshift(src_alpha, image_subpixel_shift * 2); } } @@ -339,17 +326,13 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray_2x2() {} span_image_filter_gray_2x2(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter) {} @@ -360,7 +343,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg; + long_type fg; const value_type *fg_ptr; const int16* weight_array = base_type::filter().weight_array() + @@ -380,7 +363,7 @@ namespace agg24 int y_lr = y_hr >> image_subpixel_shift; unsigned weight; - fg = image_filter_scale / 2; + fg = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -414,10 +397,10 @@ namespace agg24 fg += weight * *fg_ptr; fg >>= image_filter_shift; - if(fg > base_mask) fg = base_mask; + if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); } while(--len); @@ -438,17 +421,13 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_gray() {} span_image_filter_gray(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter) {} @@ -458,7 +437,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - int fg; + long_type fg; const value_type *fg_ptr; unsigned diameter = base_type::filter().diameter(); @@ -481,7 +460,7 @@ namespace agg24 int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; - fg = image_filter_scale / 2; + fg = 0; int x_fract = x_hr & image_subpixel_mask; unsigned y_count = diameter; @@ -511,11 +490,11 @@ namespace agg24 fg_ptr = (const value_type*)base_type::source().next_y(); } - fg >>= image_filter_shift; + fg = color_type::downshift(fg, image_filter_shift); if(fg < 0) fg = 0; - if(fg > base_mask) fg = base_mask; + if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -540,8 +519,6 @@ namespace agg24 typedef typename color_type::long_type long_type; enum base_scale_e { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, downscale_shift = image_filter_shift }; @@ -549,7 +526,7 @@ namespace agg24 span_image_resample_gray_affine() {} span_image_resample_gray_affine(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, filter) {} @@ -579,7 +556,7 @@ namespace agg24 x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; - fg = image_filter_scale / 2; + fg = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * @@ -617,10 +594,10 @@ namespace agg24 fg /= total_weight; if(fg < 0) fg = 0; - if(fg > base_mask) fg = base_mask; + if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -644,8 +621,6 @@ namespace agg24 typedef typename color_type::long_type long_type; enum base_scale_e { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, downscale_shift = image_filter_shift }; @@ -653,7 +628,7 @@ namespace agg24 span_image_resample_gray() {} span_image_resample_gray(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, filter) {} @@ -676,35 +651,10 @@ namespace agg24 int ry_inv = image_subpixel_scale; base_type::interpolator().coordinates(&x, &y); base_type::interpolator().local_scale(&rx, &ry); + base_type::adjust_scale(&rx, &ry); - rx = (rx * base_type::m_blur_x) >> image_subpixel_shift; - ry = (ry * base_type::m_blur_y) >> image_subpixel_shift; - - if(rx < image_subpixel_scale) - { - rx = image_subpixel_scale; - } - else - { - if(rx > image_subpixel_scale * base_type::m_scale_limit) - { - rx = image_subpixel_scale * base_type::m_scale_limit; - } - rx_inv = image_subpixel_scale * image_subpixel_scale / rx; - } - - if(ry < image_subpixel_scale) - { - ry = image_subpixel_scale; - } - else - { - if(ry > image_subpixel_scale * base_type::m_scale_limit) - { - ry = image_subpixel_scale * base_type::m_scale_limit; - } - ry_inv = image_subpixel_scale * image_subpixel_scale / ry; - } + rx_inv = image_subpixel_scale * image_subpixel_scale / rx; + ry_inv = image_subpixel_scale * image_subpixel_scale / ry; int radius_x = (diameter * rx) >> 1; int radius_y = (diameter * ry) >> 1; @@ -715,7 +665,7 @@ namespace agg24 x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; - fg = image_filter_scale / 2; + fg = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * @@ -752,10 +702,10 @@ namespace agg24 fg /= total_weight; if(fg < 0) fg = 0; - if(fg > base_mask) fg = base_mask; + if(fg > color_type::full_value()) fg = color_type::full_value(); span->v = (value_type)fg; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); diff --git a/kiva/agg/agg-24/include/agg_span_image_filter_rgb.h b/kiva/agg/agg-24/include/agg_span_image_filter_rgb.h index 6cce709c2..a3eef85ed 100644 --- a/kiva/agg/agg-24/include/agg_span_image_filter_rgb.h +++ b/kiva/agg/agg-24/include/agg_span_image_filter_rgb.h @@ -44,11 +44,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_nn() {} @@ -72,7 +68,7 @@ namespace agg24 span->r = fg_ptr[order_type::R]; span->g = fg_ptr[order_type::G]; span->b = fg_ptr[order_type::B]; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -95,11 +91,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_bilinear() {} @@ -114,7 +106,7 @@ namespace agg24 { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg[3]; + long_type fg[3]; const value_type *fg_ptr; do { @@ -131,9 +123,7 @@ namespace agg24 unsigned weight; - fg[0] = - fg[1] = - fg[2] = image_subpixel_scale * image_subpixel_scale / 2; + fg[0] = fg[1] = fg[2] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -163,10 +153,10 @@ namespace agg24 fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; - span->r = value_type(fg[order_type::R] >> (image_subpixel_shift * 2)); - span->g = value_type(fg[order_type::G] >> (image_subpixel_shift * 2)); - span->b = value_type(fg[order_type::B] >> (image_subpixel_shift * 2)); - span->a = base_mask; + span->r = color_type::downshift(fg[order_type::R], image_subpixel_shift * 2); + span->g = color_type::downshift(fg[order_type::G], image_subpixel_shift * 2); + span->b = color_type::downshift(fg[order_type::B], image_subpixel_shift * 2); + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -190,11 +180,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_bilinear_clip() {} @@ -212,8 +198,8 @@ namespace agg24 { base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg[3]; - calc_type src_alpha; + long_type fg[3]; + long_type src_alpha; value_type back_r = m_back_color.r; value_type back_g = m_back_color.g; value_type back_b = m_back_color.b; @@ -241,9 +227,7 @@ namespace agg24 if(x_lr >= 0 && y_lr >= 0 && x_lr < maxx && y_lr < maxy) { - fg[0] = - fg[1] = - fg[2] = image_subpixel_scale * image_subpixel_scale / 2; + fg[0] = fg[1] = fg[2] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -276,10 +260,10 @@ namespace agg24 fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - src_alpha = base_mask; + fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); + fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); + fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); + src_alpha = color_type::full_value(); } else { @@ -293,10 +277,7 @@ namespace agg24 } else { - fg[0] = - fg[1] = - fg[2] = - src_alpha = image_subpixel_scale * image_subpixel_scale / 2; + fg[0] = fg[1] = fg[2] = src_alpha = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -312,7 +293,7 @@ namespace agg24 fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -334,7 +315,7 @@ namespace agg24 fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -357,7 +338,7 @@ namespace agg24 fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -379,7 +360,7 @@ namespace agg24 fg[0] += weight * *fg_ptr++; fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr++; - src_alpha += weight * base_mask; + src_alpha += weight * color_type::full_value(); } else { @@ -389,10 +370,10 @@ namespace agg24 src_alpha += back_a * weight; } - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - src_alpha >>= image_subpixel_shift * 2; + fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); + fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); + fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); + src_alpha = color_type::downshift(src_alpha, image_subpixel_shift * 2); } } @@ -424,17 +405,13 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb_2x2() {} span_image_filter_rgb_2x2(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter) {} @@ -445,7 +422,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg[3]; + long_type fg[3]; const value_type *fg_ptr; const int16* weight_array = base_type::filter().weight_array() + @@ -465,7 +442,7 @@ namespace agg24 int y_lr = y_hr >> image_subpixel_shift; unsigned weight; - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -506,18 +483,18 @@ namespace agg24 fg[1] += weight * *fg_ptr++; fg[2] += weight * *fg_ptr; - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; + fg[0] = color_type::downshift(fg[0], image_filter_shift); + fg[1] = color_type::downshift(fg[1], image_filter_shift); + fg[2] = color_type::downshift(fg[2], image_filter_shift); - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; + if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); + if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); + if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -541,17 +518,13 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgb() {} span_image_filter_rgb(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter) {} @@ -561,7 +534,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - int fg[3]; + long_type fg[3]; const value_type *fg_ptr; unsigned diameter = base_type::filter().diameter(); @@ -584,7 +557,7 @@ namespace agg24 int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = 0; int x_fract = x_hr & image_subpixel_mask; unsigned y_count = diameter; @@ -618,22 +591,22 @@ namespace agg24 fg_ptr = (const value_type*)base_type::source().next_y(); } - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; + fg[0] = color_type::downshift(fg[0], image_filter_shift); + fg[1] = color_type::downshift(fg[1], image_filter_shift); + fg[2] = color_type::downshift(fg[2], image_filter_shift); if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; + if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); + if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); + if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -659,8 +632,6 @@ namespace agg24 typedef typename color_type::long_type long_type; enum base_scale_e { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, downscale_shift = image_filter_shift }; @@ -668,7 +639,7 @@ namespace agg24 span_image_resample_rgb_affine() {} span_image_resample_rgb_affine(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, filter) {} @@ -698,7 +669,7 @@ namespace agg24 x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * @@ -744,14 +715,14 @@ namespace agg24 if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; + if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); + if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); + if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); @@ -776,8 +747,6 @@ namespace agg24 typedef typename color_type::long_type long_type; enum base_scale_e { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, downscale_shift = image_filter_shift }; @@ -785,7 +754,7 @@ namespace agg24 span_image_resample_rgb() {} span_image_resample_rgb(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, filter) {} @@ -808,35 +777,10 @@ namespace agg24 int ry_inv = image_subpixel_scale; base_type::interpolator().coordinates(&x, &y); base_type::interpolator().local_scale(&rx, &ry); + base_type::adjust_scale(&rx, &ry); - rx = (rx * base_type::m_blur_x) >> image_subpixel_shift; - ry = (ry * base_type::m_blur_y) >> image_subpixel_shift; - - if(rx < image_subpixel_scale) - { - rx = image_subpixel_scale; - } - else - { - if(rx > image_subpixel_scale * base_type::m_scale_limit) - { - rx = image_subpixel_scale * base_type::m_scale_limit; - } - rx_inv = image_subpixel_scale * image_subpixel_scale / rx; - } - - if(ry < image_subpixel_scale) - { - ry = image_subpixel_scale; - } - else - { - if(ry > image_subpixel_scale * base_type::m_scale_limit) - { - ry = image_subpixel_scale * base_type::m_scale_limit; - } - ry_inv = image_subpixel_scale * image_subpixel_scale / ry; - } + rx_inv = image_subpixel_scale * image_subpixel_scale / rx; + ry_inv = image_subpixel_scale * image_subpixel_scale / ry; int radius_x = (diameter * rx) >> 1; int radius_y = (diameter * ry) >> 1; @@ -847,7 +791,7 @@ namespace agg24 x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; - fg[0] = fg[1] = fg[2] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * @@ -892,14 +836,14 @@ namespace agg24 if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; - if(fg[order_type::R] > base_mask) fg[order_type::R] = base_mask; - if(fg[order_type::G] > base_mask) fg[order_type::G] = base_mask; - if(fg[order_type::B] > base_mask) fg[order_type::B] = base_mask; + if(fg[order_type::R] > color_type::full_value()) fg[order_type::R] = color_type::full_value(); + if(fg[order_type::G] > color_type::full_value()) fg[order_type::G] = color_type::full_value(); + if(fg[order_type::B] > color_type::full_value()) fg[order_type::B] = color_type::full_value(); span->r = (value_type)fg[order_type::R]; span->g = (value_type)fg[order_type::G]; span->b = (value_type)fg[order_type::B]; - span->a = base_mask; + span->a = color_type::full_value(); ++span; ++base_type::interpolator(); diff --git a/kiva/agg/agg-24/include/agg_span_image_filter_rgba.h b/kiva/agg/agg-24/include/agg_span_image_filter_rgba.h index 70387272d..b6e58f964 100644 --- a/kiva/agg/agg-24/include/agg_span_image_filter_rgba.h +++ b/kiva/agg/agg-24/include/agg_span_image_filter_rgba.h @@ -44,11 +44,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_nn() {} @@ -85,7 +81,7 @@ namespace agg24 //=========================================span_image_filter_rgba_bilinear template class span_image_filter_rgba_bilinear : - public span_image_filter + public span_image_filter { public: typedef Source source_type; @@ -95,11 +91,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_bilinear() {} @@ -115,7 +107,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg[4]; + long_type fg[4]; const value_type *fg_ptr; do @@ -170,10 +162,10 @@ namespace agg24 fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; - span->r = value_type(fg[order_type::R] >> (image_subpixel_shift * 2)); - span->g = value_type(fg[order_type::G] >> (image_subpixel_shift * 2)); - span->b = value_type(fg[order_type::B] >> (image_subpixel_shift * 2)); - span->a = value_type(fg[order_type::A] >> (image_subpixel_shift * 2)); + span->r = value_type(color_type::downshift(fg[order_type::R], image_subpixel_shift * 2)); + span->g = value_type(color_type::downshift(fg[order_type::G], image_subpixel_shift * 2)); + span->b = value_type(color_type::downshift(fg[order_type::B], image_subpixel_shift * 2)); + span->a = value_type(color_type::downshift(fg[order_type::A], image_subpixel_shift * 2)); ++span; ++base_type::interpolator(); @@ -196,11 +188,7 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_bilinear_clip() {} @@ -220,7 +208,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg[4]; + long_type fg[4]; value_type back_r = m_back_color.r; value_type back_g = m_back_color.g; value_type back_b = m_back_color.b; @@ -248,10 +236,7 @@ namespace agg24 if(x_lr >= 0 && y_lr >= 0 && x_lr < maxx && y_lr < maxy) { - fg[0] = - fg[1] = - fg[2] = - fg[3] = image_subpixel_scale * image_subpixel_scale / 2; + fg[0] = fg[1] = fg[2] = fg[3] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -288,10 +273,10 @@ namespace agg24 fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr++; - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - fg[3] >>= image_subpixel_shift * 2; + fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); + fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); + fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); + fg[3] = color_type::downshift(fg[3], image_subpixel_shift * 2); } else { @@ -305,10 +290,7 @@ namespace agg24 } else { - fg[0] = - fg[1] = - fg[2] = - fg[3] = image_subpixel_scale * image_subpixel_scale / 2; + fg[0] = fg[1] = fg[2] = fg[3] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -401,10 +383,10 @@ namespace agg24 fg[order_type::A] += back_a * weight; } - fg[0] >>= image_subpixel_shift * 2; - fg[1] >>= image_subpixel_shift * 2; - fg[2] >>= image_subpixel_shift * 2; - fg[3] >>= image_subpixel_shift * 2; + fg[0] = color_type::downshift(fg[0], image_subpixel_shift * 2); + fg[1] = color_type::downshift(fg[1], image_subpixel_shift * 2); + fg[2] = color_type::downshift(fg[2], image_subpixel_shift * 2); + fg[3] = color_type::downshift(fg[3], image_subpixel_shift * 2); } } @@ -435,17 +417,13 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba_2x2() {} span_image_filter_rgba_2x2(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter) {} @@ -456,7 +434,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - calc_type fg[4]; + long_type fg[4]; const value_type *fg_ptr; const int16* weight_array = base_type::filter().weight_array() + @@ -477,7 +455,7 @@ namespace agg24 int y_lr = y_hr >> image_subpixel_shift; unsigned weight; - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = fg[3] = 0; x_hr &= image_subpixel_mask; y_hr &= image_subpixel_mask; @@ -522,12 +500,12 @@ namespace agg24 fg[2] += weight * *fg_ptr++; fg[3] += weight * *fg_ptr; - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; - fg[3] >>= image_filter_shift; + fg[0] = color_type::downshift(fg[0], image_filter_shift); + fg[1] = color_type::downshift(fg[1], image_filter_shift); + fg[2] = color_type::downshift(fg[2], image_filter_shift); + fg[3] = color_type::downshift(fg[3], image_filter_shift); - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; + if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; @@ -558,17 +536,13 @@ namespace agg24 typedef span_image_filter base_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 - }; + typedef typename color_type::long_type long_type; //-------------------------------------------------------------------- span_image_filter_rgba() {} span_image_filter_rgba(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, &filter) {} @@ -578,7 +552,7 @@ namespace agg24 base_type::interpolator().begin(x + base_type::filter_dx_dbl(), y + base_type::filter_dy_dbl(), len); - int fg[4]; + long_type fg[4]; const value_type *fg_ptr; unsigned diameter = base_type::filter().diameter(); @@ -601,7 +575,7 @@ namespace agg24 int x_lr = x_hr >> image_subpixel_shift; int y_lr = y_hr >> image_subpixel_shift; - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = fg[3] = 0; int x_fract = x_hr & image_subpixel_mask; unsigned y_count = diameter; @@ -636,17 +610,17 @@ namespace agg24 fg_ptr = (const value_type*)base_type::source().next_y(); } - fg[0] >>= image_filter_shift; - fg[1] >>= image_filter_shift; - fg[2] >>= image_filter_shift; - fg[3] >>= image_filter_shift; + fg[0] = color_type::downshift(fg[0], image_filter_shift); + fg[1] = color_type::downshift(fg[1], image_filter_shift); + fg[2] = color_type::downshift(fg[2], image_filter_shift); + fg[3] = color_type::downshift(fg[3], image_filter_shift); if(fg[0] < 0) fg[0] = 0; if(fg[1] < 0) fg[1] = 0; if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; + if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; @@ -679,8 +653,6 @@ namespace agg24 typedef typename color_type::long_type long_type; enum base_scale_e { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, downscale_shift = image_filter_shift }; @@ -688,7 +660,7 @@ namespace agg24 span_image_resample_rgba_affine() {} span_image_resample_rgba_affine(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, filter) {} @@ -718,7 +690,7 @@ namespace agg24 x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = fg[3] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * @@ -767,7 +739,7 @@ namespace agg24 if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; + if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::A]) fg[order_type::R] = fg[order_type::A]; if(fg[order_type::G] > fg[order_type::A]) fg[order_type::G] = fg[order_type::A]; if(fg[order_type::B] > fg[order_type::A]) fg[order_type::B] = fg[order_type::A]; @@ -800,8 +772,6 @@ namespace agg24 typedef typename color_type::long_type long_type; enum base_scale_e { - base_shift = color_type::base_shift, - base_mask = color_type::base_mask, downscale_shift = image_filter_shift }; @@ -809,7 +779,7 @@ namespace agg24 span_image_resample_rgba() {} span_image_resample_rgba(source_type& src, interpolator_type& inter, - const image_filter_lut& filter) : + image_filter_lut& filter) : base_type(src, inter, filter) {} @@ -832,35 +802,10 @@ namespace agg24 int ry_inv = image_subpixel_scale; base_type::interpolator().coordinates(&x, &y); base_type::interpolator().local_scale(&rx, &ry); + base_type::adjust_scale(&rx, &ry); - rx = (rx * base_type::m_blur_x) >> image_subpixel_shift; - ry = (ry * base_type::m_blur_y) >> image_subpixel_shift; - - if(rx < image_subpixel_scale) - { - rx = image_subpixel_scale; - } - else - { - if(rx > image_subpixel_scale * base_type::m_scale_limit) - { - rx = image_subpixel_scale * base_type::m_scale_limit; - } - rx_inv = image_subpixel_scale * image_subpixel_scale / rx; - } - - if(ry < image_subpixel_scale) - { - ry = image_subpixel_scale; - } - else - { - if(ry > image_subpixel_scale * base_type::m_scale_limit) - { - ry = image_subpixel_scale * base_type::m_scale_limit; - } - ry_inv = image_subpixel_scale * image_subpixel_scale / ry; - } + rx_inv = image_subpixel_scale * image_subpixel_scale / rx; + ry_inv = image_subpixel_scale * image_subpixel_scale / ry; int radius_x = (diameter * rx) >> 1; int radius_y = (diameter * ry) >> 1; @@ -871,7 +816,7 @@ namespace agg24 x += base_type::filter_dx_int() - radius_x; y += base_type::filter_dy_int() - radius_y; - fg[0] = fg[1] = fg[2] = fg[3] = image_filter_scale / 2; + fg[0] = fg[1] = fg[2] = fg[3] = 0; int y_lr = y >> image_subpixel_shift; int y_hr = ((image_subpixel_mask - (y & image_subpixel_mask)) * @@ -919,7 +864,7 @@ namespace agg24 if(fg[2] < 0) fg[2] = 0; if(fg[3] < 0) fg[3] = 0; - if(fg[order_type::A] > base_mask) fg[order_type::A] = base_mask; + if(fg[order_type::A] > color_type::full_value()) fg[order_type::A] = color_type::full_value(); if(fg[order_type::R] > fg[order_type::R]) fg[order_type::R] = fg[order_type::R]; if(fg[order_type::G] > fg[order_type::G]) fg[order_type::G] = fg[order_type::G]; if(fg[order_type::B] > fg[order_type::B]) fg[order_type::B] = fg[order_type::B]; diff --git a/kiva/agg/agg-24/include/agg_span_interpolator_adaptor.h b/kiva/agg/agg-24/include/agg_span_interpolator_adaptor.h index 2e3c9447b..f98931a4a 100644 --- a/kiva/agg/agg-24/include/agg_span_interpolator_adaptor.h +++ b/kiva/agg/agg-24/include/agg_span_interpolator_adaptor.h @@ -32,16 +32,16 @@ namespace agg24 //-------------------------------------------------------------------- span_interpolator_adaptor() {} - span_interpolator_adaptor(const trans_type& trans, - const distortion_type& dist) : + span_interpolator_adaptor(trans_type& trans, + distortion_type& dist) : base_type(trans), m_distortion(&dist) { } //-------------------------------------------------------------------- - span_interpolator_adaptor(const trans_type& trans, - const distortion_type& dist, + span_interpolator_adaptor(trans_type& trans, + distortion_type& dist, double x, double y, unsigned len) : base_type(trans, x, y, len), m_distortion(&dist) @@ -49,13 +49,13 @@ namespace agg24 } //-------------------------------------------------------------------- - const distortion_type& distortion() const + distortion_type& distortion() const { return *m_distortion; } //-------------------------------------------------------------------- - void distortion(const distortion_type& dist) + void distortion(distortion_type& dist) { m_distortion = dist; } @@ -69,7 +69,7 @@ namespace agg24 private: //-------------------------------------------------------------------- - const distortion_type* m_distortion; + distortion_type* m_distortion; }; } diff --git a/kiva/agg/agg-24/include/agg_span_interpolator_linear.h b/kiva/agg/agg-24/include/agg_span_interpolator_linear.h index d91cf870b..5d90f9f31 100644 --- a/kiva/agg/agg-24/include/agg_span_interpolator_linear.h +++ b/kiva/agg/agg-24/include/agg_span_interpolator_linear.h @@ -38,8 +38,8 @@ namespace agg24 //-------------------------------------------------------------------- span_interpolator_linear() {} - span_interpolator_linear(const trans_type& trans) : m_trans(&trans) {} - span_interpolator_linear(const trans_type& trans, + span_interpolator_linear(trans_type& trans) : m_trans(&trans) {} + span_interpolator_linear(trans_type& trans, double x, double y, unsigned len) : m_trans(&trans) { @@ -48,7 +48,7 @@ namespace agg24 //---------------------------------------------------------------- const trans_type& transformer() const { return *m_trans; } - void transformer(const trans_type& trans) { m_trans = &trans; } + void transformer(trans_type& trans) { m_trans = &trans; } //---------------------------------------------------------------- void begin(double x, double y, unsigned len) @@ -95,7 +95,7 @@ namespace agg24 } private: - const trans_type* m_trans; + trans_type* m_trans; dda2_line_interpolator m_li_x; dda2_line_interpolator m_li_y; }; @@ -125,14 +125,14 @@ namespace agg24 m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1) {} - span_interpolator_linear_subdiv(const trans_type& trans, + span_interpolator_linear_subdiv(trans_type& trans, unsigned subdiv_shift = 4) : m_subdiv_shift(subdiv_shift), m_subdiv_size(1 << m_subdiv_shift), m_subdiv_mask(m_subdiv_size - 1), m_trans(&trans) {} - span_interpolator_linear_subdiv(const trans_type& trans, + span_interpolator_linear_subdiv(trans_type& trans, double x, double y, unsigned len, unsigned subdiv_shift = 4) : m_subdiv_shift(subdiv_shift), @@ -213,7 +213,7 @@ namespace agg24 unsigned m_subdiv_shift; unsigned m_subdiv_size; unsigned m_subdiv_mask; - const trans_type* m_trans; + trans_type* m_trans; dda2_line_interpolator m_li_x; dda2_line_interpolator m_li_y; int m_src_x; diff --git a/kiva/agg/agg-24/include/agg_span_interpolator_trans.h b/kiva/agg/agg-24/include/agg_span_interpolator_trans.h index 4c791cca9..54005e823 100644 --- a/kiva/agg/agg-24/include/agg_span_interpolator_trans.h +++ b/kiva/agg/agg-24/include/agg_span_interpolator_trans.h @@ -39,8 +39,8 @@ namespace agg24 //-------------------------------------------------------------------- span_interpolator_trans() {} - span_interpolator_trans(const trans_type& trans) : m_trans(&trans) {} - span_interpolator_trans(const trans_type& trans, + span_interpolator_trans(trans_type& trans) : m_trans(&trans) {} + span_interpolator_trans(trans_type& trans, double x, double y, unsigned) : m_trans(&trans) { @@ -80,7 +80,7 @@ namespace agg24 } private: - const trans_type* m_trans; + trans_type* m_trans; double m_x; double m_y; int m_ix; diff --git a/kiva/agg/agg-24/include/agg_span_pattern_rgba.h b/kiva/agg/agg-24/include/agg_span_pattern_rgba.h index 968922518..706a5aec9 100644 --- a/kiva/agg/agg-24/include/agg_span_pattern_rgba.h +++ b/kiva/agg/agg-24/include/agg_span_pattern_rgba.h @@ -75,7 +75,7 @@ namespace agg24 span->g = p[order_type::G]; span->b = p[order_type::B]; span->a = p[order_type::A]; - p = m_src->next_x(); + p = (const value_type*)m_src->next_x(); ++span; } while(--len); diff --git a/kiva/agg/agg-24/include/agg_trans_affine.h b/kiva/agg/agg-24/include/agg_trans_affine.h index 70cd547ec..25c707411 100644 --- a/kiva/agg/agg-24/include/agg_trans_affine.h +++ b/kiva/agg/agg-24/include/agg_trans_affine.h @@ -24,7 +24,7 @@ namespace agg24 { - const double affine_epsilon = 1e-14; // About of precision of doubles + const double affine_epsilon = 1e-14; //============================================================trans_affine // @@ -84,48 +84,58 @@ namespace agg24 // m *= agg24::trans_affine_rotation(30.0 * 3.1415926 / 180.0); // rotate // m *= agg24::trans_affine_translation(100.0, 100.0); // move back to (100,100) //---------------------------------------------------------------------- - class trans_affine + struct trans_affine { - public: + double sx, shy, shx, sy, tx, ty; + //------------------------------------------ Construction - // Construct an identity matrix - it does not transform anything + // Identity matrix trans_affine() : - m0(1.0), m1(0.0), m2(0.0), m3(1.0), m4(0.0), m5(0.0) + sx(1.0), shy(0.0), shx(0.0), sy(1.0), tx(0.0), ty(0.0) {} - // Construct a custom matrix. Usually used in derived classes - trans_affine(double v0, double v1, double v2, double v3, double v4, double v5) : - m0(v0), m1(v1), m2(v2), m3(v3), m4(v4), m5(v5) + // Custom matrix. Usually used in derived classes + trans_affine(double v0, double v1, double v2, + double v3, double v4, double v5) : + sx(v0), shy(v1), shx(v2), sy(v3), tx(v4), ty(v5) {} - // Construct a matrix to transform a parallelogram to another one. - trans_affine(const double* rect, const double* parl) - { - parl_to_parl(rect, parl); - } + // Custom matrix from m[6] + explicit trans_affine(const double* m) : + sx(m[0]), shy(m[1]), shx(m[2]), sy(m[3]), tx(m[4]), ty(m[5]) + {} - // Construct a matrix to transform a rectangle to a parallelogram. + // Rectangle to a parallelogram. trans_affine(double x1, double y1, double x2, double y2, const double* parl) { rect_to_parl(x1, y1, x2, y2, parl); } - // Construct a matrix to transform a parallelogram to a rectangle. + // Parallelogram to a rectangle. trans_affine(const double* parl, double x1, double y1, double x2, double y2) { parl_to_rect(parl, x1, y1, x2, y2); } + // Arbitrary parallelogram transformation. + trans_affine(const double* src, const double* dst) + { + parl_to_parl(src, dst); + } //---------------------------------- Parellelogram transformations - // Calculate a matrix to transform a parallelogram to another one. - // src and dst are pointers to arrays of three points - // (double[6], x,y,...) that identify three corners of the - // parallelograms assuming implicit fourth points. - // There are also transformations rectangtle to parallelogram and - // parellelogram to rectangle + // transform a parallelogram to another one. Src and dst are + // pointers to arrays of three points (double[6], x1,y1,...) that + // identify three corners of the parallelograms assuming implicit + // fourth point. The arguments are arrays of double[6] mapped + // to x1,y1, x2,y2, x3,y3 where the coordinates are: + // *-----------------* + // / (x3,y3)/ + // / / + // /(x1,y1) (x2,y2)/ + // *-----------------* const trans_affine& parl_to_parl(const double* src, const double* dst); @@ -139,9 +149,15 @@ namespace agg24 //------------------------------------------ Operations - // Reset - actually load an identity matrix + // Reset - load an identity matrix const trans_affine& reset(); + // Direct transformations operations + const trans_affine& translate(double x, double y); + const trans_affine& rotate(double a); + const trans_affine& scale(double s); + const trans_affine& scale(double x, double y); + // Multiply matrix to another one const trans_affine& multiply(const trans_affine& m); @@ -169,40 +185,40 @@ namespace agg24 // Store matrix to an array [6] of double void store_to(double* m) const { - *m++ = m0; *m++ = m1; *m++ = m2; *m++ = m3; *m++ = m4; *m++ = m5; + *m++ = sx; *m++ = shy; *m++ = shx; *m++ = sy; *m++ = tx; *m++ = ty; } // Load matrix from an array [6] of double const trans_affine& load_from(const double* m) { - m0 = *m++; m1 = *m++; m2 = *m++; m3 = *m++; m4 = *m++; m5 = *m++; + sx = *m++; shy = *m++; shx = *m++; sy = *m++; tx = *m++; ty = *m++; return *this; } //------------------------------------------- Operators - // Multiply current matrix to another one + // Multiply the matrix by another one const trans_affine& operator *= (const trans_affine& m) { return multiply(m); } - // Multiply current matrix to inverse of another one + // Multiply the matrix by inverse of another one const trans_affine& operator /= (const trans_affine& m) { return multiply_inv(m); } - // Multiply current matrix to another one and return + // Multiply the matrix by another one and return // the result in a separete matrix. - trans_affine operator * (const trans_affine& m) + trans_affine operator * (const trans_affine& m) const { return trans_affine(*this).multiply(m); } - // Multiply current matrix to inverse of another one + // Multiply the matrix by inverse of another one // and return the result in a separete matrix. - trans_affine operator / (const trans_affine& m) + trans_affine operator / (const trans_affine& m) const { return trans_affine(*this).multiply_inv(m); } @@ -227,22 +243,28 @@ namespace agg24 } //-------------------------------------------- Transformations - // Direct transformation x and y + // Direct transformation of x and y void transform(double* x, double* y) const; - // Direct transformation x and y, 2x2 matrix only, no translation + // Direct transformation of x and y, 2x2 matrix only, no translation void transform_2x2(double* x, double* y) const; - // Inverse transformation x and y. It works slower than the - // direct transformation, so if the performance is critical - // it's better to invert() the matrix and then use transform() + // Inverse transformation of x and y. It works slower than the + // direct transformation. For massive operations it's better to + // invert() the matrix and then use direct transformations. void inverse_transform(double* x, double* y) const; //-------------------------------------------- Auxiliary // Calculate the determinant of matrix double determinant() const { - return 1.0 / (m0 * m3 - m1 * m2); + return sx * sy - shy * shx; + } + + // Calculate the reciprocal of the determinant + double determinant_reciprocal() const + { + return 1.0 / (sx * sy - shy * shx); } // Get the average scale (by X and Y). @@ -250,65 +272,109 @@ namespace agg24 // decomposinting curves into line segments. double scale() const; + // Check to see if the matrix is not degenerate + bool is_valid(double epsilon = affine_epsilon) const; + // Check to see if it's an identity matrix bool is_identity(double epsilon = affine_epsilon) const; // Check to see if two matrices are equal bool is_equal(const trans_affine& m, double epsilon = affine_epsilon) const; - // Determine the major parameters. Use carefully considering degenerate matrices + // Determine the major parameters. Use with caution considering + // possible degenerate cases. double rotation() const; void translation(double* dx, double* dy) const; - void scaling(double* sx, double* sy) const; - void scaling_abs(double* sx, double* sy) const - { - *sx = sqrt(m0*m0 + m2*m2); - *sy = sqrt(m1*m1 + m3*m3); - } - - public: - double m0; - double m1; - double m2; - double m3; - double m4; - double m5; + void scaling(double* x, double* y) const; + void scaling_abs(double* x, double* y) const; }; //------------------------------------------------------------------------ inline void trans_affine::transform(double* x, double* y) const { - register double tx = *x; - *x = tx * m0 + *y * m2 + m4; - *y = tx * m1 + *y * m3 + m5; + register double tmp = *x; + *x = tmp * sx + *y * shx + tx; + *y = tmp * shy + *y * sy + ty; } //------------------------------------------------------------------------ inline void trans_affine::transform_2x2(double* x, double* y) const { - register double tx = *x; - *x = tx * m0 + *y * m2; - *y = tx * m1 + *y * m3; + register double tmp = *x; + *x = tmp * sx + *y * shx; + *y = tmp * shy + *y * sy; } //------------------------------------------------------------------------ inline void trans_affine::inverse_transform(double* x, double* y) const { - register double d = determinant(); - register double a = (*x - m4) * d; - register double b = (*y - m5) * d; - *x = a * m3 - b * m2; - *y = b * m0 - a * m1; + 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; } //------------------------------------------------------------------------ inline double trans_affine::scale() const { - double x = 0.707106781 * m0 + 0.707106781 * m2; - double y = 0.707106781 * m1 + 0.707106781 * m3; + double x = 0.707106781 * sx + 0.707106781 * shx; + double y = 0.707106781 * shy + 0.707106781 * sy; return sqrt(x*x + y*y); } + //------------------------------------------------------------------------ + inline const trans_affine& trans_affine::translate(double x, double y) + { + tx += x; + ty += y; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_affine& trans_affine::rotate(double a) + { + double ca = cos(a); + double sa = sin(a); + double t0 = sx * ca - shy * sa; + double t2 = shx * ca - sy * sa; + double t4 = tx * ca - ty * sa; + shy = sx * sa + shy * ca; + sy = shx * sa + sy * ca; + ty = tx * sa + ty * ca; + sx = t0; + shx = t2; + tx = t4; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_affine& trans_affine::scale(double x, double y) + { + double mm0 = x; // Possible hint for the optimizer + double mm3 = y; + sx *= mm0; + shx *= mm0; + tx *= mm0; + shy *= mm3; + sy *= mm3; + ty *= mm3; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_affine& trans_affine::scale(double s) + { + double m = s; // Possible hint for the optimizer + sx *= m; + shx *= m; + tx *= m; + shy *= m; + sy *= m; + ty *= m; + return *this; + } + //------------------------------------------------------------------------ inline const trans_affine& trans_affine::premultiply(const trans_affine& m) { @@ -321,8 +387,7 @@ namespace agg24 { trans_affine t = m; t.invert(); - multiply(t); - return *this; + return multiply(t); } //------------------------------------------------------------------------ @@ -333,6 +398,16 @@ namespace agg24 return *this = t.multiply(*this); } + //------------------------------------------------------------------------ + inline void trans_affine::scaling_abs(double* x, double* y) const + { + // Used to calculate scaling coefficients in image resampling. + // When there is considerable shear this method gives us much + // better estimation than just sx, sy. + *x = sqrt(sx * sx + shx * shx); + *y = sqrt(shy * shy + sy * sy); + } + //====================================================trans_affine_rotation // Rotation matrix. sin() and cos() are calculated twice for the same angle. // There's no harm because the performance of sin()/cos() is very good on all @@ -347,12 +422,12 @@ namespace agg24 }; //====================================================trans_affine_scaling - // Scaling matrix. sx, sy - scale coefficients by X and Y respectively + // Scaling matrix. x, y - scale coefficients by X and Y respectively class trans_affine_scaling : public trans_affine { public: - trans_affine_scaling(double sx, double sy) : - trans_affine(sx, 0.0, 0.0, sy, 0.0, 0.0) + trans_affine_scaling(double x, double y) : + trans_affine(x, 0.0, 0.0, y, 0.0, 0.0) {} trans_affine_scaling(double s) : @@ -365,8 +440,8 @@ namespace agg24 class trans_affine_translation : public trans_affine { public: - trans_affine_translation(double tx, double ty) : - trans_affine(1.0, 0.0, 0.0, 1.0, tx, ty) + trans_affine_translation(double x, double y) : + trans_affine(1.0, 0.0, 0.0, 1.0, x, y) {} }; @@ -375,8 +450,8 @@ namespace agg24 class trans_affine_skewing : public trans_affine { public: - trans_affine_skewing(double sx, double sy) : - trans_affine(1.0, tan(sy), tan(sx), 1.0, 0.0, 0.0) + trans_affine_skewing(double x, double y) : + trans_affine(1.0, tan(y), tan(x), 1.0, 0.0, 0.0) {} }; @@ -402,6 +477,40 @@ namespace agg24 }; + //============================================trans_affine_reflection_unit + // Reflection matrix. Reflect coordinates across the line through + // the origin containing the unit vector (ux, uy). + // Contributed by John Horigan + class trans_affine_reflection_unit : public trans_affine + { + public: + trans_affine_reflection_unit(double ux, double uy) : + trans_affine(2.0 * ux * ux - 1.0, + 2.0 * ux * uy, + 2.0 * ux * uy, + 2.0 * uy * uy - 1.0, + 0.0, 0.0) + {} + }; + + + //=================================================trans_affine_reflection + // Reflection matrix. Reflect coordinates across the line through + // the origin at the angle a or containing the non-unit vector (x, y). + // Contributed by John Horigan + class trans_affine_reflection : public trans_affine_reflection_unit + { + public: + trans_affine_reflection(double a) : + trans_affine_reflection_unit(cos(a), sin(a)) + {} + + + trans_affine_reflection(double x, double y) : + trans_affine_reflection_unit(x / sqrt(x * x + y * y), y / sqrt(x * x + y * y)) + {} + }; + } diff --git a/kiva/agg/agg-24/include/agg_trans_lens.h b/kiva/agg/agg-24/include/agg_trans_lens.h deleted file mode 100644 index 46882725c..000000000 --- a/kiva/agg/agg-24/include/agg_trans_lens.h +++ /dev/null @@ -1,79 +0,0 @@ -//---------------------------------------------------------------------------- -// Anti-Grain Geometry - Version 2.1 -// 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_WARP_MAGNIFIER_INCLUDED -#define AGG_WARP_MAGNIFIER_INCLUDED - -#include -#include "agg_basics.h" - - -namespace agg24 -{ - - class trans_warp_magnifier - { - public: - trans_warp_magnifier() : m_xc(0.0), m_yc(0.0), m_magn(1.0), m_radius(1.0), m_warp(false) {} - - void center(double x, double y) { m_xc = x; m_yc = y; } - void magnification(double m) { m_magn = m; } - void radius(double r) { m_radius = r; } - void warp(bool w) { m_warp = w; } - - void transform(double* x, double* y) const - { - double dx = *x - m_xc; - double dy = *y - m_yc; - double r = sqrt(dx * dx + dy * dy); - double rm = m_radius / m_magn; - if(r < rm) - { - *x = m_xc + dx * m_magn; - *y = m_yc + dy * m_magn; - return; - } - - if(m_warp) - { - double m = (r + rm * (m_magn - 1.0)) / r; - *x = m_xc + dx * m; - *y = m_yc + dy * m; - return; - } - - if(r < m_radius) - { - double m = m_radius / r; - *x = m_xc + dx * m; - *y = m_yc + dy * m; - } - } - - private: - double m_xc; - double m_yc; - double m_magn; - double m_radius; - bool m_warp; - }; - - - -} - - -#endif - diff --git a/kiva/agg/agg-24/include/agg_trans_perspective.h b/kiva/agg/agg-24/include/agg_trans_perspective.h index 8ef8f8583..d6f737dbd 100644 --- a/kiva/agg/agg-24/include/agg_trans_perspective.h +++ b/kiva/agg/agg-24/include/agg_trans_perspective.h @@ -19,124 +19,211 @@ #ifndef AGG_TRANS_PERSPECTIVE_INCLUDED #define AGG_TRANS_PERSPECTIVE_INCLUDED -#include "agg_basics.h" -#include "agg_simul_eq.h" +#include "agg_trans_affine.h" namespace agg24 { //=======================================================trans_perspective - class trans_perspective + struct trans_perspective { - public: - //-------------------------------------------------------------------- - trans_perspective() : m_valid(false) {} + double sx, shy, w0, shx, sy, w1, tx, ty, w2; + //------------------------------------------------------- Construction + // Identity matrix + trans_perspective() : + sx (1), shy(0), w0(0), + shx(0), sy (1), w1(0), + tx (0), ty (0), w2(1) {} - //-------------------------------------------------------------------- - // Arbitrary quadrangle transformations - trans_perspective(const double* src, const double* dst) - { - quad_to_quad(src, dst); - } + // Custom matrix + trans_perspective(double v0, double v1, double v2, + double v3, double v4, double v5, + double v6, double v7, double v8) : + sx (v0), shy(v1), w0(v2), + shx(v3), sy (v4), w1(v5), + tx (v6), ty (v7), w2(v8) {} + // Custom matrix from m[9] + explicit trans_perspective(const double* m) : + sx (m[0]), shy(m[1]), w0(m[2]), + shx(m[3]), sy (m[4]), w1(m[5]), + tx (m[6]), ty (m[7]), w2(m[8]) {} - //-------------------------------------------------------------------- - // Direct transformations + // From affine + explicit trans_perspective(const trans_affine& a) : + sx (a.sx ), shy(a.shy), w0(0), + shx(a.shx), sy (a.sy ), w1(0), + tx (a.tx ), ty (a.ty ), w2(1) {} + + // Rectangle to quadrilateral trans_perspective(double x1, double y1, double x2, double y2, - const double* quad) + const double* quad); + + // Quadrilateral to rectangle + trans_perspective(const double* quad, + double x1, double y1, double x2, double y2); + + // Arbitrary quadrilateral transformations + trans_perspective(const double* src, const double* dst); + + //-------------------------------------- Quadrilateral transformations + // The arguments are double[8] that are mapped to quadrilaterals: + // x1,y1, x2,y2, x3,y3, x4,y4 + bool quad_to_quad(const double* qs, const double* qd); + + bool rect_to_quad(double x1, double y1, + double x2, double y2, + const double* q); + + bool quad_to_rect(const double* q, + double x1, double y1, + double x2, double y2); + + // Map square (0,0,1,1) to the quadrilateral and vice versa + bool square_to_quad(const double* q); + bool quad_to_square(const double* q); + + + //--------------------------------------------------------- Operations + // Reset - load an identity matrix + const trans_perspective& reset(); + + // Invert matrix. Returns false in degenerate case + bool invert(); + + // Direct transformations operations + const trans_perspective& translate(double x, double y); + const trans_perspective& rotate(double a); + const trans_perspective& scale(double s); + const trans_perspective& scale(double x, double y); + + // Multiply the matrix by another one + const trans_perspective& multiply(const trans_perspective& m); + + // Multiply "m" by "this" and assign the result to "this" + const trans_perspective& premultiply(const trans_perspective& m); + + // Multiply matrix to inverse of another one + const trans_perspective& multiply_inv(const trans_perspective& m); + + // Multiply inverse of "m" by "this" and assign the result to "this" + const trans_perspective& premultiply_inv(const trans_perspective& m); + + // Multiply the matrix by another one + const trans_perspective& multiply(const trans_affine& m); + + // Multiply "m" by "this" and assign the result to "this" + const trans_perspective& premultiply(const trans_affine& m); + + // Multiply the matrix by inverse of another one + const trans_perspective& multiply_inv(const trans_affine& m); + + // Multiply inverse of "m" by "this" and assign the result to "this" + const trans_perspective& premultiply_inv(const trans_affine& m); + + //--------------------------------------------------------- Load/Store + void store_to(double* m) const; + const trans_perspective& load_from(const double* m); + + //---------------------------------------------------------- Operators + // Multiply the matrix by another one + const trans_perspective& operator *= (const trans_perspective& m) + { + return multiply(m); + } + const trans_perspective& operator *= (const trans_affine& m) { - rect_to_quad(x1, y1, x2, y2, quad); + return multiply(m); } + // Multiply the matrix by inverse of another one + const trans_perspective& operator /= (const trans_perspective& m) + { + return multiply_inv(m); + } + const trans_perspective& operator /= (const trans_affine& m) + { + return multiply_inv(m); + } - //-------------------------------------------------------------------- - // Reverse transformations - trans_perspective(const double* quad, - double x1, double y1, double x2, double y2) + // Multiply the matrix by another one and return + // the result in a separete matrix. + trans_perspective operator * (const trans_perspective& m) const + { + return trans_perspective(*this).multiply(m); + } + trans_perspective operator * (const trans_affine& m) const { - quad_to_rect(quad, x1, y1, x2, y2); + return trans_perspective(*this).multiply(m); } + // Multiply the matrix by inverse of another one + // and return the result in a separete matrix. + trans_perspective operator / (const trans_perspective& m) const + { + return trans_perspective(*this).multiply_inv(m); + } + trans_perspective operator / (const trans_affine& m) const + { + return trans_perspective(*this).multiply_inv(m); + } - //-------------------------------------------------------------------- - // Set the transformations using two arbitrary quadrangles. - void quad_to_quad(const double* src, const double* dst) + // Calculate and return the inverse matrix + trans_perspective operator ~ () const { + trans_perspective ret = *this; + ret.invert(); + return ret; + } - double left[8][8]; - double right[8][1]; + // Equal operator with default epsilon + bool operator == (const trans_perspective& m) const + { + return is_equal(m, affine_epsilon); + } - unsigned i; - for (i = 0; i < 4; i++) - { - unsigned ix = i * 2; - unsigned iy = ix + 1; - - left[ix][0] = 1.0; - left[ix][1] = src[ix]; - left[ix][2] = src[iy]; - left[ix][3] = 0.0; - left[ix][4] = 0.0; - left[ix][5] = 0.0; - left[ix][6] = -src[ix] * dst[ix]; - left[ix][7] = -src[iy] * dst[ix]; - right[ix][0] = dst[ix]; - - left[iy][0] = 0.0; - left[iy][1] = 0.0; - left[iy][2] = 0.0; - left[iy][3] = 1.0; - left[iy][4] = src[ix]; - left[iy][5] = src[iy]; - left[iy][6] = -src[ix] * dst[iy]; - left[iy][7] = -src[iy] * dst[iy]; - right[iy][0] = dst[iy]; - } - m_valid = simul_eq<8, 1>::solve(left, right, m_mtx); + // Not Equal operator with default epsilon + bool operator != (const trans_perspective& m) const + { + return !is_equal(m, affine_epsilon); } + //---------------------------------------------------- Transformations + // Direct transformation of x and y + void transform(double* x, double* y) const; - //-------------------------------------------------------------------- - // Set the direct transformations, i.e., rectangle -> quadrangle - void rect_to_quad(double x1, double y1, double x2, double y2, - const double* quad) - { - double src[8]; - src[0] = src[6] = x1; - src[2] = src[4] = x2; - src[1] = src[3] = y1; - src[5] = src[7] = y2; - quad_to_quad(src, quad); - } + // Direct transformation of x and y, affine part only + void transform_affine(double* x, double* y) const; + // Direct transformation of x and y, 2x2 matrix only, no translation + void transform_2x2(double* x, double* y) const; - //-------------------------------------------------------------------- - // Set the reverse transformations, i.e., quadrangle -> rectangle - void quad_to_rect(const double* quad, - double x1, double y1, double x2, double y2) - { - double dst[8]; - dst[0] = dst[6] = x1; - dst[2] = dst[4] = x2; - dst[1] = dst[3] = y1; - dst[5] = dst[7] = y2; - quad_to_quad(quad, dst); - } + // Inverse transformation of x and y. It works slow because + // it explicitly inverts the matrix on every call. For massive + // operations it's better to invert() the matrix and then use + // direct transformations. + void inverse_transform(double* x, double* y) const; + + + //---------------------------------------------------------- Auxiliary + const trans_perspective& from_affine(const trans_affine& a); + double determinant() const; + double determinant_reciprocal() const; + + bool is_valid(double epsilon = affine_epsilon) const; + bool is_identity(double epsilon = affine_epsilon) const; + bool is_equal(const trans_perspective& m, + double epsilon = affine_epsilon) const; + + // Determine the major affine parameters. Use with caution + // considering possible degenerate cases. + double scale() const; + double rotation() const; + void translation(double* dx, double* dy) const; + void scaling(double* x, double* y) const; + void scaling_abs(double* x, double* y) const; - //-------------------------------------------------------------------- - // Check if the equations were solved successfully - bool is_valid() const { return m_valid; } - //-------------------------------------------------------------------- - // Transform a point (x, y) - void transform(double* x, double* y) const - { - double tx = *x; - double ty = *y; - double d = 1.0 / (m_mtx[6][0] * tx + m_mtx[7][0] * ty + 1.0); - *x = (m_mtx[0][0] + m_mtx[1][0] * tx + m_mtx[2][0] * ty) * d; - *y = (m_mtx[3][0] + m_mtx[4][0] * tx + m_mtx[5][0] * ty) * d; - } //-------------------------------------------------------------------- class iterator_x @@ -153,17 +240,16 @@ namespace agg24 double y; iterator_x() {} - iterator_x(double tx, double ty, double step, const double m[8][1]) : - den(m[6][0] * tx + m[7][0] * ty + 1.0), - den_step(m[6][0] * step), - nom_x(m[0][0] + m[1][0] * tx + m[2][0] * ty), - nom_x_step(m[1][0] * step), - nom_y(m[3][0] + m[4][0] * tx + m[5][0] * ty), - nom_y_step(m[4][0] * step), + iterator_x(double px, double py, double step, const trans_perspective& m) : + den(px * m.w0 + py * m.w1 + m.w2), + den_step(m.w0 * step), + nom_x(px * m.sx + py * m.shx + m.tx), + nom_x_step(step * m.sx), + nom_y(px * m.shy + py * m.sy + m.ty), + nom_y_step(step * m.shy), x(nom_x / den), y(nom_y / den) - { - } + {} void operator ++ () { @@ -179,14 +265,467 @@ namespace agg24 //-------------------------------------------------------------------- iterator_x begin(double x, double y, double step) const { - return iterator_x(x, y, step, m_mtx); + return iterator_x(x, y, step, *this); } - - private: - double m_mtx[8][1]; - bool m_valid; }; + + + + + + + + + + + + + + //------------------------------------------------------------------------ + inline bool trans_perspective::square_to_quad(const double* q) + { + double dx = q[0] - q[2] + q[4] - q[6]; + double dy = q[1] - q[3] + q[5] - q[7]; + if(dx == 0.0 && dy == 0.0) + { + // Affine case (parallelogram) + //--------------- + sx = q[2] - q[0]; + shy = q[3] - q[1]; + w0 = 0.0; + shx = q[4] - q[2]; + sy = q[5] - q[3]; + w1 = 0.0; + tx = q[0]; + ty = q[1]; + w2 = 1.0; + } + else + { + double dx1 = q[2] - q[4]; + double dy1 = q[3] - q[5]; + double dx2 = q[6] - q[4]; + double dy2 = q[7] - q[5]; + double den = dx1 * dy2 - dx2 * dy1; + if(den == 0.0) + { + // Singular case + //--------------- + sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0; + return false; + } + // General case + //--------------- + double u = (dx * dy2 - dy * dx2) / den; + double v = (dy * dx1 - dx * dy1) / den; + sx = q[2] - q[0] + u * q[2]; + shy = q[3] - q[1] + u * q[3]; + w0 = u; + shx = q[6] - q[0] + v * q[6]; + sy = q[7] - q[1] + v * q[7]; + w1 = v; + tx = q[0]; + ty = q[1]; + w2 = 1.0; + } + return true; + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::invert() + { + double d0 = sy * w2 - w1 * ty; + double d1 = w0 * ty - shy * w2; + double d2 = shy * w1 - w0 * sy; + double d = sx * d0 + shx * d1 + tx * d2; + if(d == 0.0) + { + sx = shy = w0 = shx = sy = w1 = tx = ty = w2 = 0.0; + return false; + } + d = 1.0 / d; + trans_perspective a = *this; + sx = d * d0; + shy = d * d1; + w0 = d * d2; + shx = d * (a.w1 *a.tx - a.shx*a.w2); + sy = d * (a.sx *a.w2 - a.w0 *a.tx); + w1 = d * (a.w0 *a.shx - a.sx *a.w1); + tx = d * (a.shx*a.ty - a.sy *a.tx); + ty = d * (a.shy*a.tx - a.sx *a.ty); + w2 = d * (a.sx *a.sy - a.shy*a.shx); + return true; + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::quad_to_square(const double* q) + { + if(!square_to_quad(q)) return false; + invert(); + return true; + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::quad_to_quad(const double* qs, + const double* qd) + { + trans_perspective p; + if(! quad_to_square(qs)) return false; + if(!p.square_to_quad(qd)) return false; + multiply(p); + return true; + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::rect_to_quad(double x1, double y1, + double x2, double y2, + const double* q) + { + double r[8]; + r[0] = r[6] = x1; + r[2] = r[4] = x2; + r[1] = r[3] = y1; + r[5] = r[7] = y2; + return quad_to_quad(r, q); + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::quad_to_rect(const double* q, + double x1, double y1, + double x2, double y2) + { + double r[8]; + r[0] = r[6] = x1; + r[2] = r[4] = x2; + r[1] = r[3] = y1; + r[5] = r[7] = y2; + return quad_to_quad(q, r); + } + + //------------------------------------------------------------------------ + inline trans_perspective::trans_perspective(double x1, double y1, + double x2, double y2, + const double* quad) + { + rect_to_quad(x1, y1, x2, y2, quad); + } + + //------------------------------------------------------------------------ + inline trans_perspective::trans_perspective(const double* quad, + double x1, double y1, + double x2, double y2) + { + quad_to_rect(quad, x1, y1, x2, y2); + } + + //------------------------------------------------------------------------ + inline trans_perspective::trans_perspective(const double* src, + const double* dst) + { + quad_to_quad(src, dst); + } + + //------------------------------------------------------------------------ + inline const trans_perspective& trans_perspective::reset() + { + sx = 1; shy = 0; w0 = 0; + shx = 0; sy = 1; w1 = 0; + tx = 0; ty = 0; w2 = 1; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& + trans_perspective::multiply(const trans_perspective& a) + { + trans_perspective b = *this; + sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; + shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; + tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; + shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; + sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; + ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; + w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0; + w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1; + w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& + trans_perspective::multiply(const trans_affine& a) + { + trans_perspective b = *this; + sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; + shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; + tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; + shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; + sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; + ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& + trans_perspective::premultiply(const trans_perspective& b) + { + trans_perspective a = *this; + sx = a.sx *b.sx + a.shx*b.shy + a.tx*b.w0; + shx = a.sx *b.shx + a.shx*b.sy + a.tx*b.w1; + tx = a.sx *b.tx + a.shx*b.ty + a.tx*b.w2; + shy = a.shy*b.sx + a.sy *b.shy + a.ty*b.w0; + sy = a.shy*b.shx + a.sy *b.sy + a.ty*b.w1; + ty = a.shy*b.tx + a.sy *b.ty + a.ty*b.w2; + w0 = a.w0 *b.sx + a.w1 *b.shy + a.w2*b.w0; + w1 = a.w0 *b.shx + a.w1 *b.sy + a.w2*b.w1; + w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2*b.w2; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& + trans_perspective::premultiply(const trans_affine& b) + { + trans_perspective a = *this; + sx = a.sx *b.sx + a.shx*b.shy; + shx = a.sx *b.shx + a.shx*b.sy; + tx = a.sx *b.tx + a.shx*b.ty + a.tx; + shy = a.shy*b.sx + a.sy *b.shy; + sy = a.shy*b.shx + a.sy *b.sy; + ty = a.shy*b.tx + a.sy *b.ty + a.ty; + w0 = a.w0 *b.sx + a.w1 *b.shy; + w1 = a.w0 *b.shx + a.w1 *b.sy; + w2 = a.w0 *b.tx + a.w1 *b.ty + a.w2; + return *this; + } + + //------------------------------------------------------------------------ + const trans_perspective& + trans_perspective::multiply_inv(const trans_perspective& m) + { + trans_perspective t = m; + t.invert(); + return multiply(t); + } + + //------------------------------------------------------------------------ + const trans_perspective& + trans_perspective::multiply_inv(const trans_affine& m) + { + trans_affine t = m; + t.invert(); + return multiply(t); + } + + //------------------------------------------------------------------------ + const trans_perspective& + trans_perspective::premultiply_inv(const trans_perspective& m) + { + trans_perspective t = m; + t.invert(); + return *this = t.multiply(*this); + } + + //------------------------------------------------------------------------ + const trans_perspective& + trans_perspective::premultiply_inv(const trans_affine& m) + { + trans_perspective t(m); + t.invert(); + return *this = t.multiply(*this); + } + + //------------------------------------------------------------------------ + inline const trans_perspective& + trans_perspective::translate(double x, double y) + { + tx += x; + ty += y; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& trans_perspective::rotate(double a) + { + multiply(trans_affine_rotation(a)); + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& trans_perspective::scale(double s) + { + multiply(trans_affine_scaling(s)); + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& trans_perspective::scale(double x, double y) + { + multiply(trans_affine_scaling(x, y)); + return *this; + } + + //------------------------------------------------------------------------ + inline void trans_perspective::transform(double* px, double* py) const + { + double x = *px; + double y = *py; + double m = 1.0 / (x*w0 + y*w1 + w2); + *px = m * (x*sx + y*shx + tx); + *py = m * (x*shy + y*sy + ty); + } + + //------------------------------------------------------------------------ + inline void trans_perspective::transform_affine(double* x, double* y) const + { + double tmp = *x; + *x = tmp * sx + *y * shx + tx; + *y = tmp * shy + *y * sy + ty; + } + + //------------------------------------------------------------------------ + inline void trans_perspective::transform_2x2(double* x, double* y) const + { + double tmp = *x; + *x = tmp * sx + *y * shx; + *y = tmp * shy + *y * sy; + } + + //------------------------------------------------------------------------ + inline void trans_perspective::inverse_transform(double* x, double* y) const + { + trans_perspective t(*this); + if(t.invert()) t.transform(x, y); + } + + //------------------------------------------------------------------------ + inline void trans_perspective::store_to(double* m) const + { + *m++ = sx; *m++ = shy; *m++ = w0; + *m++ = shx; *m++ = sy; *m++ = w1; + *m++ = tx; *m++ = ty; *m++ = w2; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& trans_perspective::load_from(const double* m) + { + sx = *m++; shy = *m++; w0 = *m++; + shx = *m++; sy = *m++; w1 = *m++; + tx = *m++; ty = *m++; w2 = *m++; + return *this; + } + + //------------------------------------------------------------------------ + inline const trans_perspective& + trans_perspective::from_affine(const trans_affine& a) + { + sx = a.sx; shy = a.shy; w0 = 0; + shx = a.shx; sy = a.sy; w1 = 0; + tx = a.tx; ty = a.ty; w2 = 1; + return *this; + } + + //------------------------------------------------------------------------ + inline double trans_perspective::determinant() const + { + return sx * (sy * w2 - ty * w1) + + shx * (ty * w0 - shy * w2) + + tx * (shy * w1 - sy * w0); + } + + //------------------------------------------------------------------------ + inline double trans_perspective::determinant_reciprocal() const + { + return 1.0 / determinant(); + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::is_valid(double epsilon) const + { + return fabs(sx) > epsilon && fabs(sy) > epsilon && fabs(w2) > epsilon; + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::is_identity(double epsilon) const + { + return is_equal_eps(sx, 1.0, epsilon) && + is_equal_eps(shy, 0.0, epsilon) && + is_equal_eps(w0, 0.0, epsilon) && + is_equal_eps(shx, 0.0, epsilon) && + is_equal_eps(sy, 1.0, epsilon) && + is_equal_eps(w1, 0.0, epsilon) && + is_equal_eps(tx, 0.0, epsilon) && + is_equal_eps(ty, 0.0, epsilon) && + is_equal_eps(w2, 1.0, epsilon); + } + + //------------------------------------------------------------------------ + inline bool trans_perspective::is_equal(const trans_perspective& m, + double epsilon) const + { + return is_equal_eps(sx, m.sx, epsilon) && + is_equal_eps(shy, m.shy, epsilon) && + is_equal_eps(w0, m.w0, epsilon) && + is_equal_eps(shx, m.shx, epsilon) && + is_equal_eps(sy, m.sy, epsilon) && + is_equal_eps(w1, m.w1, epsilon) && + is_equal_eps(tx, m.tx, epsilon) && + is_equal_eps(ty, m.ty, epsilon) && + is_equal_eps(w2, m.w2, epsilon); + } + + //------------------------------------------------------------------------ + inline double trans_perspective::scale() const + { + double x = 0.707106781 * sx + 0.707106781 * shx; + double y = 0.707106781 * shy + 0.707106781 * sy; + return sqrt(x*x + y*y); + } + + //------------------------------------------------------------------------ + inline double trans_perspective::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_perspective::translation(double* dx, double* dy) const + { + *dx = tx; + *dy = ty; + } + + //------------------------------------------------------------------------ + void trans_perspective::scaling(double* x, double* y) const + { + double x1 = 0.0; + double y1 = 0.0; + double x2 = 1.0; + double y2 = 1.0; + trans_perspective t(*this); + t *= trans_affine_rotation(-rotation()); + t.transform(&x1, &y1); + t.transform(&x2, &y2); + *x = x2 - x1; + *y = y2 - y1; + } + + //------------------------------------------------------------------------ + void trans_perspective::scaling_abs(double* x, double* y) const + { + *x = sqrt(sx * sx + shx * shx); + *y = sqrt(shy * shy + sy * sy); + } + + } #endif + diff --git a/kiva/agg/agg-24/include/agg_trans_warp_magnifier.h b/kiva/agg/agg-24/include/agg_trans_warp_magnifier.h index 5c37b26c2..43f163e3b 100644 --- a/kiva/agg/agg-24/include/agg_trans_warp_magnifier.h +++ b/kiva/agg/agg-24/include/agg_trans_warp_magnifier.h @@ -33,6 +33,11 @@ namespace agg24 void magnification(double m) { m_magn = m; } void radius(double r) { m_radius = r; } + double xc() const { return m_xc; } + double yc() const { return m_yc; } + double magnification() const { return m_magn; } + double radius() const { return m_radius; } + void transform(double* x, double* y) const; void inverse_transform(double* x, double* y) const; diff --git a/kiva/agg/agg-24/include/platform/agg_platform_support.h b/kiva/agg/agg-24/include/platform/agg_platform_support.h index a25e159fa..468411ef9 100644 --- a/kiva/agg/agg-24/include/platform/agg_platform_support.h +++ b/kiva/agg/agg-24/include/platform/agg_platform_support.h @@ -18,7 +18,7 @@ // It's not a part of the AGG library, it's just a helper class to create // interactive demo examples. Since the examples should not be too complex // this class is provided to support some very basic interactive graphical -// funtionality, such as putting the rendered image to the window, simple +// functionality, such as putting the rendered image to the window, simple // keyboard and mouse input, window resizing, setting the window title, // and catching the "idle" events. // @@ -105,7 +105,9 @@ namespace agg24 pix_format_undefined = 0, // By default. No conversions are applied pix_format_bw, // 1 bit per color B/W pix_format_gray8, // Simple 256 level grayscale + pix_format_sgray8, // Simple 256 level grayscale (sRGB) pix_format_gray16, // Simple 65535 level grayscale + pix_format_gray32, // Grayscale, one 32-bit float per pixel pix_format_rgb555, // 15 bit rgb. Depends on the byte ordering! pix_format_rgb565, // 16 bit rgb. Depends on the byte ordering! pix_format_rgbAAA, // 30 bit rgb. Depends on the byte ordering! @@ -113,18 +115,30 @@ namespace agg24 pix_format_bgrAAA, // 30 bit bgr. Depends on the byte ordering! pix_format_bgrABB, // 32 bit bgr. Depends on the byte ordering! pix_format_rgb24, // R-G-B, one byte per color component - pix_format_bgr24, // B-G-R, native win32 BMP format. + pix_format_srgb24, // R-G-B, one byte per color component (sRGB) + pix_format_bgr24, // B-G-R, one byte per color component + pix_format_sbgr24, // B-G-R, native win32 BMP format (sRGB) pix_format_rgba32, // R-G-B-A, one byte per color component + pix_format_srgba32, // R-G-B-A, one byte per color component (sRGB) pix_format_argb32, // A-R-G-B, native MAC format + pix_format_sargb32, // A-R-G-B, native MAC format (sRGB) pix_format_abgr32, // A-B-G-R, one byte per color component + pix_format_sabgr32, // A-B-G-R, one byte per color component (sRGB) pix_format_bgra32, // B-G-R-A, native win32 BMP format + pix_format_sbgra32, // B-G-R-A, native win32 BMP format (sRGB) pix_format_rgb48, // R-G-B, 16 bits per color component pix_format_bgr48, // B-G-R, native win32 BMP format. + pix_format_rgb96, // R-G-B, one 32-bit float per color component + pix_format_bgr96, // B-G-R, one 32-bit float per color component pix_format_rgba64, // R-G-B-A, 16 bits byte per color component pix_format_argb64, // A-R-G-B, native MAC format pix_format_abgr64, // A-B-G-R, one byte per color component pix_format_bgra64, // B-G-R-A, native win32 BMP format - + pix_format_rgba128, // R-G-B-A, one 32-bit float per color component + pix_format_argb128, // A-R-G-B, one 32-bit float per color component + pix_format_abgr128, // A-B-G-R, one 32-bit float per color component + pix_format_bgra128, // B-G-R-A, one 32-bit float per color component + end_of_pix_formats }; @@ -592,6 +606,7 @@ namespace agg24 double(height) / double(m_initial_height)); } } + trans_affine& trans_affine_resizing() { return m_resize_mtx; } const trans_affine& trans_affine_resizing() const { return m_resize_mtx; } double width() const { return m_rbuf_window.width(); } double height() const { return m_rbuf_window.height(); } @@ -629,7 +644,7 @@ namespace agg24 // open it in the current directory. The demos usually expect // all the supplementary files to be placed in the current // directory, that is usually coincides with the directory where - // the the executable is. However, in some systems (BeOS) it's not so. + // the executable is. However, in some systems (BeOS) it's not so. // For those kinds of systems full_file_name() can help access files // preserving commonly used policy. // So, it's a good idea to use in the demos the following: diff --git a/kiva/agg/agg-24/include/util/agg_color_conv.h b/kiva/agg/agg-24/include/util/agg_color_conv.h index 48be97fd2..40684e15c 100644 --- a/kiva/agg/agg-24/include/util/agg_color_conv.h +++ b/kiva/agg/agg-24/include/util/agg_color_conv.h @@ -77,6 +77,50 @@ namespace agg24 }; + // Generic pixel converter. + template + struct conv_pixel + { + void operator()(void* dst, const void* src) const + { + // Read a pixel from the source format and write it to the destination format. + DstFormat::write_plain_color(dst, SrcFormat::read_plain_color(src)); + } + }; + + // Generic row converter. Uses conv_pixel to convert individual pixels. + template + struct conv_row + { + void operator()(void* dst, const void* src, unsigned width) const + { + conv_pixel conv; + do + { + conv(dst, src); + dst = (int8u*)dst + DstFormat::pix_width; + src = (int8u*)src + SrcFormat::pix_width; + } + while (--width); + } + }; + + // Specialization for case where source and destination formats are identical. + template + struct conv_row + { + void operator()(void* dst, const void* src, unsigned width) const + { + memmove(dst, src, width * Format::pix_width); + } + }; + + // Top-level conversion function, converts one pixel format to any other. + template + void convert(RenBuf* dst, const RenBuf* src) + { + color_conv(dst, src, conv_row()); + } } diff --git a/kiva/agg/agg-24/include/util/agg_color_conv_rgb8.h b/kiva/agg/agg-24/include/util/agg_color_conv_rgb8.h index 9831ef64b..808339d28 100644 --- a/kiva/agg/agg-24/include/util/agg_color_conv_rgb8.h +++ b/kiva/agg/agg-24/include/util/agg_color_conv_rgb8.h @@ -48,10 +48,13 @@ namespace agg24 { do { - *dst++ = src[2]; - *dst++ = src[1]; - *dst++ = src[0]; - src += 3; + int8u tmp[3]; + tmp[0] = *src++; + tmp[1] = *src++; + tmp[2] = *src++; + *dst++ = tmp[2]; + *dst++ = tmp[1]; + *dst++ = tmp[0]; } while(--width); } @@ -75,11 +78,15 @@ namespace agg24 { do { - *dst++ = src[I1]; - *dst++ = src[I2]; - *dst++ = src[I3]; - *dst++ = src[I4]; - src += 4; + int8u tmp[4]; + tmp[0] = *src++; + tmp[1] = *src++; + tmp[2] = *src++; + tmp[3] = *src++; + *dst++ = tmp[I1]; + *dst++ = tmp[I2]; + *dst++ = tmp[I3]; + *dst++ = tmp[I4]; } while(--width); } diff --git a/kiva/agg/agg-24/src/agg_curves.cpp b/kiva/agg/agg-24/src/agg_curves.cpp index 404b42407..9a4fd95ea 100644 --- a/kiva/agg/agg-24/src/agg_curves.cpp +++ b/kiva/agg/agg-24/src/agg_curves.cpp @@ -82,9 +82,6 @@ namespace agg24 m_step = m_num_steps; } - - - //------------------------------------------------------------------------ void curve3_inc::rewind(unsigned) { @@ -100,9 +97,6 @@ namespace agg24 m_dfy = m_saved_dfy; } - - - //------------------------------------------------------------------------ unsigned curve3_inc::vertex(double* x, double* y) { @@ -131,7 +125,6 @@ namespace agg24 return path_cmd_line_to; } - //------------------------------------------------------------------------ void curve3_div::init(double x1, double y1, double x2, double y2, @@ -140,12 +133,10 @@ namespace agg24 m_points.remove_all(); m_distance_tolerance_square = 0.5 / m_approximation_scale; m_distance_tolerance_square *= m_distance_tolerance_square; - m_distance_tolerance_manhattan = 4.0 / m_approximation_scale; bezier(x1, y1, x2, y2, x3, y3); m_count = 0; } - //------------------------------------------------------------------------ void curve3_div::recursive_bezier(double x1, double y1, double x2, double y2, @@ -169,10 +160,11 @@ namespace agg24 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 care + // Regular case //----------------- if(d * d <= m_distance_tolerance_square * (dx*dx + dy*dy)) { @@ -187,7 +179,7 @@ namespace agg24 // Angle & Cusp Condition //---------------------- - double da = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); + da = fabs(atan2(y3 - y2, x3 - x2) - atan2(y2 - y1, x2 - x1)); if(da >= pi) da = 2*pi - da; if(da < m_angle_tolerance) @@ -201,12 +193,31 @@ namespace agg24 } else { - if(fabs(x1 + x3 - x2 - x2) + - fabs(y1 + y3 - y2 - y2) <= m_distance_tolerance_manhattan) + // 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(x123, y123)); + m_points.add(point_d(x2, y2)); return; - } + } } // Continue subdivision @@ -241,8 +252,10 @@ namespace agg24 return m_scale; } +#if defined(_MSC_VER) && _MSC_VER <= 1200 //------------------------------------------------------------------------ static double MSC60_fix_ICE(double v) { return v; } +#endif //------------------------------------------------------------------------ void curve4_inc::init(double x1, double y1, @@ -307,9 +320,6 @@ namespace agg24 m_step = m_num_steps; } - - - //------------------------------------------------------------------------ void curve4_inc::rewind(unsigned) { @@ -327,10 +337,6 @@ namespace agg24 m_ddfy = m_saved_ddfy; } - - - - //------------------------------------------------------------------------ unsigned curve4_inc::vertex(double* x, double* y) { @@ -376,12 +382,10 @@ namespace agg24 m_points.remove_all(); m_distance_tolerance_square = 0.5 / m_approximation_scale; m_distance_tolerance_square *= m_distance_tolerance_square; - m_distance_tolerance_manhattan = 4.0 / m_approximation_scale; 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, @@ -409,6 +413,7 @@ namespace agg24 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; @@ -416,7 +421,7 @@ namespace agg24 double d2 = fabs(((x2 - x4) * dy - (y2 - y4) * dx)); double d3 = fabs(((x3 - x4) * dy - (y3 - y4) * dx)); - double da1, da2; + double da1, da2, k; switch((int(d2 > curve_collinearity_epsilon) << 1) + int(d3 > curve_collinearity_epsilon)) @@ -424,18 +429,55 @@ namespace agg24 case 0: // All collinear OR p1==p4 //---------------------- - if(fabs(x1 + x3 - x2 - x2) + - fabs(y1 + y3 - y2 - y2) + - fabs(x2 + x4 - x3 - x3) + - fabs(y2 + y4 - y3 - y3) <= m_distance_tolerance_manhattan) + k = dx*dx + dy*dy; + if(k == 0) { - m_points.add(point_d(x1234, y1234)); - return; - } + 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 considerable + // p1,p2,p4 are collinear, p3 is significant //---------------------- if(d3 * d3 <= m_distance_tolerance_square * (dx*dx + dy*dy)) { @@ -469,7 +511,7 @@ namespace agg24 break; case 2: - // p1,p3,p4 are collinear, p2 is considerable + // p1,p3,p4 are collinear, p2 is significant //---------------------- if(d2 * d2 <= m_distance_tolerance_square * (dx*dx + dy*dy)) { @@ -503,7 +545,7 @@ namespace agg24 break; case 3: - // Regular care + // Regular case //----------------- if((d2 + d3)*(d2 + d3) <= m_distance_tolerance_square * (dx*dx + dy*dy)) { @@ -518,9 +560,9 @@ namespace agg24 // Angle & Cusp Condition //---------------------- - double a23 = atan2(y3 - y2, x3 - x2); - da1 = fabs(a23 - atan2(y2 - y1, x2 - x1)); - da2 = fabs(atan2(y4 - y3, x4 - x3) - a23); + 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; diff --git a/kiva/agg/agg-24/src/agg_gsv_text.cpp b/kiva/agg/agg-24/src/agg_gsv_text.cpp index 97469df16..2b478cca2 100644 --- a/kiva/agg/agg-24/src/agg_gsv_text.cpp +++ b/kiva/agg/agg-24/src/agg_gsv_text.cpp @@ -19,6 +19,8 @@ #include #include #include "agg_gsv_text.h" +#include "agg_bounding_rect.h" + namespace agg24 @@ -504,8 +506,6 @@ namespace agg24 if(*(char*)&t == 0) m_big_endian = true; } - - //------------------------------------------------------------------------- void gsv_text::font(const void* font) { @@ -540,7 +540,6 @@ namespace agg24 //if(m_flip) m_y += m_height; } - //------------------------------------------------------------------------- void gsv_text::load_font(const char* file) { @@ -563,7 +562,6 @@ namespace agg24 } } - //------------------------------------------------------------------------- void gsv_text::text(const char* text) { @@ -582,8 +580,6 @@ namespace agg24 m_text = &m_text_buf[0]; } - - //------------------------------------------------------------------------- void gsv_text::rewind(unsigned) { @@ -600,7 +596,6 @@ namespace agg24 m_cur_chr = m_text; } - //------------------------------------------------------------------------- unsigned gsv_text::vertex(double* x, double* y) { @@ -608,7 +603,6 @@ namespace agg24 int8 yc, yf; int dx, dy; bool quit = false; - while(!quit) { @@ -669,6 +663,13 @@ namespace agg24 return path_cmd_stop; } + //------------------------------------------------------------------------- + double gsv_text::text_width() + { + double x1, y1, x2, y2; + bounding_rect_single(*this, 0, &x1, &y1, &x2, &y2); + return x2 - x1; + } } diff --git a/kiva/agg/agg-24/src/agg_sqrt_tables.cpp b/kiva/agg/agg-24/src/agg_sqrt_tables.cpp index 4970694c5..6605f1d30 100644 --- a/kiva/agg/agg-24/src/agg_sqrt_tables.cpp +++ b/kiva/agg/agg-24/src/agg_sqrt_tables.cpp @@ -21,7 +21,7 @@ namespace agg24 { - int16u g_sqrt_table[1024] = + int16u g_sqrt_table[1024] = //----------g_sqrt_table { 0, 2048,2896,3547,4096,4579,5017,5418,5793,6144,6476,6792,7094,7384,7663,7932,8192,8444, @@ -100,7 +100,7 @@ namespace agg24 }; - int8 g_elder_bit_table[256] = + int8 g_elder_bit_table[256] = //---------g_elder_bit_table { 0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, diff --git a/kiva/agg/agg-24/src/agg_trans_affine.cpp b/kiva/agg/agg-24/src/agg_trans_affine.cpp index f1bfbbc72..0b3d366bc 100644 --- a/kiva/agg/agg-24/src/agg_trans_affine.cpp +++ b/kiva/agg/agg-24/src/agg_trans_affine.cpp @@ -27,12 +27,12 @@ namespace agg24 const trans_affine& trans_affine::parl_to_parl(const double* src, const double* dst) { - m0 = src[2] - src[0]; - m1 = src[3] - src[1]; - m2 = src[4] - src[0]; - m3 = src[5] - src[1]; - m4 = src[0]; - m5 = src[1]; + 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], @@ -69,15 +69,15 @@ namespace agg24 //------------------------------------------------------------------------ const trans_affine& trans_affine::multiply(const trans_affine& m) { - double t0 = m0 * m.m0 + m1 * m.m2; - double t2 = m2 * m.m0 + m3 * m.m2; - double t4 = m4 * m.m0 + m5 * m.m2 + m.m4; - m1 = m0 * m.m1 + m1 * m.m3; - m3 = m2 * m.m1 + m3 * m.m3; - m5 = m4 * m.m1 + m5 * m.m3 + m.m5; - m0 = t0; - m2 = t2; - m4 = t4; + 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; } @@ -85,18 +85,18 @@ namespace agg24 //------------------------------------------------------------------------ const trans_affine& trans_affine::invert() { - double d = determinant(); + double d = determinant_reciprocal(); - double t0 = m3 * d; - m3 = m0 * d; - m1 = -m1 * d; - m2 = -m2 * d; + double t0 = sy * d; + sy = sx * d; + shy = -shy * d; + shx = -shx * d; - double t4 = -m4 * t0 - m5 * m2; - m5 = -m4 * m1 - m5 * m3; + double t4 = -tx * t0 - ty * shx; + ty = -tx * shy - ty * sy; - m0 = t0; - m4 = t4; + sx = t0; + tx = t4; return *this; } @@ -104,55 +104,55 @@ namespace agg24 //------------------------------------------------------------------------ const trans_affine& trans_affine::flip_x() { - m0 = -m0; - m1 = -m1; - m4 = -m4; + sx = -sx; + shy = -shy; + tx = -tx; return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::flip_y() { - m2 = -m2; - m3 = -m3; - m5 = -m5; + shx = -shx; + sy = -sy; + ty = -ty; return *this; } //------------------------------------------------------------------------ const trans_affine& trans_affine::reset() { - m0 = m3 = 1.0; - m1 = m2 = m4 = m5 = 0.0; + sx = sy = 1.0; + shy = shx = tx = ty = 0.0; return *this; } //------------------------------------------------------------------------ - inline bool is_equal_eps(double v1, double v2, double epsilon) + bool trans_affine::is_identity(double epsilon) const { - return fabs(v1 - v2) < epsilon; + 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_identity(double epsilon) const + bool trans_affine::is_valid(double epsilon) const { - return is_equal_eps(m0, 1.0, epsilon) && - is_equal_eps(m1, 0.0, epsilon) && - is_equal_eps(m2, 0.0, epsilon) && - is_equal_eps(m3, 1.0, epsilon) && - is_equal_eps(m4, 0.0, epsilon) && - is_equal_eps(m5, 0.0, epsilon); + return fabs(sx) > epsilon && fabs(sy) > epsilon; } //------------------------------------------------------------------------ bool trans_affine::is_equal(const trans_affine& m, double epsilon) const { - return is_equal_eps(m0, m.m0, epsilon) && - is_equal_eps(m1, m.m1, epsilon) && - is_equal_eps(m2, m.m2, epsilon) && - is_equal_eps(m3, m.m3, epsilon) && - is_equal_eps(m4, m.m4, epsilon) && - is_equal_eps(m5, m.m5, epsilon); + 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); } //------------------------------------------------------------------------ @@ -170,13 +170,12 @@ namespace agg24 //------------------------------------------------------------------------ void trans_affine::translation(double* dx, double* dy) const { - trans_affine t(*this); - t *= trans_affine_rotation(-rotation()); - t.transform(dx, dy); + *dx = tx; + *dy = ty; } //------------------------------------------------------------------------ - void trans_affine::scaling(double* sx, double* sy) const + void trans_affine::scaling(double* x, double* y) const { double x1 = 0.0; double y1 = 0.0; @@ -186,8 +185,8 @@ namespace agg24 t *= trans_affine_rotation(-rotation()); t.transform(&x1, &y1); t.transform(&x2, &y2); - *sx = x2 - x1; - *sy = y2 - y1; + *x = x2 - x1; + *y = y2 - y1; } diff --git a/kiva/agg/agg-24/src/agg_trans_warp_magnifier.cpp b/kiva/agg/agg-24/src/agg_trans_warp_magnifier.cpp index fb6fa862a..904ef3021 100644 --- a/kiva/agg/agg-24/src/agg_trans_warp_magnifier.cpp +++ b/kiva/agg/agg-24/src/agg_trans_warp_magnifier.cpp @@ -40,10 +40,30 @@ namespace agg24 //------------------------------------------------------------------------ void trans_warp_magnifier::inverse_transform(double* x, double* y) const { - trans_warp_magnifier t(*this); - t.magnification(1.0 / m_magn); - t.radius(m_radius * m_magn); - t.transform(x, y); + // New version by Andrew Skalkin + //----------------- + double dx = *x - m_xc; + double dy = *y - m_yc; + double r = sqrt(dx * dx + dy * dy); + + if(r < m_radius * m_magn) + { + *x = m_xc + dx / m_magn; + *y = m_yc + dy / m_magn; + } + else + { + double rnew = r - m_radius * (m_magn - 1.0); + *x = m_xc + rnew * dx / r; + *y = m_yc + rnew * dy / r; + } + + // Old version + //----------------- + //trans_warp_magnifier t(*this); + //t.magnification(1.0 / m_magn); + //t.radius(m_radius * m_magn); + //t.transform(x, y); } diff --git a/kiva/agg/src/kiva_graphics_context.h b/kiva/agg/src/kiva_graphics_context.h index 30c191ec6..931dec277 100644 --- a/kiva/agg/src/kiva_graphics_context.h +++ b/kiva/agg/src/kiva_graphics_context.h @@ -588,7 +588,7 @@ namespace kiva agg24::path_storage img_outline = img.boundary_path(img_mtx); - agg24::rendering_buffer* src_buf = img.rendering_buffer_ptr(); + agg_pixfmt src_pix(img.rendering_buffer()); agg24::trans_affine inv_img_mtx = img_mtx; inv_img_mtx.invert(); @@ -602,20 +602,20 @@ namespace kiva { case nearest: { - typedef typename kiva::image_filters::nearest_type span_gen_type; - typedef typename kiva::image_filters::source_type source_type; + typedef typename kiva::image_filters::nearest_type span_gen_type; + typedef typename kiva::image_filters::source_type source_type; - source_type source(*src_buf, back_color); + source_type source(src_pix, back_color); span_gen_type span_generator(source, interpolator); this->transform_image_final(img_outline, span_generator); break; } case bilinear: { - typedef typename kiva::image_filters::bilinear_type span_gen_type; - typedef typename kiva::image_filters::source_type source_type; + typedef typename kiva::image_filters::bilinear_type span_gen_type; + typedef typename kiva::image_filters::source_type source_type; - source_type source(*src_buf, back_color); + source_type source(src_pix, back_color); span_gen_type span_generator(source, interpolator); this->transform_image_final(img_outline, span_generator); break; @@ -666,10 +666,10 @@ namespace kiva break; } - typedef typename kiva::image_filters::general_type span_gen_type; - typedef typename kiva::image_filters::source_type source_type; + typedef typename kiva::image_filters::general_type span_gen_type; + typedef typename kiva::image_filters::source_type source_type; - source_type source(*src_buf, back_color); + source_type source(src_pix, back_color); span_gen_type span_generator(source, interpolator, filter); this->transform_image_final(img_outline, span_generator); diff --git a/kiva/agg/src/kiva_graphics_context_base.cpp b/kiva/agg/src/kiva_graphics_context_base.cpp index 7667337f9..935c0ffcf 100755 --- a/kiva/agg/src/kiva_graphics_context_base.cpp +++ b/kiva/agg/src/kiva_graphics_context_base.cpp @@ -84,9 +84,9 @@ int graphics_context_base::bottom_up() } -agg24::rendering_buffer* graphics_context_base::rendering_buffer_ptr() +agg24::rendering_buffer& graphics_context_base::rendering_buffer() { - return &(this->buf); + return this->buf; } diff --git a/kiva/agg/src/kiva_graphics_context_base.h b/kiva/agg/src/kiva_graphics_context_base.h index 2eb9645fc..94604677b 100644 --- a/kiva/agg/src/kiva_graphics_context_base.h +++ b/kiva/agg/src/kiva_graphics_context_base.h @@ -83,7 +83,7 @@ namespace kiva virtual kiva::pix_format_e format() = 0; - agg24::rendering_buffer* rendering_buffer_ptr(); + agg24::rendering_buffer& rendering_buffer(); kiva::interpolation_e get_image_interpolation(); void set_image_interpolation(interpolation_e interpolation); diff --git a/kiva/agg/tests/affine_matrix_test_case.py b/kiva/agg/tests/affine_matrix_test_case.py index 9d848a9fa..0d5d1182d 100644 --- a/kiva/agg/tests/affine_matrix_test_case.py +++ b/kiva/agg/tests/affine_matrix_test_case.py @@ -86,7 +86,7 @@ def test_multiply(self): def test_determinant(self): orig = array((1.0,2.0,3.0,1.0,4.0,5.0)) - desired = -0.2 + desired = -5.0 m = agg.AffineMatrix(orig) result = m.determinant() assert(alltrue(result == desired)) diff --git a/kiva/agg/tests/join_stroke_path_test_case.py b/kiva/agg/tests/join_stroke_path_test_case.py index 4092bf8e8..967d6cf60 100644 --- a/kiva/agg/tests/join_stroke_path_test_case.py +++ b/kiva/agg/tests/join_stroke_path_test_case.py @@ -126,7 +126,7 @@ def test_antialias_miter(self): [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], - [255, 127, 127, 127, 127, 0, 0, 0, 127, 255], + [255, 127, 127, 127, 127, 63, 0, 0, 127, 255], [255, 0, 0, 0, 0, 0, 0, 0, 127, 255], [255, 0, 0, 0, 0, 0, 0, 0, 127, 255], [255, 127, 127, 127, 127, 127, 127, 127, 191, 255], @@ -146,7 +146,7 @@ def test_antialias_bevel(self): [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], - [255, 127, 127, 127, 127, 0, 0, 0, 127, 255], + [255, 127, 127, 127, 127, 63, 0, 0, 127, 255], [255, 0, 0, 0, 0, 0, 0, 0, 127, 255], [255, 0, 0, 0, 0, 0, 0, 31, 223, 255], [255, 127, 127, 127, 127, 127, 127, 223, 255, 255], @@ -168,7 +168,7 @@ def test_antialias_round(self): [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], [255, 255, 255, 255, 255, 127, 0, 0, 127, 255], - [255, 127, 127, 127, 127, 0, 0, 0, 127, 255], + [255, 127, 127, 127, 127, 63, 0, 0, 127, 255], [255, 0, 0, 0, 0, 0, 0, 0, 127, 255], [255, 0, 0, 0, 0, 0, 0, 0, 180, 255], [255, 127, 127, 127, 127, 127, 127, 179, 253, 255], diff --git a/kiva/agg/tests/stroke_path_test_case.py b/kiva/agg/tests/stroke_path_test_case.py index 145b6bc91..200e151b1 100644 --- a/kiva/agg/tests/stroke_path_test_case.py +++ b/kiva/agg/tests/stroke_path_test_case.py @@ -462,7 +462,7 @@ def test_curve_to(self): x2, y2 = 6.0, 1.0 x3, y3 = 9.0, 5.0 gc.move_to(x0, y0) - gc.curve_to(x1, y1, x2, y2, x3, y3); + gc.curve_to(x1, y1, x2, y2, x3, y3) # Set up stroke gc. set_stroke_color((0.0, 0.0, 0.0)) # black @@ -487,8 +487,8 @@ def test_curve_to(self): [255, 255, 231, 25, 212, 255, 255, 255, 255, 255], [255, 252, 65, 128, 255, 255, 255, 255, 255, 255], [255, 103, 26, 143, 229, 255, 255, 255, 255, 255], - [179, 2, 115, 96, 23, 189, 255, 255, 204, 255], - [255, 205, 255, 255, 189, 23, 97, 116, 2, 179], + [180, 2, 118, 96, 23, 189, 255, 255, 205, 255], + [255, 206, 255, 255, 189, 23, 97, 119, 2, 180], [255, 255, 255, 255, 255, 229, 142, 25, 103, 255], [255, 255, 255, 255, 255, 255, 127, 66, 252, 255], [255, 255, 255, 255, 255, 212, 26, 231, 255, 255], diff --git a/kiva/tests/agg/image_test_case.py b/kiva/tests/agg/image_test_case.py index a202c9b87..ed73ad7e9 100644 --- a/kiva/tests/agg/image_test_case.py +++ b/kiva/tests/agg/image_test_case.py @@ -144,7 +144,6 @@ def test_rotate(self): save(gc,test_name()+'.bmp') -@unittest.skipIf(six.PY3, reason="Crashes on python 3. See GH #95.") class test_sun(unittest.TestCase): def generic_sun(self,scheme): img = sun(scheme) diff --git a/kiva/tests/test_graphics_context.py b/kiva/tests/test_graphics_context.py index 8b6e9699a..4d177311c 100644 --- a/kiva/tests/test_graphics_context.py +++ b/kiva/tests/test_graphics_context.py @@ -89,7 +89,6 @@ def test_ambient_plus_image_alpha(self, color): # alpha blending is approximate, allow channel differences of to 2. self.assert_images_close(desired, actual, diff_allowed=slop_allowed) - @unittest.skipIf(six.PY3, reason="Crashes on python 3. See GH #95.") def test_rect_scale(self): color = 0.0 orig_sz = (10, 10) @@ -108,7 +107,6 @@ def test_rect_scale(self): desired = gc.bmp_array self.assert_images_equal(desired, actual) - @unittest.skipIf(six.PY3, reason="Crashes on python 3. See GH #95.") def test_rect_scale_translate(self): color = 0.0 orig_sz = (10, 10) diff --git a/setup.py b/setup.py index ef3b9857a..bfc2ca790 100644 --- a/setup.py +++ b/setup.py @@ -215,6 +215,7 @@ def run(self): join("agg", "_agg.pyd"), join("agg", "_plat_support.pyd"), join("agg", "src", "win32", "plat_support.pyd"), + join("agg", "src", "win32", "plat_support_wrap.cpp"), # *nix Agg join("agg", "_agg.so"), From 20984df317a73f72720aba204890112aef007de9 Mon Sep 17 00:00:00 2001 From: Jean-Mathieu Deschenes Date: Tue, 8 Aug 2017 20:15:14 -0400 Subject: [PATCH 2/4] as per @jwiggins suggestion fixed the image interpolation error. --- kiva/agg/src/kiva_graphics_context.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/kiva/agg/src/kiva_graphics_context.h b/kiva/agg/src/kiva_graphics_context.h index 931dec277..a8ed28d7a 100644 --- a/kiva/agg/src/kiva_graphics_context.h +++ b/kiva/agg/src/kiva_graphics_context.h @@ -588,7 +588,7 @@ namespace kiva agg24::path_storage img_outline = img.boundary_path(img_mtx); - agg_pixfmt src_pix(img.rendering_buffer()); + other_format src_pix(img.rendering_buffer()); agg24::trans_affine inv_img_mtx = img_mtx; inv_img_mtx.invert(); @@ -602,8 +602,8 @@ namespace kiva { case nearest: { - typedef typename kiva::image_filters::nearest_type span_gen_type; - typedef typename kiva::image_filters::source_type source_type; + typedef typename kiva::image_filters::nearest_type span_gen_type; + typedef typename kiva::image_filters::source_type source_type; source_type source(src_pix, back_color); span_gen_type span_generator(source, interpolator); @@ -612,8 +612,8 @@ namespace kiva } case bilinear: { - typedef typename kiva::image_filters::bilinear_type span_gen_type; - typedef typename kiva::image_filters::source_type source_type; + typedef typename kiva::image_filters::bilinear_type span_gen_type; + typedef typename kiva::image_filters::source_type source_type; source_type source(src_pix, back_color); span_gen_type span_generator(source, interpolator); @@ -666,8 +666,8 @@ namespace kiva break; } - typedef typename kiva::image_filters::general_type span_gen_type; - typedef typename kiva::image_filters::source_type source_type; + typedef typename kiva::image_filters::general_type span_gen_type; + typedef typename kiva::image_filters::source_type source_type; source_type source(src_pix, back_color); span_gen_type span_generator(source, interpolator, filter); From 6e5c175ed730166c5091fdb7286d77e1ada05463 Mon Sep 17 00:00:00 2001 From: Joris Vankerschaver Date: Sun, 1 Oct 2017 10:43:45 +0100 Subject: [PATCH 3/4] Update license date --- LICENSE.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.txt b/LICENSE.txt index 64ef4eeea..726be3f4d 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,7 +1,7 @@ This software is OSI Certified Open Source Software. OSI Certified is a certification mark of the Open Source Initiative. -Copyright (c) 2006, Enthought, Inc. +Copyright (c) 2006-2017, Enthought, Inc. All rights reserved. Redistribution and use in source and binary forms, with or without From c9e8eac19efef9ce7c8717dbb59eb22d920445e3 Mon Sep 17 00:00:00 2001 From: Joris Vankerschaver Date: Sun, 1 Oct 2017 11:03:39 +0100 Subject: [PATCH 4/4] MAINT: Add licenses. --- kiva/agg/LICENSES/LICENSE_Agg | 65 ++++++++++++++++++ kiva/agg/LICENSES/LICENSE_Enable | 28 ++++++++ kiva/agg/LICENSES/LICENSE_Matplotlib | 99 ++++++++++++++++++++++++++++ kiva/agg/README_Agg.txt | 11 ++++ 4 files changed, 203 insertions(+) create mode 100644 kiva/agg/LICENSES/LICENSE_Agg create mode 100644 kiva/agg/LICENSES/LICENSE_Enable create mode 100644 kiva/agg/LICENSES/LICENSE_Matplotlib create mode 100644 kiva/agg/README_Agg.txt diff --git a/kiva/agg/LICENSES/LICENSE_Agg b/kiva/agg/LICENSES/LICENSE_Agg new file mode 100644 index 000000000..f17681401 --- /dev/null +++ b/kiva/agg/LICENSES/LICENSE_Agg @@ -0,0 +1,65 @@ +The Anti-Grain Geometry Project +A high quality rendering engine for C++ +http://antigrain.com + +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. + +Note that the Modified BSD license DOES NOT restrict your rights +if you choose the Anti-Grain Geometry Public License. + + + + +Anti-Grain Geometry Public License +==================================================== + +Anti-Grain Geometry - Version 2.4 +Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) + +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. + + + + + +Modified BSD License +==================================================== +Anti-Grain Geometry - Version 2.4 +Copyright (C) 2002-2005 Maxim Shemanarev (McSeem) + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 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. + + 3. The name of the author may not be used to endorse or promote + products derived from this software without specific prior + written permission. + +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. + diff --git a/kiva/agg/LICENSES/LICENSE_Enable b/kiva/agg/LICENSES/LICENSE_Enable new file mode 100644 index 000000000..726be3f4d --- /dev/null +++ b/kiva/agg/LICENSES/LICENSE_Enable @@ -0,0 +1,28 @@ +This software is OSI Certified Open Source Software. +OSI Certified is a certification mark of the Open Source Initiative. + +Copyright (c) 2006-2017, Enthought, Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + * 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. + * Neither the name of Enthought, Inc. nor the names of its contributors may + be used to endorse or promote products derived from this software without + specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT OWNER OR CONTRIBUTORS 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. diff --git a/kiva/agg/LICENSES/LICENSE_Matplotlib b/kiva/agg/LICENSES/LICENSE_Matplotlib new file mode 100644 index 000000000..ec51537db --- /dev/null +++ b/kiva/agg/LICENSES/LICENSE_Matplotlib @@ -0,0 +1,99 @@ +License agreement for matplotlib versions 1.3.0 and later +========================================================= + +1. This LICENSE AGREEMENT is between the Matplotlib Development Team +("MDT"), and the Individual or Organization ("Licensee") accessing and +otherwise using matplotlib software in source or binary form and its +associated documentation. + +2. Subject to the terms and conditions of this License Agreement, MDT +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that MDT's +License Agreement and MDT's notice of copyright, i.e., "Copyright (c) +2012- Matplotlib Development Team; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib . + +4. MDT is making matplotlib available to Licensee on an "AS +IS" basis. MDT MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, MDT MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. MDT SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between MDT and +Licensee. This License Agreement does not grant permission to use MDT +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib , +Licensee agrees to be bound by the terms and conditions of this License +Agreement. + +License agreement for matplotlib versions prior to 1.3.0 +======================================================== + +1. This LICENSE AGREEMENT is between John D. Hunter ("JDH"), and the +Individual or Organization ("Licensee") accessing and otherwise using +matplotlib software in source or binary form and its associated +documentation. + +2. Subject to the terms and conditions of this License Agreement, JDH +hereby grants Licensee a nonexclusive, royalty-free, world-wide license +to reproduce, analyze, test, perform and/or display publicly, prepare +derivative works, distribute, and otherwise use matplotlib +alone or in any derivative version, provided, however, that JDH's +License Agreement and JDH's notice of copyright, i.e., "Copyright (c) +2002-2011 John D. Hunter; All Rights Reserved" are retained in +matplotlib alone or in any derivative version prepared by +Licensee. + +3. In the event Licensee prepares a derivative work that is based on or +incorporates matplotlib or any part thereof, and wants to +make the derivative work available to others as provided herein, then +Licensee hereby agrees to include in any such work a brief summary of +the changes made to matplotlib. + +4. JDH is making matplotlib available to Licensee on an "AS +IS" basis. JDH MAKES NO REPRESENTATIONS OR WARRANTIES, EXPRESS OR +IMPLIED. BY WAY OF EXAMPLE, BUT NOT LIMITATION, JDH MAKES NO AND +DISCLAIMS ANY REPRESENTATION OR WARRANTY OF MERCHANTABILITY OR FITNESS +FOR ANY PARTICULAR PURPOSE OR THAT THE USE OF MATPLOTLIB +WILL NOT INFRINGE ANY THIRD PARTY RIGHTS. + +5. JDH SHALL NOT BE LIABLE TO LICENSEE OR ANY OTHER USERS OF MATPLOTLIB + FOR ANY INCIDENTAL, SPECIAL, OR CONSEQUENTIAL DAMAGES OR +LOSS AS A RESULT OF MODIFYING, DISTRIBUTING, OR OTHERWISE USING +MATPLOTLIB , OR ANY DERIVATIVE THEREOF, EVEN IF ADVISED OF +THE POSSIBILITY THEREOF. + +6. This License Agreement will automatically terminate upon a material +breach of its terms and conditions. + +7. Nothing in this License Agreement shall be deemed to create any +relationship of agency, partnership, or joint venture between JDH and +Licensee. This License Agreement does not grant permission to use JDH +trademarks or trade name in a trademark sense to endorse or promote +products or services of Licensee, or any third party. + +8. By copying, installing or otherwise using matplotlib, +Licensee agrees to be bound by the terms and conditions of this License +Agreement. \ No newline at end of file diff --git a/kiva/agg/README_Agg.txt b/kiva/agg/README_Agg.txt new file mode 100644 index 000000000..3cafc1341 --- /dev/null +++ b/kiva/agg/README_Agg.txt @@ -0,0 +1,11 @@ +The folder agg24 contains a copy of the Agg-2.4 library. + +This code has been adapted from the Matplotlib version of Agg. The original +code is subject to the Anti-Grain Geometry Public License. Modifications by the +Matplotlib development team are subject to the Matplotlib license. Modifications +made as part of the Enable project are subject to the 3-clause BSD license. + +Copies of these licenses can be found in the LICENSES directory. + +See https://github.com/enthought/enable/pull/288 for more information about the +provenance of this code.