diff options
author | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 14:39:34 +0300 |
---|---|---|
committer | shumkovnd <shumkovnd@yandex-team.com> | 2023-11-10 16:42:24 +0300 |
commit | 77eb2d3fdcec5c978c64e025ced2764c57c00285 (patch) | |
tree | c51edb0748ca8d4a08d7c7323312c27ba1a8b79a /contrib/python/matplotlib/py2/src/_backend_agg.h | |
parent | dd6d20cadb65582270ac23f4b3b14ae189704b9d (diff) | |
download | ydb-77eb2d3fdcec5c978c64e025ced2764c57c00285.tar.gz |
KIKIMR-19287: add task_stats_drawing script
Diffstat (limited to 'contrib/python/matplotlib/py2/src/_backend_agg.h')
-rw-r--r-- | contrib/python/matplotlib/py2/src/_backend_agg.h | 1294 |
1 files changed, 1294 insertions, 0 deletions
diff --git a/contrib/python/matplotlib/py2/src/_backend_agg.h b/contrib/python/matplotlib/py2/src/_backend_agg.h new file mode 100644 index 0000000000..53b73f179b --- /dev/null +++ b/contrib/python/matplotlib/py2/src/_backend_agg.h @@ -0,0 +1,1294 @@ +/* -*- mode: c++; c-basic-offset: 4 -*- */ + +/* _backend_agg.h +*/ + +#ifndef __BACKEND_AGG_H__ +#define __BACKEND_AGG_H__ + +#include <cmath> +#include <vector> +#include <algorithm> + +#include "agg_alpha_mask_u8.h" +#include "agg_conv_curve.h" +#include "agg_conv_dash.h" +#include "agg_conv_stroke.h" +#include "agg_image_accessors.h" +#include "agg_pixfmt_amask_adaptor.h" +#include "agg_pixfmt_gray.h" +#include "agg_pixfmt_rgba.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_base.h" +#include "agg_renderer_scanline.h" +#include "agg_rendering_buffer.h" +#include "agg_scanline_bin.h" +#include "agg_scanline_p.h" +#include "agg_scanline_storage_aa.h" +#include "agg_scanline_storage_bin.h" +#include "agg_scanline_u.h" +#include "agg_span_allocator.h" +#include "agg_span_converter.h" +#include "agg_span_gouraud_rgba.h" +#include "agg_span_image_filter_gray.h" +#include "agg_span_image_filter_rgba.h" +#include "agg_span_interpolator_linear.h" +#include "agg_span_pattern_rgba.h" +#include "util/agg_color_conv_rgb8.h" + +#include "_backend_agg_basic_types.h" +#include "path_converters.h" +#include "array.h" +#include "agg_workaround.h" + +/**********************************************************************/ + +// a helper class to pass agg::buffer objects around. agg::buffer is +// a class in the swig wrapper +class BufferRegion +{ + public: + BufferRegion(const agg::rect_i &r) : rect(r) + { + width = r.x2 - r.x1; + height = r.y2 - r.y1; + stride = width * 4; + data = new agg::int8u[stride * height]; + } + + virtual ~BufferRegion() + { + delete[] data; + }; + + agg::int8u *get_data() + { + return data; + } + + agg::rect_i &get_rect() + { + return rect; + } + + int get_width() + { + return width; + } + + int get_height() + { + return height; + } + + int get_stride() + { + return stride; + } + + void to_string_argb(uint8_t *buf); + + private: + agg::int8u *data; + agg::rect_i rect; + int width; + int height; + int stride; + + private: + // prevent copying + BufferRegion(const BufferRegion &); + BufferRegion &operator=(const BufferRegion &); +}; + +#define MARKER_CACHE_SIZE 512 + +// the renderer +class RendererAgg +{ + public: + + typedef fixed_blender_rgba_plain<agg::rgba8, agg::order_rgba> fixed_blender_rgba32_plain; + typedef agg::pixfmt_alpha_blend_rgba<fixed_blender_rgba32_plain, agg::rendering_buffer> pixfmt; + typedef agg::renderer_base<pixfmt> renderer_base; + typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_aa; + typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_bin; + typedef agg::rasterizer_scanline_aa<agg::rasterizer_sl_clip_dbl> rasterizer; + + typedef agg::scanline_p8 scanline_p8; + typedef agg::scanline_bin scanline_bin; + typedef agg::amask_no_clip_gray8 alpha_mask_type; + typedef agg::scanline_u8_am<alpha_mask_type> scanline_am; + + typedef agg::renderer_base<agg::pixfmt_gray8> renderer_base_alpha_mask_type; + typedef agg::renderer_scanline_aa_solid<renderer_base_alpha_mask_type> renderer_alpha_mask_type; + + /* TODO: Remove facepair_t */ + typedef std::pair<bool, agg::rgba> facepair_t; + + RendererAgg(unsigned int width, unsigned int height, double dpi); + + virtual ~RendererAgg(); + + unsigned int get_width() + { + return width; + } + + unsigned int get_height() + { + return height; + } + + template <class PathIterator> + void draw_path(GCAgg &gc, PathIterator &path, agg::trans_affine &trans, agg::rgba &color); + + template <class PathIterator> + void draw_markers(GCAgg &gc, + PathIterator &marker_path, + agg::trans_affine &marker_path_trans, + PathIterator &path, + agg::trans_affine &trans, + agg::rgba face); + + template <class ImageArray> + void draw_text_image(GCAgg &gc, ImageArray &image, int x, int y, double angle); + + template <class ImageArray> + void draw_image(GCAgg &gc, + double x, + double y, + ImageArray &image); + + template <class PathGenerator, + class TransformArray, + class OffsetArray, + class ColorArray, + class LineWidthArray, + class AntialiasedArray> + void draw_path_collection(GCAgg &gc, + agg::trans_affine &master_transform, + PathGenerator &path, + TransformArray &transforms, + OffsetArray &offsets, + agg::trans_affine &offset_trans, + ColorArray &facecolors, + ColorArray &edgecolors, + LineWidthArray &linewidths, + DashesVector &linestyles, + AntialiasedArray &antialiaseds, + e_offset_position offset_position); + + template <class CoordinateArray, class OffsetArray, class ColorArray> + void draw_quad_mesh(GCAgg &gc, + agg::trans_affine &master_transform, + unsigned int mesh_width, + unsigned int mesh_height, + CoordinateArray &coordinates, + OffsetArray &offsets, + agg::trans_affine &offset_trans, + ColorArray &facecolors, + bool antialiased, + ColorArray &edgecolors); + + template <class PointArray, class ColorArray> + void draw_gouraud_triangle(GCAgg &gc, + PointArray &points, + ColorArray &colors, + agg::trans_affine &trans); + + template <class PointArray, class ColorArray> + void draw_gouraud_triangles(GCAgg &gc, + PointArray &points, + ColorArray &colors, + agg::trans_affine &trans); + + void tostring_rgb(uint8_t *buf); + void tostring_argb(uint8_t *buf); + void tostring_bgra(uint8_t *buf); + agg::rect_i get_content_extents(); + void clear(); + + BufferRegion *copy_from_bbox(agg::rect_d in_rect); + void restore_region(BufferRegion ®); + void restore_region(BufferRegion ®ion, int xx1, int yy1, int xx2, int yy2, int x, int y); + + unsigned int width, height; + double dpi; + size_t NUMBYTES; // the number of bytes in buffer + + agg::int8u *pixBuffer; + agg::rendering_buffer renderingBuffer; + + agg::int8u *alphaBuffer; + agg::rendering_buffer alphaMaskRenderingBuffer; + alpha_mask_type alphaMask; + agg::pixfmt_gray8 pixfmtAlphaMask; + renderer_base_alpha_mask_type rendererBaseAlphaMask; + renderer_alpha_mask_type rendererAlphaMask; + scanline_am scanlineAlphaMask; + + scanline_p8 slineP8; + scanline_bin slineBin; + pixfmt pixFmt; + renderer_base rendererBase; + renderer_aa rendererAA; + renderer_bin rendererBin; + rasterizer theRasterizer; + + void *lastclippath; + agg::trans_affine lastclippath_transform; + + size_t hatch_size; + agg::int8u *hatchBuffer; + agg::rendering_buffer hatchRenderingBuffer; + + agg::rgba _fill_color; + + protected: + inline double points_to_pixels(double points) + { + return points * dpi / 72.0; + } + + template <class R> + void set_clipbox(const agg::rect_d &cliprect, R &rasterizer); + + bool render_clippath(py::PathIterator &clippath, const agg::trans_affine &clippath_trans); + + template <class PathIteratorType> + void _draw_path(PathIteratorType &path, bool has_clippath, const facepair_t &face, GCAgg &gc); + + template <class PathIterator, + class PathGenerator, + class TransformArray, + class OffsetArray, + class ColorArray, + class LineWidthArray, + class AntialiasedArray> + void _draw_path_collection_generic(GCAgg &gc, + agg::trans_affine master_transform, + const agg::rect_d &cliprect, + PathIterator &clippath, + const agg::trans_affine &clippath_trans, + PathGenerator &path_generator, + TransformArray &transforms, + OffsetArray &offsets, + const agg::trans_affine &offset_trans, + ColorArray &facecolors, + ColorArray &edgecolors, + LineWidthArray &linewidths, + DashesVector &linestyles, + AntialiasedArray &antialiaseds, + e_offset_position offset_position, + int check_snap, + int has_curves); + + template <class PointArray, class ColorArray> + void _draw_gouraud_triangle(PointArray &points, + ColorArray &colors, + agg::trans_affine trans, + bool has_clippath); + + private: + void create_alpha_buffers(); + + // prevent copying + RendererAgg(const RendererAgg &); + RendererAgg &operator=(const RendererAgg &); +}; + +/*************************************************************************** + * Implementation + */ + +template <class path_t> +inline void +RendererAgg::_draw_path(path_t &path, bool has_clippath, const facepair_t &face, GCAgg &gc) +{ + typedef agg::conv_stroke<path_t> stroke_t; + typedef agg::conv_dash<path_t> dash_t; + typedef agg::conv_stroke<dash_t> stroke_dash_t; + typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; + typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; + typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type; + typedef agg::renderer_scanline_bin_solid<amask_ren_type> amask_bin_renderer_type; + + // Render face + if (face.first) { + theRasterizer.add_path(path); + + if (gc.isaa) { + if (has_clippath) { + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + amask_aa_renderer_type ren(r); + ren.color(face.second); + agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren); + } else { + rendererAA.color(face.second); + agg::render_scanlines(theRasterizer, slineP8, rendererAA); + } + } else { + if (has_clippath) { + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + amask_bin_renderer_type ren(r); + ren.color(face.second); + agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren); + } else { + rendererBin.color(face.second); + agg::render_scanlines(theRasterizer, slineP8, rendererBin); + } + } + } + + // Render hatch + if (gc.has_hatchpath()) { + // Reset any clipping that may be in effect, since we'll be + // drawing the hatch in a scratch buffer at origin (0, 0) + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + + // Create and transform the path + typedef agg::conv_transform<py::PathIterator> hatch_path_trans_t; + typedef agg::conv_curve<hatch_path_trans_t> hatch_path_curve_t; + typedef agg::conv_stroke<hatch_path_curve_t> hatch_path_stroke_t; + + py::PathIterator hatch_path(gc.hatchpath); + agg::trans_affine hatch_trans; + hatch_trans *= agg::trans_affine_scaling(1.0, -1.0); + hatch_trans *= agg::trans_affine_translation(0.0, 1.0); + hatch_trans *= agg::trans_affine_scaling(hatch_size, hatch_size); + hatch_path_trans_t hatch_path_trans(hatch_path, hatch_trans); + hatch_path_curve_t hatch_path_curve(hatch_path_trans); + hatch_path_stroke_t hatch_path_stroke(hatch_path_curve); + hatch_path_stroke.width(points_to_pixels(gc.hatch_linewidth)); + hatch_path_stroke.line_cap(agg::square_cap); + + // Render the path into the hatch buffer + pixfmt hatch_img_pixf(hatchRenderingBuffer); + renderer_base rb(hatch_img_pixf); + renderer_aa rs(rb); + rb.clear(_fill_color); + rs.color(gc.hatch_color); + + theRasterizer.add_path(hatch_path_curve); + agg::render_scanlines(theRasterizer, slineP8, rs); + theRasterizer.add_path(hatch_path_stroke); + agg::render_scanlines(theRasterizer, slineP8, rs); + + // Put clipping back on, if originally set on entry to this + // function + set_clipbox(gc.cliprect, theRasterizer); + if (has_clippath) { + render_clippath(gc.clippath.path, gc.clippath.trans); + } + + // Transfer the hatch to the main image buffer + typedef agg::image_accessor_wrap<pixfmt, + agg::wrap_mode_repeat_auto_pow2, + agg::wrap_mode_repeat_auto_pow2> img_source_type; + typedef agg::span_pattern_rgba<img_source_type> span_gen_type; + agg::span_allocator<agg::rgba8> sa; + img_source_type img_src(hatch_img_pixf); + span_gen_type sg(img_src, 0, 0); + theRasterizer.add_path(path); + + if (has_clippath) { + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type ren(pfa); + agg::render_scanlines_aa(theRasterizer, slineP8, ren, sa, sg); + } else { + agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, sa, sg); + } + } + + // Render stroke + if (gc.linewidth != 0.0) { + double linewidth = points_to_pixels(gc.linewidth); + if (!gc.isaa) { + linewidth = (linewidth < 0.5) ? 0.5 : mpl_round(linewidth); + } + if (gc.dashes.size() == 0) { + stroke_t stroke(path); + stroke.width(points_to_pixels(gc.linewidth)); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + stroke.miter_limit(points_to_pixels(gc.linewidth)); + theRasterizer.add_path(stroke); + } else { + dash_t dash(path); + gc.dashes.dash_to_stroke(dash, dpi, gc.isaa); + stroke_dash_t stroke(dash); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + stroke.width(linewidth); + stroke.miter_limit(points_to_pixels(gc.linewidth)); + theRasterizer.add_path(stroke); + } + + if (gc.isaa) { + if (has_clippath) { + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + amask_aa_renderer_type ren(r); + ren.color(gc.color); + agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren); + } else { + rendererAA.color(gc.color); + agg::render_scanlines(theRasterizer, slineP8, rendererAA); + } + } else { + if (has_clippath) { + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + amask_bin_renderer_type ren(r); + ren.color(gc.color); + agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren); + } else { + rendererBin.color(gc.color); + agg::render_scanlines(theRasterizer, slineBin, rendererBin); + } + } + } +} + +template <class PathIterator> +inline void +RendererAgg::draw_path(GCAgg &gc, PathIterator &path, agg::trans_affine &trans, agg::rgba &color) +{ + typedef agg::conv_transform<py::PathIterator> transformed_path_t; + typedef PathNanRemover<transformed_path_t> nan_removed_t; + typedef PathClipper<nan_removed_t> clipped_t; + typedef PathSnapper<clipped_t> snapped_t; + typedef PathSimplifier<snapped_t> simplify_t; + typedef agg::conv_curve<simplify_t> curve_t; + typedef Sketch<curve_t> sketch_t; + + facepair_t face(color.a != 0.0, color); + + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(gc.cliprect, theRasterizer); + bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans); + + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.0, (double)height); + bool clip = !face.first && !gc.has_hatchpath() && !path.has_curves(); + bool simplify = path.should_simplify() && clip; + double snapping_linewidth = points_to_pixels(gc.linewidth); + if (gc.color.a == 0.0) { + snapping_linewidth = 0.0; + } + + transformed_path_t tpath(path, trans); + nan_removed_t nan_removed(tpath, true, path.has_curves()); + clipped_t clipped(nan_removed, clip && !path.has_curves(), width, height); + snapped_t snapped(clipped, gc.snap_mode, path.total_vertices(), snapping_linewidth); + simplify_t simplified(snapped, simplify, path.simplify_threshold()); + curve_t curve(simplified); + sketch_t sketch(curve, gc.sketch.scale, gc.sketch.length, gc.sketch.randomness); + + _draw_path(sketch, has_clippath, face, gc); +} + +template <class PathIterator> +inline void RendererAgg::draw_markers(GCAgg &gc, + PathIterator &marker_path, + agg::trans_affine &marker_trans, + PathIterator &path, + agg::trans_affine &trans, + agg::rgba color) +{ + typedef agg::conv_transform<py::PathIterator> transformed_path_t; + typedef PathNanRemover<transformed_path_t> nan_removed_t; + typedef PathSnapper<nan_removed_t> snap_t; + typedef agg::conv_curve<snap_t> curve_t; + typedef agg::conv_stroke<curve_t> stroke_t; + typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; + typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; + typedef agg::renderer_scanline_aa_solid<amask_ren_type> amask_aa_renderer_type; + + // Deal with the difference in y-axis direction + marker_trans *= agg::trans_affine_scaling(1.0, -1.0); + + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.5, (double)height + 0.5); + + transformed_path_t marker_path_transformed(marker_path, marker_trans); + nan_removed_t marker_path_nan_removed(marker_path_transformed, true, marker_path.has_curves()); + snap_t marker_path_snapped(marker_path_nan_removed, + gc.snap_mode, + marker_path.total_vertices(), + points_to_pixels(gc.linewidth)); + curve_t marker_path_curve(marker_path_snapped); + + if (!marker_path_snapped.is_snapping()) { + // If the path snapper isn't in effect, at least make sure the marker + // at (0, 0) is in the center of a pixel. This, importantly, makes + // the circle markers look centered around the point they refer to. + marker_trans *= agg::trans_affine_translation(0.5, 0.5); + } + + transformed_path_t path_transformed(path, trans); + nan_removed_t path_nan_removed(path_transformed, false, false); + snap_t path_snapped(path_nan_removed, SNAP_FALSE, path.total_vertices(), 0.0); + curve_t path_curve(path_snapped); + path_curve.rewind(0); + + facepair_t face(color.a != 0.0, color); + + // maxim's suggestions for cached scanlines + agg::scanline_storage_aa8 scanlines; + theRasterizer.reset(); + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + agg::rect_i marker_size(0x7FFFFFFF, 0x7FFFFFFF, -0x7FFFFFFF, -0x7FFFFFFF); + + agg::int8u staticFillCache[MARKER_CACHE_SIZE]; + agg::int8u staticStrokeCache[MARKER_CACHE_SIZE]; + agg::int8u *fillCache = staticFillCache; + agg::int8u *strokeCache = staticStrokeCache; + + try + { + unsigned fillSize = 0; + if (face.first) { + theRasterizer.add_path(marker_path_curve); + agg::render_scanlines(theRasterizer, slineP8, scanlines); + fillSize = scanlines.byte_size(); + if (fillSize >= MARKER_CACHE_SIZE) { + fillCache = new agg::int8u[fillSize]; + } + scanlines.serialize(fillCache); + marker_size = agg::rect_i(scanlines.min_x(), + scanlines.min_y(), + scanlines.max_x(), + scanlines.max_y()); + } + + stroke_t stroke(marker_path_curve); + stroke.width(points_to_pixels(gc.linewidth)); + stroke.line_cap(gc.cap); + stroke.line_join(gc.join); + stroke.miter_limit(points_to_pixels(gc.linewidth)); + theRasterizer.reset(); + theRasterizer.add_path(stroke); + agg::render_scanlines(theRasterizer, slineP8, scanlines); + unsigned strokeSize = scanlines.byte_size(); + if (strokeSize >= MARKER_CACHE_SIZE) { + strokeCache = new agg::int8u[strokeSize]; + } + scanlines.serialize(strokeCache); + marker_size = agg::rect_i(std::min(marker_size.x1, scanlines.min_x()), + std::min(marker_size.y1, scanlines.min_y()), + std::max(marker_size.x2, scanlines.max_x()), + std::max(marker_size.y2, scanlines.max_y())); + + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(gc.cliprect, rendererBase); + bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans); + + double x, y; + + agg::serialized_scanlines_adaptor_aa8 sa; + agg::serialized_scanlines_adaptor_aa8::embedded_scanline sl; + + agg::rect_d clipping_rect(-1.0 - marker_size.x2, + -1.0 - marker_size.y2, + 1.0 + width - marker_size.x1, + 1.0 + height - marker_size.y1); + + if (has_clippath) { + while (path_curve.vertex(&x, &y) != agg::path_cmd_stop) { + if (!(std::isfinite(x) && std::isfinite(y))) { + continue; + } + + /* These values are correctly snapped above -- so we don't want + to round here, we really only want to truncate */ + x = floor(x); + y = floor(y); + + // Cull points outside the boundary of the image. + // Values that are too large may overflow and create + // segfaults. + // http://sourceforge.net/tracker/?func=detail&aid=2865490&group_id=80706&atid=560720 + if (!clipping_rect.hit_test(x, y)) { + continue; + } + + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + amask_aa_renderer_type ren(r); + + if (face.first) { + ren.color(face.second); + sa.init(fillCache, fillSize, x, y); + agg::render_scanlines(sa, sl, ren); + } + ren.color(gc.color); + sa.init(strokeCache, strokeSize, x, y); + agg::render_scanlines(sa, sl, ren); + } + } else { + while (path_curve.vertex(&x, &y) != agg::path_cmd_stop) { + if (!(std::isfinite(x) && std::isfinite(y))) { + continue; + } + + /* These values are correctly snapped above -- so we don't want + to round here, we really only want to truncate */ + x = floor(x); + y = floor(y); + + // Cull points outside the boundary of the image. + // Values that are too large may overflow and create + // segfaults. + // http://sourceforge.net/tracker/?func=detail&aid=2865490&group_id=80706&atid=560720 + if (!clipping_rect.hit_test(x, y)) { + continue; + } + + if (face.first) { + rendererAA.color(face.second); + sa.init(fillCache, fillSize, x, y); + agg::render_scanlines(sa, sl, rendererAA); + } + + rendererAA.color(gc.color); + sa.init(strokeCache, strokeSize, x, y); + agg::render_scanlines(sa, sl, rendererAA); + } + } + } + catch (...) + { + if (fillCache != staticFillCache) + delete[] fillCache; + if (strokeCache != staticStrokeCache) + delete[] strokeCache; + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + throw; + } + + if (fillCache != staticFillCache) + delete[] fillCache; + if (strokeCache != staticStrokeCache) + delete[] strokeCache; + + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); +} + +/** + * This is a custom span generator that converts spans in the + * 8-bit inverted greyscale font buffer to rgba that agg can use. + */ +template <class ChildGenerator> +class font_to_rgba +{ + public: + typedef ChildGenerator child_type; + typedef agg::rgba8 color_type; + typedef typename child_type::color_type child_color_type; + typedef agg::span_allocator<child_color_type> span_alloc_type; + + private: + child_type *_gen; + color_type _color; + span_alloc_type _allocator; + + public: + font_to_rgba(child_type *gen, color_type color) : _gen(gen), _color(color) + { + } + + inline void generate(color_type *output_span, int x, int y, unsigned len) + { + _allocator.allocate(len); + child_color_type *input_span = _allocator.span(); + _gen->generate(input_span, x, y, len); + + do { + *output_span = _color; + output_span->a = ((unsigned int)_color.a * (unsigned int)input_span->v) >> 8; + ++output_span; + ++input_span; + } while (--len); + } + + void prepare() + { + _gen->prepare(); + } +}; + +template <class ImageArray> +inline void RendererAgg::draw_text_image(GCAgg &gc, ImageArray &image, int x, int y, double angle) +{ + typedef agg::span_allocator<agg::rgba8> color_span_alloc_type; + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::image_accessor_clip<agg::pixfmt_gray8> image_accessor_type; + typedef agg::span_image_filter_gray<image_accessor_type, interpolator_type> image_span_gen_type; + typedef font_to_rgba<image_span_gen_type> span_gen_type; + typedef agg::renderer_scanline_aa<renderer_base, color_span_alloc_type, span_gen_type> + renderer_type; + + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + if (angle != 0.0) { + agg::rendering_buffer srcbuf( + image.data(), (unsigned)image.dim(1), + (unsigned)image.dim(0), (unsigned)image.dim(1)); + agg::pixfmt_gray8 pixf_img(srcbuf); + + set_clipbox(gc.cliprect, theRasterizer); + + agg::trans_affine mtx; + mtx *= agg::trans_affine_translation(0, -image.dim(0)); + mtx *= agg::trans_affine_rotation(-angle * agg::pi / 180.0); + mtx *= agg::trans_affine_translation(x, y); + + agg::path_storage rect; + rect.move_to(0, 0); + rect.line_to(image.dim(1), 0); + rect.line_to(image.dim(1), image.dim(0)); + rect.line_to(0, image.dim(0)); + rect.line_to(0, 0); + agg::conv_transform<agg::path_storage> rect2(rect, mtx); + + agg::trans_affine inv_mtx(mtx); + inv_mtx.invert(); + + agg::image_filter_lut filter; + filter.calculate(agg::image_filter_spline36()); + interpolator_type interpolator(inv_mtx); + color_span_alloc_type sa; + image_accessor_type ia(pixf_img, agg::gray8(0)); + image_span_gen_type image_span_generator(ia, interpolator, filter); + span_gen_type output_span_generator(&image_span_generator, gc.color); + renderer_type ri(rendererBase, sa, output_span_generator); + + theRasterizer.add_path(rect2); + agg::render_scanlines(theRasterizer, slineP8, ri); + } else { + agg::rect_i fig, text; + + fig.init(0, 0, width, height); + text.init(x, y - image.dim(0), x + image.dim(1), y); + text.clip(fig); + + if (gc.cliprect.x1 != 0.0 || gc.cliprect.y1 != 0.0 || gc.cliprect.x2 != 0.0 || gc.cliprect.y2 != 0.0) { + agg::rect_i clip; + + clip.init(int(mpl_round(gc.cliprect.x1)), + int(mpl_round(height - gc.cliprect.y2)), + int(mpl_round(gc.cliprect.x2)), + int(mpl_round(height - gc.cliprect.y1))); + text.clip(clip); + } + + if (text.x2 > text.x1) { + for (int yi = text.y1; yi < text.y2; ++yi) { + pixFmt.blend_solid_hspan(text.x1, yi, (text.x2 - text.x1), gc.color, + &image(yi - (y - image.dim(0)), text.x1 - x)); + } + } + } +} + +class span_conv_alpha +{ + public: + typedef agg::rgba8 color_type; + + double m_alpha; + + span_conv_alpha(double alpha) : m_alpha(alpha) + { + } + + void prepare() + { + } + void generate(color_type *span, int x, int y, unsigned len) const + { + do { + span->a = (agg::int8u)((double)span->a * m_alpha); + ++span; + } while (--len); + } +}; + +template <class ImageArray> +inline void RendererAgg::draw_image(GCAgg &gc, + double x, + double y, + ImageArray &image) +{ + double alpha = gc.alpha; + + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(gc.cliprect, theRasterizer); + bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans); + + agg::rendering_buffer buffer; + buffer.attach( + image.data(), (unsigned)image.dim(1), (unsigned)image.dim(0), -(int)image.dim(1) * 4); + pixfmt pixf(buffer); + + if (has_clippath) { + agg::trans_affine mtx; + agg::path_storage rect; + + mtx *= agg::trans_affine_translation((int)x, (int)(height - (y + image.dim(0)))); + + rect.move_to(0, 0); + rect.line_to(image.dim(1), 0); + rect.line_to(image.dim(1), image.dim(0)); + rect.line_to(0, image.dim(0)); + rect.line_to(0, 0); + + agg::conv_transform<agg::path_storage> rect2(rect, mtx); + + agg::trans_affine inv_mtx(mtx); + inv_mtx.invert(); + + typedef agg::span_allocator<agg::rgba8> color_span_alloc_type; + typedef agg::image_accessor_clip<pixfmt> image_accessor_type; + typedef agg::span_interpolator_linear<> interpolator_type; + typedef agg::span_image_filter_rgba_nn<image_accessor_type, interpolator_type> + image_span_gen_type; + typedef agg::span_converter<image_span_gen_type, span_conv_alpha> span_conv; + + color_span_alloc_type sa; + image_accessor_type ia(pixf, agg::rgba8(0, 0, 0, 0)); + interpolator_type interpolator(inv_mtx); + image_span_gen_type image_span_generator(ia, interpolator); + span_conv_alpha conv_alpha(alpha); + span_conv spans(image_span_generator, conv_alpha); + + typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; + typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; + typedef agg::renderer_scanline_aa<amask_ren_type, color_span_alloc_type, span_conv> + renderer_type_alpha; + + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + renderer_type_alpha ri(r, sa, spans); + + theRasterizer.add_path(rect2); + agg::render_scanlines(theRasterizer, scanlineAlphaMask, ri); + } else { + set_clipbox(gc.cliprect, rendererBase); + rendererBase.blend_from( + pixf, 0, (int)x, (int)(height - (y + image.dim(0))), (agg::int8u)(alpha * 255)); + } + + rendererBase.reset_clipping(true); +} + +template <class PathIterator, + class PathGenerator, + class TransformArray, + class OffsetArray, + class ColorArray, + class LineWidthArray, + class AntialiasedArray> +inline void RendererAgg::_draw_path_collection_generic(GCAgg &gc, + agg::trans_affine master_transform, + const agg::rect_d &cliprect, + PathIterator &clippath, + const agg::trans_affine &clippath_trans, + PathGenerator &path_generator, + TransformArray &transforms, + OffsetArray &offsets, + const agg::trans_affine &offset_trans, + ColorArray &facecolors, + ColorArray &edgecolors, + LineWidthArray &linewidths, + DashesVector &linestyles, + AntialiasedArray &antialiaseds, + e_offset_position offset_position, + int check_snap, + int has_curves) +{ + typedef agg::conv_transform<typename PathGenerator::path_iterator> transformed_path_t; + typedef PathNanRemover<transformed_path_t> nan_removed_t; + typedef PathClipper<nan_removed_t> clipped_t; + typedef PathSnapper<clipped_t> snapped_t; + typedef agg::conv_curve<snapped_t> snapped_curve_t; + typedef agg::conv_curve<clipped_t> curve_t; + + size_t Npaths = path_generator.num_paths(); + size_t Noffsets = offsets.size(); + size_t N = std::max(Npaths, Noffsets); + + size_t Ntransforms = transforms.size(); + size_t Nfacecolors = facecolors.size(); + size_t Nedgecolors = edgecolors.size(); + size_t Nlinewidths = linewidths.size(); + size_t Nlinestyles = std::min(linestyles.size(), N); + size_t Naa = antialiaseds.size(); + + if ((Nfacecolors == 0 && Nedgecolors == 0) || Npaths == 0) { + return; + } + + // Handle any clipping globally + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(cliprect, theRasterizer); + bool has_clippath = render_clippath(clippath, clippath_trans); + + // Set some defaults, assuming no face or edge + gc.linewidth = 0.0; + facepair_t face; + face.first = Nfacecolors != 0; + agg::trans_affine trans; + + for (int i = 0; i < (int)N; ++i) { + typename PathGenerator::path_iterator path = path_generator(i); + + if (Ntransforms) { + int it = i % Ntransforms; + trans = agg::trans_affine(transforms(it, 0, 0), + transforms(it, 1, 0), + transforms(it, 0, 1), + transforms(it, 1, 1), + transforms(it, 0, 2), + transforms(it, 1, 2)); + trans *= master_transform; + } else { + trans = master_transform; + } + + if (Noffsets) { + double xo = offsets(i % Noffsets, 0); + double yo = offsets(i % Noffsets, 1); + offset_trans.transform(&xo, &yo); + if (offset_position == OFFSET_POSITION_DATA) { + trans = agg::trans_affine_translation(xo, yo) * trans; + } else { + trans *= agg::trans_affine_translation(xo, yo); + } + } + + // These transformations must be done post-offsets + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.0, (double)height); + + if (Nfacecolors) { + int ic = i % Nfacecolors; + face.second = agg::rgba(facecolors(ic, 0), facecolors(ic, 1), facecolors(ic, 2), facecolors(ic, 3)); + } + + if (Nedgecolors) { + int ic = i % Nedgecolors; + gc.color = agg::rgba(edgecolors(ic, 0), edgecolors(ic, 1), edgecolors(ic, 2), edgecolors(ic, 3)); + + if (Nlinewidths) { + gc.linewidth = linewidths(i % Nlinewidths); + } else { + gc.linewidth = 1.0; + } + if (Nlinestyles) { + gc.dashes = linestyles[i % Nlinestyles]; + } + } + + bool do_clip = !face.first && !gc.has_hatchpath() && !has_curves; + + if (check_snap) { + gc.isaa = antialiaseds(i % Naa); + + transformed_path_t tpath(path, trans); + nan_removed_t nan_removed(tpath, true, has_curves); + clipped_t clipped(nan_removed, do_clip && !has_curves, width, height); + snapped_t snapped( + clipped, gc.snap_mode, path.total_vertices(), points_to_pixels(gc.linewidth)); + if (has_curves) { + snapped_curve_t curve(snapped); + _draw_path(curve, has_clippath, face, gc); + } else { + _draw_path(snapped, has_clippath, face, gc); + } + } else { + gc.isaa = antialiaseds(i % Naa); + + transformed_path_t tpath(path, trans); + nan_removed_t nan_removed(tpath, true, has_curves); + clipped_t clipped(nan_removed, do_clip, width, height); + if (has_curves) { + curve_t curve(clipped); + _draw_path(curve, has_clippath, face, gc); + } else { + _draw_path(clipped, has_clippath, face, gc); + } + } + } +} + +template <class PathGenerator, + class TransformArray, + class OffsetArray, + class ColorArray, + class LineWidthArray, + class AntialiasedArray> +inline void RendererAgg::draw_path_collection(GCAgg &gc, + agg::trans_affine &master_transform, + PathGenerator &path, + TransformArray &transforms, + OffsetArray &offsets, + agg::trans_affine &offset_trans, + ColorArray &facecolors, + ColorArray &edgecolors, + LineWidthArray &linewidths, + DashesVector &linestyles, + AntialiasedArray &antialiaseds, + e_offset_position offset_position) +{ + _draw_path_collection_generic(gc, + master_transform, + gc.cliprect, + gc.clippath.path, + gc.clippath.trans, + path, + transforms, + offsets, + offset_trans, + facecolors, + edgecolors, + linewidths, + linestyles, + antialiaseds, + offset_position, + 1, + 1); +} + +template <class CoordinateArray> +class QuadMeshGenerator +{ + unsigned m_meshWidth; + unsigned m_meshHeight; + CoordinateArray m_coordinates; + + class QuadMeshPathIterator + { + unsigned m_iterator; + unsigned m_m, m_n; + const CoordinateArray *m_coordinates; + + public: + QuadMeshPathIterator(unsigned m, unsigned n, const CoordinateArray *coordinates) + : m_iterator(0), m_m(m), m_n(n), m_coordinates(coordinates) + { + } + + private: + inline unsigned vertex(unsigned idx, double *x, double *y) + { + size_t m = m_m + ((idx & 0x2) >> 1); + size_t n = m_n + (((idx + 1) & 0x2) >> 1); + *x = (*m_coordinates)(n, m, 0); + *y = (*m_coordinates)(n, m, 1); + return (idx) ? agg::path_cmd_line_to : agg::path_cmd_move_to; + } + + public: + inline unsigned vertex(double *x, double *y) + { + if (m_iterator >= total_vertices()) { + return agg::path_cmd_stop; + } + return vertex(m_iterator++, x, y); + } + + inline void rewind(unsigned path_id) + { + m_iterator = path_id; + } + + inline unsigned total_vertices() + { + return 5; + } + + inline bool should_simplify() + { + return false; + } + }; + + public: + typedef QuadMeshPathIterator path_iterator; + + inline QuadMeshGenerator(unsigned meshWidth, unsigned meshHeight, CoordinateArray &coordinates) + : m_meshWidth(meshWidth), m_meshHeight(meshHeight), m_coordinates(coordinates) + { + } + + inline size_t num_paths() const + { + return m_meshWidth * m_meshHeight; + } + + inline path_iterator operator()(size_t i) const + { + return QuadMeshPathIterator(i % m_meshWidth, i / m_meshWidth, &m_coordinates); + } +}; + +template <class CoordinateArray, class OffsetArray, class ColorArray> +inline void RendererAgg::draw_quad_mesh(GCAgg &gc, + agg::trans_affine &master_transform, + unsigned int mesh_width, + unsigned int mesh_height, + CoordinateArray &coordinates, + OffsetArray &offsets, + agg::trans_affine &offset_trans, + ColorArray &facecolors, + bool antialiased, + ColorArray &edgecolors) +{ + QuadMeshGenerator<CoordinateArray> path_generator(mesh_width, mesh_height, coordinates); + + array::empty<double> transforms; + array::scalar<double, 1> linewidths(gc.linewidth); + array::scalar<uint8_t, 1> antialiaseds(antialiased); + DashesVector linestyles; + ColorArray *edgecolors_ptr = &edgecolors; + + if (edgecolors.size() == 0) { + if (antialiased) { + edgecolors_ptr = &facecolors; + } + } + + _draw_path_collection_generic(gc, + master_transform, + gc.cliprect, + gc.clippath.path, + gc.clippath.trans, + path_generator, + transforms, + offsets, + offset_trans, + facecolors, + *edgecolors_ptr, + linewidths, + linestyles, + antialiaseds, + OFFSET_POSITION_FIGURE, + 0, + 0); +} + +template <class PointArray, class ColorArray> +inline void RendererAgg::_draw_gouraud_triangle(PointArray &points, + ColorArray &colors, + agg::trans_affine trans, + bool has_clippath) +{ + typedef agg::rgba8 color_t; + typedef agg::span_gouraud_rgba<color_t> span_gen_t; + typedef agg::span_allocator<color_t> span_alloc_t; + + trans *= agg::trans_affine_scaling(1.0, -1.0); + trans *= agg::trans_affine_translation(0.0, (double)height); + + double tpoints[3][2]; + + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 2; ++j) { + tpoints[i][j] = points(i, j); + } + trans.transform(&tpoints[i][0], &tpoints[i][1]); + } + + span_alloc_t span_alloc; + span_gen_t span_gen; + + span_gen.colors(agg::rgba(colors(0, 0), colors(0, 1), colors(0, 2), colors(0, 3)), + agg::rgba(colors(1, 0), colors(1, 1), colors(1, 2), colors(1, 3)), + agg::rgba(colors(2, 0), colors(2, 1), colors(2, 2), colors(2, 3))); + span_gen.triangle(tpoints[0][0], + tpoints[0][1], + tpoints[1][0], + tpoints[1][1], + tpoints[2][0], + tpoints[2][1], + 0.5); + + theRasterizer.add_path(span_gen); + + if (has_clippath) { + typedef agg::pixfmt_amask_adaptor<pixfmt, alpha_mask_type> pixfmt_amask_type; + typedef agg::renderer_base<pixfmt_amask_type> amask_ren_type; + typedef agg::renderer_scanline_aa<amask_ren_type, span_alloc_t, span_gen_t> + amask_aa_renderer_type; + + pixfmt_amask_type pfa(pixFmt, alphaMask); + amask_ren_type r(pfa); + amask_aa_renderer_type ren(r, span_alloc, span_gen); + agg::render_scanlines(theRasterizer, scanlineAlphaMask, ren); + } else { + agg::render_scanlines_aa(theRasterizer, slineP8, rendererBase, span_alloc, span_gen); + } +} + +template <class PointArray, class ColorArray> +inline void RendererAgg::draw_gouraud_triangle(GCAgg &gc, + PointArray &points, + ColorArray &colors, + agg::trans_affine &trans) +{ + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(gc.cliprect, theRasterizer); + bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans); + + _draw_gouraud_triangle(points, colors, trans, has_clippath); +} + +template <class PointArray, class ColorArray> +inline void RendererAgg::draw_gouraud_triangles(GCAgg &gc, + PointArray &points, + ColorArray &colors, + agg::trans_affine &trans) +{ + theRasterizer.reset_clipping(); + rendererBase.reset_clipping(true); + set_clipbox(gc.cliprect, theRasterizer); + bool has_clippath = render_clippath(gc.clippath.path, gc.clippath.trans); + + for (int i = 0; i < points.dim(0); ++i) { + typename PointArray::sub_t point = points.subarray(i); + typename ColorArray::sub_t color = colors.subarray(i); + + _draw_gouraud_triangle(point, color, trans, has_clippath); + } +} + +template <class R> +void RendererAgg::set_clipbox(const agg::rect_d &cliprect, R &rasterizer) +{ + // set the clip rectangle from the gc + + if (cliprect.x1 != 0.0 || cliprect.y1 != 0.0 || cliprect.x2 != 0.0 || cliprect.y2 != 0.0) { + rasterizer.clip_box(std::max(int(floor(cliprect.x1 + 0.5)), 0), + std::max(int(floor(height - cliprect.y1 + 0.5)), 0), + std::min(int(floor(cliprect.x2 + 0.5)), int(width)), + std::min(int(floor(height - cliprect.y2 + 0.5)), int(height))); + } else { + rasterizer.clip_box(0, 0, width, height); + } +} + +#endif |