diff options
Diffstat (limited to '')
-rw-r--r-- | src/object/sp-mesh-gradient.cpp | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/src/object/sp-mesh-gradient.cpp b/src/object/sp-mesh-gradient.cpp new file mode 100644 index 0000000..47293da --- /dev/null +++ b/src/object/sp-mesh-gradient.cpp @@ -0,0 +1,270 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/** @file + * TODO: insert short description here + *//* + * Authors: see git history + * + * Copyright (C) 2018 Authors + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ +#include <glibmm.h> + +#include "attributes.h" +#include "display/cairo-utils.h" + +#include "sp-mesh-gradient.h" + +/* + * Mesh Gradient + */ +//#define MESH_DEBUG +//#define OBJECT_TRACE + +SPMeshGradient::SPMeshGradient() : SPGradient(), type( SP_MESH_TYPE_COONS ), type_set(false) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::SPMeshGradient" ); +#endif + + // Start coordinate of mesh + this->x.unset(SVGLength::NONE, 0.0, 0.0); + this->y.unset(SVGLength::NONE, 0.0, 0.0); + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::SPMeshGradient", false ); +#endif +} + +SPMeshGradient::~SPMeshGradient() { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::~SPMeshGradient (empty function)" ); + objectTrace( "SPMeshGradient::~SPMeshGradient", false ); +#endif +} + +void SPMeshGradient::build(SPDocument *document, Inkscape::XML::Node *repr) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::build" ); +#endif + + SPGradient::build(document, repr); + + // Start coordinate of meshgradient + this->readAttr(SPAttr::X); + this->readAttr(SPAttr::Y); + + this->readAttr(SPAttr::TYPE); + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::build", false ); +#endif +} + + +void SPMeshGradient::set(SPAttr key, gchar const *value) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::set" ); +#endif + + switch (key) { + case SPAttr::X: + if (!this->x.read(value)) { + this->x.unset(SVGLength::NONE, 0.0, 0.0); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SPAttr::Y: + if (!this->y.read(value)) { + this->y.unset(SVGLength::NONE, 0.0, 0.0); + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + case SPAttr::TYPE: + if (value) { + if (!strcmp(value, "coons")) { + this->type = SP_MESH_TYPE_COONS; + } else if (!strcmp(value, "bicubic")) { + this->type = SP_MESH_TYPE_BICUBIC; + } else { + std::cerr << "SPMeshGradient::set(): invalid value " << value << std::endl; + } + this->type_set = TRUE; + } else { + // std::cout << "SPMeshGradient::set() No value " << std::endl; + this->type = SP_MESH_TYPE_COONS; + this->type_set = FALSE; + } + + this->requestModified(SP_OBJECT_MODIFIED_FLAG); + break; + + default: + SPGradient::set(key, value); + break; + } + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::set", false ); +#endif +} + +/** + * Write mesh gradient attributes to associated repr. + */ +Inkscape::XML::Node* SPMeshGradient::write(Inkscape::XML::Document *xml_doc, Inkscape::XML::Node *repr, guint flags) { +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::write", false ); +#endif + + if ((flags & SP_OBJECT_WRITE_BUILD) && !repr) { + repr = xml_doc->createElement("svg:meshgradient"); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->x._set) { + repr->setAttributeSvgDouble("x", this->x.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->y._set) { + repr->setAttributeSvgDouble("y", this->y.computed); + } + + if ((flags & SP_OBJECT_WRITE_ALL) || this->type_set) { + switch (this->type) { + case SP_MESH_TYPE_COONS: + repr->setAttribute("type", "coons"); + break; + case SP_MESH_TYPE_BICUBIC: + repr->setAttribute("type", "bicubic"); + break; + default: + // Do nothing + break; + } + } + + SPGradient::write(xml_doc, repr, flags); + +#ifdef OBJECT_TRACE + objectTrace( "SPMeshGradient::write", false ); +#endif + return repr; +} + +cairo_pattern_t* SPMeshGradient::pattern_new(cairo_t * /*ct*/, + Geom::OptRect const &bbox, + double opacity) +{ + using Geom::X; + using Geom::Y; + +#ifdef MESH_DEBUG + std::cout << "sp_meshgradient_create_pattern: " << (*bbox) << " " << opacity << std::endl; +#endif + + this->ensureArray(); + + cairo_pattern_t *cp = nullptr; + + SPMeshNodeArray* my_array = &array; + + if( type_set ) { + switch (type) { + case SP_MESH_TYPE_COONS: + // std::cout << "SPMeshGradient::pattern_new: Coons" << std::endl; + break; + case SP_MESH_TYPE_BICUBIC: + array.bicubic( &array_smoothed, type ); + my_array = &array_smoothed; + break; + } + } + + cp = cairo_pattern_create_mesh(); + + for( unsigned int i = 0; i < my_array->patch_rows(); ++i ) { + for( unsigned int j = 0; j < my_array->patch_columns(); ++j ) { + + SPMeshPatchI patch( &(my_array->nodes), i, j ); + + cairo_mesh_pattern_begin_patch( cp ); + cairo_mesh_pattern_move_to( cp, patch.getPoint( 0, 0 )[X], patch.getPoint( 0, 0 )[Y] ); + + for( unsigned int k = 0; k < 4; ++k ) { +#ifdef DEBUG_MESH + std::cout << i << " " << j << " " + << patch.getPathType( k ) << " ("; + for( int p = 0; p < 4; ++p ) { + std::cout << patch.getPoint( k, p ); + } + std::cout << ") " + << patch.getColor( k ).toString() << std::endl; +#endif + + switch ( patch.getPathType( k ) ) { + case 'l': + case 'L': + case 'z': + case 'Z': + cairo_mesh_pattern_line_to( cp, + patch.getPoint( k, 3 )[X], + patch.getPoint( k, 3 )[Y] ); + break; + case 'c': + case 'C': + { + std::vector< Geom::Point > pts = patch.getPointsForSide( k ); + cairo_mesh_pattern_curve_to( cp, + pts[1][X], pts[1][Y], + pts[2][X], pts[2][Y], + pts[3][X], pts[3][Y] ); + break; + } + default: + // Shouldn't happen + std::cout << "sp_mesh_create_pattern: path error" << std::endl; + } + + if( patch.tensorIsSet(k) ) { + // Tensor point defined relative to corner. + Geom::Point t = patch.getTensorPoint(k); + cairo_mesh_pattern_set_control_point( cp, k, t[X], t[Y] ); + //std::cout << " sp_mesh_create_pattern: tensor " << k + // << " set to " << t << "." << std::endl; + } else { + // Geom::Point t = patch.coonsTensorPoint(k); + //std::cout << " sp_mesh_create_pattern: tensor " << k + // << " calculated as " << t << "." <<std::endl; + } + + cairo_mesh_pattern_set_corner_color_rgba( + cp, k, + patch.getColor( k ).v.c[0], + patch.getColor( k ).v.c[1], + patch.getColor( k ).v.c[2], + patch.getOpacity( k ) * opacity ); + } + + cairo_mesh_pattern_end_patch( cp ); + } + } + + // set pattern matrix + Geom::Affine gs2user = this->gradientTransform; + if (this->getUnits() == SP_GRADIENT_UNITS_OBJECTBOUNDINGBOX) { + Geom::Affine bbox2user(bbox->width(), 0, 0, bbox->height(), bbox->left(), bbox->top()); + gs2user *= bbox2user; + } + ink_cairo_pattern_set_matrix(cp, gs2user.inverse()); + + /* + cairo_pattern_t *cp = cairo_pattern_create_radial( + rg->fx.computed, rg->fy.computed, 0, + rg->cx.computed, rg->cy.computed, rg->r.computed); + sp_gradient_pattern_common_setup(cp, gr, bbox, opacity); + */ + + return cp; +} |