Skip to content

Commit

Permalink
Break canvas C++ code into smaller pieces (celiagg#101)
Browse files Browse the repository at this point in the history
  • Loading branch information
jwiggins authored Mar 26, 2021
1 parent 56c86bf commit 9e6a3a8
Show file tree
Hide file tree
Showing 12 changed files with 831 additions and 638 deletions.
38 changes: 9 additions & 29 deletions celiagg/_ndarray_canvas.pxd → celiagg/_canvas.pxd
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,8 @@ cimport _vertex_source
cimport _transform


cdef extern from "ndarray_canvas.h" namespace "agg":
cdef cppclass pixfmt_rgba128:
pass
cdef cppclass pixfmt_bgra32:
pass
cdef cppclass pixfmt_rgba32:
pass
cdef cppclass pixfmt_rgb24:
pass
cdef cppclass pixfmt_gray16:
pass
cdef cppclass pixfmt_gray8:
pass
cdef cppclass pixfmt_rgb48:
pass
cdef cppclass pixfmt_rgba64:
pass


cdef extern from "ndarray_canvas.h":
cdef cppclass ndarray_canvas_base:
cdef extern from "canvas_impl.h":
cdef cppclass canvas_base:
const size_t channel_count() const
unsigned width() const
unsigned height() const
Expand All @@ -79,11 +60,10 @@ cdef extern from "ndarray_canvas.h":
_paint.Paint& linePaint, _paint.Paint& fillPaint,
const _graphics_state.GraphicsState& gs)

cdef cppclass ndarray_canvas[pixfmt_T]:
ndarray_canvas(unsigned char* buf,
const unsigned width,
const unsigned height,
const int stride,
const size_t channel_count,
_font_cache.FontCache& cache,
const bool bottom_up)
# Factory functions
cdef canvas_base* canvas_rgba128(unsigned char* buf, const unsigned width, const unsigned height, const int stride, _font_cache.FontCache& cache, const bool bottom_up);
cdef canvas_base* canvas_bgra32(unsigned char* buf, const unsigned width, const unsigned height, const int stride, _font_cache.FontCache& cache, const bool bottom_up);
cdef canvas_base* canvas_rgba32(unsigned char* buf, const unsigned width, const unsigned height, const int stride, _font_cache.FontCache& cache, const bool bottom_up);
cdef canvas_base* canvas_rgb24(unsigned char* buf, const unsigned width, const unsigned height, const int stride, _font_cache.FontCache& cache, const bool bottom_up);
cdef canvas_base* canvas_ga16(unsigned char* buf, const unsigned width, const unsigned height, const int stride, _font_cache.FontCache& cache, const bool bottom_up);
cdef canvas_base* canvas_g8(unsigned char* buf, const unsigned width, const unsigned height, const int stride, _font_cache.FontCache& cache, const bool bottom_up);
4 changes: 2 additions & 2 deletions celiagg/_celiagg.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ cimport _font_cache
cimport _font
cimport _graphics_state
cimport _image
cimport _ndarray_canvas
cimport _canvas
cimport _paint
cimport _vertex_source
cimport _text_support
Expand Down Expand Up @@ -66,7 +66,7 @@ include "font.pxi"
include "font_cache.pxi"
include "graphics_state.pxi"
include "image.pxi"
include "ndarray_canvas.pxi"
include "canvas.pxi"
include "paint.pxi"
include "transform.pxi"
include "vertex_source.pxi"
Expand Down
66 changes: 18 additions & 48 deletions celiagg/ndarray_canvas.h → celiagg/canvas.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,59 +47,25 @@
#include <agg_renderer_scanline.h>
#include <agg_rendering_buffer.h>
#include <agg_scanline_p.h>
#include <ctrl/agg_polygon_ctrl.h>

#include "canvas_impl.h"
#include "font_cache.h"
#include "glyph_iter.h"
#include "graphics_state.h"
#include "image.h"
#include "paint.h"
#include "vertex_source.h"

// Interface to ndarray_canvas that is generic for all pixfmts, for the
// convenience of being able to implement functionality common to cython
// wrappers of ndarray_canvas template instances representing pixfmts
// in a cython base class.
class ndarray_canvas_base
{
public:
virtual ~ndarray_canvas_base(){}

virtual const size_t channel_count() const = 0;
virtual unsigned width() const = 0;
virtual unsigned height() const = 0;

virtual void clear(const double r, const double g,
const double b, const double a) = 0;

virtual void draw_image(Image& img,
const agg::trans_affine& transform,
const GraphicsState& gs) = 0;
virtual void draw_shape(VertexSource& shape,
const agg::trans_affine& transform,
Paint& linePaint, Paint& fillPaint,
const GraphicsState& gs) = 0;
virtual void draw_shape_at_points(VertexSource& shape,
const double* points,
const size_t point_count,
const agg::trans_affine& transform,
Paint& linePaint, Paint& fillPaint,
const GraphicsState& gs) = 0;
virtual void draw_text(const char* text, Font& font,
const agg::trans_affine& transform,
Paint& linePaint, Paint& fillPaint,
const GraphicsState& gs) = 0;
};

template<typename pixfmt_t>
class ndarray_canvas : public ndarray_canvas_base
class canvas : public canvas_base
{
public:
ndarray_canvas(unsigned char* buf,
const unsigned width, const unsigned height, const int stride,
const size_t channel_count, FontCache& cache,
const bool bottom_up = false);
virtual ~ndarray_canvas() {}
canvas(unsigned char* buf,
const unsigned width, const unsigned height, const int stride,
const size_t channel_count, FontCache& cache,
const bool bottom_up = false);
virtual ~canvas() {}

const size_t channel_count() const;
unsigned width() const;
Expand Down Expand Up @@ -199,13 +165,17 @@ class ndarray_canvas : public ndarray_canvas_base
private:
// Target buffer/numpy array must be supplied to constructor. The following line ensures that no default
// constructor is user-accessible, even if the buffer-accepting constructor is deleted (presence of a constructor
// taking one or more parameters suppresses automatic default constructor generation).
ndarray_canvas(){}
// ndarray_canvases are non-copyable in order to dodge the question of whether a copied ndarray_canvas refers to the
// taking one or more parameters suppresses automatic default constructor generation).
canvas(){}
// canvases are non-copyable in order to dodge the question of whether a copied canvas refers to the
// original's buffer/numpy array or receives its own copy. The compiler does autogenerate assignment and copy
// constructors if these are not defined; so, we define them such that they are not user-accessible.
ndarray_canvas(const ndarray_canvas&){}
ndarray_canvas& operator = (const ndarray_canvas&){ return *this; }
// constructors if these are not defined; so, we define them such that they are not user-accessible.
canvas(const canvas&){}
canvas& operator = (const canvas&){ return *this; }
};

#include "ndarray_canvas.hxx"
// The implementation is broken out into several files to keep things focused
#include "canvas.hxx"
#include "canvas_image.hxx"
#include "canvas_shape.hxx"
#include "canvas_text.hxx"
200 changes: 200 additions & 0 deletions celiagg/canvas.hxx
Original file line number Diff line number Diff line change
@@ -0,0 +1,200 @@
// The MIT License (MIT)
//
// Copyright (c) 2014-2015 WUSTL ZPLAB
// Copyright (c) 2016-2021 Celiagg Contributors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Authors: Erik Hvatum <[email protected]>
// John Wiggins

// NOTE: The renderer object constructed here keeps pointers to objects which
// are allocated on the stack, so in order to avoid code duplication, we get
// this funky macro...
#define _WITH_MASKED_RENDERER(gs, name) \
Image* stencil = const_cast<Image*>(gs.stencil());\
agg::rendering_buffer& stencilbuf = stencil->get_buffer();\
alpha_mask_t stencil_mask(stencilbuf);\
masked_pxfmt_t masked_pixfmt(m_pixfmt, stencil_mask);\
masked_renderer_t name(masked_pixfmt);


template<typename pixfmt_t>
canvas<pixfmt_t>::canvas(unsigned char* buf,
const unsigned width, const unsigned height, const int stride,
const size_t channel_count, FontCache& cache, const bool bottom_up)
: m_channel_count(channel_count)
, m_font_cache(cache)
, m_renbuf(buf, width, height, bottom_up ? -stride : stride)
, m_pixfmt(m_renbuf)
, m_renderer(m_pixfmt)
, m_bottom_up(bottom_up)
{
}

template<typename pixfmt_t>
const size_t canvas<pixfmt_t>::channel_count() const
{
// typedef typename pixfmt_t::order_type T;
// return T::N;
// Something like the above should work, but the cop-out of just storing channel count
// ourselves definitely works.
return m_channel_count;
}

template<typename pixfmt_t>
unsigned canvas<pixfmt_t>::width() const
{
return m_renbuf.width();
}

template<typename pixfmt_t>
unsigned canvas<pixfmt_t>::height() const
{
return m_renbuf.height();
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::clear(const double r, const double g,
const double b, const double a)
{
typename pixfmt_t::color_type c(agg::rgba(r, g, b, a));
m_renderer.clear(c);
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::draw_image(Image& img,
const agg::trans_affine& transform, const GraphicsState& gs)
{
_set_clipping(gs.clip_box());
// XXX: Apply master alpha here somehow!

if (gs.stencil() == NULL)
{
_draw_image_internal<renderer_t>(img, transform, gs, m_renderer);
}
else
{
_WITH_MASKED_RENDERER(gs, renderer)
_draw_image_internal<masked_renderer_t>(img, transform, gs, renderer);
}
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::draw_shape(VertexSource& shape,
const agg::trans_affine& transform, Paint& linePaint, Paint& fillPaint,
const GraphicsState& gs)
{
_set_clipping(gs.clip_box());
linePaint.master_alpha(gs.master_alpha());
fillPaint.master_alpha(gs.master_alpha());

if (gs.stencil() == NULL)
{
_draw_shape_internal(shape, transform, linePaint, fillPaint, gs, m_renderer);
}
else
{
_WITH_MASKED_RENDERER(gs, renderer)
_draw_shape_internal(shape, transform, linePaint, fillPaint, gs, renderer);
}
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::draw_shape_at_points(VertexSource& shape,
const double* points, const size_t point_count,
const agg::trans_affine& transform, Paint& linePaint, Paint& fillPaint,
const GraphicsState& gs)
{
agg::simple_polygon_vertex_source _points(points, point_count, false, false);
agg::trans_affine pt_trans;
unsigned cmd;

_set_clipping(gs.clip_box());
linePaint.master_alpha(gs.master_alpha());
fillPaint.master_alpha(gs.master_alpha());

if (gs.stencil() == NULL)
{
for (;;)
{
cmd = _points.vertex(&pt_trans.tx, &pt_trans.ty);
if (cmd == agg::path_cmd_end_poly) break;

_draw_shape_internal(shape, pt_trans * transform, linePaint, fillPaint, gs, m_renderer);
}
}
else
{
_WITH_MASKED_RENDERER(gs, renderer)
for (;;)
{
cmd = _points.vertex(&pt_trans.tx, &pt_trans.ty);
if (cmd == agg::path_cmd_end_poly) break;

_draw_shape_internal(shape, pt_trans * transform, linePaint, fillPaint, gs, renderer);
}
}
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::draw_text(const char* text,
Font& font, const agg::trans_affine& transform,
Paint& linePaint, Paint& fillPaint, const GraphicsState& gs)
{
_set_clipping(gs.clip_box());
linePaint.master_alpha(gs.master_alpha());
fillPaint.master_alpha(gs.master_alpha());

if (gs.stencil() == NULL)
{
_draw_text_internal(text, font, transform, linePaint, fillPaint, gs, m_renderer);
}
else
{
_WITH_MASKED_RENDERER(gs, renderer)
_draw_text_internal(text, font, transform, linePaint, fillPaint, gs, renderer);
}
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::_set_aa(const bool& aa)
{
if(aa)
{
m_rasterizer.gamma(agg::gamma_linear());
}
else
{
m_rasterizer.gamma(agg::gamma_threshold(0.5));
}
}

template<typename pixfmt_t>
void canvas<pixfmt_t>::_set_clipping(const GraphicsState::Rect& rect)
{
if (rect.is_valid())
{
m_rasterizer.clip_box(rect.x1, rect.y1, rect.x2, rect.y2);
}
else
{
m_rasterizer.reset_clipping();
}
}
Loading

0 comments on commit 9e6a3a8

Please sign in to comment.