agg/include/agg_renderer_scanline.h

856 lines
34 KiB
C++

//----------------------------------------------------------------------------
// 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 <limits>
#include <cstdlib>
#include <cstring>
#include "agg_basics.h"
#include "agg_renderer_base.h"
namespace agg
{
//================================================render_scanline_aa_solid
template<class Scanline, class BaseRenderer, class ColorT>
void render_scanline_aa_solid(const Scanline& sl,
BaseRenderer& ren,
const ColorT& color)
{
int y = sl.y();
unsigned num_spans = sl.num_spans();
typename Scanline::const_iterator span = sl.begin();
for(;;)
{
int x = span->x;
if(span->len > 0)
{
ren.blend_solid_hspan(x, y, (unsigned)span->len,
color,
span->covers);
}
else
{
ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
color,
*(span->covers));
}
if(--num_spans == 0) break;
++span;
}
}
//===============================================render_scanlines_aa_solid
template<class Rasterizer, class Scanline,
class BaseRenderer, class ColorT>
void render_scanlines_aa_solid(Rasterizer& ras, Scanline& sl,
BaseRenderer& ren, const ColorT& color)
{
if(ras.rewind_scanlines())
{
// Explicitly convert "color" to the BaseRenderer color type.
// For example, it can be called with color type "rgba", while
// "rgba8" is needed. Otherwise it will be implicitly
// converted in the loop many times.
//----------------------
typename BaseRenderer::color_type ren_color = color;
sl.reset(ras.min_x(), ras.max_x());
while(ras.sweep_scanline(sl))
{
//render_scanline_aa_solid(sl, ren, ren_color);
// This code is equivalent to the above call (copy/paste).
// It's just a "manual" optimization for old compilers,
// like Microsoft Visual C++ v6.0
//-------------------------------
int y = sl.y();
unsigned num_spans = sl.num_spans();
typename Scanline::const_iterator span = sl.begin();
for(;;)
{
int x = span->x;
if(span->len > 0)
{
ren.blend_solid_hspan(x, y, (unsigned)span->len,
ren_color,
span->covers);
}
else
{
ren.blend_hline(x, y, (unsigned)(x - span->len - 1),
ren_color,
*(span->covers));
}
if(--num_spans == 0) break;
++span;
}
}
}
}
//==============================================renderer_scanline_aa_solid
template<class BaseRenderer> class renderer_scanline_aa_solid
{
public:
typedef BaseRenderer base_ren_type;
typedef typename base_ren_type::color_type color_type;
//--------------------------------------------------------------------
renderer_scanline_aa_solid() : m_ren(0) {}
explicit renderer_scanline_aa_solid(base_ren_type& ren) : m_ren(&ren) {}
void attach(base_ren_type& ren)
{
m_ren = &ren;
}
//--------------------------------------------------------------------
void color(const color_type& c) { m_color = c; }
const color_type& color() const { return m_color; }
//--------------------------------------------------------------------
void prepare() {}
//--------------------------------------------------------------------
template<class Scanline> void render(const Scanline& sl)
{
render_scanline_aa_solid(sl, *m_ren, m_color);
}
private:
base_ren_type* m_ren;
color_type m_color;
};
//======================================================render_scanline_aa
template<class Scanline, class BaseRenderer,
class SpanAllocator, class SpanGenerator>
void render_scanline_aa(const Scanline& sl, BaseRenderer& ren,
SpanAllocator& alloc, SpanGenerator& span_gen)
{
int y = sl.y();
unsigned num_spans = sl.num_spans();
typename Scanline::const_iterator span = sl.begin();
for(;;)
{
int x = span->x;
int len = span->len;
const typename Scanline::cover_type* covers = span->covers;
if(len < 0) len = -len;
typename BaseRenderer::color_type* colors = alloc.allocate(len);
span_gen.generate(colors, x, y, len);
ren.blend_color_hspan(x, y, len, colors,
(span->len < 0) ? 0 : covers, *covers);
if(--num_spans == 0) break;
++span;
}
}
//=====================================================render_scanlines_aa
template<class Rasterizer, class Scanline, class BaseRenderer,
class SpanAllocator, class SpanGenerator>
void render_scanlines_aa(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
SpanAllocator& alloc, SpanGenerator& span_gen)
{
if(ras.rewind_scanlines())
{
sl.reset(ras.min_x(), ras.max_x());
span_gen.prepare();
while(ras.sweep_scanline(sl))
{
render_scanline_aa(sl, ren, alloc, span_gen);
}
}
}
//====================================================renderer_scanline_aa
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
class renderer_scanline_aa
{
public:
typedef BaseRenderer base_ren_type;
typedef SpanAllocator alloc_type;
typedef SpanGenerator span_gen_type;
//--------------------------------------------------------------------
renderer_scanline_aa() : m_ren(0), m_alloc(0), m_span_gen(0) {}
renderer_scanline_aa(base_ren_type& ren,
alloc_type& alloc,
span_gen_type& span_gen) :
m_ren(&ren),
m_alloc(&alloc),
m_span_gen(&span_gen)
{}
void attach(base_ren_type& ren,
alloc_type& alloc,
span_gen_type& span_gen)
{
m_ren = &ren;
m_alloc = &alloc;
m_span_gen = &span_gen;
}
//--------------------------------------------------------------------
void prepare() { m_span_gen->prepare(); }
//--------------------------------------------------------------------
template<class Scanline> void render(const Scanline& sl)
{
render_scanline_aa(sl, *m_ren, *m_alloc, *m_span_gen);
}
private:
base_ren_type* m_ren;
alloc_type* m_alloc;
span_gen_type* m_span_gen;
};
//===============================================render_scanline_bin_solid
template<class Scanline, class BaseRenderer, class ColorT>
void render_scanline_bin_solid(const Scanline& sl,
BaseRenderer& ren,
const ColorT& color)
{
unsigned num_spans = sl.num_spans();
typename Scanline::const_iterator span = sl.begin();
for(;;)
{
ren.blend_hline(span->x,
sl.y(),
span->x - 1 + ((span->len < 0) ?
-span->len :
span->len),
color,
cover_full);
if(--num_spans == 0) break;
++span;
}
}
//==============================================render_scanlines_bin_solid
template<class Rasterizer, class Scanline,
class BaseRenderer, class ColorT>
void render_scanlines_bin_solid(Rasterizer& ras, Scanline& sl,
BaseRenderer& ren, const ColorT& color)
{
if(ras.rewind_scanlines())
{
// Explicitly convert "color" to the BaseRenderer color type.
// For example, it can be called with color type "rgba", while
// "rgba8" is needed. Otherwise it will be implicitly
// converted in the loop many times.
//----------------------
typename BaseRenderer::color_type ren_color(color);
sl.reset(ras.min_x(), ras.max_x());
while(ras.sweep_scanline(sl))
{
//render_scanline_bin_solid(sl, ren, ren_color);
// This code is equivalent to the above call (copy/paste).
// It's just a "manual" optimization for old compilers,
// like Microsoft Visual C++ v6.0
//-------------------------------
unsigned num_spans = sl.num_spans();
typename Scanline::const_iterator span = sl.begin();
for(;;)
{
ren.blend_hline(span->x,
sl.y(),
span->x - 1 + ((span->len < 0) ?
-span->len :
span->len),
ren_color,
cover_full);
if(--num_spans == 0) break;
++span;
}
}
}
}
//=============================================renderer_scanline_bin_solid
template<class BaseRenderer> class renderer_scanline_bin_solid
{
public:
typedef BaseRenderer base_ren_type;
typedef typename base_ren_type::color_type color_type;
//--------------------------------------------------------------------
renderer_scanline_bin_solid() : m_ren(0) {}
explicit renderer_scanline_bin_solid(base_ren_type& ren) : m_ren(&ren) {}
void attach(base_ren_type& ren)
{
m_ren = &ren;
}
//--------------------------------------------------------------------
void color(const color_type& c) { m_color = c; }
const color_type& color() const { return m_color; }
//--------------------------------------------------------------------
void prepare() {}
//--------------------------------------------------------------------
template<class Scanline> void render(const Scanline& sl)
{
render_scanline_bin_solid(sl, *m_ren, m_color);
}
private:
base_ren_type* m_ren;
color_type m_color;
};
//======================================================render_scanline_bin
template<class Scanline, class BaseRenderer,
class SpanAllocator, class SpanGenerator>
void render_scanline_bin(const Scanline& sl, BaseRenderer& ren,
SpanAllocator& alloc, SpanGenerator& span_gen)
{
int y = sl.y();
unsigned num_spans = sl.num_spans();
typename Scanline::const_iterator span = sl.begin();
for(;;)
{
int x = span->x;
int len = span->len;
if(len < 0) len = -len;
typename BaseRenderer::color_type* colors = alloc.allocate(len);
span_gen.generate(colors, x, y, len);
ren.blend_color_hspan(x, y, len, colors, 0, cover_full);
if(--num_spans == 0) break;
++span;
}
}
//=====================================================render_scanlines_bin
template<class Rasterizer, class Scanline, class BaseRenderer,
class SpanAllocator, class SpanGenerator>
void render_scanlines_bin(Rasterizer& ras, Scanline& sl, BaseRenderer& ren,
SpanAllocator& alloc, SpanGenerator& span_gen)
{
if(ras.rewind_scanlines())
{
sl.reset(ras.min_x(), ras.max_x());
span_gen.prepare();
while(ras.sweep_scanline(sl))
{
render_scanline_bin(sl, ren, alloc, span_gen);
}
}
}
//====================================================renderer_scanline_bin
template<class BaseRenderer, class SpanAllocator, class SpanGenerator>
class renderer_scanline_bin
{
public:
typedef BaseRenderer base_ren_type;
typedef SpanAllocator alloc_type;
typedef SpanGenerator span_gen_type;
//--------------------------------------------------------------------
renderer_scanline_bin() : m_ren(0), m_alloc(0), m_span_gen(0) {}
renderer_scanline_bin(base_ren_type& ren,
alloc_type& alloc,
span_gen_type& span_gen) :
m_ren(&ren),
m_alloc(&alloc),
m_span_gen(&span_gen)
{}
void attach(base_ren_type& ren,
alloc_type& alloc,
span_gen_type& span_gen)
{
m_ren = &ren;
m_alloc = &alloc;
m_span_gen = &span_gen;
}
//--------------------------------------------------------------------
void prepare() { m_span_gen->prepare(); }
//--------------------------------------------------------------------
template<class Scanline> void render(const Scanline& sl)
{
render_scanline_bin(sl, *m_ren, *m_alloc, *m_span_gen);
}
private:
base_ren_type* m_ren;
alloc_type* m_alloc;
span_gen_type* m_span_gen;
};
//========================================================render_scanlines
template<class Rasterizer, class Scanline, class Renderer>
void render_scanlines(Rasterizer& ras, Scanline& sl, Renderer& ren)
{
if(ras.rewind_scanlines())
{
sl.reset(ras.min_x(), ras.max_x());
ren.prepare();
while(ras.sweep_scanline(sl))
{
ren.render(sl);
}
}
}
//========================================================render_all_paths
template<class Rasterizer, class Scanline, class Renderer,
class VertexSource, class ColorStorage, class PathId>
void render_all_paths(Rasterizer& ras,
Scanline& sl,
Renderer& r,
VertexSource& vs,
const ColorStorage& as,
const PathId& path_id,
unsigned num_paths)
{
for(unsigned i = 0; i < num_paths; i++)
{
ras.reset();
ras.add_path(vs, path_id[i]);
r.color(as[i]);
render_scanlines(ras, sl, r);
}
}
//=============================================render_scanlines_compound
template<class Rasterizer,
class ScanlineAA,
class ScanlineBin,
class BaseRenderer,
class SpanAllocator,
class StyleHandler>
void render_scanlines_compound(Rasterizer& ras,
ScanlineAA& sl_aa,
ScanlineBin& sl_bin,
BaseRenderer& ren,
SpanAllocator& alloc,
StyleHandler& sh)
{
if(ras.rewind_scanlines())
{
int min_x = ras.min_x();
int len = ras.max_x() - min_x + 2;
sl_aa.reset(min_x, ras.max_x());
sl_bin.reset(min_x, ras.max_x());
typedef typename BaseRenderer::color_type color_type;
color_type* color_span = alloc.allocate(len * 2);
color_type* mix_buffer = color_span + len;
unsigned num_spans;
unsigned num_styles;
unsigned style;
bool solid;
while((num_styles = ras.sweep_styles()) > 0)
{
typename ScanlineAA::const_iterator span_aa;
if(num_styles == 1)
{
// Optimization for a single style. Happens often
//-------------------------
if(ras.sweep_scanline(sl_aa, 0))
{
style = ras.style(0);
if(sh.is_solid(style))
{
// Just solid fill
//-----------------------
render_scanline_aa_solid(sl_aa, ren, sh.color(style));
}
else
{
// Arbitrary span generator
//-----------------------
span_aa = sl_aa.begin();
num_spans = sl_aa.num_spans();
for(;;)
{
len = span_aa->len;
sh.generate_span(color_span,
span_aa->x,
sl_aa.y(),
len,
style);
ren.blend_color_hspan(span_aa->x,
sl_aa.y(),
span_aa->len,
color_span,
span_aa->covers);
if(--num_spans == 0) break;
++span_aa;
}
}
}
}
else
{
if(ras.sweep_scanline(sl_bin, -1))
{
// Clear the spans of the mix_buffer
//--------------------
typename ScanlineBin::const_iterator span_bin = sl_bin.begin();
num_spans = sl_bin.num_spans();
for(;;)
{
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<class Rasterizer,
class ScanlineAA,
class BaseRenderer,
class SpanAllocator,
class StyleHandler>
void render_scanlines_compound_layered(Rasterizer& ras,
ScanlineAA& sl_aa,
BaseRenderer& ren,
SpanAllocator& alloc,
StyleHandler& sh)
{
if(ras.rewind_scanlines())
{
int min_x = ras.min_x();
int len = ras.max_x() - min_x + 2;
sl_aa.reset(min_x, ras.max_x());
typedef typename BaseRenderer::color_type color_type;
color_type* color_span = alloc.allocate(len * 2);
color_type* mix_buffer = color_span + len;
cover_type* cover_buffer = ras.allocate_cover_buffer(len);
unsigned num_spans;
unsigned num_styles;
unsigned style;
bool solid;
while((num_styles = ras.sweep_styles()) > 0)
{
typename ScanlineAA::const_iterator span_aa;
if(num_styles == 1)
{
// Optimization for a single style. Happens often
//-------------------------
if(ras.sweep_scanline(sl_aa, 0))
{
style = ras.style(0);
if(sh.is_solid(style))
{
// Just solid fill
//-----------------------
render_scanline_aa_solid(sl_aa, ren, sh.color(style));
}
else
{
// Arbitrary span generator
//-----------------------
span_aa = sl_aa.begin();
num_spans = sl_aa.num_spans();
for(;;)
{
len = span_aa->len;
sh.generate_span(color_span,
span_aa->x,
sl_aa.y(),
len,
style);
ren.blend_color_hspan(span_aa->x,
sl_aa.y(),
span_aa->len,
color_span,
span_aa->covers);
if(--num_spans == 0) break;
++span_aa;
}
}
}
}
else
{
int sl_start = ras.scanline_start();
unsigned sl_len = ras.scanline_length();
if(sl_len)
{
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<int>::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