//---------------------------------------------------------------------------- // Anti-Grain Geometry - Version 2.4 // Copyright (C) 2002-2005 Maxim Shemanarev (http://www.antigrain.com) // // Permission to copy, use, modify, sell and distribute this software // is granted provided this copyright notice appears in all copies. // This software is provided "as is" without express or implied // warranty, and with no claim as to its suitability for any purpose. // //---------------------------------------------------------------------------- // Contact: mcseem@antigrain.com // mcseemagg@yahoo.com // http://www.antigrain.com //---------------------------------------------------------------------------- #ifndef AGG_RENDERER_SCANLINE_INCLUDED #define AGG_RENDERER_SCANLINE_INCLUDED #include #include #include #include "agg_basics.h" #include "agg_renderer_base.h" namespace agg { //================================================render_scanline_aa_solid template void render_scanline_aa_solid(const Scanline& sl, BaseRenderer& ren, const ColorT& color) { int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; if(span->len > 0) { ren.blend_solid_hspan(x, y, (unsigned)span->len, color, span->covers); } else { ren.blend_hline(x, y, (unsigned)(x - span->len - 1), color, *(span->covers)); } if(--num_spans == 0) break; ++span; } } //===============================================render_scanlines_aa_solid template void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, const ColorT& color) { if(ras.rewind_scanlines()) { // Explicitly convert "color" to the BaseRenderer color type. // For example, it can be called with color type "rgba", while // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- typename BaseRenderer::color_type ren_color = color; sl.reset(ras.min_x(), ras.max_x()); while(ras.sweep_scanline(sl)) { //render_scanline_aa_solid(sl, ren, ren_color); // This code is equivalent to the above call (copy/paste). // It's just a "manual" optimization for old compilers, // like Microsoft Visual C++ v6.0 //------------------------------- int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; if(span->len > 0) { ren.blend_solid_hspan(x, y, (unsigned)span->len, ren_color, span->covers); } else { ren.blend_hline(x, y, (unsigned)(x - span->len - 1), ren_color, *(span->covers)); } if(--num_spans == 0) break; ++span; } } } } //==============================================renderer_scanline_aa_solid template class renderer_scanline_aa_solid { public: typedef BaseRenderer base_ren_type; typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- renderer_scanline_aa_solid() : m_ren(0) {} explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {} void attach(base_ren_type& ren) { m_ren = &ren; } //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_aa_solid(sl, *m_ren, m_color); } private: base_ren_type* m_ren; color_type m_color; }; //======================================================render_scanline_aa template void render_scanline_aa(const Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; int len = span->len; const typename Scanline::cover_type* covers = span->covers; if(len < 0) len = -len; typename BaseRenderer::color_type* colors = alloc.allocate(len); span_gen.generate(colors, x, y, len); ren.blend_color_hspan(x, y, len, colors, (span->len < 0) ? 0 : covers, *covers); if(--num_spans == 0) break; ++span; } } //=====================================================render_scanlines_aa template void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); span_gen.prepare(); while(ras.sweep_scanline(sl)) { render_scanline_aa(sl, ren, alloc, span_gen); } } } //====================================================renderer_scanline_aa template class renderer_scanline_aa { public: typedef BaseRenderer base_ren_type; typedef SpanAllocator alloc_type; typedef SpanGenerator span_gen_type; //-------------------------------------------------------------------- renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {} renderer_scanline_aa(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) : m_ren(&ren), m_alloc(&alloc), m_span_gen(&span_gen) {} void attach(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) { m_ren = &ren; m_alloc = &alloc; m_span_gen = &span_gen; } //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); } //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen); } private: base_ren_type* m_ren; alloc_type* m_alloc; span_gen_type* m_span_gen; }; //===============================================render_scanline_bin_solid template void render_scanline_bin_solid(const Scanline& sl, BaseRenderer& ren, const ColorT& color) { unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { ren.blend_hline(span->x, sl.y(), span->x - 1 + ((span->len < 0) ? -span->len : span->len), color, cover_full); if(--num_spans == 0) break; ++span; } } //==============================================render_scanlines_bin_solid template void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, const ColorT& color) { if(ras.rewind_scanlines()) { // Explicitly convert "color" to the BaseRenderer color type. // For example, it can be called with color type "rgba", while // "rgba8" is needed. Otherwise it will be implicitly // converted in the loop many times. //---------------------- typename BaseRenderer::color_type ren_color(color); sl.reset(ras.min_x(), ras.max_x()); while(ras.sweep_scanline(sl)) { //render_scanline_bin_solid(sl, ren, ren_color); // This code is equivalent to the above call (copy/paste). // It's just a "manual" optimization for old compilers, // like Microsoft Visual C++ v6.0 //------------------------------- unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { ren.blend_hline(span->x, sl.y(), span->x - 1 + ((span->len < 0) ? -span->len : span->len), ren_color, cover_full); if(--num_spans == 0) break; ++span; } } } } //=============================================renderer_scanline_bin_solid template class renderer_scanline_bin_solid { public: typedef BaseRenderer base_ren_type; typedef typename base_ren_type::color_type color_type; //-------------------------------------------------------------------- renderer_scanline_bin_solid() : m_ren(0) {} explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {} void attach(base_ren_type& ren) { m_ren = &ren; } //-------------------------------------------------------------------- void color(const color_type& c) { m_color = c; } const color_type& color() const { return m_color; } //-------------------------------------------------------------------- void prepare() {} //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_bin_solid(sl, *m_ren, m_color); } private: base_ren_type* m_ren; color_type m_color; }; //======================================================render_scanline_bin template void render_scanline_bin(const Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { int y = sl.y(); unsigned num_spans = sl.num_spans(); typename Scanline::const_iterator span = sl.begin(); for(;;) { int x = span->x; int len = span->len; if(len < 0) len = -len; typename BaseRenderer::color_type* colors = alloc.allocate(len); span_gen.generate(colors, x, y, len); ren.blend_color_hspan(x, y, len, colors, 0, cover_full); if(--num_spans == 0) break; ++span; } } //=====================================================render_scanlines_bin template void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren, SpanAllocator& alloc, SpanGenerator& span_gen) { if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); span_gen.prepare(); while(ras.sweep_scanline(sl)) { render_scanline_bin(sl, ren, alloc, span_gen); } } } //====================================================renderer_scanline_bin template class renderer_scanline_bin { public: typedef BaseRenderer base_ren_type; typedef SpanAllocator alloc_type; typedef SpanGenerator span_gen_type; //-------------------------------------------------------------------- renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {} renderer_scanline_bin(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) : m_ren(&ren), m_alloc(&alloc), m_span_gen(&span_gen) {} void attach(base_ren_type& ren, alloc_type& alloc, span_gen_type& span_gen) { m_ren = &ren; m_alloc = &alloc; m_span_gen = &span_gen; } //-------------------------------------------------------------------- void prepare() { m_span_gen->prepare(); } //-------------------------------------------------------------------- template void render(const Scanline& sl) { render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen); } private: base_ren_type* m_ren; alloc_type* m_alloc; span_gen_type* m_span_gen; }; //========================================================render_scanlines template void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren) { if(ras.rewind_scanlines()) { sl.reset(ras.min_x(), ras.max_x()); ren.prepare(); while(ras.sweep_scanline(sl)) { ren.render(sl); } } } //========================================================render_all_paths template void render_all_paths(Rasterizer& ras, Scanline& sl, Renderer& r, VertexSource& vs, const ColorStorage& as, const PathId& path_id, unsigned num_paths) { for(unsigned i = 0; i < num_paths; i++) { ras.reset(); ras.add_path(vs, path_id[i]); r.color(as[i]); render_scanlines(ras, sl, r); } } //=============================================render_scanlines_compound template void render_scanlines_compound(Rasterizer& ras, ScanlineAA& sl_aa, ScanlineBin& sl_bin, BaseRenderer& ren, SpanAllocator& alloc, StyleHandler& sh) { if(ras.rewind_scanlines()) { int min_x = ras.min_x(); int len = ras.max_x() - min_x + 2; sl_aa.reset(min_x, ras.max_x()); sl_bin.reset(min_x, ras.max_x()); typedef typename BaseRenderer::color_type color_type; color_type* color_span = alloc.allocate(len * 2); color_type* mix_buffer = color_span + len; unsigned num_spans; unsigned num_styles; unsigned style; bool solid; while((num_styles = ras.sweep_styles()) > 0) { typename ScanlineAA::const_iterator span_aa; if(num_styles == 1) { // Optimization for a single style. Happens often //------------------------- if(ras.sweep_scanline(sl_aa, 0)) { style = ras.style(0); if(sh.is_solid(style)) { // Just solid fill //----------------------- render_scanline_aa_solid(sl_aa, ren, sh.color(style)); } else { // Arbitrary span generator //----------------------- span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); for(;;) { len = span_aa->len; sh.generate_span(color_span, span_aa->x, sl_aa.y(), len, style); ren.blend_color_hspan(span_aa->x, sl_aa.y(), span_aa->len, color_span, span_aa->covers); if(--num_spans == 0) break; ++span_aa; } } } } else { if(ras.sweep_scanline(sl_bin, -1)) { // Clear the spans of the mix_buffer //-------------------- typename ScanlineBin::const_iterator span_bin = sl_bin.begin(); num_spans = sl_bin.num_spans(); for(;;) { std::memset(mix_buffer + span_bin->x - min_x, 0, span_bin->len * sizeof(color_type)); if(--num_spans == 0) break; ++span_bin; } unsigned i; for(i = 0; i < num_styles; i++) { style = ras.style(i); solid = sh.is_solid(style); if(ras.sweep_scanline(sl_aa, i)) { color_type* colors; color_type* cspan; typename ScanlineAA::cover_type* covers; span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); if(solid) { // Just solid fill //----------------------- for(;;) { color_type c = sh.color(style); len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; covers = span_aa->covers; do { if(*covers == cover_full) { *colors = c; } else { colors->add(c, *covers); } ++colors; ++covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } else { // Arbitrary span generator //----------------------- for(;;) { len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; cspan = color_span; sh.generate_span(cspan, span_aa->x, sl_aa.y(), len, style); covers = span_aa->covers; do { if(*covers == cover_full) { *colors = *cspan; } else { colors->add(*cspan, *covers); } ++cspan; ++colors; ++covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } } } // Emit the blended result as a color hspan //------------------------- span_bin = sl_bin.begin(); num_spans = sl_bin.num_spans(); for(;;) { ren.blend_color_hspan(span_bin->x, sl_bin.y(), span_bin->len, mix_buffer + span_bin->x - min_x, 0, cover_full); if(--num_spans == 0) break; ++span_bin; } } // if(ras.sweep_scanline(sl_bin, -1)) } // if(num_styles == 1) ... else } // while((num_styles = ras.sweep_styles()) > 0) } // if(ras.rewind_scanlines()) } //=======================================render_scanlines_compound_layered template 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) { std::memset(mix_buffer + sl_start - min_x, 0, sl_len * sizeof(color_type)); std::memset(cover_buffer + sl_start - min_x, 0, sl_len * sizeof(cover_type)); int sl_y = std::numeric_limits::max(); unsigned i; for(i = 0; i < num_styles; i++) { style = ras.style(i); solid = sh.is_solid(style); if(ras.sweep_scanline(sl_aa, i)) { unsigned cover; color_type* colors; color_type* cspan; cover_type* src_covers; cover_type* dst_covers; span_aa = sl_aa.begin(); num_spans = sl_aa.num_spans(); sl_y = sl_aa.y(); if(solid) { // Just solid fill //----------------------- for(;;) { color_type c = sh.color(style); len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; src_covers = span_aa->covers; dst_covers = cover_buffer + span_aa->x - min_x; do { cover = *src_covers; if(*dst_covers + cover > cover_full) { cover = cover_full - *dst_covers; } if(cover) { colors->add(c, cover); *dst_covers += cover; } ++colors; ++src_covers; ++dst_covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } else { // Arbitrary span generator //----------------------- for(;;) { len = span_aa->len; colors = mix_buffer + span_aa->x - min_x; cspan = color_span; sh.generate_span(cspan, span_aa->x, sl_aa.y(), len, style); src_covers = span_aa->covers; dst_covers = cover_buffer + span_aa->x - min_x; do { cover = *src_covers; if(*dst_covers + cover > cover_full) { cover = cover_full - *dst_covers; } if(cover) { colors->add(*cspan, cover); *dst_covers += cover; } ++cspan; ++colors; ++src_covers; ++dst_covers; } while(--len); if(--num_spans == 0) break; ++span_aa; } } } } ren.blend_color_hspan(sl_start, sl_y, sl_len, mix_buffer + sl_start - min_x, 0, cover_full); } //if(sl_len) } //if(num_styles == 1) ... else } //while((num_styles = ras.sweep_styles()) > 0) } //if(ras.rewind_scanlines()) } } #endif