diff --git a/synfig-core/src/modules/lyr_freetype/lyr_freetype.h b/synfig-core/src/modules/lyr_freetype/lyr_freetype.h index 79fdcef..807d03d 100644 --- a/synfig-core/src/modules/lyr_freetype/lyr_freetype.h +++ b/synfig-core/src/modules/lyr_freetype/lyr_freetype.h @@ -35,7 +35,7 @@ //#define USE_MAC_FT_FUNCS (1) //#endif -#include +#include #include #include #include diff --git a/synfig-core/src/modules/lyr_std/bevel.h b/synfig-core/src/modules/lyr_std/bevel.h index 565cc77..fd2a52e 100644 --- a/synfig-core/src/modules/lyr_std/bevel.h +++ b/synfig-core/src/modules/lyr_std/bevel.h @@ -29,7 +29,7 @@ /* -- H E A D E R S --------------------------------------------------------- */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/lyr_std/booleancurve.h b/synfig-core/src/modules/lyr_std/booleancurve.h index 90053d9..4d716b7 100644 --- a/synfig-core/src/modules/lyr_std/booleancurve.h +++ b/synfig-core/src/modules/lyr_std/booleancurve.h @@ -26,7 +26,7 @@ #define __SYNFIG_BOOLEAN_CURVE_H /* === H E A D E R S ======================================================= */ -#include +#include #include #include diff --git a/synfig-core/src/modules/lyr_std/import.h b/synfig-core/src/modules/lyr_std/import.h index 7b2aa17..ed3bb6d 100644 --- a/synfig-core/src/modules/lyr_std/import.h +++ b/synfig-core/src/modules/lyr_std/import.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/lyr_std/shade.h b/synfig-core/src/modules/lyr_std/shade.h index a4ad2ff..2b2d9a1 100644 --- a/synfig-core/src/modules/lyr_std/shade.h +++ b/synfig-core/src/modules/lyr_std/shade.h @@ -29,7 +29,7 @@ /* -- H E A D E R S --------------------------------------------------------- */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/lyr_std/sphere_distort.h b/synfig-core/src/modules/lyr_std/sphere_distort.h index 9079101..d8fa31b 100644 --- a/synfig-core/src/modules/lyr_std/sphere_distort.h +++ b/synfig-core/src/modules/lyr_std/sphere_distort.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include diff --git a/synfig-core/src/modules/lyr_std/twirl.h b/synfig-core/src/modules/lyr_std/twirl.h index 9b20d7b..48cc12d 100644 --- a/synfig-core/src/modules/lyr_std/twirl.h +++ b/synfig-core/src/modules/lyr_std/twirl.h @@ -29,7 +29,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/lyr_std/xorpattern.h b/synfig-core/src/modules/lyr_std/xorpattern.h index fac862b..361f19a 100644 --- a/synfig-core/src/modules/lyr_std/xorpattern.h +++ b/synfig-core/src/modules/lyr_std/xorpattern.h @@ -31,7 +31,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_example/filledrect.h b/synfig-core/src/modules/mod_example/filledrect.h index a63e720..de43d19 100644 --- a/synfig-core/src/modules/mod_example/filledrect.h +++ b/synfig-core/src/modules/mod_example/filledrect.h @@ -27,7 +27,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_example/metaballs.h b/synfig-core/src/modules/mod_example/metaballs.h index 93ec494..47d21e2 100644 --- a/synfig-core/src/modules/mod_example/metaballs.h +++ b/synfig-core/src/modules/mod_example/metaballs.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_example/simplecircle.h b/synfig-core/src/modules/mod_example/simplecircle.h index da3a010..2c035e1 100644 --- a/synfig-core/src/modules/mod_example/simplecircle.h +++ b/synfig-core/src/modules/mod_example/simplecircle.h @@ -27,10 +27,10 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include -#include +#include #include /* === M A C R O S ========================================================= */ diff --git a/synfig-core/src/modules/mod_filter/blur.h b/synfig-core/src/modules/mod_filter/blur.h index cb026f0..e009b6f 100644 --- a/synfig-core/src/modules/mod_filter/blur.h +++ b/synfig-core/src/modules/mod_filter/blur.h @@ -29,7 +29,7 @@ /* -- H E A D E R S --------------------------------------------------------- */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_filter/halftone2.h b/synfig-core/src/modules/mod_filter/halftone2.h index 9ae2a83..425108f 100644 --- a/synfig-core/src/modules/mod_filter/halftone2.h +++ b/synfig-core/src/modules/mod_filter/halftone2.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include "halftone.h" diff --git a/synfig-core/src/modules/mod_filter/halftone3.h b/synfig-core/src/modules/mod_filter/halftone3.h index 5b8783d..d6c315a 100644 --- a/synfig-core/src/modules/mod_filter/halftone3.h +++ b/synfig-core/src/modules/mod_filter/halftone3.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include "halftone.h" diff --git a/synfig-core/src/modules/mod_filter/lumakey.h b/synfig-core/src/modules/mod_filter/lumakey.h index 2fc344e..ea0299a 100644 --- a/synfig-core/src/modules/mod_filter/lumakey.h +++ b/synfig-core/src/modules/mod_filter/lumakey.h @@ -31,7 +31,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include diff --git a/synfig-core/src/modules/mod_filter/radialblur.h b/synfig-core/src/modules/mod_filter/radialblur.h index a50b917..79fe4e7 100644 --- a/synfig-core/src/modules/mod_filter/radialblur.h +++ b/synfig-core/src/modules/mod_filter/radialblur.h @@ -32,7 +32,7 @@ #include #include -#include +#include /* === M A C R O S ========================================================= */ diff --git a/synfig-core/src/modules/mod_geometry/advanced_outline.h b/synfig-core/src/modules/mod_geometry/advanced_outline.h index 9395d3d..8234862 100644 --- a/synfig-core/src/modules/mod_geometry/advanced_outline.h +++ b/synfig-core/src/modules/mod_geometry/advanced_outline.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include diff --git a/synfig-core/src/modules/mod_geometry/checkerboard.h b/synfig-core/src/modules/mod_geometry/checkerboard.h index f29ed06..f1f364d 100644 --- a/synfig-core/src/modules/mod_geometry/checkerboard.h +++ b/synfig-core/src/modules/mod_geometry/checkerboard.h @@ -31,7 +31,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include diff --git a/synfig-core/src/modules/mod_geometry/circle.h b/synfig-core/src/modules/mod_geometry/circle.h index 1e51b24..cf6ddc9 100644 --- a/synfig-core/src/modules/mod_geometry/circle.h +++ b/synfig-core/src/modules/mod_geometry/circle.h @@ -29,7 +29,7 @@ /* -- H E A D E R S --------------------------------------------------------- */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_geometry/outline.h b/synfig-core/src/modules/mod_geometry/outline.h index e93c2cd..d80902c 100644 --- a/synfig-core/src/modules/mod_geometry/outline.h +++ b/synfig-core/src/modules/mod_geometry/outline.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include diff --git a/synfig-core/src/modules/mod_geometry/rectangle.h b/synfig-core/src/modules/mod_geometry/rectangle.h index 1c68845..9c66525 100644 --- a/synfig-core/src/modules/mod_geometry/rectangle.h +++ b/synfig-core/src/modules/mod_geometry/rectangle.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_geometry/region.h b/synfig-core/src/modules/mod_geometry/region.h index 0249e3d..8a6a158 100644 --- a/synfig-core/src/modules/mod_geometry/region.h +++ b/synfig-core/src/modules/mod_geometry/region.h @@ -30,7 +30,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_geometry/star.h b/synfig-core/src/modules/mod_geometry/star.h index 29918da..54c9cdc 100644 --- a/synfig-core/src/modules/mod_geometry/star.h +++ b/synfig-core/src/modules/mod_geometry/star.h @@ -31,7 +31,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_gradient/conicalgradient.h b/synfig-core/src/modules/mod_gradient/conicalgradient.h index 4a3f992..d3e8ab4 100644 --- a/synfig-core/src/modules/mod_gradient/conicalgradient.h +++ b/synfig-core/src/modules/mod_gradient/conicalgradient.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_gradient/curvegradient.h b/synfig-core/src/modules/mod_gradient/curvegradient.h index 3a0e805..9569d54 100644 --- a/synfig-core/src/modules/mod_gradient/curvegradient.h +++ b/synfig-core/src/modules/mod_gradient/curvegradient.h @@ -31,7 +31,7 @@ /* === H E A D E R S ======================================================= */ #include -#include +#include #include #include diff --git a/synfig-core/src/modules/mod_gradient/lineargradient.h b/synfig-core/src/modules/mod_gradient/lineargradient.h index 7aa7f91..f6defc5 100644 --- a/synfig-core/src/modules/mod_gradient/lineargradient.h +++ b/synfig-core/src/modules/mod_gradient/lineargradient.h @@ -31,7 +31,7 @@ /* === H E A D E R S ======================================================= */ #include -#include +#include #include /* === M A C R O S ========================================================= */ diff --git a/synfig-core/src/modules/mod_gradient/radialgradient.h b/synfig-core/src/modules/mod_gradient/radialgradient.h index 665f953..650786e 100644 --- a/synfig-core/src/modules/mod_gradient/radialgradient.h +++ b/synfig-core/src/modules/mod_gradient/radialgradient.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_gradient/spiralgradient.h b/synfig-core/src/modules/mod_gradient/spiralgradient.h index d5c8c5b..f81eb0a 100644 --- a/synfig-core/src/modules/mod_gradient/spiralgradient.h +++ b/synfig-core/src/modules/mod_gradient/spiralgradient.h @@ -27,7 +27,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_noise/distort.h b/synfig-core/src/modules/mod_noise/distort.h index 36ec18c..376f0ca 100644 --- a/synfig-core/src/modules/mod_noise/distort.h +++ b/synfig-core/src/modules/mod_noise/distort.h @@ -31,7 +31,7 @@ #include #include -#include +#include #include #include #include "random_noise.h" diff --git a/synfig-core/src/modules/mod_noise/noise.h b/synfig-core/src/modules/mod_noise/noise.h index 09ca5b4..bde4089 100644 --- a/synfig-core/src/modules/mod_noise/noise.h +++ b/synfig-core/src/modules/mod_noise/noise.h @@ -32,7 +32,7 @@ #include #include -#include +#include #include #include #include "random_noise.h" diff --git a/synfig-core/src/modules/mod_particle/plant.h b/synfig-core/src/modules/mod_particle/plant.h index 4140009..ce4af45 100644 --- a/synfig-core/src/modules/mod_particle/plant.h +++ b/synfig-core/src/modules/mod_particle/plant.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include #include diff --git a/synfig-core/src/modules/mod_svg/layer_svg.h b/synfig-core/src/modules/mod_svg/layer_svg.h index 20a38cd..e198a79 100644 --- a/synfig-core/src/modules/mod_svg/layer_svg.h +++ b/synfig-core/src/modules/mod_svg/layer_svg.h @@ -30,7 +30,7 @@ #include #include -#include +#include #include #include "svg_parser.h" diff --git a/synfig-core/src/synfig/Makefile.am b/synfig-core/src/synfig/Makefile.am index f2001f6..5126e47 100644 --- a/synfig-core/src/synfig/Makefile.am +++ b/synfig-core/src/synfig/Makefile.am @@ -15,41 +15,6 @@ EXTRA_DIST = \ nodebase.h -LAYERHEADERS = \ - layer_bitmap.h \ - layer_composite.h \ - layer_duplicate.h \ - layer_group.h \ - layer_meshtransform.h \ - layer_mime.h \ - layer_motionblur.h \ - layer_pastecanvas.h \ - layer_polygon.h \ - layer_shape.h \ - layer_solidcolor.h \ - layer_sound.h \ - layer_skeleton.h \ - layer_skeletondeformation.h \ - layer_switch.h - -LAYERSOURCES = \ - layer_bitmap.cpp \ - layer_composite.cpp \ - layer_duplicate.cpp \ - layer_group.cpp \ - layer_meshtransform.cpp \ - layer_mime.cpp \ - layer_motionblur.cpp \ - layer_pastecanvas.cpp \ - layer_polygon.cpp \ - layer_shape.cpp \ - layer_solidcolor.cpp \ - layer_sound.cpp \ - layer_skeleton.cpp \ - layer_skeletondeformation.cpp \ - layer_switch.cpp - - TARGETHEADERS = \ target_multi.h \ target_null.h \ @@ -231,8 +196,6 @@ SYNFIGSOURCES = \ libsynfig_src = \ $(VALUEHEADERS) \ $(VALUESOURCES) \ - $(LAYERSOURCES) \ - $(LAYERHEADERS) \ $(TARGETHEADERS) \ $(TARGETSOURCES) \ $(SYNFIGHEADERS) \ @@ -242,11 +205,11 @@ libsynfig_src = \ libsynfig_include_HH = \ $(SYNFIGHEADERS) \ - $(LAYERHEADERS) \ $(TARGETHEADERS) \ $(IMPORTERHEADERS) \ $(VALUEHEADERS) +include layers/Makefile_insert include valuenodes/Makefile_insert lib_LTLIBRARIES = libsynfig.la diff --git a/synfig-core/src/synfig/canvas.cpp b/synfig-core/src/synfig/canvas.cpp index 6920abf..17e1d5f 100644 --- a/synfig-core/src/synfig/canvas.cpp +++ b/synfig-core/src/synfig/canvas.cpp @@ -36,9 +36,9 @@ #include "exception.h" #include "time.h" #include "context.h" -#include "layer_pastecanvas.h" -#include "valuenodes/valuenode_const.h" -#include "valuenodes/valuenode_scale.h" +#include +#include +#include #include "loadcanvas.h" #include "filesystemnative.h" #include diff --git a/synfig-core/src/synfig/context.cpp b/synfig-core/src/synfig/context.cpp index 7204213..ae1dd92 100644 --- a/synfig-core/src/synfig/context.cpp +++ b/synfig-core/src/synfig/context.cpp @@ -33,7 +33,7 @@ #include "context.h" #include "layer.h" -#include "layer_pastecanvas.h" +#include #include "string.h" #include "vector.h" #include "color.h" diff --git a/synfig-core/src/synfig/context.h b/synfig-core/src/synfig/context.h index 46b9d0f..f4bbc66 100644 --- a/synfig-core/src/synfig/context.h +++ b/synfig-core/src/synfig/context.h @@ -32,7 +32,7 @@ #include "rect.h" #include "renddesc.h" #include "surface.h" -#include "layer_composite.h" +#include #include "general.h" /* === M A C R O S ========================================================= */ diff --git a/synfig-core/src/synfig/layer.cpp b/synfig-core/src/synfig/layer.cpp index 2677d17..cbf89eb 100644 --- a/synfig-core/src/synfig/layer.cpp +++ b/synfig-core/src/synfig/layer.cpp @@ -35,21 +35,21 @@ #include "layer.h" #include "render.h" #include "value.h" -#include "layer_bitmap.h" -#include "layer_mime.h" +#include +#include #include "context.h" #include "paramdesc.h" #include "surface.h" -#include "layer_solidcolor.h" -#include "layer_polygon.h" -#include "layer_group.h" -#include "layer_switch.h" -#include "layer_motionblur.h" -#include "layer_duplicate.h" -#include "layer_skeleton.h" -#include "layer_skeletondeformation.h" -#include "layer_sound.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include #include "valuenodes/valuenode_const.h" diff --git a/synfig-core/src/synfig/layer_bitmap.cpp b/synfig-core/src/synfig/layer_bitmap.cpp deleted file mode 100644 index e0a10ac..0000000 --- a/synfig-core/src/synfig/layer_bitmap.cpp +++ /dev/null @@ -1,824 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_bitmap.cpp -** \brief Template Header -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2012-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_bitmap.h" -#include "layer.h" -#include "time.h" -#include "string.h" -#include "vector.h" - -#include "context.h" -#include "time.h" -#include "color.h" -#include "surface.h" -#include "renddesc.h" -#include "target.h" - -#include "general.h" -#include "paramdesc.h" -#include - -#endif - -/* === U S I N G =========================================================== */ - -using namespace synfig; -using namespace std; -using namespace etl; - -/* === G L O B A L S ======================================================= */ - -/* === P R O C E D U R E S ================================================= */ - -/* === M E T H O D S ======================================================= */ - -synfig::Layer_Bitmap::Layer_Bitmap(): - Layer_Composite (1.0,Color::BLEND_COMPOSITE), - method (SOFTWARE), - param_tl (Point(-0.5,0.5)), - param_br (Point(0.5,-0.5)), - param_c (int(1)), - param_gamma_adjust (Real(1.0)), - surface (128,128), - trimmed (false) -{ - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -bool -synfig::Layer_Bitmap::set_param(const String & param, const ValueBase & value) -{ - IMPORT_VALUE(param_tl); - IMPORT_VALUE(param_br); - IMPORT_VALUE(param_c); - IMPORT_VALUE_PLUS(param_gamma_adjust, - if(param=="gamma_adjust"&& value.get_type()==type_real) - { - param_gamma_adjust.set(Real(1.0/value.get(Real()))); - return true; - } - ); - - return Layer_Composite::set_param(param,value); -} - -ValueBase -synfig::Layer_Bitmap::get_param(const String & param)const -{ - EXPORT_VALUE(param_tl); - EXPORT_VALUE(param_br); - EXPORT_VALUE(param_c); - if(param=="gamma_adjust") - { - ValueBase ret=param_gamma_adjust; - ret.set(1.0/param_gamma_adjust.get(Real())); - return ret; - } - - if(param=="_width") - { - ValueBase ret1(type_integer); - ret1=int(width); - ValueBase ret2(type_integer); - switch (method) - { - case SOFTWARE: - ret2=int(surface.get_w()); - break; - case CAIRO: - default: - ret2=int(csurface.get_w()); - break; - } - if (trimmed) return ret1; - return ret2; - } - if(param=="_height") - { - ValueBase ret1(type_integer); - ret1=int(height); - ValueBase ret2(type_integer); - switch (method) - { - case SOFTWARE: - ret2=int(surface.get_h()); - break; - case CAIRO: - default: - ret2=int(csurface.get_h()); - break; - } - if (trimmed) return ret1; - return ret2; - } - - return Layer_Composite::get_param(param); -} - - -Layer::Vocab -Layer_Bitmap::get_param_vocab()const -{ - Layer::Vocab ret(Layer_Composite::get_param_vocab()); - - ret.push_back(ParamDesc("tl") - .set_local_name(_("Top-Left")) - .set_description(_("Upper left-hand Corner of image")) - ); - - ret.push_back(ParamDesc("br") - .set_local_name(_("Bottom-Right")) - .set_description(_("Lower right-hand Corner of image")) - ); - - ret.push_back(ParamDesc("c") - .set_local_name(_("Interpolation")) - .set_description(_("What type of interpolation to use")) - .set_hint("enum") - .add_enum_value(0,"nearest",_("Nearest Neighbor")) - .add_enum_value(1,"linear",_("Linear")) - .add_enum_value(2,"cosine",_("Cosine")) - .add_enum_value(3,"cubic",_("Cubic")) - .set_static(true) - ); - - ret.push_back(ParamDesc("gamma_adjust") - .set_local_name(_("Gamma Adjustment")) - ); - - return ret; -} - -synfig::Layer::Handle -Layer_Bitmap::hit_check(synfig::Context context, const synfig::Point &pos)const -{ - Point tl(param_tl.get(Point())); - Point br(param_br.get(Point())); - Point surface_pos; - surface_pos=pos-tl; - - surface_pos[0]/=br[0]-tl[0]; - if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0) - { - surface_pos[1]/=br[1]-tl[1]; - if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0) - { - return const_cast(this); - } - } - - return context.hit_check(pos); -} - -void -synfig::Layer_Bitmap::set_render_method(Context context, RenderMethod x) -{ - set_method(x); - context.set_render_method(x); -} - -inline -const Color& -synfig::Layer_Bitmap::filter(Color& x)const -{ - Real gamma_adjust(param_gamma_adjust.get(Real())); - if(gamma_adjust!=1.0) - { - x.set_r(powf((float)x.get_r(),gamma_adjust)); - x.set_g(powf((float)x.get_g(),gamma_adjust)); - x.set_b(powf((float)x.get_b(),gamma_adjust)); - } - return x; -} - -inline -const CairoColor& -synfig::Layer_Bitmap::filter(CairoColor& x)const -{ - Real gamma_adjust(param_gamma_adjust.get(Real())); - if(gamma_adjust!=1.0) - { - x.set_r(powf((float)(x.get_r()/CairoColor::range),gamma_adjust)*CairoColor::range); - x.set_g(powf((float)(x.get_g()/CairoColor::range),gamma_adjust)*CairoColor::range); - x.set_b(powf((float)(x.get_b()/CairoColor::range),gamma_adjust)*CairoColor::range); - } - return x; -} - - -Color -synfig::Layer_Bitmap::get_color(Context context, const Point &pos)const -{ - Point tl(param_tl.get(Point())); - Point br(param_br.get(Point())); - int c(param_c.get(int())); - - Point surface_pos; - - if(!get_amount()) - return context.get_color(pos); - - surface_pos=pos-tl; - - surface_pos[0]/=br[0]-tl[0]; - if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0) - { - surface_pos[1]/=br[1]-tl[1]; - if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0) - { - Mutex::Lock lock(mutex); - - if (trimmed) - { - surface_pos[0]*=width; - surface_pos[1]*=height; - - if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top) - return context.get_color(pos); - - surface_pos[0] -= left; - surface_pos[1] -= top; - } - else - { - surface_pos[0]*=surface.get_w(); - surface_pos[1]*=surface.get_h(); - } - - Color ret(Color::alpha()); - - switch(c) - { - case 6: // Undefined - case 5: // Undefined - case 4: // Undefined - case 3: // Cubic - ret=surface.cubic_sample(surface_pos[0],surface_pos[1]); - break; - - case 2: // Cosine - ret=surface.cosine_sample(surface_pos[0],surface_pos[1]); - break; - case 1: // Linear - ret=surface.linear_sample(surface_pos[0],surface_pos[1]); - break; - case 0: // Nearest Neighbor - default: - { - int x(min(surface.get_w()-1,max(0,round_to_int(surface_pos[0])))); - int y(min(surface.get_h()-1,max(0,round_to_int(surface_pos[1])))); - ret= surface[y][x]; - } - break; - } - - ret=filter(ret); - - if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT) - return ret; - else - return Color::blend(ret,context.get_color(pos),get_amount(),get_blend_method()); - } - } - - return context.get_color(pos); -} - - -CairoColor -synfig::Layer_Bitmap::get_cairocolor(Context context, const Point &pos)const -{ - Point tl(param_tl.get(Point())); - Point br(param_br.get(Point())); - int c(param_c.get(int())); - - Point surface_pos; - - if(!get_amount()) - return context.get_cairocolor(pos); - - surface_pos=pos-tl; - - surface_pos[0]/=br[0]-tl[0]; - if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0) - { - surface_pos[1]/=br[1]-tl[1]; - if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0) - { - Mutex::Lock lock(mutex); - - if (trimmed) - { - surface_pos[0]*=width; - surface_pos[1]*=height; - - if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top) - return context.get_cairocolor(pos); - - surface_pos[0] -= left; - surface_pos[1] -= top; - } - else - { - surface_pos[0]*=csurface.get_w(); - surface_pos[1]*=csurface.get_h(); - } - - CairoColor ret(CairoColor::alpha()); - - switch(c) - { - case 6: // Undefined - case 5: // Undefined - case 4: // Undefined - case 3: // Cubic - ret=csurface.cubic_sample_cooked(surface_pos[0],surface_pos[1]); - break; - - case 2: // Cosine - ret=csurface.cosine_sample_cooked(surface_pos[0],surface_pos[1]); - break; - case 1: // Linear - ret=csurface.linear_sample_cooked(surface_pos[0],surface_pos[1]); - break; - case 0: // Nearest Neighbor - default: - { - int x(min(csurface.get_w()-1,max(0,round_to_int(surface_pos[0])))); - int y(min(csurface.get_h()-1,max(0,round_to_int(surface_pos[1])))); - ret= csurface[y][x]; - } - break; - } - ret=ret.demult_alpha(); - ret=filter(ret); - - if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT) - return ret; - else - return CairoColor::blend(ret,context.get_cairocolor(pos),get_amount(),get_blend_method()); - } - } - return context.get_cairocolor(pos); -} - - -bool -Layer_Bitmap::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const -{ - RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) - - Mutex::Lock lock(mutex); - - Point tl(param_tl.get(Point())); - Point br(param_br.get(Point())); - int c(param_c.get(int())); - Real gamma_adjust(param_gamma_adjust.get(Real())); - - int interp=c; - if(quality>=10) - interp=0; - else if(quality>=5 && interp>1) - interp=1; - - // We can only handle NN and Linear at the moment - //if(interp>1) - // return Layer_Composite::accelerated_render(context,surface,quality,renddesc,cb); - - //if we don't actually have a valid surface just skip us - if(!this->surface.is_valid()) - { - // Render what is behind us - return context.accelerated_render(surface,quality,renddesc,cb); - } - - SuperCallback subcb(cb,1,10000,10001+renddesc.get_h()); - - if( get_amount()==1 && - get_blend_method()==Color::BLEND_STRAIGHT && - !trimmed && - renddesc.get_tl()==tl && - renddesc.get_br()==br) - { - // Check for the trivial case - if(this->surface.get_w()==renddesc.get_w() && this->surface.get_h()==renddesc.get_h() && gamma_adjust==1.0f) - { - if(cb && !cb->amount_complete(0,100)) return false; - *surface=this->surface; - if(cb && !cb->amount_complete(100,100)) return false; - return true; - } - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - } - else - { - // Render what is behind us - if(!context.accelerated_render(surface,quality,renddesc,&subcb)) - return false; - } - - if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false; - - Point obr = renddesc.get_br(), - otl = renddesc.get_tl(); - - //Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]); - //Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]); - - //A = representation of input (just tl,br) //just a scaling right now - //B = representation of output (just tl,br) //just a scaling right now - //sa = scaling for input (0,1) -> (0,w/h) - //sb = scaling for output (0,1) -> (0,w/h) - - float outwf = obr[0] - otl[0]; - float outhf = obr[1] - otl[1]; - - int inw = this->surface.get_w(); - int inh = this->surface.get_h(); - - int outw = renddesc.get_w(); - int outh = renddesc.get_h(); - - float inwf, inhf; - Point itl, ibr; - - if (trimmed) - { - inwf = (br[0] - tl[0])*this->surface.get_w()/width; - inhf = (br[1] - tl[1])*this->surface.get_h()/height; - itl = Point(tl[0] + (br[0]-tl[0])*left/width, - tl[1] + (br[1]-tl[1])*top/height); - ibr = Point(tl[0] + (br[0]-tl[0])*(left+inw)/width, - tl[1] + (br[1]-tl[1])*(top+inh)/height); - } - else - { - inwf = br[0] - tl[0]; - inhf = br[1] - tl[1]; - itl = tl; - ibr = br; - } - - //need to get the input coords in output space, so we can clip - - //get the desired corners of the bitmap (in increasing order) in integers - //floating point corners - float x1f = (itl[0] - otl[0])*outw/outwf; - float x2f = (ibr[0] - otl[0])*outw/outwf; - float y1f = (itl[1] - otl[1])*outh/outhf; - float y2f = (ibr[1] - otl[1])*outh/outhf; - - if(x1f > x2f) swap(x1f,x2f); - if(y1f > y2f) swap(y1f,y2f); - - int x_start = max(0,(int)floor(x1f)); //probably floor - int x_end = min(outw,(int)ceil(x2f)); //probably ceil - int y_start = max(0,(int)floor(y1f)); //probably floor - int y_end = min(outh,(int)ceil(y2f)); //probably ceil - - //need to get the x,y,dx,dy values from output space to input, so we can do fast interpolation - - //get the starting position in input space... for interpolating - - // in int -> out float: - // Sb(B^-1)A(Sa^-1) x - float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - itl[0])*inw/inwf; //may want to bias this (center of pixel)??? - float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - itl[1])*inh/inhf; //may want to bias this (center of pixel)??? - - //calculate the delta values in input space for one pixel movement in output space - //same matrix but with a vector instead of a point... - float indx = outwf*(inw)/((outw)*inwf); //translations died - float indy = outhf*(inh)/((outh)*inhf); //translations died - - //perhaps use a DDA algorithm... if faster... - // will still want pixel fractions to be floating point since colors are - - //synfig::info("xstart:%d ystart:%d xend:%d yend:%d",x_start,y_start,x_end,y_end); - - //start drawing at the start of the bitmap (either origin or corner of input...) - //and get other info - Surface::alpha_pen pen(surface->get_pen(x_start,y_start)); - pen.set_alpha(get_amount()); - pen.set_blend_method(get_blend_method()); - - //check if we should use the downscale filtering - if(quality <= 7) - { - //the stride of the value should be inverted because we want to downsample - //when the stride is small, not big - //int multw = (int)ceil(indx); - //int multh = (int)ceil(indy); - - if(indx > 1.7 || indy > 1.7) - { - /*synfig::info("Decided to downsample? ratios - (%f,%f) -> (%d,%d)", - indx, indy, multw, multh); */ - - //use sample rect here... - - float iny, inx; - int x,y; - - //Point sample - truncate - iny = iny_start;//+0.5f; - for(y = y_start; y < y_end; ++y, pen.inc_y(), iny += indy) - { - inx = inx_start;//+0.5f; - for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) - { - Color rc = this->surface.sample_rect_clip(inx,iny,inx+indx,iny+indy); - pen.put_value(filter(rc)); - } - pen.dec_x(x_end-x_start); - } - - //Color c = (*surface)[0][0]; - //synfig::info("ValueBase of first pixel = (%f,%f,%f,%f)",c.get_r(),c.get_g(),c.get_b(),c.get_a()); - - return true; - } - } - - //perform normal interpolation - if(interp==0) - { - //synfig::info("Decided to do nearest neighbor"); - float iny, inx; - int x,y; - - //Point sample - truncate - iny = iny_start;//+0.5f; - for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) - { - inx = inx_start;//+0.5f; - int yclamp = min(inh-1, max(0, round_to_int(iny))); - for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) - { - int xclamp = min(inw-1, max(0, round_to_int(inx))); - Color c = filter(this->surface[yclamp][xclamp]); - pen.put_value(c); //must get rid of the clip - } - pen.dec_x(x_end-x_start); - } - } - else - if(interp==1) - { - //bilinear filtering - - //float xmf,xpf,ymf,ypf; - //int xm,xp,ym,yp; - float inx,iny; - int x,y; - - //can probably buffer for x values... - - //loop and based on inx,iny sample input image - iny = iny_start; - for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) - { - inx = inx_start; - for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) - { - Color col(this->surface.linear_sample(inx,iny)); - pen.put_value(filter(col)); - } - pen.dec_x(x_end-x_start); - - } - } - else - if(interp==2) - { - //cosine filtering - - //float xmf,xpf,ymf,ypf; - //int xm,xp,ym,yp; - float inx,iny; - int x,y; - - //can probably buffer for x values... - - //loop and based on inx,iny sample input image - iny = iny_start; - for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) - { - inx = inx_start; - for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) - { - Color col(this->surface.cosine_sample(inx,iny)); - pen.put_value(filter(col)); - } - pen.dec_x(x_end-x_start); - - } - } - else - { - //cubic filtering - - //float xmf,xpf,ymf,ypf; - //int xm,xp,ym,yp; - float inx,iny; - int x,y; - - //can probably buffer for x values... - - //loop and based on inx,iny sample input image - iny = iny_start; - for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) - { - inx = inx_start; - for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) - { - Color col(this->surface.cubic_sample(inx,iny)); - pen.put_value(filter(col)); - } - pen.dec_x(x_end-x_start); - - } - } - - return true; -} - -///// -///// - -bool -Layer_Bitmap::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb) const -{ - Mutex::Lock lock(mutex); - - Point tl(param_tl.get(Point())); - Point br(param_br.get(Point())); - int c(param_c.get(int())); - Real gamma_adjust(param_gamma_adjust.get(Real())); - - int interp=c; - if(quality>=10) - interp=0; - else if(quality>=5 && interp>1) - interp=1; - - //if we don't actually have a valid surface just skip us - if(!csurface.is_mapped()) - { - // Render what is behind us - return context.accelerated_cairorender(cr,quality,renddesc,cb); - } - - cairo_surface_t* cs=csurface.get_cairo_image_surface(); - - if(cairo_surface_status(cs) || cairo_surface_get_type(cs)!=CAIRO_SURFACE_TYPE_IMAGE) - { - // Render what is behind us - return context.accelerated_cairorender(cr,quality,renddesc,cb); - } - - SuperCallback subcb(cb,1,10000,10001+renddesc.get_h()); - - Point obr = renddesc.get_br(); - Point otl = renddesc.get_tl(); - - int outw = renddesc.get_w(); - int outh = renddesc.get_h(); - - int inw = cairo_image_surface_get_width(cs); - int inh = cairo_image_surface_get_height(cs); - - - if( get_amount()==1 && // our bitmap is full opaque - get_blend_method()==Color::BLEND_STRAIGHT && // and it doesn't draw the context - otl==tl && - obr==br) // and the tl and br are the same ... - { - // Check for the trivial case: the Bitmap and the destiny surface have same dimensions and there is not gamma adjust - if(inw==outw && inh==outh && gamma_adjust==1.0f) - { - if(cb && !cb->amount_complete(0,100)) return false; - { - cairo_save(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); // set operator to ignore destiny - cairo_set_source_surface(cr, cs, 0, 0); // set the source our cairosurface - cairo_paint(cr); // paint on the destiny - cairo_restore(cr); - } - if(cb && !cb->amount_complete(100,100)) return false; - return true; - } - } - else // It is not the trivial case - { - // Render what is behind us... - if(!context.accelerated_cairorender(cr,quality,renddesc,&subcb)) - return false; - } - - if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false; - - - // Calculate the width and height in pixels of the bitmap in the output surface - float wp=(br[0]-tl[0])/renddesc.get_pw(); - float hp=(br[1]-tl[1])/renddesc.get_ph(); - // So we need to scale the bitmap by wp/inw in horizontal and hp/inh in vertical. - float scalex=wp/inw; - float scaley=hp/inh; - // Now let's calculate the displacement of the image in the output surface. - Point disp=tl-otl; - // Calculate the cairo interpolation to do by the interpolation parameter c - cairo_filter_t filter; - switch(c) - { - case 3: // Cubic - filter=CAIRO_FILTER_BEST; - break; - case 2: // Cosine - filter=CAIRO_FILTER_GOOD; - break; - case 1: // Linear - filter=CAIRO_FILTER_FAST; - break; - case 0: // Nearest Neighbor - default: - filter=CAIRO_FILTER_NEAREST; - break; - } - // TODO: filter the image with gamma_adjust!! - cairo_save(cr); - // Need to scale down to user coordinates before pass to cr - cairo_translate(cr, renddesc.get_tl()[0], renddesc.get_tl()[1]); - cairo_scale(cr, renddesc.get_pw(), renddesc.get_ph()); - // Apply the bitmap scale and tanslate - cairo_translate(cr, disp[0]/renddesc.get_pw(), disp[1]/renddesc.get_ph()); - cairo_scale(cr, scalex, scaley); - // set the surface, filter, and paint - cairo_pattern_set_filter(cairo_get_source(cr), filter); - cairo_set_source_surface(cr, cs, 0,0); - cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); - // we don't need cs anymore - cairo_surface_destroy(cs); - cairo_restore(cr); - - return true; -} - -///// - - -Rect -Layer_Bitmap::get_bounding_rect()const -{ - Point tl(param_tl.get(Point())); - Point br(param_br.get(Point())); - - return Rect(tl,br); -} - - -void -Layer_Bitmap::set_cairo_surface(cairo_surface_t *cs) -{ - if(cs==NULL) - { - synfig::error("Layer_Bitmap received a NULL cairo_surface_t"); - return; - } - if(cairo_surface_status(cs)) - { - synfig::error("Layer_Bitmap received a non valid cairo_surface_t"); - return; - } - csurface.set_cairo_surface(cs); - csurface.map_cairo_image(); -} diff --git a/synfig-core/src/synfig/layer_bitmap.h b/synfig-core/src/synfig/layer_bitmap.h deleted file mode 100644 index bf5a804..0000000 --- a/synfig-core/src/synfig/layer_bitmap.h +++ /dev/null @@ -1,98 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_bitmap.h -** \brief Template Header -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2012-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_BITMAP_H -#define __SYNFIG_LAYER_BITMAP_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_composite.h" -#include "surface.h" -#include "target.h" // for RenderMethod - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -/*! \class Layer_Bitmap -** \todo writeme -*/ -class Layer_Bitmap : public Layer_Composite, public Layer_NoDeform -{ - const Color& filter(Color& c)const; - const CairoColor& filter(CairoColor& c)const; - RenderMethod method; -public: - typedef etl::handle Handle; - - ValueBase param_tl; - ValueBase param_br; - ValueBase param_c; - ValueBase param_gamma_adjust; - - mutable synfig::Mutex mutex; - mutable Surface surface; - mutable CairoSurface csurface; - mutable bool trimmed; - mutable unsigned int width, height, top, left; - - - Layer_Bitmap(); - ~Layer_Bitmap() { - if(csurface.is_mapped()) csurface.unmap_cairo_image(); } - - virtual bool set_param(const String & param, const ValueBase & value); - - virtual ValueBase get_param(const String & param)const; - - virtual Color get_color(Context context, const Point &pos)const; - virtual CairoColor get_cairocolor(Context context, const Point &pos)const; - - virtual Vocab get_param_vocab()const; - - virtual Rect get_bounding_rect()const; - - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - - virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; - - virtual void set_render_method(Context context, RenderMethod x); - void set_method(RenderMethod x) { method=x;} - RenderMethod get_method()const { return method;} - - void set_cairo_surface(cairo_surface_t* cs); - -}; // END of class Layer_Bitmap - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_composite.cpp b/synfig-core/src/synfig/layer_composite.cpp deleted file mode 100644 index 3b98156..0000000 --- a/synfig-core/src/synfig/layer_composite.cpp +++ /dev/null @@ -1,316 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_composite.cpp -** \brief Template File -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2008 Chris Moore -** Copyright (c) 2011-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_composite.h" -#include "layer_pastecanvas.h" -#include "context.h" -#include "time.h" -#include "color.h" -#include "surface.h" -#include "renddesc.h" -#include "target.h" - -#include "layer_bitmap.h" - -#include "general.h" -#include "render.h" -#include "paramdesc.h" -#include "cairo_renddesc.h" - - -#endif - -/* === U S I N G =========================================================== */ - -using namespace std; -using namespace etl; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -/* === G L O B A L S ======================================================= */ - -/* === P R O C E D U R E S ================================================= */ - -/* === M E T H O D S ======================================================= */ -Layer_Composite::Layer_Composite(Real a, Color::BlendMethod bm): - param_amount (a), - param_blend_method ((int)Color::BlendMethod(bm)), - converted_blend_ (false), - transparent_color_ (false) - { - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); - } - -bool -Layer_Composite::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const -{ - RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) - - Real amount(param_amount.get(Real())); - if(!amount) - return context.accelerated_render(surface,quality,renddesc,cb); - - CanvasBase image; - - SuperCallback stageone(cb,0,50000,100000); - SuperCallback stagetwo(cb,50000,100000,100000); - - Layer_Bitmap::Handle surfacelayer(new class Layer_Bitmap()); - - Context iter; - - for(iter=context;*iter;iter++) - image.push_back(*iter); - - image.push_front(surfacelayer.get()); - - // We want to go ahead and schedule any other - // layers... -// while(dynamic_cast(context->get())) -// while(context->get() && -// &context->get()->AcceleratedRender== -// &Layer_Composite::AcceleratedRender) -// image.push_back(*(context++)); - - image.push_back(0); // Alpha black - - // Render the backdrop on the surface layer's surface. - if(!context.accelerated_render(&surfacelayer->surface,quality,renddesc,&stageone)) - return false; - // Sets up the interpolation of the context (now the surface layer is the first one) - // depending on the quality - if(quality<=4)surfacelayer->set_param("c", 3);else - if(quality<=5)surfacelayer->set_param("c", 2); - else if(quality<=6)surfacelayer->set_param("c", 1); - else surfacelayer->set_param("c",0); - surfacelayer->set_param("tl",renddesc.get_tl()); - surfacelayer->set_param("br",renddesc.get_br()); - // Sets the blend method to straight. See below - surfacelayer->set_blend_method(Color::BLEND_STRAIGHT); - // Push this layer on the image. The blending result is only this layer - // adn the surface layer. The rest of the context is ignored by the straight - // blend method of surface layer - image.push_front(const_cast(this)); - - // Set up a surface target - Target_Scanline::Handle target(surface_target(surface)); - - if(!target) - { - if(cb)cb->error(_("Unable to create surface target")); - return false; - } - - RendDesc desc(renddesc); - - target->set_rend_desc(&desc); - - // Render the scene - return render(Context(image.begin(),context),target,desc,&stagetwo); - //return render_threaded(Context(image.begin()),target,desc,&stagetwo,2); -} - - -///// -bool -Layer_Composite::accelerated_cairorender(Context context,cairo_t *cr, int quality, const RendDesc &renddesc_, ProgressCallback *cb) const -{ - RendDesc renddesc(renddesc_); - Real amount(param_amount.get(Real())); - - if(!amount) - return context.accelerated_cairorender(cr,quality,renddesc,cb); - - // Untransform the render desc - if(!cairo_renddesc_untransform(cr, renddesc)) - return false; - const Real pw(renddesc.get_pw()),ph(renddesc.get_ph()); - const Point tl(renddesc.get_tl()); - const int w(renddesc.get_w()); - const int h(renddesc.get_h()); - - CanvasBase image; - - SuperCallback stageone(cb,0,50000,100000); - SuperCallback stagetwo(cb,50000,100000,100000); - - Layer_Bitmap::Handle surfacelayer(new class Layer_Bitmap()); - - Context iter; - - for(iter=context;*iter;iter++) - image.push_back(*iter); - - // Add one Bitmap Layer on top - image.push_front(surfacelayer.get()); - - image.push_back(0); // and Alpha black at end - - // Render the backdrop on the surface layer's surface. - cairo_surface_t* cs=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); - cairo_surface_t* result=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); - cairo_t* cr_cs=cairo_create(cs); - cairo_scale(cr_cs, 1/pw, 1/ph); - cairo_translate(cr_cs, -tl[0], -tl[1]); - if(!context.accelerated_cairorender(cr_cs,quality,renddesc,&stageone)) - { - cairo_surface_destroy(cs); - cairo_destroy(cr_cs); - return false; - } - cairo_destroy(cr_cs); - surfacelayer->set_cairo_surface(cs); - cairo_surface_destroy(cs); - // Sets up the interpolation of the context (now the surface layer is the first one) - // depending on the quality - if(quality<=4)surfacelayer->set_param("c", 3);else - if(quality<=5)surfacelayer->set_param("c", 2); - else if(quality<=6)surfacelayer->set_param("c", 1); - else surfacelayer->set_param("c",0); - surfacelayer->set_param("tl",renddesc.get_tl()); - surfacelayer->set_param("br",renddesc.get_br()); - // Sets the blend method to straight. See below - surfacelayer->set_blend_method(Color::BLEND_STRAIGHT); - surfacelayer->set_render_method(context, CAIRO); - // Push this layer on the image. The blending result is only this layer - // and the surface layer. The rest of the context is ignored by the straight - // blend method of surface layer - image.push_front(const_cast(this)); - - // Render the scene - if(!cairorender(Context(image.begin(),context),result,renddesc,&stagetwo)) - { - cairo_surface_destroy(result); - return false; - } - // Put the result on the cairo context - cairo_save(cr); - cairo_translate(cr, tl[0], tl[1]); - cairo_scale(cr, pw, ph); - cairo_set_source_surface(cr, result, 0, 0); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_restore(cr); - - cairo_surface_destroy(result); - // Mark our progress as finished - if(cb && !cb->amount_complete(10000,10000)) - return false; - return true; -} - - -Rect -Layer_Composite::get_full_bounding_rect(Context context)const -{ - if(is_disabled() || Color::is_onto(get_blend_method())) - return context.get_full_bounding_rect(); - - return context.get_full_bounding_rect()|get_bounding_rect(); -} - -Layer::Vocab -Layer_Composite::get_param_vocab()const -{ - //! First fills the returning vocabulary with the ancestor class - Layer::Vocab ret(Layer::get_param_vocab()); - //! Now inserts the two parameters that this layer knows. - ret.push_back(ParamDesc(param_amount,"amount") - .set_local_name(_("Amount")) - .set_description(_("Alpha channel of the layer")) - ); - ret.push_back(ParamDesc(param_blend_method,"blend_method") - .set_local_name(_("Blend Method")) - .set_description(_("The blending method used to composite on the layers below")) - .set_static(true) - ); - - return ret; -} - -bool -Layer_Composite::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE(param_amount) - IMPORT_VALUE_PLUS(param_blend_method, - Color::BlendMethod blend_method = static_cast(value.get(int())); - if (blend_method < 0 || blend_method >= Color::BLEND_END) - { - warning("illegal value (%d) for blend_method - using Composite instead", blend_method); - param_blend_method.set((int)Color::BLEND_COMPOSITE); - return false; - } - - if (blend_method == Color::BLEND_STRAIGHT && !reads_context()) - { - Canvas::Handle canvas(get_canvas()); - if (canvas) - { - String version(canvas->get_version()); - - if (version == "0.1" || version == "0.2") - { - if (dynamic_cast(this) != NULL) - warning("loaded a version %s canvas with a 'Straight' blended PasteCanvas (%s) - check it renders OK", - version.c_str(), get_non_empty_description().c_str()); - else - { - param_blend_method.set(int(Color::BLEND_COMPOSITE)); - converted_blend_ = true; - - // if this layer has a transparent color, go back and set the color again - // now that we know we are converting the blend method as well. that will - // make the color non-transparent, and change the blend method to alpha over - if (transparent_color_) - set_param("color", get_param("color")); - } - } - } - } - ); - - return Layer::set_param(param,value); -} - -ValueBase -Layer_Composite::get_param(const String & param)const -{ - - EXPORT_VALUE(param_amount) - EXPORT_VALUE(param_blend_method) - //! If it is unknown then call the ancestor's get param member - //! to see if it can handle that parameter's string. - return Layer::get_param(param); -} diff --git a/synfig-core/src/synfig/layer_composite.h b/synfig-core/src/synfig/layer_composite.h deleted file mode 100644 index 7bca828..0000000 --- a/synfig-core/src/synfig/layer_composite.h +++ /dev/null @@ -1,100 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_composite.h -** \brief Composite Layer Class Implementation -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_COMPOSITE_H -#define __SYNFIG_LAYER_COMPOSITE_H - -/* === H E A D E R S ======================================================= */ - -#include "layer.h" -#include "color.h" -#include "cairo_operators.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -class Layer_NoDeform {}; - - -/*! \class Layer_Composite -** \brief Base class for layers that put stuff on top of lower layers -*/ -class Layer_Composite : public Layer -{ -private: - //! The amount of composite - ValueBase param_amount; - //! The blend method for the composition - ValueBase param_blend_method; - -protected: - //! Default constructor. Not used directly. - Layer_Composite(Real amount=1.0, Color::BlendMethod blend_method=Color::BLEND_COMPOSITE); - - //! Converted blend is used to check if an old version of canvas - //! is used in the composition. Old Straight was used as new Composite - //! \todo verify this - bool converted_blend_; - //! Transparent color is used for old canvas versions. - //!Old Straight plus transparent color seems to be the same new than alpha over. - bool transparent_color_; - -public: - //! Gets the amount of the layer - float get_amount()const { return param_amount.get(Real()); } - //! Sets the amount of the layer and returns this layer - Layer_Composite& set_amount(float x) { param_amount.set(x); return *this; } - //! Gets the blend method of the layer - Color::BlendMethod get_blend_method()const { return Color::BlendMethod((param_blend_method.get(int()))); } - //! Sets the blend method of the layer and returns this layer - Layer_Composite& set_blend_method(Color::BlendMethod x) { param_blend_method.set(int(x)); return *this; } - //! Returns true is amount is 1 and blend method is straight - virtual bool is_solid_color()const { return param_amount.get(Real())==1.0f && param_blend_method.get(int())==Color::BLEND_STRAIGHT; } - //! Returns true if the amount is zero. - bool is_disabled()const { return param_amount.get(Real())==0.0f; } - //! Gets the parameter vocabulary. To be overrided by the derived. - virtual Vocab get_param_vocab()const; - //! Sets the value for the given parameter. - virtual bool set_param(const String ¶m, const ValueBase &value); - //! Gets the value of the given parameter - virtual ValueBase get_param(const String ¶m)const; - //!Returns the rectangle that includes the context of the layer and - //! the intersection of the layer in case it is active and not onto - virtual Rect get_full_bounding_rect(Context context)const; - //! Renders the layer composited on the context and puts it on the target surface. - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; -}; // END of class Layer_Composite - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_duplicate.cpp b/synfig-core/src/synfig/layer_duplicate.cpp deleted file mode 100644 index 1e81dd7..0000000 --- a/synfig-core/src/synfig/layer_duplicate.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_duplicate.cpp -** \brief Implementation of the "Duplicate" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "string.h" -#include "layer_duplicate.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenode.h" -#include "canvas.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace synfig; -using namespace etl; -using namespace std; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Duplicate); -SYNFIG_LAYER_SET_NAME(Layer_Duplicate,"duplicate"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Duplicate,N_("Duplicate")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Duplicate,N_("Other")); -SYNFIG_LAYER_SET_VERSION(Layer_Duplicate,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Duplicate,"$Id$"); - -/* === M E M B E R S ======================================================= */ - -Layer_Duplicate::Layer_Duplicate(): - Layer_Composite(1.0,Color::BLEND_COMPOSITE) -{ - LinkableValueNode* index_value_node = ValueNode_Duplicate::create(Real(3)); - connect_dynamic_param("index", index_value_node); - - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer::Handle -Layer_Duplicate::clone(Canvas::LooseHandle canvas, const GUID& deriv_guid)const -{ - Layer::Handle ret = (Layer::Handle)Layer_Composite::clone(canvas, deriv_guid); - - const DynamicParamList &dpl = dynamic_param_list(); - DynamicParamList::const_iterator iter = dpl.find("index"); - - // if we have a dynamic "index" parameter, make a new one in the clone - // it's not good to have two references to the same index valuenode, - // or nested duplications cause an infinite loop - if (iter != dpl.end()) - ret->connect_dynamic_param(iter->first,iter->second->clone(canvas, deriv_guid)); - - return ret; -} - -bool -Layer_Duplicate::set_param(const String ¶m, const ValueBase &value) -{ - IMPORT_VALUE(param_index); - return Layer_Composite::set_param(param,value); -} - -ValueBase -Layer_Duplicate::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_index); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_Composite::get_param(param); -} - -void -Layer_Duplicate::set_time(IndependentContext context, Time time)const -{ - context.set_time(time); - time_cur=time; -} - -void -Layer_Duplicate::set_time(IndependentContext context, Time time, const Point &pos)const -{ - context.set_time(time,pos); - time_cur=time; -} - -Color -Layer_Duplicate::get_color(Context context, const Point &pos)const -{ - handle duplicate_param = get_duplicate_param(); - if (!duplicate_param) return context.get_color(pos); - - Color::BlendMethod blend_method(get_blend_method()); - float amount(get_amount()); - Color color; - - Mutex::Lock lock(mutex); - duplicate_param->reset_index(time_cur); - do - { - context.set_time(time_cur+1); - context.set_time(time_cur); - color = Color::blend(context.get_color(pos),color,amount,blend_method); - } while (duplicate_param->step(time_cur)); - - return color; -} - -Layer::Vocab -Layer_Duplicate::get_param_vocab()const -{ - Layer::Vocab ret; - ret=Layer_Composite::get_param_vocab(); - - ret.push_back(ParamDesc("index") - .set_local_name(_("Index")) - .set_description(_("Copy Index")) - ); - - return ret; -} - -ValueNode_Duplicate::Handle -Layer_Duplicate::get_duplicate_param()const -{ - const DynamicParamList &dpl = dynamic_param_list(); - DynamicParamList::const_iterator iter = dpl.find("index"); - if (iter == dpl.end()) return NULL; - etl::rhandle param(iter->second); - return ValueNode_Duplicate::Handle::cast_dynamic(param); -} - -bool -Layer_Duplicate::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) - - if(quality == 10) - return context.accelerated_render(surface,quality,renddesc,cb); - - if(context->empty()) - { - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - surface->clear(); - return true; - } - - SuperCallback subimagecb; - Surface tmp; - int i = 0; - - handle duplicate_param = get_duplicate_param(); - if (!duplicate_param) return context.accelerated_render(surface,quality,renddesc,cb); - - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - surface->clear(); - - Color::BlendMethod blend_method(get_blend_method()); - int steps = duplicate_param->count_steps(time_cur); - - Mutex::Lock lock(mutex); - duplicate_param->reset_index(time_cur); - do - { - subimagecb=SuperCallback(cb,i*(5000/steps),(i+1)*(5000/steps),5000); - // \todo can we force a re-evaluation of all the variables without changing the time twice? - context.set_time(time_cur+1); - context.set_time(time_cur); - if(!context.accelerated_render(&tmp,quality,renddesc,&subimagecb)) return false; - - Surface::alpha_pen apen(surface->begin()); - apen.set_alpha(get_amount()); - // \todo have a checkbox allowing use of 'behind' to reverse the order? - apen.set_blend_method(i ? blend_method : Color::BLEND_COMPOSITE); - tmp.blit_to(apen); - i++; - } while (duplicate_param->step(time_cur)); - - return true; -} - -///// -bool -Layer_Duplicate::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - if(quality == 10) - return context.accelerated_cairorender(cr,quality,renddesc,cb); - - if(context->empty()) - { - cairo_save(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_paint(cr); - cairo_restore(cr); - return true; - } - - SuperCallback subimagecb; - - int i = 0; - - handle duplicate_param = get_duplicate_param(); - if (!duplicate_param) return context.accelerated_cairorender(cr,quality,renddesc,cb); - - Color::BlendMethod blend_method(get_blend_method()); - int steps = duplicate_param->count_steps(time_cur); - - Mutex::Lock lock(mutex); - duplicate_param->reset_index(time_cur); - cairo_save(cr); - do - { - subimagecb=SuperCallback(cb,i*(5000/steps),(i+1)*(5000/steps),5000); - // \todo can we force a re-evaluation of all the variables without changing the time twice? - context.set_time(time_cur+1); - context.set_time(time_cur); - cairo_push_group(cr); - if(!context.accelerated_cairorender(cr,quality,renddesc,&subimagecb)) - { - cairo_pop_group(cr); - return false; - } - cairo_pop_group_to_source(cr);; - // \todo have a checkbox allowing use of 'behind' to reverse the order? - cairo_paint_with_alpha_operator(cr, get_amount(), i ? blend_method : Color::BLEND_COMPOSITE); - i++; - } while (duplicate_param->step(time_cur)); - cairo_restore(cr); - return true; -} diff --git a/synfig-core/src/synfig/layer_duplicate.h b/synfig-core/src/synfig/layer_duplicate.h deleted file mode 100644 index 4c7f0ff..0000000 --- a/synfig-core/src/synfig/layer_duplicate.h +++ /dev/null @@ -1,70 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_duplicate.h -** \brief Header file for implementation of the "Duplicate" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2008 Chris Moore -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_DUPLICATE_H__ -#define __SYNFIG_LAYER_DUPLICATE_H__ - -/* === H E A D E R S ======================================================= */ - -#include "valuenodes/valuenode_duplicate.h" -#include "layer_composite.h" -#include "time.h" - -/* === S T R U C T S & C L A S S E S ======================================= */ - -namespace synfig { - -class Layer_Duplicate : public synfig::Layer_Composite -{ - SYNFIG_LAYER_MODULE_EXT - -private: - mutable ValueBase param_index; - mutable Time time_cur; - mutable synfig::Mutex mutex; - -public: - - Layer_Duplicate(); - - //! Duplicates the Layer - virtual Layer::Handle clone(etl::loose_handle canvas, const GUID& deriv_guid=GUID())const; - virtual bool set_param(const String & param, const synfig::ValueBase &value); - virtual ValueBase get_param(const String & param)const; - virtual Color get_color(Context context, const Point &pos)const; - virtual void set_time(IndependentContext context, Time time)const; - virtual void set_time(IndependentContext context, Time time, const Point &point)const; - virtual ValueNode_Duplicate::Handle get_duplicate_param()const; - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual Vocab get_param_vocab()const; - virtual bool reads_context()const { return true; } -}; // END of class Layer_Duplicate - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_group.cpp b/synfig-core/src/synfig/layer_group.cpp deleted file mode 100644 index d62b6a1..0000000 --- a/synfig-core/src/synfig/layer_group.cpp +++ /dev/null @@ -1,150 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_group.cpp -** \brief Implementation of the "Group" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** Copyright (c) 2011-2013 Carlos López -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_group.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "value.h" -#include "valuenode.h" -#include "canvas.h" - - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -/* === C L A S S E S ======================================================= */ - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Group); -SYNFIG_LAYER_SET_NAME(Layer_Group,"group"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Group,N_("Group")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Group,N_("Other")); -SYNFIG_LAYER_SET_VERSION(Layer_Group,"0.2"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Group,"$Id$"); - -/* === M E T H O D S ======================================================= */ - -Layer_Group::Layer_Group() -{ - param_z_range=ValueBase(bool(false)); - param_z_range_position=ValueBase(Real(0.0)); - param_z_range_depth=ValueBase(Real(0.0)); - param_z_range_blur=ValueBase(Real(0.0)); - - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer_Group::~Layer_Group() -{ -} - -String -Layer_Group::get_local_name()const -{ - String s = Layer_PasteCanvas::get_local_name(); - return s.empty() ? _("Group") : '[' + s + ']'; -} - -Layer::Vocab -Layer_Group::get_param_vocab()const -{ - Layer::Vocab ret(Layer_PasteCanvas::get_param_vocab()); - - ret.push_back(ParamDesc("z_range") - .set_local_name(_("Z Range")) - .set_description(_("When checked, only layers inside range are visible")) - .set_static(true) - ); - ret.push_back(ParamDesc("z_range_position") - .set_local_name(_("Z Range Position")) - .set_description(_("Starting position where layers are visible")) - ); - ret.push_back(ParamDesc("z_range_depth") - .set_local_name(_("Z Range Depth")) - .set_description(_("Depth where layers are visible in range")) - ); - ret.push_back(ParamDesc("z_range_blur") - .set_local_name(_("Z Range Blur")) - .set_description(_("Area where layers inside are partially visible")) - ); - - return ret; -} - -bool -Layer_Group::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE(param_z_range); - IMPORT_VALUE(param_z_range_position); - IMPORT_VALUE(param_z_range_depth); - IMPORT_VALUE(param_z_range_blur); - return Layer_PasteCanvas::set_param(param,value); -} - -ValueBase -Layer_Group::get_param(const String& param)const -{ - EXPORT_VALUE(param_z_range); - EXPORT_VALUE(param_z_range_position); - EXPORT_VALUE(param_z_range_depth); - EXPORT_VALUE(param_z_range_blur); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_PasteCanvas::get_param(param); -} - - -void -Layer_Group::apply_z_range_to_params(ContextParams &cp)const -{ - if (optimized()) return; // z_range already applied while optimizxation - - cp.z_range=param_z_range.get(bool()); - cp.z_range_position=param_z_range_position.get(Real()); - cp.z_range_depth=param_z_range_depth.get(Real()); - cp.z_range_blur=param_z_range_blur.get(Real()); -} diff --git a/synfig-core/src/synfig/layer_group.h b/synfig-core/src/synfig/layer_group.h deleted file mode 100644 index ddc8ad1..0000000 --- a/synfig-core/src/synfig/layer_group.h +++ /dev/null @@ -1,82 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_group.h -** \brief Header file for implementation of the "Group" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** Copyright (c) 2012-2013 Carlos López -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_GROUP_H -#define __SYNFIG_LAYER_GROUP_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_pastecanvas.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { -/*! \class Layer_Group -** \brief Class of the Group layer. -*/ -class Layer_Group : public Layer_PasteCanvas -{ - //! Layer module: defines the needed members to belong to a layer's factory. - SYNFIG_LAYER_MODULE_EXT -private: - //! Parameter: (bool) Z_Depth Range is active - ValueBase param_z_range; - //! Parameter: (Real) Z_Depth Range position - ValueBase param_z_range_position; - //! Parameter: (Real) Z_Depth Range depth - ValueBase param_z_range_depth; - //! Parameter: (Real) Z_Depth Range transition - ValueBase param_z_range_blur; - -public: - //! Default constructor - Layer_Group(); - //! Destructor - virtual ~Layer_Group(); - //! Returns a string with the localized name of this layer - virtual String get_local_name()const; - - //! Sets the parameter described by \a param to \a value. \see Layer::set_param - virtual bool set_param(const String & param, const synfig::ValueBase &value); - //! Get the value of the specified parameter. \see Layer::get_param - virtual ValueBase get_param(const String & param)const; - //! Gets the parameter vocabulary - virtual Vocab get_param_vocab()const; - - //! Sets z_range* fields of specified ContextParams \a cp - virtual void apply_z_range_to_params(ContextParams &cp)const; -}; // END of class Layer_Group - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_meshtransform.cpp b/synfig-core/src/synfig/layer_meshtransform.cpp deleted file mode 100644 index 5874dea..0000000 --- a/synfig-core/src/synfig/layer_meshtransform.cpp +++ /dev/null @@ -1,292 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_meshtransform.cpp -** \brief Implementation of the "MeshTransform" layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_meshtransform.h" -#include "renderersoftware.h" -#include -#include -#include -#include "transform.h" -#include "context.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -/* === C L A S S E S ======================================================= */ - -class synfig::Mesh_Trans : public Transform -{ - etl::handle layer; -public: - Mesh_Trans(const Layer_MeshTransform* x):Transform(x->get_guid()),layer(x) { } - - synfig::Vector perform(const synfig::Vector& x)const - { - Vector v(INFINITY, INFINITY); - layer->mesh.transform_coord_texture_to_world(x, v); - return v; - } - - synfig::Vector unperform(const synfig::Vector& x)const - { - Vector v(INFINITY, INFINITY); - layer->mesh.transform_coord_world_to_texture(x, v); - return v; - } - - synfig::String get_string()const - { - return "mesh"; - } -}; - -/* === G L O B A L S ======================================================= */ - -/* === M E T H O D S ======================================================= */ - -Layer_MeshTransform::Layer_MeshTransform(): - max_texture_size(4096), - max_texture_scale(INFINITY), - world_bounds(Rect::zero()), - texture_bounds(Rect::zero()) -{ - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer_MeshTransform::~Layer_MeshTransform() -{ -} - -void -Layer_MeshTransform::update_mesh_and_mask() -{ - // TODO: check mask to calculate bounds - - texture_scale_dependency_from_x = Vector::zero(); - texture_scale_dependency_from_y = Vector::zero(); - - if (mesh.vertices.empty()) - { - world_bounds = Rect::zero(); - texture_bounds = Rect::zero(); - } - else - { - Mesh::VertexList::const_iterator i = mesh.vertices.begin(); - world_bounds.set_point(i->position); - texture_bounds.set_point(i->tex_coords); - for(++i; i != mesh.vertices.end(); ++i) - { - world_bounds.expand(i->position); - texture_bounds.expand(i->position); - } - - const Real epsilon = 1e-10; - for(Mesh::TriangleList::const_iterator i = mesh.triangles.begin(); i != mesh.triangles.end(); ++i) - { - for(int j = 0; j < 3; ++j) - { - const Mesh::Vertex &v0 = mesh.vertices[i->vertices[j]]; - const Mesh::Vertex &v1 = mesh.vertices[i->vertices[(j+1)%3]]; - Vector wd( fabs(v1.position[0] - v0.position[0]), - fabs(v1.position[1] - v0.position[1]) ); - Vector td( fabs(v1.tex_coords[0] - v0.tex_coords[0]), - fabs(v1.tex_coords[1] - v0.tex_coords[1]) ); - if (td[0] > epsilon) - { - Vector dep(wd[0]/td[0], wd[1]/td[0]); - if (dep[0] > texture_scale_dependency_from_x[0]) - texture_scale_dependency_from_x[0] = dep[0]; - if (dep[1] > texture_scale_dependency_from_y[0]) - texture_scale_dependency_from_y[0] = dep[1]; - } - if (td[1] > epsilon) - { - Vector dep(wd[0]/td[1], wd[1]/td[1]); - if (dep[0] > texture_scale_dependency_from_x[1]) - texture_scale_dependency_from_x[1] = dep[0]; - if (dep[1] > texture_scale_dependency_from_y[1]) - texture_scale_dependency_from_y[1] = dep[1]; - } - } - } - - if (max_texture_scale > 0.0) - { - if (texture_scale_dependency_from_x[0] > max_texture_scale) - texture_scale_dependency_from_x[0] = max_texture_scale; - if (texture_scale_dependency_from_x[1] > max_texture_scale) - texture_scale_dependency_from_x[1] = max_texture_scale; - if (texture_scale_dependency_from_y[0] > max_texture_scale) - texture_scale_dependency_from_y[0] = max_texture_scale; - if (texture_scale_dependency_from_y[1] > max_texture_scale) - texture_scale_dependency_from_y[1] = max_texture_scale; - } - } -} - -Layer::Handle -Layer_MeshTransform::hit_check(synfig::Context context, const synfig::Point &point)const -{ - // TODO: check mask - Vector v; - return mesh.transform_coord_world_to_texture(point, v) - ? context.hit_check(v) - : Layer::Handle(); -} - -Color -Layer_MeshTransform::get_color(Context context, const Point &pos)const -{ - // TODO: check mask - Vector v; - return mesh.transform_coord_world_to_texture(pos, v) - ? context.get_color(v) - : Color(); -} - -Rect -Layer_MeshTransform::get_full_bounding_rect(Context /* context */)const -{ - return world_bounds; -} - -etl::handle -Layer_MeshTransform::get_transform()const -{ - return new Mesh_Trans(this); -} - -bool -Layer_MeshTransform::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - const Real epsilon = 1e-10; - - // initialize surface - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - surface->clear(); - - // calculate texture size - RendDesc texture_renddesc(renddesc); - texture_renddesc.set_transformation_matrix(Matrix()); - texture_renddesc.set_tl(texture_bounds.get_min()); - texture_renddesc.set_br(texture_bounds.get_max()); - { - int texture_width, texture_height; - Real pw = fabs(renddesc.get_pw()); - Real ph = fabs(renddesc.get_ph()); - if (pw < epsilon || pw < epsilon) return true; - pw = 1.0/pw; - ph = 1.0/ph; - Vector texture_size = texture_bounds.get_max() - texture_bounds.get_min(); - Real texture_pw = std::max( - texture_scale_dependency_from_x[0]*pw, - texture_scale_dependency_from_y[0]*ph ); - Real texture_ph = std::max( - texture_scale_dependency_from_x[1]*pw, - texture_scale_dependency_from_y[1]*ph ); - texture_width = std::max(1, (int)roundf(texture_pw*texture_size[0])); - texture_height = std::max(1, (int)roundf(texture_ph*texture_size[1])); - if (max_texture_size > 0) - { - if (texture_width > max_texture_size) texture_width = max_texture_size; - if (texture_height > max_texture_size) texture_height = max_texture_size; - } - texture_renddesc.set_w(texture_width); - texture_renddesc.set_h(texture_height); - } - - // render texture - Surface texture; - if(!context.accelerated_render(&texture,quality,texture_renddesc,cb)) - { - if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__)); - return false; - } - - { // render mask - Surface maskSurface; - maskSurface.set_wh(texture.get_w(), texture.get_h()); - maskSurface.fill(Color::alpha()); - RendererSoftware::render_polygon( - maskSurface, - mask, - texture_renddesc.get_transformation_matrix() - * texture_renddesc.get_world_to_pixels_matrix(), - Color::white(), - Color::BLEND_COMPOSITE ); - - // apply mask - Surface::pen a(texture.get_pen(0, 0)); - Surface::pen b(maskSurface.get_pen(0, 0)); - for(int i = 0; i < texture.get_h(); ++i) - { - for(int j = 0; j < texture.get_w(); ++j) - { - a.put_value(a.get_value()*b.get_value().get_a()); - a.inc_x(); - b.inc_x(); - } - a.dec_x(texture.get_w()); - b.dec_x(texture.get_w()); - a.inc_y(); - b.inc_y(); - } - } - - // prepare transformation matrices - Matrix world_to_pixels_matrix = - renddesc.get_transformation_matrix() - * renddesc.get_world_to_pixels_matrix(); - Matrix texture_to_texels_matrix = - texture_renddesc.get_world_to_pixels_matrix(); - - // render mesh - RendererSoftware::render_mesh( - *surface, - mesh, - texture, - world_to_pixels_matrix, - texture_to_texels_matrix, - 1.0, - Color::BLEND_COMPOSITE - ); - - return true; -} diff --git a/synfig-core/src/synfig/layer_meshtransform.h b/synfig-core/src/synfig/layer_meshtransform.h deleted file mode 100644 index 783165f..0000000 --- a/synfig-core/src/synfig/layer_meshtransform.h +++ /dev/null @@ -1,78 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_meshtransform.h -** \brief Header file for implementation of the "MeshTransform" layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_MESHTRANSFORM_H -#define __SYNFIG_LAYER_MESHTRANSFORM_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_composite.h" -#include "mesh.h" -#include "polygon.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { -class Mesh_Trans; -class Layer_MeshTransform : public Layer_Composite -{ -protected: - friend class Mesh_Trans; - Mesh mesh; - Polygon mask; - - int max_texture_size; - Real max_texture_scale; - -private: - Vector texture_scale_dependency_from_x; - Vector texture_scale_dependency_from_y; - Rect world_bounds; - Rect texture_bounds; - -protected: - void update_mesh_and_mask(); - -public: - //! Default constructor - Layer_MeshTransform(); - //! Destructor - virtual ~Layer_MeshTransform(); - - synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; - virtual Color get_color(Context context, const Point &pos)const; - virtual Rect get_full_bounding_rect(Context context)const; - virtual etl::handle get_transform()const; - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; -}; // END of class Layer_MeshTransform - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_mime.cpp b/synfig-core/src/synfig/layer_mime.cpp deleted file mode 100644 index 3998c8f..0000000 --- a/synfig-core/src/synfig/layer_mime.cpp +++ /dev/null @@ -1,148 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_mime.cpp -** \brief Template File -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_mime.h" - -#include "layer.h" -#include "time.h" -#include "string.h" -#include "vector.h" - -#include "context.h" -#include "time.h" -#include "color.h" -#include "surface.h" -#include "renddesc.h" -#include "target.h" - -#include "general.h" -#include "paramdesc.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace std; -using namespace etl; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -/* === G L O B A L S ======================================================= */ - -/* === P R O C E D U R E S ================================================= */ - -/* === M E T H O D S ======================================================= */ - -Layer_Mime::Layer_Mime(String x):name(x) -{ - // Throw a bogus default version onto the parameter list. - param_list["Version"]=(const char*)"9"; -} - -String -Layer_Mime::get_version()const -{ - return get_param("Version").get(String()); -} - -bool -Layer_Mime::set_version(const String &ver) -{ - return set_param("Version",ver); -} - -String -Layer_Mime::get_local_name()const -{ - return _("[MIME]")+get_name(); -} - -bool -Layer_Mime::set_param(const String ¶m, const ValueBase &value) -{ - // Don't try to set the name - if(param=="name" || param=="Name" || param=="name__") - return false; - - // Otherwise, remember this parameter's value - param_list[param]=value; - return true; -} - -ValueBase -Layer_Mime::get_param(const String ¶m)const -{ - // If they are requesting the name of - // the layer, just return it - if(param=="name" || param=="Name" || param=="name__") - return ValueBase(name); - - // Otherwise, return the stored parameter value - map::const_iterator iter=param_list.find(param); - if(iter!=param_list.end()) - return iter->second; - return ValueBase(); -} - -Color -Layer_Mime::get_color(Context context, const Point &pos)const -{ - // A Layer_Mime layer should do nothing at all. - return context.get_color(pos); -} - -bool -Layer_Mime::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - // A Layer_Mime layer should do nothing at all. - return context.accelerated_render(surface,quality,renddesc,cb); -} - -Layer::Vocab -Layer_Mime::get_param_vocab()const -{ - Layer::Vocab ret; - map::const_iterator iter; - - // Construct the vocabulary from the stored - // parameters - for(iter=param_list.begin();iter!=param_list.end();iter++) - { - // Make sure that we don't add the version - // into the vocabulary - if(iter->first!="Version") - ret.push_back(ParamDesc(iter->first)); - } - - // ... and return it - return ret; -} diff --git a/synfig-core/src/synfig/layer_mime.h b/synfig-core/src/synfig/layer_mime.h deleted file mode 100644 index 9befa47..0000000 --- a/synfig-core/src/synfig/layer_mime.h +++ /dev/null @@ -1,75 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_mime.h -** \brief Template Header -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_MIME_H -#define __SYNFIG_LAYER_MIME_H - -/* === H E A D E R S ======================================================= */ - -#include "layer.h" -#include "string.h" -#include - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -/*! \class Layer_Mime -** The mime layer is a layer that is used when an unknown -** layer type is requested. This allows people without -** all of the correct layers installed to still work with -** that composition. -*/ -class Layer_Mime : public Layer -{ - std::map param_list; - String name; -public: - Layer_Mime(String name); - - virtual String get_version()const; - - virtual bool set_version(const String &ver); - - virtual bool set_param(const String ¶m, const ValueBase &value); - - virtual ValueBase get_param(const String ¶m)const; - - virtual Color get_color(Context context, const Point &pos)const; - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - - virtual Vocab get_param_vocab()const; - virtual String get_local_name()const; - -}; - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_motionblur.cpp b/synfig-core/src/synfig/layer_motionblur.cpp deleted file mode 100644 index 435a7a0..0000000 --- a/synfig-core/src/synfig/layer_motionblur.cpp +++ /dev/null @@ -1,413 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_motionblur.cpp -** \brief Implementation of the "Motion Blur" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "string.h" -#include "layer_motionblur.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenode.h" -#include "canvas.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace synfig; -using namespace etl; -using namespace std; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_MotionBlur); -SYNFIG_LAYER_SET_NAME(Layer_MotionBlur,"MotionBlur"); // todo: use motion_blur -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_MotionBlur,N_("Motion Blur")); -SYNFIG_LAYER_SET_CATEGORY(Layer_MotionBlur,N_("Blurs")); -SYNFIG_LAYER_SET_VERSION(Layer_MotionBlur,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_MotionBlur,"$Id$"); - -/* === M E M B E R S ======================================================= */ - -Layer_MotionBlur::Layer_MotionBlur(): - Layer_Composite (1.0,Color::BLEND_STRAIGHT), - param_aperture (ValueBase(Time(0))), - param_subsamples_factor (ValueBase(Real(1.0))), - param_subsampling_type (ValueBase(int(SUBSAMPLING_HYPERBOLIC))), - param_subsample_start (ValueBase(Real(0.0))), - param_subsample_end (ValueBase(Real(1.0))) -{ - -} - -bool -Layer_MotionBlur::set_param(const String ¶m, const ValueBase &value) -{ - - IMPORT_VALUE(param_aperture); - IMPORT_VALUE(param_subsamples_factor); - IMPORT_VALUE(param_subsampling_type); - IMPORT_VALUE(param_subsample_start); - IMPORT_VALUE(param_subsample_end); - return Layer_Composite::set_param(param,value); -} - -ValueBase -Layer_MotionBlur::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_aperture); - EXPORT_VALUE(param_subsamples_factor); - EXPORT_VALUE(param_subsampling_type); - EXPORT_VALUE(param_subsample_start); - EXPORT_VALUE(param_subsample_end); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_Composite::get_param(param); -} - -void -Layer_MotionBlur::set_time(IndependentContext context, Time time)const -{ - context.set_time(time); - time_cur=time; -} - -void -Layer_MotionBlur::set_time(IndependentContext context, Time time, const Point &pos)const -{ - context.set_time(time,pos); - time_cur=time; -} - -Color -Layer_MotionBlur::get_color(Context context, const Point &pos)const -{ -/* if(aperture) - { - Time time(time_cur); - time+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) *aperture -aperture*0.5; - context.set_time(time, pos); - } -*/ - return context.get_color(pos); -} - -Layer::Vocab -Layer_MotionBlur::get_param_vocab()const -{ - Layer::Vocab ret; - //ret=Layer_Composite::get_param_vocab(); - - ret.push_back(ParamDesc("aperture") - .set_local_name(_("Aperture")) - .set_description(_("Shutter Time")) - ); - - ret.push_back(ParamDesc("subsamples_factor") - .set_local_name(_("Subsamples Factor")) - .set_description(_("Multiplies The Number Of Subsamples Rendered")) - ); - - ret.push_back(ParamDesc("subsampling_type") - .set_local_name(_("Subsampling Type")) - .set_description(_("Curve Type For Weighting Subsamples")) - .set_hint("enum") - .add_enum_value(SUBSAMPLING_CONSTANT,"constant",_("Constant")) - .add_enum_value(SUBSAMPLING_LINEAR,"linear",_("Linear")) - .add_enum_value(SUBSAMPLING_HYPERBOLIC,"hyperbolic",_("Hyperbolic")) - ); - - ret.push_back(ParamDesc("subsample_start") - .set_local_name(_("Subsample Start Amount")) - .set_description(_("Relative Amount Of The First Subsample, For Linear Weighting")) - ); - - ret.push_back(ParamDesc("subsample_end") - .set_local_name(_("Subsample End Amount")) - .set_description(_("Relative Amount Of The Last Subsample, For Linear Weighting")) - ); - - return ret; -} - -bool -Layer_MotionBlur::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) - - Time aperture=param_aperture.get(Time()); - Real subsamples_factor=param_subsamples_factor.get(Real()); - SubsamplingType subsampling_type=(SubsamplingType)param_subsampling_type.get(int()); - Real subsample_start=param_subsample_start.get(Real()); - Real subsample_end=param_subsample_end.get(Real()); - - if(aperture && quality<=10) - { - //int x, y; - SuperCallback subimagecb; - int samples=1; - switch(quality) - { - case 1: // Production Quality - samples=32; - break; - case 2: // Excellent Quality - samples=24; - break; - case 3: // Good Quality - samples=16; - break; - case 4: // Moderate Quality - samples=12; - break; - case 5: // Draft Quality - samples=7; - break; - case 6: - samples=6; - break; - case 7: - samples=5; - break; - case 8: - samples=3; - break; - case 9: - samples=2; - break; - case 10: // Rough Quality - default: - samples=1; - break; - - } - - samples *= subsamples_factor; - - if (samples <= 1) return context.accelerated_render(surface,quality,renddesc,cb); - - // Only in modes where subsample_start/end matters... - if(subsampling_type == SUBSAMPLING_LINEAR) - { - // We won't render when the scale==0, so we'll use those samples elsewhere - if(subsample_start == 0) samples++; - if(subsample_end == 0) samples++; - } - - Surface tmp; - int i; - float scale, divisor = 0; - - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - surface->clear(); - - // Render subsamples from time_cur-aperture to time_cur - for(i=0;i -#endif - -#include "layer_pastecanvas.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenode.h" -#include "canvas.h" -#include "cairo_renddesc.h" - - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -#define MAX_DEPTH 10 - -// if this isn't defined, the 'dead heads' in examples/pirates.sifz don't render properly -#define SYNFIG_CLIP_PASTECANVAS - -//#ifdef __APPLE__ -//#undef SYNFIG_CLIP_PASTECANVAS -//#endif - -/* === C L A S S E S ======================================================= */ - -class depth_counter // Makes our recursive depth counter exception-safe -{ - int *depth; -public: - depth_counter(int &x):depth(&x) { (*depth)++; } - ~depth_counter() { (*depth)--; } -}; - -/* === G L O B A L S ======================================================= */ - -/* === M E T H O D S ======================================================= */ - -Layer_PasteCanvas::Layer_PasteCanvas(): - param_origin(Point()), - param_transformation(Transformation()), - param_time_offset (Time(0)), - depth(0), - extra_reference(false) -{ - param_children_lock=ValueBase(bool(false)); - param_outline_grow=ValueBase(Real(0)); - param_curr_time=ValueBase(Time::begin()); - - muck_with_time_=true; - - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer_PasteCanvas::~Layer_PasteCanvas() -{ -/* if(canvas) - canvas->parent_set.erase(this); -*/ - - //if(canvas)DEBUGINFO(strprintf("%d",canvas->count())); - - set_sub_canvas(0); - - //if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root())) - //if(extra_reference) - // canvas->unref(); -} - -String -Layer_PasteCanvas::get_local_name()const -{ - if(!canvas || canvas->is_inline()) return String(); - if(canvas->get_root()==get_canvas()->get_root()) return canvas->get_id(); - return canvas->get_file_name(); -} - -Layer::Vocab -Layer_PasteCanvas::get_param_vocab()const -{ - Layer::Vocab ret(Layer_Composite::get_param_vocab()); - - ret.push_back(ParamDesc("origin") - .set_local_name(_("Origin")) - .set_description(_("Position offset")) - ); - - ret.push_back(ParamDesc("transformation") - .set_local_name(_("Transformation")) - .set_description(_("Position, rotation, skew and scale")) - ); - - ret.push_back(ParamDesc("canvas") - .set_local_name(_("Canvas")) - .set_description(_("Group content")) - ); - - ret.push_back(ParamDesc("time_offset") - .set_local_name(_("Time Offset")) - .set_description(_("Time Offset to apply to the context")) - ); - - ret.push_back(ParamDesc("children_lock") - .set_local_name(_("Lock Selection")) - .set_description(_("When checked prevents to select the children using the mouse click")) - .set_static(true) - ); - - ret.push_back(ParamDesc("outline_grow") - .set_local_name(_("Outline Grow")) - .set_description(_("Exponential value to grow children Outline layers width")) - ); - if(canvas && !(canvas->is_inline())) - { - ret.back().hidden(); - } - - // optimize_layers() in canvas.cpp makes a new PasteCanvas layer - // and copies over the parameters of the old layer. the - // 'curr_time' member wasn't being copied, so I've added it as a - // hidden, non critical parameter, and now it will be. this - // allows a single exported subcanvas to be used more than once at - // a time, with different time offets in each. see bug #1896557. - ret.push_back(ParamDesc("curr_time") - .set_local_name(_("Current Time")) - .not_critical() - .hidden() - ); - - return ret; -} - -bool -Layer_PasteCanvas::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE(param_origin); - IMPORT_VALUE(param_transformation); - - // IMPORT(canvas); - if(param=="canvas" && value.can_get(Canvas::Handle())) - { - set_sub_canvas(value.get(Canvas::Handle())); - return true; - } - //! \todo this introduces bug 1844764 if enabled; it was introduced in r954. - // http://synfig.org/images/3/3d/Moving-waypoints.sifz is an - // example of an animation that has its waypoints displayed - // incorrectly without this fix; select the outer layer and drag - // the time slider. The linear waypoints don't take effect until - // 5s, but the time slider appears to pass the first one at 3s. -#if 0 - if (param=="time_offset" && value.same_type_as(time_offset)) - { - if (time_offset != value.get(Time())) - { - value.put(&time_offset); - // notify that the time_offset has changed so we can update the - // waypoint positions in parent layers - changed(); - } - return true; - } -#else - IMPORT_VALUE(param_time_offset); -#endif - - IMPORT_VALUE(param_children_lock); - IMPORT_VALUE(param_outline_grow); - IMPORT_VALUE(param_curr_time); - return Layer_Composite::set_param(param,value); -} - -void -Layer_PasteCanvas::set_sub_canvas(etl::handle x) -{ - if(canvas && muck_with_time_) - remove_child(canvas.get()); - - // if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root())) - if (extra_reference) - canvas->unref(); - - child_changed_connection.disconnect(); - - if (canvas != x) signal_subcanvas_changed()(); - - canvas=x; - - /*if(canvas) - child_changed_connection=canvas->signal_changed().connect( - sigc::mem_fun( - *this, - &Layer_PasteCanvas::changed - ) - ); - */ - - if(canvas && muck_with_time_) - add_child(canvas.get()); - - if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root())) - { - canvas->ref(); - extra_reference = true; - } - else - extra_reference = false; - - if(canvas) - on_canvas_set(); -} - -// when a pastecanvas that contains another pastecanvas is copy/pasted -// from one document to another, only the outermost pastecanvas was -// getting its renddesc set to match that of its new parent. this -// function is used to recurse through the pastecanvas copying its -// renddesc to any pastecanvases it contains (bug #2116947, svn r2200) -void -Layer_PasteCanvas::update_renddesc() -{ - if(!get_canvas() || !canvas || !canvas->is_inline()) return; - - canvas->rend_desc()=get_canvas()->rend_desc(); - for (IndependentContext iter = canvas->get_independent_context(); !iter->empty(); iter++) - { - etl::handle paste = etl::handle::cast_dynamic(*iter); - if (paste) paste->update_renddesc(); - } -} - -// This is called whenever the parent canvas gets set/changed -void -Layer_PasteCanvas::on_canvas_set() -{ - if(get_canvas() && canvas && canvas->is_inline() && canvas->parent()!=get_canvas()) - { - canvas->set_inline(get_canvas()); - } -} - -ValueBase -Layer_PasteCanvas::get_param(const String& param)const -{ - EXPORT_VALUE(param_origin); - EXPORT_VALUE(param_transformation); - if (param=="canvas") - { - synfig::ValueBase ret(canvas); - return ret; - } - EXPORT_VALUE(param_time_offset); - EXPORT_VALUE(param_children_lock); - EXPORT_VALUE(param_curr_time); - EXPORT_VALUE(param_outline_grow); - - return Layer_Composite::get_param(param); -} - -void -Layer_PasteCanvas::set_time(IndependentContext context, Time time)const -{ - Time time_offset=param_time_offset.get(Time()); - - if(depth==MAX_DEPTH)return;depth_counter counter(depth); - param_curr_time.set(time); - - context.set_time(time); - if(canvas) - canvas->set_time(time+time_offset); -} - -void -Layer_PasteCanvas::apply_z_range_to_params(ContextParams &/*cp*/)const -{ -} - -synfig::Layer::Handle -Layer_PasteCanvas::hit_check(synfig::Context context, const synfig::Point &pos)const -{ - if(depth==MAX_DEPTH)return 0;depth_counter counter(depth); - - Transformation transformation(get_summary_transformation()); - - bool children_lock=param_children_lock.get(bool(true)); - ContextParams cp(context.get_params()); - apply_z_range_to_params(cp); - if (canvas) { - Point target_pos = transformation.back_transform(pos); - - if(canvas && get_amount() && canvas->get_context(cp).get_color(target_pos).get_a()>=0.25) - { - if(!children_lock) - { - return canvas->get_context(cp).hit_check(target_pos); - } - return const_cast(this); - } - } - return context.hit_check(pos); -} - -Color -Layer_PasteCanvas::get_color(Context context, const Point &pos)const -{ - Transformation transformation(get_summary_transformation()); - - ContextParams cp(context.get_params()); - apply_z_range_to_params(cp); - if(!canvas || !get_amount()) - return context.get_color(pos); - - if(depth==MAX_DEPTH)return Color::alpha();depth_counter counter(depth); - - Point target_pos = transformation.back_transform(pos); - - return Color::blend(canvas->get_context(cp).get_color(target_pos),context.get_color(pos),get_amount(),get_blend_method()); -} - -Rect -Layer_PasteCanvas::get_bounding_rect_context_dependent(const ContextParams &context_params)const -{ - if (canvas) - { - ContextParams cp(context_params); - apply_z_range_to_params(cp); - - return get_summary_transformation() - .transform_bounds( - canvas->get_context(cp).get_full_bounding_rect() ); - } - return Rect::zero(); -} - -Rect -Layer_PasteCanvas::get_full_bounding_rect(Context context)const -{ - if(is_disabled() || Color::is_onto(get_blend_method())) - return context.get_full_bounding_rect(); - - return context.get_full_bounding_rect()|get_bounding_rect_context_dependent(context.get_params()); -} - -bool -Layer_PasteCanvas::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - Transformation transformation( - get_summary_transformation().get_matrix() - * renddesc.get_transformation_matrix() ); - - Real outline_grow=param_outline_grow.get(Real()); - Time time_offset=param_time_offset.get(Time()); - Time curr_time=param_curr_time.get(Time()); - - if(cb && !cb->amount_complete(0,10000)) return false; - - if(depth==MAX_DEPTH) - // if we are at the extent of our depth, - // then we should just return whatever is under us. - return context.accelerated_render(surface,quality,renddesc,cb); - - depth_counter counter(depth); - - if(!canvas || !get_amount()) - return context.accelerated_render(surface,quality,renddesc,cb); - - SuperCallback stageone(cb,0,4500,10000); - SuperCallback stagetwo(cb,4500,9000,10000); - SuperCallback stagethree(cb,9000,9999,10000); - - Context canvasContext = canvas->get_context(context); - - if (is_solid_color()) - { - RendDesc intermediate_desc(renddesc); - intermediate_desc.clear_flags(); - intermediate_desc.set_transformation_matrix(transformation.get_matrix()); - return canvasContext.accelerated_render(surface,quality,intermediate_desc,&stagetwo); - } - else - if (!context.accelerated_render(surface,quality,renddesc,&stageone)) - return false; - - Real grow_value(get_parent_canvas_grow_value()); - canvas->set_grow_value(outline_grow+grow_value); - - if(muck_with_time_ && curr_time!=Time::begin() /*&& canvas->get_time()!=curr_time+time_offset*/) - canvas->set_time(curr_time+time_offset); - - Color::BlendMethod blend_method(get_blend_method()); - const Rect full_bounding_rect(canvasContext.get_full_bounding_rect()); - - Rect inner_bounds( - full_bounding_rect.get_min(), - full_bounding_rect.get_max() - ); - inner_bounds &= transformation.back_transform_bounds(renddesc.get_rect()); - Rect outer_bounds(transformation.transform_bounds(inner_bounds)); - outer_bounds &= renddesc.get_rect(); - if (!outer_bounds.is_valid()) - return true; - - Rect next_bounds( Transformation::transform_bounds(renddesc.get_transformation_matrix(), context.get_full_bounding_rect()) ); - - // sometimes the user changes the parameters while we're - // rendering, causing our pasted canvas' bounding box to shrink - // and no longer overlap with our tile. if that has happened, - // let's just stop now - we'll be refreshing soon anyway - //! \todo shouldn't a mutex ensure this isn't needed? - // http://synfig.org/images/d/d2/Bbox-change.sifz is an example - // that shows this happening - open the encapsulation, select the - // 'shade', and toggle the 'invert' parameter quickly. - // Occasionally you'll see: - // error: Context::accelerated_render(): Layer "shade" threw a bad_alloc exception! - // where the shade layer tries to allocate itself a canvas of - // negative proportions, due to changing bounding boxes. - if (!inner_bounds.is_valid()) - { - warning("%s:%d bounding box shrank while rendering?", __FILE__, __LINE__); - return true; - } - - bool blend_using_straight = false; // use 'straight' just for the central blit - - if (!etl::intersect(next_bounds,outer_bounds)) - { - // if there's no intersection between the context and our - // surface, and we're rendering 'onto', then we're done - if (Color::is_onto(blend_method) && !Color::is_straight(blend_method)) - return true; - - /* 'straight' is faster than 'composite' and has the same - * effect if the affected area of the lower layer is - * transparent; however, if we're not clipping the blit to - * just the bounding rectangle, the affected area is the whole - * tile, so we can't use this optimisation. if we are - * clipping, then we can use 'straight' to blit the clipped - * rectangle, but we shouldn't set blend_method to 'straight', - * or the surrounding areas will be blanked, which we don't - * want. - */ -#ifdef SYNFIG_CLIP_PASTECANVAS - if (blend_method==Color::BLEND_COMPOSITE) blend_using_straight = true; -#endif // SYNFIG_CLIP_PASTECANVAS - } - - int w = renddesc.get_w(); - int h = renddesc.get_h(); - Vector tl = renddesc.get_tl(); - Vector br = renddesc.get_br(); - Vector size = br - tl; - Real rx0 = (outer_bounds.minx - tl[0])/size[0]*w; - Real rx1 = (outer_bounds.maxx - tl[0])/size[0]*w; - Real ry0 = (outer_bounds.miny - tl[1])/size[1]*h; - Real ry1 = (outer_bounds.maxy - tl[1])/size[1]*h; - if (rx1 < rx0) { Real rx = rx0; rx0 = rx1; rx1 = rx; } - if (ry1 < ry0) { Real ry = ry0; ry0 = ry1; ry1 = ry; } - int x0((floor(rx0))); - int x1((ceil(rx1))); - int y0((floor(ry0))); - int y1((ceil(ry1))); - - if (x0 < 0) x0 = 0; else if (x0 > w) x0 = w; - if (x1 < 0) x1 = 0; else if (x1 > w) x1 = w; - if (y0 < 0) y0 = 0; else if (y0 > h) y0 = h; - if (y1 < 0) y1 = 0; else if (y1 > h) y1 = h; - int intermediate_w = x1 - x0; - int intermediate_h = y1 - y0; - Vector pixel_aligned_tl( - (Real)x0/(Real)w*size[0] + tl[0], - (Real)y0/(Real)h*size[1] + tl[1] ); - Vector pixel_aligned_br( - (Real)x1/(Real)w*size[0] + tl[0], - (Real)y1/(Real)h*size[1] + tl[1] ); - - if (intermediate_w > 0 && intermediate_h > 0) { - RendDesc intermediate_desc(renddesc); - intermediate_desc.clear_flags(); - intermediate_desc.set_transformation_matrix(transformation.get_matrix()); - intermediate_desc.set_wh(intermediate_w, intermediate_h); - intermediate_desc.set_tl(pixel_aligned_tl); - intermediate_desc.set_br(pixel_aligned_br); - Surface intermediate_surface; - if(!canvasContext.accelerated_render(&intermediate_surface,quality,intermediate_desc,&stagetwo)) - return false; - Surface::alpha_pen apen(surface->get_pen(x0, y0)); - apen.set_alpha(get_amount()); - apen.set_blend_method(blend_using_straight ? Color::BLEND_STRAIGHT : blend_method); - intermediate_surface.blit_to(apen); - } - - if(cb && !cb->amount_complete(10000,10000)) return false; - return true; -} - -/////// - -bool -Layer_PasteCanvas::accelerated_cairorender(Context context,cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - Transformation transformation(get_summary_transformation()); - - Real outline_grow=param_outline_grow.get(Real()); - Time time_offset=param_time_offset.get(Time()); - Time curr_time=param_curr_time.get(Time()); - - if(cb && !cb->amount_complete(0,10000)) return false; - - if(depth==MAX_DEPTH) - // if we are at the extent of our depth, - // then we should just return whatever is under us. - return context.accelerated_cairorender(cr,quality,renddesc,cb); - - depth_counter counter(depth); - - if(!canvas || !get_amount()) - return context.accelerated_cairorender(cr,quality,renddesc,cb); - - SuperCallback stageone(cb,0,4500,10000); - SuperCallback stagetwo(cb,4500,9000,10000); - SuperCallback stagethree(cb,9000,9999,10000); - - - Real grow_value(get_parent_canvas_grow_value()); - canvas->set_grow_value(outline_grow+grow_value); - - if(muck_with_time_ && curr_time!=Time::begin() /*&& canvas->get_time()!=curr_time+time_offset*/) - canvas->set_time(curr_time+time_offset); - - bool ret; - RendDesc workdesc(renddesc); - - // Render the background - ret=context.accelerated_cairorender(cr, quality, renddesc, &stagethree); - if(!ret) - return false; - - - // render the canvas to be pasted onto pastesurface - cairo_surface_t* pastesurface=cairo_surface_create_similar_image(cairo_get_target(cr), CAIRO_FORMAT_ARGB32, workdesc.get_w(), workdesc.get_h()); - cairo_t* subcr=cairo_create(pastesurface); - // apply the transformations form the current context - cairo_matrix_t matrix; - cairo_get_matrix(cr, &matrix); - - // apply the transformations form the (paste canvas) group layer - cairo_set_matrix(subcr, &matrix); - - cairo_matrix_t cairo_transformation_matrix; - Matrix transformation_matrix(transformation.get_matrix()); - cairo_matrix_init( - &cairo_transformation_matrix, - transformation_matrix.m00, - transformation_matrix.m01, - transformation_matrix.m10, - transformation_matrix.m11, - transformation_matrix.m20, - transformation_matrix.m21 ); - - cairo_transform(subcr, &cairo_transformation_matrix); - - // Effectively render the canvas content - ret=canvas->get_context(context).accelerated_cairorender(subcr, quality, workdesc, &stagetwo); - // we are done apply the result to the source - cairo_destroy(subcr); - - if(!ret) - return false; - // Let's paint the result with its alpha - cairo_save(cr); - - cairo_status_t status; - status=cairo_matrix_invert(&matrix); - if(status) // doh! the matrix can't be inverted! - { - synfig::error("Can't invert current Cairo matrix!"); - return false; - } - // apply the inverse of the transformation of the current context to - // compensate the pending transformations form cr to be applied. - cairo_transform(cr, &matrix); - cairo_set_source_surface(cr, pastesurface, 0, 0); - cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); - - cairo_restore(cr); - cairo_surface_destroy(pastesurface); - - if(cb && !cb->amount_complete(10000,10000)) return false; - - return true; -} -/////// - - -void Layer_PasteCanvas::get_times_vfunc(Node::time_set &set) const -{ - Time time_offset=param_time_offset.get(Time()); - - Node::time_set tset; - if(canvas) tset = canvas->get_times(); - - Node::time_set::iterator i = tset.begin(), end = tset.end(); - - //Make sure we offset the time... - //! \todo: SOMETHING STILL HAS TO BE DONE WITH THE OTHER DIRECTION - // (recursing down the tree needs to take this into account too...) - for(; i != end; ++i) - set.insert(*i -#ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET // see node.h - - time_offset -#endif - ); - - Layer::get_times_vfunc(set); -} - - -void -Layer_PasteCanvas::set_render_method(Context context, RenderMethod x) -{ - if(canvas) // if there is a canvas pass down to it - canvas->get_context(context).set_render_method(x); - - // in any case pass it down - context.set_render_method(x); -} - -void -Layer_PasteCanvas::fill_sound_processor(SoundProcessor &soundProcessor) const -{ - if (active() && canvas) canvas->fill_sound_processor(soundProcessor); -} diff --git a/synfig-core/src/synfig/layer_pastecanvas.h b/synfig-core/src/synfig/layer_pastecanvas.h deleted file mode 100644 index 5bfb7a7..0000000 --- a/synfig-core/src/synfig/layer_pastecanvas.h +++ /dev/null @@ -1,203 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_pastecanvas.h -** \brief Header file for implementation of the "Paste Canvas" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** Copyright (c) 2012-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_PASTECANVAS_H -#define __SYNFIG_LAYER_PASTECANVAS_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_composite.h" -#include "color.h" -#include "vector.h" -#include "real.h" -#include "time.h" -#include "canvasbase.h" -#include "canvas.h" -#include "rect.h" -#include "transformation.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { -/*! \class Layer_PasteCanvas -** \brief Class of the Pasted Canvas layer. -*/ -class Layer_PasteCanvas : public Layer_Composite, public Layer_NoDeform -{ -private: - //! Parameter: (Origin) Position offset - ValueBase param_origin; - //! Parameter: (Transfromation) Position, rotation and scale of the paste canvas layer - ValueBase param_transformation; - //! Parameter: (etl::loose_handle) The canvas parameter - etl::loose_handle canvas; - //! Parameter: (Time) Time offset of the paste canvas layer - ValueBase param_time_offset; - //! Parameter: (Real) The value to grow the children outline layers - ValueBase param_outline_grow; - //! Parameter: (bool) Value that avoid hit check to go depth into the children. - ValueBase param_children_lock; - //! Parameter: Current time of the paste canvas layer. \see set_time - mutable ValueBase param_curr_time; - - //! \todo writeme! - bool muck_with_time_; - //! Recursion depth counter. - mutable int depth; - - //! Boundaries of the paste canvas layer. It is the canvas's boundary - //! affected by the origin and transformation. - mutable Rect bounds; - //! signal connection for children. Seems to be used only here - sigc::connection child_changed_connection; - - // Nasty hack: Remember whether we called an extra ref() when - // setting the canvas, so we know whether to call an extra unref() - // when finished with the canvas. - // - // Here's the story: - // - // The root canvas is destructed first. That sets the - // Layer::canvas_ (the parent canvas) of any PasteCanvas layer it - // contains to nil, due to a call to Layer::set_canvas(0), - // triggered by the connection made when Layer::set_canvas - // originally set its canvas_ member to point to the root canvas. - // ~Canvas does begin_delete() which triggers that connection. - // - // After ~Canvas has run, the members of the root canvas are - // freed, including its children_ list. If this was the last - // reference to the child canvas that the pastecanvas uses, that - // child canvas will Layer_PasteCanvas::set_sub_canvas(0) on the - // PasteCanvas layer to set its canvas (the child, pasted canvas) - // not to refer to the soon-to-be destroys child canvas. But - // set_sub_canvas() originally looked at the value of - // Layer::canvas_ (the parent canvas, obtained via - // Layer::get_canvas()) to decide whether to do an extra ref() on - // canvas (the child canvas). We need to unref() it now if we - // did, but we've forgotten whether we did. So we use this - // 'extra_reference' member to store that decision. - bool extra_reference; - - /* - -- ** -- S I G N A L S ------------------------------------------------------- - */ - -private: - //! Signal used when the canvas parameter has changed. \see layertreestore.cpp - sigc::signal signal_subcanvas_changed_; - - /* - -- ** -- S I G N A L I N T E R F A C E ------------------------------------- - */ - -public: - //! Wrapper for the subcanvas changed signal - sigc::signal& signal_subcanvas_changed() { return signal_subcanvas_changed_; } - -public: - - //! Recursively update the Render Description for the inner inline only pasted canvases. - //! Used for copy and paste Paste Canvas Layers between compositions. - void update_renddesc(); - - //! Every time the Paste Canvas Layer parent canvas is changed, this - //! is called and it sets the parent of the canvas parameter to that canvas - //! if it is on line - virtual void on_canvas_set(); - //! Sets muck_with_time. - //! \todo writeme! - void set_muck_with_time(bool x=false) { muck_with_time_=x; } - - //! Gets the canvas parameter. It is called sub_canvas to avoid confusion - //! with the get_canvas from the Layer class. - etl::handle get_sub_canvas()const { return canvas; } - //! Sets the canvas parameter. - //! \see get_sub_canvas() - void set_sub_canvas(etl::handle x); - //! Gets time offset parameter - Time get_time_offset()const { return param_time_offset.get(Time()); } - - //! Get origin parameter - Point get_origin()const { return param_origin.get(Point()); } - //! Get transformation parameter - Transformation get_transformation()const { return param_transformation.get(Transformation()); } - //! Get summary transformation - Transformation get_summary_transformation()const - { - return get_transformation().transform( Transformation(-get_origin()) ); - } - - //! Default constructor - Layer_PasteCanvas(); - //! Destructor - virtual ~Layer_PasteCanvas(); - //! Returns a string with the localized name of this layer - virtual String get_local_name()const; - //! Sets the parameter described by \a param to \a value. \see Layer::set_param - virtual bool set_param(const String & param, const synfig::ValueBase &value); - //! Get the value of the specified parameter. \see Layer::get_param - virtual ValueBase get_param(const String & param)const; - //! Sets z_range* fields of specified ContextParams \a cp - virtual void apply_z_range_to_params(ContextParams &cp)const; - //! Gets the blend color of the Layer in the context at \a pos - virtual Color get_color(Context context, const Point &pos)const; - //! Sets the time of the Paste Canvas Layer and those under it - virtual void set_time(IndependentContext context, Time time)const; - //! Renders the Canvas to the given Surface in an accelerated manner - //! See Layer::accelerated_render - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - //! Bounding rect for this layer depends from context_params - Rect get_bounding_rect_context_dependent(const ContextParams &context_params)const; - //!Returns the rectangle that includes the context of the layer and - //! the intersection of the layer in case it is active and not onto - virtual Rect get_full_bounding_rect(Context context)const; - //! Gets the parameter vocabulary - virtual Vocab get_param_vocab()const; - //! Checks to see if a part of the Paste Canvas Layer is directly under \a point - virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; - virtual void set_render_method(Context context, RenderMethod x); - - virtual void fill_sound_processor(SoundProcessor &soundProcessor) const; - -protected: - //! Function to be overloaded that fills the Time Point Set with - //! all the children Time Points. In this case the children Time Points - //! are the canvas parameter children layers Time points and the Paste Canvas - //! Layer time points. \todo clarify all this comments. - virtual void get_times_vfunc(Node::time_set &set) const; - -}; // END of class Layer_PasteCanvas - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_polygon.cpp b/synfig-core/src/synfig/layer_polygon.cpp deleted file mode 100644 index 12017e4..0000000 --- a/synfig-core/src/synfig/layer_polygon.cpp +++ /dev/null @@ -1,194 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_polygon.cpp -** \brief Implementation of the "Polygon" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007 Chris Moore -** Copyright (c) 2011-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_polygon.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenode.h" -#include - -#include -using std::deque; - -#endif - -/* === U S I N G =========================================================== */ - -using namespace synfig; -using namespace std; -using namespace etl; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Polygon); -SYNFIG_LAYER_SET_NAME(Layer_Polygon,"polygon"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Polygon,N_("Polygon")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Polygon,N_("Geometry")); -SYNFIG_LAYER_SET_VERSION(Layer_Polygon,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Polygon,"$Id$"); - -/* === C L A S S E S ======================================================= */ - -/* === M E T H O D S ======================================================= */ - -Layer_Polygon::Layer_Polygon(): - Layer_Shape(1.0,Color::BLEND_COMPOSITE), - param_vector_list(ValueBase(std::vector())) -{ - std::vector vector_list; - vector_list.push_back(Point(0,0.5)); - vector_list.push_back(Point(-0.333333,0)); - vector_list.push_back(Point(0.333333,0)); - param_vector_list.set_list_of(vector_list); - sync(); - - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer_Polygon::~Layer_Polygon() -{ -} - -void -Layer_Polygon::sync() -{ -/* - int i,pointcount=vector_list.size(); - - if(pointcount<3) - return; - - //Layer_Shape::clear(); - //clear(); - - // Build edge table - move_to(vector_list[0][0],vector_list[0][1]); - - for(i = 1;i < pointcount; i++) - { - if(isnan(vector_list[i][0]) || isnan(vector_list[i][1])) - break; - line_to(vector_list[i][0],vector_list[i][1]); - } - close(); - //endpath(); -*/ -} - -void -Layer_Polygon::add_polygon(const std::vector &point_list) -{ - int i,pointcount=point_list.size(); - - if(pointcount<3) - return; - - //Layer_Shape::clear(); - //clear(); - - // Build edge table - move_to(point_list[0][0],point_list[0][1]); - - for(i = 1;i < pointcount; i++) - { - if(isnan(point_list[i][0]) || isnan(point_list[i][1])) - break; - line_to(point_list[i][0],point_list[i][1]); - } - close(); - //endpath(); -} - -void -Layer_Polygon::upload_polygon(const std::vector &point_list) -{ - ValueBase::List vector_list; - vector_list.reserve(point_list.size()); - for(std::vector::const_iterator i = point_list.begin(); i != point_list.end(); ++i) - vector_list.push_back(*i); - param_vector_list.set(vector_list); -} - -void -Layer_Polygon::clear() -{ - Layer_Shape::clear(); - param_vector_list.set(ValueBase::List()); -} - -bool -Layer_Polygon::set_param(const String & param, const ValueBase &value) -{ - if( param=="vector_list" && param_vector_list.get_type()==value.get_type()) - { - param_vector_list=value; - Layer_Shape::clear(); - add_polygon(value.get_list_of(Vector())); - sync(); - return true; - } - - return Layer_Shape::set_param(param,value); -} - -ValueBase -Layer_Polygon::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_vector_list); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_Shape::get_param(param); -} - -Layer::Vocab -Layer_Polygon::get_param_vocab()const -{ - Layer::Vocab ret(Layer_Shape::get_param_vocab()); - - ret.push_back(ParamDesc("vector_list") - .set_local_name(_("Vertices List")) - .set_description(_("Define the corners of the polygon")) - .set_origin("origin") - ); - - return ret; -} - diff --git a/synfig-core/src/synfig/layer_polygon.h b/synfig-core/src/synfig/layer_polygon.h deleted file mode 100644 index d129b87..0000000 --- a/synfig-core/src/synfig/layer_polygon.h +++ /dev/null @@ -1,100 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_polygon.h -** \brief Header file for implementation of the "Polygon" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2011-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_POLYGON_H -#define __SYNFIG_LAYER_POLYGON_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_shape.h" -#include "color.h" -#include "vector.h" -#include -#include - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -/*! \class Layer_Polygon -** \brief writeme -** \todo This layer needs to support multiple polygons */ -class Layer_Polygon : public Layer_Shape -{ - SYNFIG_LAYER_MODULE_EXT - -private: - - //! Parameter: (std::vector) - ValueBase param_vector_list; - -protected: - - Layer_Polygon(); - -public: - - ~Layer_Polygon(); - - //! Adds a polygon to the layer - /*! The edge data is automatically added to the - ** EdgeTable, so there is no need to call sync() - ** after adding a polygon using this function. - ** \param point_list A list containing the - ** points that define the polygon's parameter. - */ - void add_polygon(const std::vector &point_list); - - // Places the point_list on the vector_list, for later render as polygon. - void upload_polygon(const std::vector &point_list); - - //! Clears out any polygon data - /*! Also clears out the EdgeTable, so there is no - ** need to call sync() after using this function. - */ - void clear(); - - //! Updates EdgeTable so it will reflect the parameter data - void sync(); - - virtual bool set_param(const String & param, const synfig::ValueBase &value); - - virtual ValueBase get_param(const String & param)const; - - virtual Vocab get_param_vocab()const; -private: - class PolySpan; - bool render_polyspan(Surface *surface,PolySpan &polyspan)const; - -}; // END of Layer_Polygon - -}; // END of namespace synfig -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_shape.cpp b/synfig-core/src/synfig/layer_shape.cpp deleted file mode 100644 index c3d2f20..0000000 --- a/synfig-core/src/synfig/layer_shape.cpp +++ /dev/null @@ -1,3566 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_shape.cpp -** \brief Implementation of the "Shape" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** Copyright (c) 2012-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_shape.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenode.h" -#include "float.h" -#include "blur.h" -#include "cairo_renddesc.h" - - -#include "curve_helper.h" - -#include - -#include - -#endif - -/* === U S I N G =========================================================== */ - -using namespace synfig; -using namespace std; -using namespace etl; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Shape); -SYNFIG_LAYER_SET_NAME(Layer_Shape,"shape"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shape,N_("Shape")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Shape,N_("Internal")); -SYNFIG_LAYER_SET_VERSION(Layer_Shape,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Shape,"$Id$"); - -#define EPSILON 1e-12 - -template < class T > -inline bool IsZero(const T &n) -{ - return (n < EPSILON) && (n > -EPSILON); -} - -/* === C L A S S E S ======================================================= */ - -//Assumes 64 byte aligned structures if at all -struct Primitive -{ - int operation; - int number; - - //Point data[0]; - - enum Operations - { - NONE = -1, - MOVE_TO = 0, //(x,y)+ after first point treated as line_to - CLOSE, // NOT RUNLENGTH enabled - LINE_TO, //(x,y)+ continuous func - CONIC_TO, //(x1,y1,x,y)+ " " - CONIC_TO_SMOOTH, //(x,y)+ " " - CUBIC_TO, //(x1,y1,x2,y2,x,y)+ " " - CUBIC_TO_SMOOTH, //(x2,y2,x,y)+ " " - END - }; -}; - -//******** CURVE FUNCTIONS ***************** -const int MAX_SUBDIVISION_SIZE = 64; -const int MIN_SUBDIVISION_DRAW_LEVELS = 4; - -static void Subd_Conic_Stack(Point *arc) -{ - /* - - b0 - * 0+1 a - b1 b * 1+2*1+2 a - * 1+2 b * - b2 * - * - - 0.1.2 -> 0.1 2 3.4 - - */ - - Real a,b; - - - arc[4][0] = arc[2][0]; - b = arc[1][0]; - - a = arc[1][0] = (arc[0][0] + b)/2; - b = arc[3][0] = (arc[4][0] + b)/2; - arc[2][0] = (a + b)/2; - - - arc[4][1] = arc[2][1]; - b = arc[1][1]; - - a = arc[1][1] = (arc[0][1] + b)/2; - b = arc[3][1] = (arc[4][1] + b)/2; - arc[2][1] = (a + b)/2; - - /* //USING SIMD - - arc[4] = arc[2]; - - arc[3] = (arc[2] + arc[1])/2; - arc[1] = (arc[0] + arc[1])/2; - - arc[2] = (arc[1] + arc[3])/2; - - */ - -} - -static void Subd_Cubic_Stack(Point *arc) -{ - Real a,b,c; - - /* - - b0 - * 0+1 a - b1 b * 1+2*1+2 a - * 1+2 b * 0+3*1+3*2+3 - b2 c * 1+2*2+2 b * - * 2+3 c * - b3 * - * - - 0.1 2.3 -> 0.1 2 3 4 5.6 - - */ - - arc[6][0] = arc[3][0]; - - b = arc[1][0]; - c = arc[2][0]; - - a = arc[1][0] = (arc[0][0] + b)/2; - b = (b + c)/2; - c = arc[5][0] = (arc[6][0] + c)/2; - - a = arc[2][0] = (a + b)/2; - b = arc[4][0] = (b + c)/2; - - arc[3][0] = (a + b)/2; - - - arc[6][1] = arc[3][1]; - - b = arc[1][1]; - c = arc[2][1]; - - a = arc[1][1] = (arc[0][1] + b)/2; - b = (b + c)/2; - c = arc[5][1] = (arc[6][1] + c)/2; - - a = arc[2][1] = (a + b)/2; - b = arc[4][1] = (b + c)/2; - - arc[3][1] = (a + b)/2; - - /* //USING SIMD - temp - - arc[6] = arc[3]; - - //backwards to avoid overwriting - arc[5] = (arc[2] + arc[3])/2; - temp = (arc[1] + arc[2])/2; - arc[1] = (arc[0] + arc[1])/2; - - arc[4] = (temp + arc[5])/2; - arc[2] = (arc[1] + temp)/2; - - arc[3] = (arc[2] + arc[4])/2; - - */ -} - -//************** PARAMETRIC RENDERER SUPPORT STRUCTURES **************** - -// super segment -struct MonoSegment -{ - Rect aabb; - int ydir; - vector pointlist; - - MonoSegment(int dir = 0, Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0) - { - aabb.minx = x0; - aabb.maxx = x1; - aabb.miny = y0; - aabb.maxy = y1; - - ydir = dir; - } - - int intersect(Real x,Real y) const - { - if((y < aabb.miny+EPSILON) || (y > aabb.maxy) || (x < aabb.minx)) return 0; - if(x > aabb.maxx) return ydir; - - //int i = 0; - //int size = pointlist.size(); - //vector::const_iterator end = pointlist.end(); - vector::const_iterator p = pointlist.begin(); - - //assumes that the rect culled away anything that would be beyond the edges - if(ydir > 0) - { - while(y > (*++p)[1]) - ; - } - else - { - while(y < (*++p)[1]) - ; - } - - //for the loop to break there must have been a slope (straight line would do nothing) - //vector::const_iterator p1 = p-1; - Real dy = p[-1][1] - p[0][1]; - Real dx = p[-1][0] - p[0][0]; - - assert(dy != 0); - - Real xi = p[0][0] + (y - p[0][1]) * dx / dy; - return (x > xi)*ydir; - } -}; - -struct CurveArray -{ - Rect aabb; //not necessarily as effective - can only reject values - vector pointlist; //run length - p0, p1, p2, p3 = p10, p11, p12, p13 = p20 ... - vector degrees; - - CurveArray(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0) - { - aabb.set(x0,y0,x1,y1); - } - - void reset(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0) - { - aabb.set(x0,y0,x1,y1); - pointlist.clear(); - degrees.clear(); - } - - int size () const - { - return degrees.size(); - } - - void Start(Point m) - { - reset(m[0],m[0],m[1],m[1]); - pointlist.push_back(m); - } - - void AddCubic(Point p1, Point p2, Point dest) - { - aabb.expand(p1[0],p1[1]); - aabb.expand(p2[0],p2[1]); - aabb.expand(dest[0],dest[1]); - - pointlist.push_back(p1); - pointlist.push_back(p2); - pointlist.push_back(dest); - - degrees.push_back(3); - } - - void AddConic(Point p1, Point dest) - { - aabb.expand(p1[0],p1[1]); - aabb.expand(dest[0],dest[1]); - - pointlist.push_back(p1); - pointlist.push_back(dest); - - degrees.push_back(2); - } - - static int intersect_conic(Real x, Real y, Point *p, int /*level*/ = 0) - { - Real ymin,ymax,xmin,xmax; - int intersects = 0; - - //sort the overall curve ys - degenerate detection - ymin = min(p[0][1],p[2][1]); - ymax = max(p[0][1],p[2][1]); - - xmin = min(min(p[0][0],p[1][0]),p[2][0]); - xmax = max(max(p[0][0],p[1][0]),p[2][0]); - - //to the left, to the right and out of range y, or completely out of range y - if( x < xmin ) return 0; - if( x > xmax && (y > ymax || y < ymin) ) return 0; - if( (y > ymax && y > p[1][1]) || (y < ymin && y < p[1][1]) ) return 0; - - //degenerate line max - if(ymin == ymax && ymax == p[1][1]) - return 0; - - //degenerate accept - to the right and crossing the base line - if(x > xmax) - { - return (y <= ymax && y >= ymin); - } - - //solve for curve = y - - //real roots: - //0 roots - 0 intersection - //1 root - get x, and figure out x - //2 roots (non-double root) - get 2 xs, and count xs to the left - - //for conic we can assume 1 intersection for monotonic curve - Real a = p[2][1] - 2*p[1][1] + p[0][1], - b = 2*p[1][1] - 2*p[0][1], - c = p[0][1] - y; - - Real t1 = -1, t2 = -1; - - if(a == 0) - { - //linear - easier :) - if(b == 0) return 0; //may not need this check - - t1 = - c / b; //bt + c = 0 solved - }else - { - //2 degree polynomial - Real b2_4ac = b*b - 4*a*c; - - //if there are double/no roots - no intersections (in real #s that is) - if(b2_4ac <= 0) - { - return 0; - } - - b2_4ac = sqrt(b2_4ac); - - t1 = (-b - b2_4ac) / 2*a, - t2 = (-b + b2_4ac) / 2*a; - } - - //calculate number of intersections - if(t1 >= 0 && t1 <= 1) - { - const Real t = t1; - const Real invt = 1 - t; - - //find x val and it counts if it's to the left of the point - const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0]; - const Real dy_t = 2*a*t + b; - - if(dy_t) - { - intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1); - } - } - - if(t2 >= 0 && t2 <= 1) - { - const Real t = t2; - const Real invt = 1 - t; - - //find x val and it counts if it's to the left of the point - const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0]; - const Real dy_t = 2*a*t + b; - - if(dy_t) - { - intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1); - } - } - - return intersects; - } - - static int quadratic_eqn(Real a, Real b, Real c, Real *t0, Real *t1) - { - const Real b2_4ac = b*b - 4*a*c; - - //degenerate reject (can't take sqrt) - if(b2_4ac < 0) - { - return 0; - } - - const Real sqrtb2_4ac = sqrt(b2_4ac); - const Real signb = b < 0 ? -1 : 1; - const Real q = - 0.5 * (b + signb * sqrtb2_4ac); - - *t0 = q/a; - *t1 = c/q; - - return sqrtb2_4ac == 0 ? 1 : 2; - } - - /* TODO: function not finished - no return value. To remove? - //Newton-Raphson root polishing (we don't care about bounds, assumes very near the desired root) - static Real polish_cubicroot(Real a, Real b, Real c, Real d, Real t, Real *dpdt) - { - const Real cn[4] = {a,b,c,d}; - Real p,dp,newt,oldpmag=FLT_MAX; - - //eval cubic eqn and its derivative - for(;;) - { - p = cn[0]*t + cn[1]; - dp = cn[0]; - - for(int i = 2; i < 4; i++) - { - dp = p + dp*t; - p = cn[i] + p*t; - } - - if(dp == 0) - { - synfig::warning("polish_cubicroot: Derivative should not vanish!!!"); - return t; - } - - newt = t - p/dp; - - if(newt == t || fabs(p) >= oldpmag) - { - *dpdt = dp; - return t; - } - - t = newt; - oldpmag = fabs(p); - } - } - */ - - static int intersect_cubic(Real x, Real y, Point *p, int /*level*/ = 0) - { - const Real INVALIDROOT = -FLT_MAX; - Real ymin,ymax,xmin,xmax; - Real ymin2,ymax2,ymintot,ymaxtot; - int intersects = 0; - - //sort the overall curve ys and xs - degenerate detection - - //open span for the two end points - ymin = min(p[0][1],p[3][1]); - ymax = max(p[0][1],p[3][1]); - - //other points etc. - ymin2 = min(p[1][1],p[2][1]); - ymax2 = max(p[1][1],p[2][1]); - - ymintot = min(ymin,ymin2); - ymaxtot = max(ymax,ymax2); - - //the entire curve control polygon is in this x range - xmin = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0])); - xmax = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][0])); - - //outside all y boundaries (no intersect) - if( (y > ymaxtot) || (y < ymintot) ) return 0; - - //left of curve (no intersect) - if(x < xmin) return 0; - - //right of curve (and outside base range) - if( x > xmax ) - { - if( (y > ymax) || (y < ymin) ) return 0; - - //degenerate accept - to the right and inside the [ymin,ymax] range (already rejected if out of range) - const Real n = p[3][1] - p[0][1]; - - //extract the sign from the value (we need valid data) - return n < 0 ? -1 : 1; - } - - //degenerate horizontal line max -- doesn't happen enough to check for - if( ymintot == ymaxtot ) return 0; - - //calculate roots: - // can have 0,1,2, or 3 real roots - // if any of them are double then reject the two... - - // y-coefficients for f_y(t) - y = 0 - Real a = p[3][1] - 3*p[2][1] + 3*p[1][1] - p[0][1], - b = 3*p[2][1] - 6*p[1][1] + 3*p[0][1], - c = 3*p[1][1] - 3*p[0][1], - d = p[0][1] - y; - - Real ax = p[3][0] - 3*p[2][0] + 3*p[1][0] - p[0][0], - bx = 3*p[2][0] - 6*p[1][0] + 3*p[0][0], - cx = 3*p[1][0] - 3*p[0][0], - dx = p[0][0]; - - Real t1 = INVALIDROOT, t2 = INVALIDROOT, t3 = INVALIDROOT, t, dydt; - - if(a == 0) - { - //only 2nd degree - if(b == 0) - { - //linear - if(c == 0) return 0; - - t1 = - d / c; //equation devolved into: ct + d = 0 - solve... - }else - { - //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective) - if(quadratic_eqn(a,b,c,&t1,&t2) != 2) return 0; - } - }else - { - //cubic - sigh.... - - //algorithm courtesy of Numerical Recipes in C (algorithm copied from pg. 184/185) - Real an = b / a, - bn = c / a, - cn = d / a; - - //if cn is 0 (or really really close), then we can simplify this... - if(IsZero(cn)) - { - t3 = 0; - - //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective) - if(quadratic_eqn(a,b,c,&t1,&t2) != 2) - { - t1 = t2 = INVALIDROOT; - } - } - else - { - //otherwise run the normal cubic root equation - Real Q = (an*an - 3.0*bn) / 9.0; - Real R = ((2.0*an*an - 9.0*bn)*an + 27.0*cn)/54.0; - - if(R*R < Q*Q*Q) - { - Real theta = acos(R / sqrt(Q*Q*Q)); - - t1 = -2.0*sqrt(Q)*cos(theta/3) - an/3.0; - t2 = -2.0*sqrt(Q)*cos((theta+2*PI)/3.0) - an/3.0; - t3 = -2.0*sqrt(Q)*cos((theta-2*PI)/3.0) - an/3.0; - - //don't need to reorder,l just need to eliminate double/triple roots - //if(t3 == t2 && t1 == t2) t2 = t3 = INVALIDROOT; - if(t3 == t2) t2 = t3 = INVALIDROOT; - if(t1 == t2) t1 = t2 = INVALIDROOT; - if(t1 == t3) t1 = t3 = INVALIDROOT; - }else - { - Real signR = R < 0 ? -1 : 1; - Real A = - signR * pow(signR*R + sqrt(R*R - Q*Q*Q),1/3.0); - - Real B; - if(A == 0) B = 0; - else B = Q / A; - - //single real root in this case - t1 = (A + B) - an/3.0; - } - } - } - - //if(t1 != INVALIDROOT) - { - t = t1;//polish_cubicroot(a,b,c,d,t1,&dydt); - if(t >= 0 && t < 1) - { - //const Real invt = 1 - t; - - //find x val and it counts if it's to the left of the point - const Real xi = ((ax*t + bx)*t + cx)*t + dx; - dydt = (3*a*t + 2*b)*t + c; - - if(dydt) - { - intersects += (x >= xi) * ( dydt > 0 ? 1 : -1); - } - } - } - - //if(t2 != INVALIDROOT) - { - t = t2;//polish_cubicroot(a,b,c,d,t2,&dydt); - if(t >= 0 && t < 1) - { - //const Real invt = 1 - t; - - //find x val and it counts if it's to the left of the point - const Real xi = ((ax*t + bx)*t + cx)*t + dx; - dydt = (3*a*t + 2*b)*t + c; - - if(dydt) - { - intersects += (x >= xi) * ( dydt > 0 ? 1 : -1); - } - } - } - - //if(t3 != INVALIDROOT) - { - t = t3;//polish_cubicroot(a,b,c,d,t3,&dydt); - if(t >= 0 && t < 1) - { - //const Real invt = 1 - t; - - //find x val and it counts if it's to the left of the point - const Real xi = ((ax*t + bx)*t + cx)*t + dx; - dydt = (3*a*t + 2*b)*t + c; - - if(dydt) - { - intersects += (x >= xi) * ( dydt > 0 ? 1 : -1); - } - } - } - - return intersects; - } - - int intersect(Real x,Real y, Point *table) const - { - if((y < aabb.miny) || (y > aabb.maxy) || (x < aabb.minx)) return 0; - - int i, curdeg, intersects = 0; - const int numcurves = degrees.size(); - - vector::const_iterator p = pointlist.begin(); - - for(i=0; i < numcurves; i++) - { - curdeg = degrees[i]; - - switch(curdeg) - { - case 2: - { - table[0] = *p++; - table[1] = *p++; - table[2] = *p; //we want to include the last point for the next curve - - intersects += intersect_conic(x,y,table); - - break; - } - - case 3: - { - table[0] = *p++; - table[1] = *p++; - table[2] = *p++; - table[3] = *p; //we want to include the last point for the next curve - - intersects += intersect_cubic(x,y,table); - - break; - } - - default: - { - warning("Invalid degree (%d) inserted into the list (index: %d)\n", curdeg, i); - return 0; - } - } - } - - return intersects; - } -}; - -struct Layer_Shape::Intersector -{ - Rect aabb; - - //! true iff aabb hasn't been initialized yet - bool initaabb; - - int flags; - - enum IntersectorFlags - { - NotClosed = 0x8000 - }; - - enum PrimitiveType - { - TYPE_NONE = 0, - TYPE_LINE, - TYPE_CURVE - }; - - Real cur_x,cur_y; - Real close_x,close_y; - - vector segs; //monotonically increasing - vector curves; //big array of consecutive curves - - int prim; - Vector tangent; - - Intersector() - { - clear(); - } - - bool notclosed() - { - return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y); - } - - void move_to(Real x, Real y) - { - close(); - - close_x = cur_x = x; - close_y = cur_y = y; - - tangent[0] = tangent[1] = 0; - - if(initaabb) - { - aabb.set_point(x,y); - initaabb = false; - }else aabb.expand(x,y); - - prim = TYPE_NONE; - } - - void line_to(Real x, Real y) - { - int dir = (y > cur_y)*1 + (-1)*(y < cur_y); - - //check for context (if not line start a new segment) - //if we're not in line mode (covers 0 set case), or if directions are different (not valid for 0 direction) - if(prim != TYPE_LINE || (dir && segs.back().ydir != dir)) - { - MonoSegment seg(dir,x,x,y,y); - - seg.aabb.expand(cur_x,cur_y); - seg.pointlist.push_back(Point(cur_x,cur_y)); - seg.pointlist.push_back(Point(x,y)); - segs.push_back(seg); - } - //add to the last segment, because it works - else - { - segs.back().pointlist.push_back(Point(x,y)); - segs.back().aabb.expand(x,y); - } - - - - cur_x = x; - cur_y = y; - aabb.expand(x,y); //expand the entire thing's bounding box - - tangent[0] = x - cur_x; - tangent[1] = x - cur_y; - - flags |= NotClosed; - prim = TYPE_LINE; - } - - void conic_to_smooth(Real x, Real y) - { - const Real x1 = tangent[0]/2.0 + cur_x; - const Real y1 = tangent[1]/2.0 + cur_y; - - conic_to(x1,y1,x,y); - } - - void conic_to(Real x1, Real y1, Real x, Real y) - { - //if we're not already a curve start one - if(prim != TYPE_CURVE) - { - CurveArray c; - - c.Start(Point(cur_x,cur_y)); - c.AddConic(Point(x1,y1),Point(x,y)); - - curves.push_back(c); - }else - { - curves.back().AddConic(Point(x1,y1),Point(x,y)); - } - - cur_x = x; - cur_y = y; - - aabb.expand(x1,y1); - aabb.expand(x,y); - - tangent[0] = 2*(x - x1); - tangent[1] = 2*(y - y1); - - flags |= NotClosed; - prim = TYPE_CURVE; - } - - void curve_to_smooth(Real x2, Real y2, Real x, Real y) - { - Real x1 = tangent[0]/3.0 + cur_x; - Real y1 = tangent[1]/3.0 + cur_y; - - curve_to(x1,y1,x2,y2,x,y); - } - - void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y) - { - //if we're not already a curve start one - if(prim != TYPE_CURVE) - { - CurveArray c; - - c.Start(Point(cur_x,cur_y)); - c.AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y)); - - curves.push_back(c); - }else - { - curves.back().AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y)); - } - - cur_x = x; - cur_y = y; - - //expand bounding box around ALL of it - aabb.expand(x1,y1); - aabb.expand(x2,y2); - aabb.expand(x,y); - - tangent[0] = 3*(x - x2); - tangent[1] = 3*(y - y2); - - flags |= NotClosed; - prim = TYPE_CURVE; - } - - void close() - { - if(flags & NotClosed) - { - if(cur_x != close_x || cur_y != close_y) - { - line_to(close_x,close_y); - } - - flags &= ~NotClosed; - } - } - - //assumes the line to count the intersections with is (-1,0) - int intersect (Real x, Real y) const - { - int inter = 0; - unsigned int i; - vector::const_iterator s = segs.begin(); - vector::const_iterator c = curves.begin(); - - Point memory[3*MAX_SUBDIVISION_SIZE + 1]; - - for(i = 0; i < segs.size(); i++,s++) - { - inter += s->intersect(x,y); - } - - for(i=0; i < curves.size(); i++,c++) - inter += c->intersect(x,y,memory); - - return inter; - } - - //intersect an arbitrary line - //int intersect (Real x, Real y, Real vx, Real vy) {return 0;} - - void clear() - { - segs.clear(); - curves.clear(); - - flags = 0; - cur_x = cur_y = close_x = close_y = 0; - prim = TYPE_NONE; - tangent[0] = tangent[1] = 0; - initaabb = true; - } -}; - -//*********** SCANLINE RENDERER SUPPORT STRUCTURES *************** -struct PenMark -{ - int y,x; - Real cover,area; - - PenMark(): y(), x(), cover(), area() {} - PenMark(int xin, int yin, Real c, Real a) - :y(yin),x(xin),cover(c),area(a) {} - - void set(int xin, int yin, Real c, Real a) { y = yin; x = xin; cover = c; area = a; } - - void setcoord(int xin, int yin) { y = yin; x = xin; } - - void setcover(Real c, Real a) { cover = c; area = a; } - void addcover(Real c, Real a) { cover += c; area += a; } - - bool operator<(const PenMark &rhs) const - { - return y == rhs.y ? x < rhs.x : y < rhs.y; - } -}; - -typedef rect ContextRect; - -class Layer_Shape::PolySpan -{ -public: - typedef vector cover_array; - - Point arc[3*MAX_SUBDIVISION_SIZE + 1]; - - cover_array covers; - PenMark current; - - int open_index; - - //ending position of last primitive - Real cur_x; - Real cur_y; - - //starting position of current primitive list - Real close_x; - Real close_y; - - //flags for the current segment - int flags; - - //the window that will be drawn (used for clipping) - ContextRect window; - - //for assignment to flags value - enum PolySpanFlags - { - NotSorted = 0x8000, - NotClosed = 0x4000 - }; - - //default constructor - 0 everything - PolySpan() :current(0,0,0,0),flags(NotSorted) - { - cur_x = cur_y = close_x = close_y = 0; - open_index = 0; - } - - bool notclosed() const - { - return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y); - } - - //0 out all the variables involved in processing - void clear() - { - covers.clear(); - cur_x = cur_y = close_x = close_y = 0; - open_index = 0; - current.set(0,0,0,0); - flags = NotSorted; - } - - //add the current cell, but only if there is information to add - void addcurrent() - { - if(current.cover || current.area) - { - if (covers.size() == covers.capacity()) - covers.reserve(covers.size() + 1024*1024); - covers.push_back(current); - } - } - - //move to the next cell (cover values 0 initially), keeping the current if necessary - void move_pen(int x, int y) - { - if(y != current.y || x != current.x) - { - addcurrent(); - current.set(x,y,0,0); - } - } - - //close the primitives with a line (or rendering will not work as expected) - void close() - { - if(flags & NotClosed) - { - if(cur_x != close_x || cur_y != close_y) - { - line_to(close_x,close_y); - addcurrent(); - current.setcover(0,0); - } - flags &= ~NotClosed; - } - } - - // Not recommended - destroys any separation of spans currently held - void merge_all() - { - sort(covers.begin(),covers.end()); - open_index = 0; - } - - //will sort the marks if they are not sorted - void sort_marks() - { - if(flags & NotSorted) - { - //only sort the open index - addcurrent(); - current.setcover(0,0); - - sort(covers.begin() + open_index,covers.end()); - flags &= ~NotSorted; - } - } - - //encapsulate the current sublist of marks (used for drawing) - void encapsulate_current() - { - //sort the current list then reposition the open list section - sort_marks(); - open_index = covers.size(); - } - - //move to start a new primitive list (enclose the last primitive if need be) - void move_to(Real x, Real y) - { - close(); - if(isnan(x))x=0; - if(isnan(y))y=0; - move_pen((int)floor(x),(int)floor(y)); - close_y = cur_y = y; - close_x = cur_x = x; - } - - //primitive_to functions - void line_to(Real x, Real y); - void conic_to(Real x1, Real y1, Real x, Real y); - void cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y); - - void draw_scanline(int y, Real x1, Real y1, Real x2, Real y2); - void draw_line(Real x1, Real y1, Real x2, Real y2); - - Real ExtractAlpha(Real area, WindingStyle winding_style) - { - if (area < 0) - area = -area; - - if (winding_style == WINDING_NON_ZERO) - { - // non-zero winding style - if (area > 1) - return 1; - } - else // if (winding_style == WINDING_EVEN_ODD) - { - // even-odd winding style - while (area > 1) - area -= 2; - - // want pyramid like thing - if (area < 0) - area = -area; - } - - return area; - } -}; - -/* === M E T H O D S ======================================================= */ - -Layer_Shape::Layer_Shape(const Real &a, const Color::BlendMethod m): - Layer_Composite (a,m), - edge_table (new Intersector), - param_color (Color::black()), - param_origin (Vector(0,0)), - param_invert (bool(false)), - param_antialias (bool(true)), - param_blurtype (int(Blur::FASTGAUSSIAN)), - param_feather (Real(0.0)), - param_winding_style (int(WINDING_NON_ZERO)), - bytestream (0), - lastbyteop (Primitive::NONE), - lastoppos (-1) -{ -} - -Layer_Shape::~Layer_Shape() -{ - delete edge_table; -} - -void -Layer_Shape::clear() -{ - edge_table->clear(); - bytestream.clear(); -} - -bool -Layer_Shape::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE_PLUS(param_color, - { - Color color=param_color.get(Color()); - if (color.get_a() == 0) - { - if (converted_blend_) - { - set_blend_method(Color::BLEND_ALPHA_OVER); - color.set_a(1); - } - else - transparent_color_ = true; - } - param_color.set(color); - } - ); - IMPORT_VALUE(param_origin); - IMPORT_VALUE(param_invert); - IMPORT_VALUE(param_antialias); - IMPORT_VALUE_PLUS(param_feather, - { - Real feather=param_feather.get(Real()); - if(feather<0) - { - feather=0; - param_feather.set(feather); - } - } - ); - - IMPORT_VALUE(param_blurtype); - IMPORT_VALUE(param_winding_style); - - if(param=="offset" && param_origin.get_type() == value.get_type()) - { - param_origin=value; - return true; - } - return Layer_Composite::set_param(param,value); -} - -ValueBase -Layer_Shape::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_color); - EXPORT_VALUE(param_origin); - EXPORT_VALUE(param_invert); - EXPORT_VALUE(param_antialias); - EXPORT_VALUE(param_feather); - EXPORT_VALUE(param_blurtype); - EXPORT_VALUE(param_winding_style); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_Composite::get_param(param); -} - -Layer::Vocab -Layer_Shape::get_param_vocab()const -{ - Layer::Vocab ret(Layer_Composite::get_param_vocab()); - - ret.push_back(ParamDesc("color") - .set_local_name(_("Color")) - .set_description(_("Layer_Shape Color")) - ); - ret.push_back(ParamDesc("origin") - .set_local_name(_("Origin")) - ); - ret.push_back(ParamDesc("invert") - .set_local_name(_("Invert")) - ); - ret.push_back(ParamDesc("antialias") - .set_local_name(_("Antialiasing")) - ); - ret.push_back(ParamDesc("feather") - .set_local_name(_("Feather")) - .set_is_distance() - ); - ret.push_back(ParamDesc("blurtype") - .set_local_name(_("Type of Feather")) - .set_description(_("Type of feathering to use")) - .set_hint("enum") - .add_enum_value(Blur::BOX,"box",_("Box Blur")) - .add_enum_value(Blur::FASTGAUSSIAN,"fastgaussian",_("Fast Gaussian Blur")) - .add_enum_value(Blur::CROSS,"cross",_("Cross-Hatch Blur")) - .add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur")) - .add_enum_value(Blur::DISC,"disc",_("Disc Blur")) - ); - ret.push_back(ParamDesc("winding_style") - .set_local_name(_("Winding Style")) - .set_description(_("Winding style to use")) - .set_hint("enum") - .add_enum_value(WINDING_NON_ZERO,"nonzero",_("Non Zero")) - .add_enum_value(WINDING_EVEN_ODD,"evenodd",_("Even/Odd")) - ); - - return ret; -} - -synfig::Layer::Handle -Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const -{ - Color color=param_color.get(Color()); - Point origin=param_origin.get(Point()); - bool invert =param_invert.get(bool(true)); - - Point pos(p-origin); - - int intercepts = edge_table->intersect(pos[0],pos[1]); - - // If we have an odd number of intercepts, we are inside. - // If we have an even number of intercepts, we are outside. - bool intersect = ((!!intercepts) ^ invert); - - if(get_amount() == 0 || get_blend_method() == Color::BLEND_ALPHA_OVER) - { - intersect = false; - } - - if(intersect) - { - synfig::Layer::Handle tmp; - if(get_blend_method()==Color::BLEND_BEHIND && (tmp=context.hit_check(p))) - return tmp; - if(Color::is_onto(get_blend_method())) - { - //if there's something in the lower layer then we're set... - if(!context.hit_check(p).empty()) - return const_cast(this); - }else if(get_blend_method() == Color::BLEND_ALPHA_OVER) - { - synfig::info("layer_shape::hit_check - we've got alphaover"); - //if there's something in the lower layer then we're set... - if(color.get_a() < 0.1 && get_amount() > .9) - { - synfig::info("layer_shape::hit_check - can see through us... so nothing"); - return Handle(); - }else return context.hit_check(p); - }else - return const_cast(this); - } - - return context.hit_check(p); -} - -Color -Layer_Shape::get_color(Context context, const Point &p)const -{ - Color color=param_color.get(Color()); - Point origin=param_origin.get(Point()); - bool invert =param_invert.get(bool(true)); - int blurtype=param_blurtype.get(int()); - Real feather=param_feather.get(Real()); - - Point pp = p; - - if(feather) - pp = Blur(feather,feather,blurtype)(p); - - Point pos(pp-origin); - - int intercepts = edge_table->intersect(pos[0],pos[1]); - - // If we have an odd number of intercepts, we are inside. - // If we have an even number of intercepts, we are outside. - bool intersect = ((!!intercepts) ^ invert); - - if(!intersect) - return Color::blend(Color::alpha(),context.get_color(pp),get_amount(),get_blend_method()); - - //Ok, we're inside... bummmm ba bum buM... - if(get_blend_method() == Color::BLEND_STRAIGHT && get_amount() == 1) - return color; - else - return Color::blend(color,context.get_color(p),get_amount(),get_blend_method()); -} - -//************** SCANLINE RENDERING ********************* -void Layer_Shape::PolySpan::line_to(Real x, Real y) -{ - Real n[4] = {0,0,0,0}; - bool afterx = false; - - const Real xin(x), yin(y); - - Real dx = x - cur_x; - Real dy = y - cur_y; - - //CLIP IT!!!! - try { - //outside y - ignore entirely - if( (cur_y >= window.maxy && y >= window.maxy) - ||(cur_y < window.miny && y < window.miny) ) - { - cur_x = x; - cur_y = y; - } - else //not degenerate - more complicated - { - if(dy > 0) //be sure it's not tooooo small - { - // cur_y ... window.miny ... window.maxy ... y - - //initial degenerate - initial clip - if(cur_y < window.miny) - { - //new clipped start point (must also move pen) - n[2] = cur_x + (window.miny - cur_y) * dx / dy; - - cur_x = n[2]; - cur_y = window.miny; - move_pen((int)floor(cur_x),window.miny); - } - - //generate data for the ending clipped info - if(y > window.maxy) - { - //initial line to intersection (and degenerate) - n[2] = x + (window.maxy - y) * dx / dy; - - //intersect coords - x = n[2]; - y = window.maxy; - } - } - else - { - //initial degenerate - initial clip - if(cur_y > window.maxy) - { - //new clipped start point (must also move pen) - n[2] = cur_x + (window.maxy - cur_y) * dx / dy; - - cur_x = n[2]; - cur_y = window.maxy; - move_pen((int)floor(cur_x),window.maxy); - } - - //generate data for the ending clipped info - if(y < window.miny) - { - //initial line to intersection (and degenerate) - n[2] = x + (window.miny - y) * dx / dy; - - //intersect coords - x = n[2]; - y = window.miny; - } - } - - //all degenerate - but require bounded clipped values - if( (cur_x >= window.maxx && x >= window.maxx) - ||(cur_x < window.minx && x < window.minx) ) - { - //clip both vertices - but only needed in the x direction - cur_x = max(cur_x, (Real)window.minx); - cur_x = min(cur_x, (Real)window.maxx); - - //clip the dest values - y is already clipped - x = max(x,(Real)window.minx); - x = min(x,(Real)window.maxx); - - //must start at new point... - move_pen((int)floor(cur_x),(int)floor(cur_y)); - - draw_line(cur_x,cur_y,x,y); - - cur_x = xin; - cur_y = yin; - } - else - { - //clip x - if(dx > 0) - { - //initial degenerate - initial clip - if(cur_x < window.minx) - { - //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty - n[2] = cur_y + (window.minx - cur_x) * dy / dx; - - move_pen(window.minx,(int)floor(cur_y)); - draw_line(window.minx,cur_y,window.minx,n[2]); - - cur_x = window.minx; - cur_y = n[2]; - } - - //generate data for the ending clipped info - if(x > window.maxx) - { - //initial line to intersection (and degenerate) - n[2] = y + (window.maxx - x) * dy / dx; - - n[0] = window.maxx; - n[1] = y; - - //intersect coords - x = window.maxx; - y = n[2]; - afterx = true; - } - }else - { - //initial degenerate - initial clip - if(cur_x > window.maxx) - { - //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty - n[2] = cur_y + (window.maxx - cur_x) * dy / dx; - - move_pen(window.maxx,(int)floor(cur_y)); - draw_line(window.maxx,cur_y,window.maxx,n[2]); - - cur_x = window.maxx; - cur_y = n[2]; - } - - //generate data for the ending clipped info - if(x < window.minx) - { - //initial line to intersection (and degenerate) - n[2] = y + (window.minx - x) * dy / dx; - - n[0] = window.minx; - n[1] = y; - - //intersect coords - x = window.minx; - y = n[2]; - afterx = true; - } - } - - move_pen((int)floor(cur_x),(int)floor(cur_y)); - //draw the relevant line (clipped) - draw_line(cur_x,cur_y,x,y); - - if(afterx) - { - draw_line(x,y,n[0],n[1]); - } - - cur_x = xin; - cur_y = yin; - } - } - } catch(...) { synfig::error("line_to: cur_x=%f, cur_y=%f, x=%f, y=%f", cur_x, cur_y, x, y); throw; } - - flags |= NotClosed|NotSorted; -} - -static inline bool clip_conic(const Point *const p, const ContextRect &r) -{ - const Real minx = min(min(p[0][0],p[1][0]),p[2][0]); - const Real miny = min(min(p[0][1],p[1][1]),p[2][1]); - const Real maxx = max(max(p[0][0],p[1][0]),p[2][0]); - const Real maxy = max(max(p[0][1],p[1][1]),p[2][1]); - - return (minx > r.maxx) || - (maxx < r.minx) || - (miny > r.maxy) || - (maxy < r.miny); -} - -static inline bool clip_cubic(const Point *const p, const ContextRect &r) -{ - /*const Real minx = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0])); - const Real miny = min(min(p[0][1],p[1][1]),min(p[2][1],p[3][1])); - const Real maxx = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][1])); - const Real maxy = max(max(p[0][1],p[1][1]),max(p[2][1],p[3][1])); - - return (minx > r.maxx) || - (maxx < r.minx) || - (miny > r.maxy) || - (maxy < r.miny);*/ - - return ((p[0][0] > r.maxx) && (p[1][0] > r.maxx) && (p[2][0] > r.maxx) && (p[3][0] > r.maxx)) || - ((p[0][0] < r.minx) && (p[1][0] < r.minx) && (p[2][0] < r.minx) && (p[3][0] < r.minx)) || - ((p[0][1] > r.maxy) && (p[1][1] > r.maxy) && (p[2][1] > r.maxy) && (p[3][1] > r.maxy)) || - ((p[0][1] < r.miny) && (p[1][1] < r.miny) && (p[2][1] < r.miny) && (p[3][1] < r.miny)); -} - -static inline Real max_edges_cubic(const Point *const p) -{ - const Real x1 = p[1][0] - p[0][0]; - const Real y1 = p[1][1] - p[0][1]; - - const Real x2 = p[2][0] - p[1][0]; - const Real y2 = p[2][1] - p[1][1]; - - const Real x3 = p[3][0] - p[2][0]; - const Real y3 = p[3][1] - p[2][1]; - - const Real d1 = x1*x1 + y1*y1; - const Real d2 = x2*x2 + y2*y2; - const Real d3 = x3*x3 + y3*y3; - - return max(max(d1,d2),d3); -} - -static inline Real max_edges_conic(const Point *const p) -{ - const Real x1 = p[1][0] - p[0][0]; - const Real y1 = p[1][1] - p[0][1]; - - const Real x2 = p[2][0] - p[1][0]; - const Real y2 = p[2][1] - p[1][1]; - - const Real d1 = x1*x1 + y1*y1; - const Real d2 = x2*x2 + y2*y2; - - return max(d1,d2); -} - -void Layer_Shape::PolySpan::conic_to(Real x1, Real y1, Real x, Real y) -{ - Point *current = arc; - int level = 0; - int num = 0; - bool onsecond = false; - - arc[0] = Point(x,y); - arc[1] = Point(x1,y1); - arc[2] = Point(cur_x,cur_y); - - //just draw the line if it's outside - if(clip_conic(arc,window)) - { - line_to(x,y); - return; - } - - //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first) - while(current >= arc) - { - if(num >= MAX_SUBDIVISION_SIZE) - { - warning("Curve subdivision somehow ran out of space while tessellating!"); - - //do something... - assert(0); - return; - }else - //if the curve is clipping then draw degenerate - if(clip_conic(current,window)) - { - line_to(current[0][0],current[0][1]); //backwards so front is destination - current -= 2; - if(onsecond) level--; - onsecond = true; - num--; - continue; - }else - //if we are not at the level minimum - if(level < MIN_SUBDIVISION_DRAW_LEVELS) - { - Subd_Conic_Stack(current); - current += 2; //cursor on second curve - level ++; - num ++; - onsecond = false; - continue; - }else - //split it again, if it's too big - if(max_edges_conic(current) > 0.25) //distance of .5 (cover no more than half the pixel) - { - Subd_Conic_Stack(current); - current += 2; //cursor on second curve - level ++; - num ++; - onsecond = false; - } - else //NOT TOO BIG? RENDER!!! - { - //cur_x,cur_y = current[2], so we need to go 1,0 - line_to(current[1][0],current[1][1]); - line_to(current[0][0],current[0][1]); - - current -= 2; - if(onsecond) level--; - num--; - onsecond = true; - } - } -} - -void Layer_Shape::PolySpan::cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y) -{ - Point *current = arc; - int num = 0; - int level = 0; - bool onsecond = false; - - arc[0] = Point(x,y); - arc[1] = Point(x2,y2); - arc[2] = Point(x1,y1); - arc[3] = Point(cur_x,cur_y); - - //just draw the line if it's outside - if(clip_cubic(arc,window)) - { - line_to(x,y); - return; - } - - //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first) - while(current >= arc) //once current goes below arc, there are no more curves left - { - if(num >= MAX_SUBDIVISION_SIZE) - { - warning("Curve subdivision somehow ran out of space while tessellating!"); - - //do something... - assert(0); - return; - }else - - //if we are not at the level minimum - if(level < MIN_SUBDIVISION_DRAW_LEVELS) - { - Subd_Cubic_Stack(current); - current += 3; //cursor on second curve - level ++; - num ++; - onsecond = false; - continue; - }else - //if the curve is clipping then draw degenerate - if(clip_cubic(current,window)) - { - line_to(current[0][0],current[0][1]); //backwards so front is destination - current -= 3; - if(onsecond) level--; - onsecond = true; - num --; - continue; - } - else - //split it again, if it's too big - if(max_edges_cubic(current) > 0.25) //could use max_edges<3> - { - Subd_Cubic_Stack(current); - current += 3; //cursor on second curve - level ++; - num ++; - onsecond = false; - } - else //NOT TOO BIG? RENDER!!! - { - //cur_x,cur_y = current[3], so we need to go 2,1,0 - line_to(current[2][0],current[2][1]); - line_to(current[1][0],current[1][1]); - line_to(current[0][0],current[0][1]); - - current -= 3; - if(onsecond) level--; - num --; - onsecond = true; - } - } -} - -//******************** LINE ALGORITHMS **************************** -// THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT -// - BROKEN UP INTO SCANLINES (draw_line - y intersections), -// THEN THE COVER AND AREA PER TOUCHED PIXEL IS CALCULATED (draw_scanline - x intersections) -void Layer_Shape::PolySpan::draw_scanline(int y, Real x1, Real fy1, Real x2, Real fy2) -{ - int ix1 = (int)floor(x1); - int ix2 = (int)floor(x2); - Real fx1 = x1 - ix1; - Real fx2 = x2 - ix2; - - Real dx,dy,dydx,mult; - - dx = x2 - x1; - dy = fy2 - fy1; - - //case horizontal line - if(fy1 == fy2) - { - move_pen(ix2,y); //pen needs to be at the last coord - return; - } - - //case all in same pixel - if(ix1 == ix2) //impossible for degenerate case (covered by the previous cases) - { - current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapezoid area - return; - } - - if(dx > 0) - { - // ----> fx1...1 0...1 ... 0...1 0...fx2 - dydx = dy / dx; - - //set initial values - //Iterate through the covered pixels - mult = (1 - fx1)*dydx; //next y intersection diff value (at 1) - - //first pixel - current.addcover(mult,(1 + fx1)*mult/2); // fx1,fy1,1,fy@1 - starting trapezoidal area - - //move to the next pixel - fy1 += mult; - ix1++; - - move_pen(ix1,y); - - //set up for whole ones - while(ix1 != ix2) - { - //trapezoid(0,y1,1,y1+dydx); - current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover - - //move to next pixel (+1) - ix1++; - fy1 += dydx; - move_pen(ix1,y); - } - - //last pixel - //final y-pos - last intersect pos - mult = fx2 * dydx; - current.addcover(mult,(0+fx2)*mult/2); - }else - { - // fx2...1 0...1 ... 0...1 0...fx1 <---- - //mult = (0 - fx1) * dy / dx; - //neg sign sucked into dydx - dydx = -dy / dx; - - //set initial values - //Iterate through the covered pixels - mult = fx1*dydx; //next y intersection diff value - - //first pixel - current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapezoidal area - - //move to next pixel - fy1 += mult; - ix1--; - - move_pen(ix1,y); - - //set up for whole ones - while(ix1 != ix2) - { - //trapezoid(0,y1,1,y1+dydx); - current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover - - //move to next pixel (-1) - fy1 += dydx; - ix1--; - move_pen(ix1,y); - } - - //last pixel - mult = fy2 - fy1; //final y-pos - last intersect pos - - current.addcover(mult,(fx2+1)*mult/2); - } -} - -void Layer_Shape::PolySpan::draw_line(Real x1, Real y1, Real x2, Real y2) -{ - int iy1 = (int)floor(y1); - int iy2 = (int)floor(y2); - Real fy1 = y1 - iy1; - Real fy2 = y2 - iy2; - - assert(!isnan(fy1)); - assert(!isnan(fy2)); - - Real dx,dy,dxdy,mult,x_from,x_to; - - const Real SLOPE_EPSILON = 1e-10; - - //case all one scanline - if(iy1 == iy2) - { - draw_scanline(iy1,x1,y1,x2,y2); - return; - } - - //difference values - dy = y2 - y1; - dx = x2 - x1; - - //case vertical line - if(dx < SLOPE_EPSILON && dx > -SLOPE_EPSILON) - { - //calc area and cover on vertical line - if(dy > 0) - { - // ----> fx1...1 0...1 ... 0...1 0...fx2 - Real sub; - - int ix1 = (int)floor(x1); - Real fx1 = x1 - ix1; - - //current pixel - sub = 1 - fy1; - - current.addcover(sub,fx1*sub); - - //next pixel - iy1++; - - //move pen to next pixel - move_pen(ix1,iy1); - - while(iy1 != iy2) - { - //accumulate cover - current.addcover(1,fx1); - - //next pixel - iy1++; - move_pen(ix1,iy1); - } - - //last pixel - current.addcover(fy2,fy2*fx1); - }else - { - Real sub; - - int ix1 = (int)floor(x1); - Real fx1 = x1 - ix1; - - //current pixel - sub = 0 - fy1; - - current.addcover(sub,fx1*sub); - - //next pixel - iy1--; - - move_pen(ix1,iy1); - - while(iy1 != iy2) - { - //accumulate in current pixel - current.addcover(-1,-fx1); - - //move to next - iy1--; - move_pen(ix1,iy1); - } - - current.addcover(fy2-1,(fy2-1)*fx1); - } - return; - } - - //case normal line - guaranteed dx != 0 && dy != 0 - - //calculate the initial intersection with "next" scanline - if(dy > 0) - { - dxdy = dx / dy; - - mult = (1 - fy1) * dxdy; - - //x intersect scanline - x_from = x1 + mult; - draw_scanline(iy1,x1,fy1,x_from,1); - - //move to next line - iy1++; - - move_pen((int)floor(x_from),iy1); - - while(iy1 != iy2) - { - //keep up on the x axis, and render the current scanline - x_to = x_from + dxdy; - draw_scanline(iy1,x_from,0,x_to,1); - x_from = x_to; - - //move to next pixel - iy1++; - move_pen((int)floor(x_from),iy1); - } - - //draw the last one, fractional - draw_scanline(iy2,x_from,0,x2,fy2); - - }else - { - dxdy = -dx / dy; - - mult = fy1 * dxdy; - - //x intersect scanline - x_from = x1 + mult; - draw_scanline(iy1,x1,fy1,x_from,0); - - //each line after - iy1--; - - move_pen((int)floor(x_from),iy1); - - while(iy1 != iy2) - { - x_to = x_from + dxdy; - draw_scanline(iy1,x_from,1,x_to,0); - x_from = x_to; - - iy1--; - move_pen((int)floor(x_from),iy1); - } - //draw the last one, fractional - draw_scanline(iy2,x_from,1,x2,fy2); - } -} - -//****** LAYER PEN OPERATIONS (move_to, line_to, etc.) ****** -void Layer_Shape::move_to(Real x, Real y) -{ - //const int sizeblock = sizeof(Primitive)+sizeof(Point); - Primitive op; - Point p(x,y); - - op.operation = Primitive::MOVE_TO; - op.number = 1; //one point for now - - if(lastbyteop == Primitive::MOVE_TO) - { - char *ptr = &bytestream[lastoppos]; - memcpy(ptr,&op,sizeof(op)); - memcpy(ptr+sizeof(op),&p,sizeof(p)); - } - else //make a new op - { - lastbyteop = Primitive::MOVE_TO; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data - } - - edge_table->move_to(x,y); -} - -void Layer_Shape::close() -{ - Primitive op; - - op.operation = Primitive::CLOSE; - op.number = 0; - - if(lastbyteop == Primitive::CLOSE) - { - }else - { - lastbyteop = Primitive::CLOSE; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert header - } - - edge_table->close(); - //should not affect the bounding box since it would just be returning to old point... -} - -void Layer_Shape::endpath() -{ - Primitive op; - - op.operation = Primitive::END; - op.number = 0; - - if(lastbyteop == Primitive::END || lastbyteop == Primitive::NONE) - { - }else - { - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); - } - //should not affect the bounding box since it would just be returning to old point... if at all -} - -void Layer_Shape::line_to(Real x, Real y) -{ - assert(!isnan(x)); - assert(!isnan(y)); - - //const int sizeblock = sizeof(Primitive)+sizeof(Point); - Primitive op; - Point p(x,y); - - op.operation = Primitive::LINE_TO; - op.number = 1; //one point for now - - if(lastbyteop == Primitive::MOVE_TO || lastbyteop == Primitive::LINE_TO) - { - //only need to insert the point - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); - - Primitive * prim = (Primitive *)&bytestream[lastoppos]; - prim->number++; //increment number of points in the list - }else - { - lastbyteop = Primitive::LINE_TO; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data - } - - edge_table->line_to(x,y); -} - -void Layer_Shape::conic_to(Real x1, Real y1, Real x, Real y) -{ - //const int sizeblock = sizeof(Primitive)+sizeof(Point)*2; - Primitive op; - Point p(x,y); - Point p1(x1,y1); - - op.operation = Primitive::CONIC_TO; - op.number = 2; //2 points for now - - if(lastbyteop == Primitive::CONIC_TO) - { - //only need to insert the new points - bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); - - Primitive * prim = (Primitive *)&bytestream[lastoppos]; - prim->number += 2; //increment number of points in the list - }else - { - lastbyteop = Primitive::CONIC_TO; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header - bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data - } - - edge_table->conic_to(x1,y1,x,y); -} - -void Layer_Shape::conic_to_smooth(Real x, Real y) //x1,y1 derived from current tangent -{ - //const int sizeblock = sizeof(Primitive)+sizeof(Point); - Primitive op; - Point p(x,y); - - op.operation = Primitive::CONIC_TO_SMOOTH; - op.number = 1; //2 points for now - - if(lastbyteop == Primitive::CONIC_TO_SMOOTH) - { - //only need to insert the new point - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); - - Primitive * prim = (Primitive *)&bytestream[lastoppos]; - prim->number += 1; //increment number of points in the list - }else - { - lastbyteop = Primitive::CONIC_TO_SMOOTH; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data - } - - edge_table->conic_to_smooth(x,y); -} - -void Layer_Shape::curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y) -{ - //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3; - Primitive op; - Point p(x,y); - Point p1(x1,y1); - Point p2(x2,y2); - - op.operation = Primitive::CUBIC_TO; - op.number = 3; //3 points for now - - if(lastbyteop == Primitive::CUBIC_TO) - { - //only need to insert the new points - bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); - bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); - - Primitive * prim = (Primitive *)&bytestream[lastoppos]; - prim->number += 3; //increment number of points in the list - }else - { - lastbyteop = Primitive::CUBIC_TO; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header - bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data - bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data - } - - edge_table->curve_to(x1,y1,x2,y2,x,y); -} - -void Layer_Shape::curve_to_smooth(Real x2, Real y2, Real x, Real y) //x1,y1 derived from current tangent -{ - //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3; - Primitive op; - Point p(x,y); - Point p2(x2,y2); - - op.operation = Primitive::CUBIC_TO_SMOOTH; - op.number = 2; //3 points for now - - if(lastbyteop == Primitive::CUBIC_TO_SMOOTH) - { - //only need to insert the new points - bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); - - Primitive * prim = (Primitive *)&bytestream[lastoppos]; - prim->number += 2; //increment number of points in the list - }else - { - lastbyteop = Primitive::CUBIC_TO_SMOOTH; - lastoppos = bytestream.size(); - - bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header - bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data - bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data - } -} - -// ACCELERATED RENDER FUNCTION - TRANSLATE BYTE CODE INTO FUNCTION CALLS - -bool Layer_Shape::render_polyspan( - Surface *surface, - PolySpan &polyspan, - Color::value_type amount, - Color::BlendMethod blend_method, - const Color &color, - bool invert, - bool antialias, - WindingStyle winding_style ) const -{ - Surface::alpha_pen p(surface->begin(), amount, blend_method); - PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin(); - PolySpan::cover_array::iterator end_mark = polyspan.covers.end(); - - Real cover,area,alpha; - - int y,x; - - p.set_value(color); - cover = 0; - - if(cur_mark == end_mark) - { - //no marks at all - if(invert) - { - p.move_to(polyspan.window.minx,polyspan.window.miny); - p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx); - } - return true; - } - - //fill initial rect / line - if(invert) - { - //fill all the area above the first vertex - p.move_to(polyspan.window.minx,polyspan.window.miny); - y = polyspan.window.miny; - int l = polyspan.window.maxx - polyspan.window.minx; - - p.put_block(cur_mark->y - polyspan.window.miny,l); - - //fill the area to the left of the first vertex on that line - l = cur_mark->x - polyspan.window.minx; - p.move_to(polyspan.window.minx,cur_mark->y); - if(l) p.put_hline(l); - } - - for(;;) - { - y = cur_mark->y; - x = cur_mark->x; - - p.move_to(x,y); - - area = cur_mark->area; - cover += cur_mark->cover; - - //accumulate for the current pixel - while(++cur_mark != polyspan.covers.end()) - { - if(y != cur_mark->y || x != cur_mark->x) - break; - - area += cur_mark->area; - cover += cur_mark->cover; - } - - //draw pixel - based on covered area - if(area) //if we're ok, draw the current pixel - { - alpha = polyspan.ExtractAlpha(cover - area, winding_style); - if(invert) alpha = 1 - alpha; - - if(!antialias) - { - if(alpha >= .5) p.put_value(); - } - else if(alpha) p.put_value_alpha(alpha); - - p.inc_x(); - x++; - } - - //if we're done, don't use iterator and exit - if(cur_mark == end_mark) break; - - //if there is no more live pixels on this line, goto next - if(y != cur_mark->y) - { - if(invert) - { - //fill the area at the end of the line - p.put_hline(polyspan.window.maxx - x); - - //fill area at the beginning of the next line - p.move_to(polyspan.window.minx,cur_mark->y); - p.put_hline(cur_mark->x - polyspan.window.minx); - } - - cover = 0; - - continue; - } - - //draw span to next pixel - based on total amount of pixel cover - if(x < cur_mark->x) - { - alpha = polyspan.ExtractAlpha(cover, winding_style); - if(invert) alpha = 1 - alpha; - - if(!antialias) - { - if(alpha >= .5) p.put_hline(cur_mark->x - x); - } - else if(alpha) p.put_hline(cur_mark->x - x,alpha); - } - } - - //fill the after stuff - if(invert) - { - //fill the area at the end of the line - p.put_hline(polyspan.window.maxx - x); - - //fill area at the beginning of the next line - p.move_to(polyspan.window.minx,y+1); - p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx); - } - - return true; -} - -bool Layer_Shape::render_polyspan(etl::surface *surface, PolySpan &polyspan) const -{ - bool invert =param_invert.get(bool(true)); - bool antialias =param_antialias.get(bool(true)); - WindingStyle winding_style=(WindingStyle)param_winding_style.get(int()); - - etl::surface::pen p(surface->begin()); - PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin(); - PolySpan::cover_array::iterator end_mark = polyspan.covers.end(); - - Real cover,area,alpha; - - int y,x; - - cover = 0; - - //the pen always writes 1 (unless told to do otherwise) - p.set_value(1); - - if(cur_mark == end_mark) - { - //no marks at all - if(invert) - { - p.move_to(polyspan.window.minx,polyspan.window.miny); - p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx); - } - return true; - } - - //fill initial rect / line - if(invert) - { - //fill all the area above the first vertex - p.move_to(polyspan.window.minx,polyspan.window.miny); - y = polyspan.window.miny; - int l = polyspan.window.maxx - polyspan.window.minx; - - p.put_block(cur_mark->y - polyspan.window.miny,l); - - //fill the area to the left of the first vertex on that line - l = cur_mark->x - polyspan.window.minx; - p.move_to(polyspan.window.minx,cur_mark->y); - if(l) p.put_hline(l); - - for(;;) - { - y = cur_mark->y; - x = cur_mark->x; - - p.move_to(x,y); - - area = cur_mark->area; - cover += cur_mark->cover; - - //accumulate for the current pixel - while(++cur_mark != polyspan.covers.end()) - { - if(y != cur_mark->y || x != cur_mark->x) - break; - - area += cur_mark->area; - cover += cur_mark->cover; - } - - //draw pixel - based on covered area - if(area) //if we're ok, draw the current pixel - { - alpha = 1 - polyspan.ExtractAlpha(cover - area, winding_style); - if(!antialias) - { - if(alpha >= .5) p.put_value(); - } - else if(alpha) p.put_value(alpha); - - p.inc_x(); - x++; - } - - //if we're done, don't use iterator and exit - if(cur_mark == end_mark) break; - - //if there is no more live pixels on this line, goto next - if(y != cur_mark->y) - { - //fill the area at the end of the line - p.put_hline(polyspan.window.maxx - x); - - //fill area at the beginning of the next line - p.move_to(polyspan.window.minx,cur_mark->y); - p.put_hline(cur_mark->x - polyspan.window.minx); - - cover = 0; - - continue; - } - - //draw span to next pixel - based on total amount of pixel cover - if(x < cur_mark->x) - { - alpha = 1 - polyspan.ExtractAlpha(cover, winding_style); - if(!antialias) - { - if(alpha >= .5) p.put_hline(cur_mark->x - x); - } - else if(alpha) p.put_hline(cur_mark->x - x,alpha); - } - } - - //fill the area at the end of the line - p.put_hline(polyspan.window.maxx - x); - - //fill area at the beginning of the next line - p.move_to(polyspan.window.minx,y+1); - p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx); - }else - { - for(;;) - { - y = cur_mark->y; - x = cur_mark->x; - - p.move_to(x,y); - - area = cur_mark->area; - cover += cur_mark->cover; - - //accumulate for the current pixel - while(++cur_mark != polyspan.covers.end()) - { - if(y != cur_mark->y || x != cur_mark->x) - break; - - area += cur_mark->area; - cover += cur_mark->cover; - } - - //draw pixel - based on covered area - if(area) //if we're ok, draw the current pixel - { - alpha = polyspan.ExtractAlpha(cover - area, winding_style); - if(!antialias) - { - if(alpha >= .5) p.put_value(); - } - else if(alpha) p.put_value(alpha); - - p.inc_x(); - x++; - } - - //if we're done, don't use iterator and exit - if(cur_mark == end_mark) break; - - //if there is no more live pixels on this line, goto next - if(y != cur_mark->y) - { - cover = 0; - - continue; - } - - //draw span to next pixel - based on total amount of pixel cover - if(x < cur_mark->x) - { - alpha = polyspan.ExtractAlpha(cover, winding_style); - if(!antialias) - { - if(alpha >= .5) p.put_hline(cur_mark->x - x); - } - else if(alpha) p.put_hline(cur_mark->x - x,alpha); - } - } - } - - return true; -} - -bool -Layer_Shape::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - Color color=param_color.get(Color()); - Point origin=param_origin.get(Point()); - bool invert =param_invert.get(bool(true)); - int blurtype=param_blurtype.get(int()); - Real feather=param_feather.get(Real()); - - const unsigned int w = renddesc.get_w(); - const unsigned int h = renddesc.get_h(); - - const Real pw = abs(renddesc.get_pw()); - const Real ph = abs(renddesc.get_ph()); - - //const Real OFFSET_EPSILON = 1e-8; - SuperCallback stageone(cb,1,10000,15001+renddesc.get_h()); - SuperCallback stagetwo(cb,10000,10001+renddesc.get_h(),15001+renddesc.get_h()); - SuperCallback stagethree(cb,10001+renddesc.get_h(),15001+renddesc.get_h(),15001+renddesc.get_h()); - - // Render what is behind us - - //clip if it satisfies the invert solid thing - if(is_solid_color() && invert) - { - Rect aabb = edge_table->aabb; - Point tl = renddesc.get_tl() - origin; - - Real pw = renddesc.get_pw(), - ph = renddesc.get_ph(); - - Rect nrect; - - Real pixelfeatherx = quality == 10 ? 0 : abs(feather/pw), - pixelfeathery = quality == 10 ? 0 : abs(feather/ph); - - nrect.set_point((aabb.minx - tl[0])/pw,(aabb.miny - tl[1])/ph); - nrect.expand((aabb.maxx - tl[0])/pw,(aabb.maxy - tl[1])/ph); - - RendDesc optdesc(renddesc); - - //make sure to expand so we gain subpixels rather than lose them - nrect.minx = floor(nrect.minx-pixelfeatherx); nrect.miny = floor(nrect.miny-pixelfeathery); - nrect.maxx = ceil(nrect.maxx+pixelfeatherx); nrect.maxy = ceil(nrect.maxy+pixelfeathery); - - //make sure the subwindow is clipped with our tile window (minimize useless drawing) - set_intersect(nrect,nrect,Rect(0,0,renddesc.get_w(),renddesc.get_h())); - - //must resize the surface first - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - surface->clear(); - - //only render anything if it's visible from our current tile - if(nrect.valid()) - { - //set the subwindow to the viewable pixels and render it to the subsurface - optdesc.set_subwindow((int)nrect.minx, (int)nrect.miny, - (int)(nrect.maxx - nrect.minx), (int)(nrect.maxy - nrect.miny)); - - Surface optimizedbacksurf; - if(!context.accelerated_render(&optimizedbacksurf,quality,optdesc,&stageone)) - return false; - - //blit that onto the original surface so we can pretend that nothing ever happened - Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny); - optimizedbacksurf.blit_to(p); - } - }else - { - if(!context.accelerated_render(surface,quality,renddesc,&stageone)) - return false; - } - - if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false; - - if(feather && quality != 10) - { - //we have to blur rather than be crappy - - //so make a separate surface - RendDesc workdesc(renddesc); - - etl::surface shapesurface; - - //the expanded size = 1/2 the size in each direction rounded up - int halfsizex = (int) (abs(feather*.5/pw) + 3), - halfsizey = (int) (abs(feather*.5/ph) + 3); - - //expand by 1/2 size in each direction on either side - switch(blurtype) - { - case Blur::DISC: - case Blur::BOX: - case Blur::CROSS: - { - workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); - break; - } - case Blur::FASTGAUSSIAN: - { - if(quality < 4) - { - halfsizex*=2; - halfsizey*=2; - } - workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); - break; - } - case Blur::GAUSSIAN: - { - #define GAUSSIAN_ADJUSTMENT (0.05) - Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]); - Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]); - - pw=pw*pw; - ph=ph*ph; - - halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5); - halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5); - - halfsizex = (halfsizex + 1)/2; - halfsizey = (halfsizey + 1)/2; - workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey ); - - break; - } - } - - shapesurface.set_wh(workdesc.get_w(),workdesc.get_h()); - shapesurface.clear(); - - //render the shape - if(!render_shape(&shapesurface,quality,workdesc,&stagetwo))return false; - - //blur the image - Blur(feather,feather,blurtype,&stagethree)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface); - - //blend with stuff below it... - unsigned int u = halfsizex, v = halfsizey, x = 0, y = 0; - for(y = 0; y < h; y++,v++) - { - u = halfsizex; - for(x = 0; x < w; x++,u++) - { - float a = shapesurface[v][u]; - if(a) - { - //a = floor(a*255+0.5f)/255; - (*surface)[y][x]=Color::blend(color,(*surface)[y][x],a*get_amount(),get_blend_method()); - } - //else (*surface)[y][x] = worksurface[v][u]; - } - } - - //we are done - if(cb && !cb->amount_complete(100,100)) - { - synfig::warning("Layer_Shape: could not set amount complete"); - return false; - } - - return true; - }else - { - //might take out to reduce code size - return render_shape(surface,true,quality,renddesc,&stagetwo); - } - -} - -//// -bool -Layer_Shape::accelerated_cairorender(Context context,cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - Color color=param_color.get(Color()); - Point origin=param_origin.get(Point()); - bool invert =param_invert.get(bool(true)); - bool antialias =param_antialias.get(bool(true)); - int blurtype=param_blurtype.get(int()); - Real feather=param_feather.get(Real()); - WindingStyle winding_style=(WindingStyle)param_winding_style.get(int()); - - // Grab the rgba values - const float r(color.get_r()); - const float g(color.get_g()); - const float b(color.get_b()); - const float a(color.get_a()); - - // First render the context - if(!is_solid_color()) - if(!context.accelerated_cairorender(cr,quality,renddesc,cb)) - { - if(cb) - cb->error(strprintf(__FILE__"%d: Accelerated Cairo Renderer Failure",__LINE__)); - return false; - } - - if(feather && quality != 10) - { - cairo_surface_t* subimage; - RendDesc workdesc(renddesc); - - // Untransform the render desc - if(!cairo_renddesc_untransform(cr, workdesc)) - return false; - - int halfsizex(0), halfsizey(0); - - int w=workdesc.get_w(), h=workdesc.get_h(); - const double wpw=(workdesc.get_br()[0]-workdesc.get_tl()[0])/w; - const double wph=(workdesc.get_br()[1]-workdesc.get_tl()[1])/h; - //the expanded size = 1/2 the size in each direction rounded up - halfsizex = (int) (abs(feather*.5/wpw) + 3), - halfsizey = (int) (abs(feather*.5/wph) + 3); - - //expand by 1/2 size in each direction on either side - switch(blurtype) - { - case Blur::DISC: - case Blur::BOX: - case Blur::CROSS: - { - workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); - break; - } - case Blur::FASTGAUSSIAN: - { - if(quality < 4) - { - halfsizex*=2; - halfsizey*=2; - } - workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); - break; - } - case Blur::GAUSSIAN: - { -#define GAUSSIAN_ADJUSTMENT (0.05) - Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]); - Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]); - - pw=pw*pw; - ph=ph*ph; - - halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5); - halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5); - - halfsizex = (halfsizex + 1)/2; - halfsizey = (halfsizey + 1)/2; - workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey ); - break; -#undef GAUSSIAN_ADJUSTMENT - } - } - - // New expanded workdesc values - const int ww=workdesc.get_w(); - const int wh=workdesc.get_h(); - const double wtlx=workdesc.get_tl()[0]; - const double wtly=workdesc.get_tl()[1]; - subimage=cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, ww, wh); - cairo_t* subcr=cairo_create(subimage); - cairo_scale(subcr, 1/wpw, 1/wph); - cairo_translate(subcr, -wtlx, -wtly); - cairo_translate(subcr, origin[0], origin[1]); - switch(winding_style) - { - case WINDING_NON_ZERO: - cairo_set_fill_rule(subcr, CAIRO_FILL_RULE_WINDING); - break; - default: - cairo_set_fill_rule(subcr, CAIRO_FILL_RULE_EVEN_ODD); - break; - } - - cairo_set_source_rgba(subcr, r, g, b, a); - if(invert) - cairo_paint(subcr); - // Draw the shape - if(!antialias) - cairo_set_antialias(subcr, CAIRO_ANTIALIAS_NONE); - if(invert) - cairo_set_operator(subcr, CAIRO_OPERATOR_CLEAR); - else - cairo_set_operator(subcr, CAIRO_OPERATOR_OVER); - - Layer_Shape::shape_to_cairo(subcr); - cairo_clip(subcr); - cairo_paint(subcr); - - if(!feather_cairo_surface(subimage, workdesc, quality)) - { - cairo_surface_destroy(subimage); - cairo_destroy(subcr); - return false; - } - cairo_destroy(subcr); - - cairo_save(cr); - cairo_translate(cr, wtlx, wtly); - cairo_scale(cr, wpw, wph); - cairo_set_source_surface(cr, subimage, 0, 0); - cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); - cairo_restore(cr); - cairo_surface_destroy(subimage); - return true; - } - cairo_save(cr); - cairo_translate(cr, origin[0], origin[1]); - cairo_set_source_rgba(cr, r, g, b, a); - switch(winding_style) - { - case WINDING_NON_ZERO: - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); - break; - default: - cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); - break; - } - if(!antialias) - cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); - if(invert) - { - cairo_push_group(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_paint(cr); - Layer_Shape::shape_to_cairo(cr); - cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); - cairo_clip(cr); - cairo_paint(cr); - cairo_pop_group_to_source(cr); - cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); - } - else - { - Layer_Shape::shape_to_cairo(cr); - cairo_clip(cr); - cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); - } - cairo_restore(cr); - return true; -} -//// - - -// -bool -Layer_Shape::shape_to_cairo(cairo_t *cr)const -{ - int tmp(0); - //pointers for processing the bytestream - const char *current = &bytestream[0]; - const char *end = &bytestream[bytestream.size()]; - int operation = Primitive::NONE; - int number = 0; - int curnum; - - Primitive *curprim; - Point *data; - - Real x,y/*,x1,y1,x2,y2*/; - while(current < end) - { - tmp++; - - try { - - //get the op code safely - curprim = (Primitive *)current; - - //advance past indices - current += sizeof(Primitive); - if(current > end) - { - warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration"); - return false; - } - - //get the relevant data - operation = curprim->operation; - number = curprim->number; - - if(operation == Primitive::END) - break; - - if(operation == Primitive::CLOSE) - { - - cairo_close_path(cr); - continue; - } - - data = (Point*)current; - current += sizeof(Point)*number; - - //check data positioning - if(current > end) - { - warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points"); - return false; - } - - } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; } - - //transfer all the data - RLE optimized - for(curnum=0; curnum < number;) - { - switch(operation) - { - case Primitive::MOVE_TO: - { - x = data[curnum][0]; - y = data[curnum][1]; - - if(curnum == 0) - { - cairo_move_to(cr, x, y); - } - else - { - cairo_line_to(cr, x, y); - } - - curnum++; //only advance one point - - break; - } - - case Primitive::LINE_TO: - { - x = data[curnum][0]; - y = data[curnum][1]; - - cairo_line_to(cr, x, y); - synfig::info("line to x,y = %f, %f", x, y); - - curnum++; - break; - } -// -// case Primitive::CONIC_TO: -// { -// x = data[curnum+1][0]; -// x = (x - tl[0] + origin[0])*pw; -// y = data[curnum+1][1]; -// y = (y - tl[1] + origin[1])*ph; -// -// x1 = data[curnum][0]; -// x1 = (x1 - tl[0] + origin[0])*pw; -// y1 = data[curnum][1]; -// y1 = (y1 - tl[1] + origin[1])*ph; -// -// tangent[0] = 2*(x - x1); -// tangent[1] = 2*(y - y1); -// -// span.conic_to(x1,y1,x,y); -// curnum += 2; -// break; -// } -// -// case Primitive::CONIC_TO_SMOOTH: -// { -// x = data[curnum][0]; -// x = (x - tl[0] + origin[0])*pw; -// y = data[curnum][1]; -// y = (y - tl[1] + origin[1])*ph; -// -// x1 = span.cur_x + tangent[0]/2; -// y1 = span.cur_y + tangent[1]/2; -// -// tangent[0] = 2*(x - x1); -// tangent[1] = 2*(y - y1); -// -// span.conic_to(x1,y1,x,y); -// curnum ++; -// -// break; -// } -// -// case Primitive::CUBIC_TO: -// { -// x = data[curnum+2][0]; -// x = (x - tl[0] + origin[0])*pw; -// y = data[curnum+2][1]; -// y = (y - tl[1] + origin[1])*ph; -// -// x2 = data[curnum+1][0]; -// x2 = (x2 - tl[0] + origin[0])*pw; -// y2 = data[curnum+1][1]; -// y2 = (y2 - tl[1] + origin[1])*ph; -// -// x1 = data[curnum][0]; -// x1 = (x1 - tl[0] + origin[0])*pw; -// y1 = data[curnum][1]; -// y1 = (y1 - tl[1] + origin[1])*ph; -// -// tangent[0] = 2*(x - x2); -// tangent[1] = 2*(y - y2); -// -// span.cubic_to(x1,y1,x2,y2,x,y); -// curnum += 3; -// -// break; -// } -// -// case Primitive::CUBIC_TO_SMOOTH: -// { -// x = data[curnum+1][0]; -// x = (x - tl[0] + origin[0])*pw; -// y = data[curnum+1][1]; -// y = (y - tl[1] + origin[1])*ph; -// -// x2 = data[curnum][0]; -// x2 = (x2 - tl[0] + origin[0])*pw; -// y2 = data[curnum][1]; -// y2 = (y2 - tl[1] + origin[1])*ph; -// -// x1 = span.cur_x + tangent[0]/3.0; -// y1 = span.cur_y + tangent[1]/3.0; -// -// tangent[0] = 2*(x - x2); -// tangent[1] = 2*(y - y2); -// -// span.cubic_to(x1,y1,x2,y2,x,y); -// curnum += 2; -// -// break; -// } - } // switch - } // for - } // while - - return true; -} -// - -bool -Layer_Shape::feather_cairo_surface(cairo_surface_t* surface, RendDesc renddesc, int quality)const -{ - Color color=param_color.get(Color()); - int blurtype=param_blurtype.get(int()); - Real feather=param_feather.get(Real()); - - if(feather && quality!=10) - { - etl::surface shapesurface; - shapesurface.set_wh(renddesc.get_w(),renddesc.get_h()); - shapesurface.clear(); - - CairoSurface cairosurface(surface); - if(!cairosurface.map_cairo_image()) - { - synfig::info("map cairo image failed"); - return false; - } - // Extract the alpha values: - int x, y; - int h(renddesc.get_h()), w(renddesc.get_w()); - float div=1.0/((float)(CairoColor::ceil)); - for(y=0; y end) - { - warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration"); - return false; - } - - //get the relevant data - operation = curprim->operation; - number = curprim->number; - - if(operation == Primitive::END) - break; - - if(operation == Primitive::CLOSE) - { - if(span.notclosed()) - { - tangent[0] = span.close_x - span.cur_x; - tangent[1] = span.close_y - span.cur_y; - span.close(); - } - continue; - } - - data = (Point*)current; - current += sizeof(Point)*number; - - //check data positioning - if(current > end) - { - warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points"); - return false; - } - - } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; } - - //transfer all the data - RLE optimized - for(curnum=0; curnum < number;) - { - switch(operation) - { - case Primitive::MOVE_TO: - { - matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); - - if(curnum == 0) - { - span.move_to(x,y); - - tangent[0] = 0; - tangent[1] = 0; - } - else - { - tangent[0] = x - span.cur_x; - tangent[1] = y - span.cur_y; - - span.line_to(x,y); - } - - curnum++; //only advance one point - - break; - } - - case Primitive::LINE_TO: - { - matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); - - tangent[0] = x - span.cur_x; - tangent[1] = y - span.cur_y; - - span.line_to(x,y); - curnum++; - break; - } - - case Primitive::CONIC_TO: - { - matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); - matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); - - tangent[0] = 2*(x - x1); - tangent[1] = 2*(y - y1); - - span.conic_to(x1,y1,x,y); - curnum += 2; - break; - } - - case Primitive::CONIC_TO_SMOOTH: - { - matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); - - x1 = span.cur_x + tangent[0]/2; - y1 = span.cur_y + tangent[1]/2; - - tangent[0] = 2*(x - x1); - tangent[1] = 2*(y - y1); - - span.conic_to(x1,y1,x,y); - curnum ++; - - break; - } - - case Primitive::CUBIC_TO: - { - matrix.get_transformed(x, y, data[curnum+2][0], data[curnum+2][1]); - matrix.get_transformed(x2, y2, data[curnum+1][0], data[curnum+1][1]); - matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); - - tangent[0] = 2*(x - x2); - tangent[1] = 2*(y - y2); - - span.cubic_to(x1,y1,x2,y2,x,y); - curnum += 3; - - break; - } - - case Primitive::CUBIC_TO_SMOOTH: - { - matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); - matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); - - x1 = span.cur_x + tangent[0]/3.0; - y1 = span.cur_y + tangent[1]/3.0; - - tangent[0] = 2*(x - x2); - tangent[1] = 2*(y - y2); - - span.cubic_to(x1,y1,x2,y2,x,y); - curnum += 2; - - break; - } - } - } - } - - //sort the bastards so we can render everything - span.sort_marks(); - - Color::value_type amount = useblend ? get_amount() : 1.0; - Color::BlendMethod blend_method = useblend ? get_blend_method() : Color::BLEND_STRAIGHT; - Color color = param_color.get(Color()); - bool invert = param_invert.get(bool(true)); - bool antialias = param_antialias.get(bool(true)); - WindingStyle winding_style = (WindingStyle)param_winding_style.get(int()); - - if (useblend && get_blend_method() == Color::BLEND_STRAIGHT_ONTO) - { - Surface s; - s.set_wh(surface->get_w(), surface->get_h()); - s.clear(); - bool result = render_polyspan( - &s, - span, - 1.0, - Color::BLEND_STRAIGHT, - color, - invert, - antialias, - winding_style ); - - Surface::alpha_pen p(surface->begin(), amount, Color::BLEND_STRAIGHT_ONTO); - s.blit_to(p, 0, 0, surface->get_w(), surface->get_h()); - - return result; - } - - return render_polyspan( - surface, - span, - amount, - blend_method, - color, - invert, - antialias, - winding_style ); -} - -bool -Layer_Shape::render_shape(etl::surface *surface,int /*quality*/, - const RendDesc &renddesc, ProgressCallback */*cb*/)const -{ - // If our amount is set to zero, no need to render anything - if(!get_amount()) - return true; - - const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]); - const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]); - - // if the pixels are zero sized then we're too zoomed out to see anything - if (pw == 0 || ph == 0) - return true; - - Matrix matrix( - Matrix().set_translate(param_origin.get(Point())) - * renddesc.get_transformation_matrix() - * Matrix().set_translate(-renddesc.get_tl()) - * Matrix().set_scale(pw, ph) - ); - - //test new polygon renderer - // Build edge table - // Width and Height of a pixel - const int w = renddesc.get_w(); - const int h = renddesc.get_h(); - - Vector tangent (0,0); - - PolySpan span; - - //optimization for tessellating only inside tiles - span.window.minx = 0; - span.window.miny = 0; - span.window.maxx = w; - span.window.maxy = h; - - //pointers for processing the bytestream - const char *current = &bytestream[0]; - const char *end = &bytestream[bytestream.size()]; - - int operation = Primitive::NONE; - int number = 0; - int curnum; - - Primitive *curprim; - Point *data; - - Real x,y,x1,y1,x2,y2; - - while(current < end) - { - //get the op code safely - curprim = (Primitive *)current; - - //advance past indices - current += sizeof(Primitive); - if(current > end) - { - warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration"); - return false; - } - - //get the relevant data - operation = curprim->operation; - number = curprim->number; - - if(operation == Primitive::END) - break; - - if(operation == Primitive::CLOSE) - { - if(span.notclosed()) - { - tangent[0] = span.close_x - span.cur_x; - tangent[1] = span.close_y - span.cur_y; - span.close(); - } - continue; - } - - data = (Point*)current; - current += sizeof(Point)*number; - - //check data positioning - if(current > end) - { - warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points"); - return false; - } - - //transfer all the data - for(curnum=0; curnum < number;) - { - switch(operation) - { - case Primitive::MOVE_TO: - { - matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); - - if(curnum == 0) - { - span.move_to(x,y); - - tangent[0] = 0; - tangent[1] = 0; - } - else - { - tangent[0] = x - span.cur_x; - tangent[1] = y - span.cur_y; - - span.line_to(x,y); - } - - curnum++; //only advance one point - - break; - } - - case Primitive::LINE_TO: - { - matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); - - tangent[0] = x - span.cur_x; - tangent[1] = y - span.cur_y; - - span.line_to(x,y); - curnum++; - break; - } - - case Primitive::CONIC_TO: - { - matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); - matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); - - tangent[0] = 2*(x - x1); - tangent[1] = 2*(y - y1); - - span.conic_to(x1,y1,x,y); - curnum += 2; - break; - } - - case Primitive::CONIC_TO_SMOOTH: - { - matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); - - x1 = span.cur_x + tangent[0]/2; - y1 = span.cur_y + tangent[1]/2; - - tangent[0] = 2*(x - x1); - tangent[1] = 2*(y - y1); - - span.conic_to(x1,y1,x,y); - curnum ++; - - break; - } - - case Primitive::CUBIC_TO: - { - matrix.get_transformed(x, y, data[curnum+2][0], data[curnum+2][1]); - matrix.get_transformed(x2, y2, data[curnum+1][0], data[curnum+1][1]); - matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); - - tangent[0] = 2*(x - x2); - tangent[1] = 2*(y - y2); - - span.cubic_to(x1,y1,x2,y2,x,y); - curnum += 3; - - break; - } - - case Primitive::CUBIC_TO_SMOOTH: - { - matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); - matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); - - x1 = span.cur_x + tangent[0]/3.0; - y1 = span.cur_y + tangent[1]/3.0; - - tangent[0] = 2*(x - x2); - tangent[1] = 2*(y - y2); - - span.cubic_to(x1,y1,x2,y2,x,y); - curnum += 2; - - break; - } - } - } - } - - //sort the bastards so we can render everything - span.sort_marks(); - - return render_polyspan(surface, span); -} - -Rect -Layer_Shape::get_bounding_rect()const -{ - Point origin=param_origin.get(Point()); - bool invert =param_invert.get(bool(true)); - Real feather=param_feather.get(Real()); - - if(invert) - return Rect::full_plane(); - - if (edge_table->initaabb) - return Rect::zero(); - - Rect bounds(edge_table->aabb+origin); - bounds.expand(max((bounds.get_min() - bounds.get_max()).mag()*0.01, - feather)); - - return bounds; -} diff --git a/synfig-core/src/synfig/layer_shape.h b/synfig-core/src/synfig/layer_shape.h deleted file mode 100644 index 039ab02..0000000 --- a/synfig-core/src/synfig/layer_shape.h +++ /dev/null @@ -1,144 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_shape.h -** \brief Header file for implementation of the "Shape" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007-2008 Chris Moore -** Copyright (c) 2012-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_SHAPE_H -#define __SYNFIG_LAYER_SHAPE_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_composite.h" -#include "color.h" -#include "vector.h" -#include "blur.h" - -#include - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -/*! \class Layer_Shape -** \brief writeme */ -class Layer_Shape : public Layer_Composite, public Layer_NoDeform -{ - SYNFIG_LAYER_MODULE_EXT - - enum WindingStyle - { - WINDING_NON_ZERO=0, //!< less than -1 --> 1; -1 --> 1; 0 --> 0; 1 --> 1; greater than 1 --> 1 - WINDING_EVEN_ODD=1, //!< add or subtract multiples of 2 to get into range -1:1, then as above - - WINDING_END=2 //!< \internal - }; - -private: - - //internal caching - struct Intersector; - Intersector *edge_table; -protected: - //!Parameter: (Color) Color of the shape - ValueBase param_color; - //!Parameter: (Point) Origin of the shape definition - ValueBase param_origin; - //!Parameter: (bool) Whether the shape is inverted or not - ValueBase param_invert; - //!Parameter: (bool) Whether the shape has antialiased edge - ValueBase param_antialias; - //!Parameter: (Blur::Type) The type of blur used for the feather - ValueBase param_blurtype; - //!Parameter: (Real) Amount of feather of the shape - ValueBase param_feather; - //!Parameter: (WindingStyle) How shape is rendered when crosses it self - ValueBase param_winding_style; -private: - std::vector< char > bytestream; - - //for use in creating the bytestream - int lastbyteop; - int lastoppos; - -protected: - - Layer_Shape(const Real &a = 1.0, const Color::BlendMethod m = Color::BLEND_COMPOSITE); - -public: - - ~Layer_Shape(); - - //! Clears out any data - /*! Also clears out the Intersector - */ - void clear(); - //void sync(); - - void move_to(Real x, Real y); - void line_to(Real x, Real y); - void conic_to(Real x1, Real y1, Real x, Real y); - void conic_to_smooth(Real x, Real y); //x1,y1 derived from current tangent - void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y); - void curve_to_smooth(Real x2, Real y2, Real x, Real y); //x1,y1 derived from current tangent - void close(); - void endpath(); - - virtual bool set_param(const String & param, const synfig::ValueBase &value); - virtual ValueBase get_param(const String & param)const; - - virtual Vocab get_param_vocab()const; - - virtual Color get_color(Context context, const Point &pos)const; - virtual bool accelerated_render(Context context, Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; - virtual Rect get_bounding_rect()const; - //This function translates Shape primitives to Cairo primitives. Currently only supported move_to and line_to. - bool shape_to_cairo(cairo_t* cr)const; - bool feather_cairo_surface(cairo_surface_t* surface, RendDesc renddesc, int quality)const; - -private: - class PolySpan; - bool render_polyspan( - Surface *surface, - PolySpan &polyspan, - Color::value_type amount, - Color::BlendMethod blend_method, - const Color &color, - bool invert, - bool antialias, - WindingStyle winding_style) const; - bool render_polyspan(etl::surface *surface,PolySpan &polyspan)const; - virtual bool render_shape(Surface *surface,bool useblend,int quality,const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool render_shape(etl::surface *surface,int quality,const RendDesc &renddesc, ProgressCallback *cb)const; -}; // END of Layer_Shape - -}; // END of namespace synfig -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_skeleton.cpp b/synfig-core/src/synfig/layer_skeleton.cpp deleted file mode 100644 index edfb3c8..0000000 --- a/synfig-core/src/synfig/layer_skeleton.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_skeleton.cpp -** \brief Implementation of the "Layer_Skeleton" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2008 Chris Moore -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "string.h" -#include "layer_skeleton.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenodes/valuenode_bone.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Skeleton); -SYNFIG_LAYER_SET_NAME(Layer_Skeleton,"skeleton"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Skeleton,N_("Skeleton")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Skeleton,N_("Other")); -SYNFIG_LAYER_SET_VERSION(Layer_Skeleton,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Skeleton,"$Id$"); - -/* === P R O C E D U R E S ================================================= */ - -/* === M E T H O D S ======================================================= */ - -/* === E N T R Y P O I N T ================================================= */ - -Layer_Skeleton::Layer_Skeleton(): - param_name(ValueBase((const char*)"skeleton")) -{ - std::vector bones; - int bone_count = 1; - if (getenv("SYNFIG_NUMBER_OF_BONES_IN_SKELETON")) - bone_count = atoi(getenv("SYNFIG_NUMBER_OF_BONES_IN_SKELETON")); - if (bone_count < 1) bone_count = 1; - else if (bone_count > 10) bone_count = 10; - - while (bone_count--) - bones.push_back(Bone()); - - param_bones.set_list_of(bones); - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); - - set_exclude_from_rendering(true); - Layer_Polygon::set_param("color", ValueBase(Color(0.5, 0.5, 1.0, 1.0))); - Layer_Polygon::set_param("amount", ValueBase(Real(0.5))); -} - -#ifdef _DEBUG -Layer_Skeleton::~Layer_Skeleton() -{ - if (getenv("SYNFIG_DEBUG_DESTRUCTORS")) - printf("%s:%d ~Layer_Skeleton()\n", __FILE__, __LINE__); -} -#endif - -bool -Layer_Skeleton::set_param(const String & param, const ValueBase &value) -{ - // lock color param - if (param == "color") return false; - - IMPORT_VALUE(param_name); - - if (param=="bones" && param_bones.get_type()==value.get_type()) - { - param_bones = value; - sync(); - return true; - } - - return Layer_Polygon::set_param(param,value); -} - -ValueBase -Layer_Skeleton::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_name); - EXPORT_VALUE(param_bones); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_Polygon::get_param(param); -} - -Layer::Vocab -Layer_Skeleton::get_param_vocab()const -{ - Layer::Vocab ret(Layer::get_param_vocab()); - - // Params from layer Layer_Shape - //ret.push_back(ParamDesc("color") - // .set_local_name(_("Color")) - //); - - ret.push_back(ParamDesc("amount") - .set_local_name(_("Amount")) - .set_description(_("Alpha channel of the layer")) - ); - - // Self params - ret.push_back(ParamDesc("name") - .set_local_name(_("Name")) - ); - ret.push_back(ParamDesc("bones") - .set_local_name(_("Bones")) - ); - - return ret; -} - -void -Layer_Skeleton::set_time(IndependentContext context, Time time)const -{ - const_cast(this)->sync(); - context.set_time(time); -} - -void -Layer_Skeleton::set_time(IndependentContext context, Time time, const Point &pos)const -{ - const_cast(this)->sync(); - context.set_time(time,pos); -} - -void -Layer_Skeleton::sync() -{ - const std::vector &list = param_bones.get_list(); - - static const Real precision = 0.000000001; - int segments_count = 64; - Real segment_angle = 2*PI/(Real)segments_count; - - clear(); - for(std::vector::const_iterator i = list.begin(); i != list.end(); ++i) - { - if (!i->same_type_as(Bone())) continue; - const Bone &bone = i->get(Bone()); - Matrix matrix = bone.get_animated_matrix(); - Vector origin = matrix.get_transformed(Vector(0.0, 0.0)); - Vector direction = matrix.get_transformed(Vector(1.0, 0.0), false).norm(); - Real length = bone.get_length() * bone.get_scalelx(); - - if (length < 0) { - length *= -1; - direction *= -1; - } - - const Vector &p0 = origin; - const Vector p1 = origin + direction * length; - - Real r0 = fabs(bone.get_width()); - Real r1 = fabs(bone.get_tipwidth()); - Real direction_angle = atan2(direction[1], direction[0]); - - Real angle0_base = length - precision > fabs(r1 - r0) - ? acos((r0 - r1)/length) - : (r0 > r1 ? 0.0 : PI); - Real angle1_base = PI - angle0_base; - - int segments_count0 = (int)round(2*angle1_base / segment_angle); - Real segment_angle0 = 2*angle1_base / (Real)segments_count0; - - int segments_count1 = (int)round(2*angle0_base / segment_angle); - Real segment_angle1 = 2*angle0_base / (Real)segments_count1; - - std::vector list; - list.reserve(segments_count0 + segments_count1 + 2); - - int j = 0; - Real angle = direction_angle + angle0_base; - while(true) - { - list.push_back( Point(r0*cos(angle) + p0[0], r0*sin(angle) + p0[1]) ); - if (j++ >= segments_count0) break; else angle += segment_angle0; - } - j = 0; - while(true) - { - list.push_back( Point(r1*cos(angle) + p1[0], r1*sin(angle) + p1[1]) ); - if (j++ >= segments_count1) break; else angle += segment_angle1; - } - - add_polygon(list); - upload_polygon(list); - } -} diff --git a/synfig-core/src/synfig/layer_skeleton.h b/synfig-core/src/synfig/layer_skeleton.h deleted file mode 100644 index 262366a..0000000 --- a/synfig-core/src/synfig/layer_skeleton.h +++ /dev/null @@ -1,77 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_skeleton.h -** \brief Header file for implementation of the "Layer_Skeleton" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_SKELETON_H -#define __SYNFIG_LAYER_SKELETON_H - -/* === H E A D E R S ======================================================= */ - -#include "bone.h" -#include "layer_polygon.h" -// #include -// #include - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -class Layer_Skeleton : public Layer_Polygon -{ - SYNFIG_LAYER_MODULE_EXT -private: - - //!Parameter: (std::vector) Bones list of the skeleton - ValueBase param_bones; - //!Parameter: (synfig::String) Name of the skeleton - ValueBase param_name; - -public: - - Layer_Skeleton(); - -#ifdef _DEBUG - ~Layer_Skeleton(); -#endif - - virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value); - - virtual synfig::ValueBase get_param(const synfig::String & param)const; - - virtual Vocab get_param_vocab()const; - - //! Updates the polygon data to match the parameters. - virtual void sync(); - virtual void set_time(IndependentContext context, Time time)const; - virtual void set_time(IndependentContext context, Time time, const Point &pos)const; -}; // END of class Layer_Skeleton - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_skeletondeformation.cpp b/synfig-core/src/synfig/layer_skeletondeformation.cpp deleted file mode 100644 index b778f1d..0000000 --- a/synfig-core/src/synfig/layer_skeletondeformation.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_skeletondeformation.cpp -** \brief SkeletonDeformation layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_skeletondeformation.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "value.h" -#include "valuenode.h" -#include "canvas.h" - -#include -#include -#include - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -/* === C L A S S E S ======================================================= */ - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_SkeletonDeformation); -SYNFIG_LAYER_SET_NAME(Layer_SkeletonDeformation,"skeleton_deformation"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_SkeletonDeformation,N_("Skeleton Deformation")); -SYNFIG_LAYER_SET_CATEGORY(Layer_SkeletonDeformation,N_("Distortions")); -SYNFIG_LAYER_SET_VERSION(Layer_SkeletonDeformation,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_SkeletonDeformation,"$Id$"); - -/* === M E T H O D S ======================================================= */ - -Layer_SkeletonDeformation::Layer_SkeletonDeformation(): - param_point1(ValueBase(Point(-4,4))), - param_point2(ValueBase(Point(4,-4))), - param_x_subdivisions(32), - param_y_subdivisions(32) -{ - max_texture_scale = 1.f; - param_bones.set_list_of(std::vector(1)); - - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer_SkeletonDeformation::~Layer_SkeletonDeformation() -{ -} - -String -Layer_SkeletonDeformation::get_local_name()const -{ - String s = Layer_MeshTransform::get_local_name(); - return s.empty() ? _("Skeleton Deformation") : '[' + s + ']'; -} - -Layer::Vocab -Layer_SkeletonDeformation::get_param_vocab()const -{ - Layer::Vocab ret(Layer_MeshTransform::get_param_vocab()); - - ret.push_back(ParamDesc("bones") - .set_local_name(_("Bones")) - .set_description(_("List of bones")) - .set_static(true) - ); - - ret.push_back(ParamDesc("point1") - .set_local_name(_("Point 1")) - .set_box("point2") - .set_description(_("First corner of the bounds rectangle")) - ); - - ret.push_back(ParamDesc("point2") - .set_local_name(_("Point 2")) - .set_description(_("Second corner of the bounds rectangle")) - ); - - ret.push_back(ParamDesc("x_subdivisions") - .set_local_name(_("Horizontal subdivisions")) - .set_description(_("Count of horizontal subdivisions of the transformation grid")) - ); - - ret.push_back(ParamDesc("y_subdivisions") - .set_local_name(_("Vertical subdivisions")) - .set_description(_("Count of vertical subdivisions of the transformation grid")) - ); - - return ret; -} - -void -Layer_SkeletonDeformation::prepare_mask() -{ - const std::vector &list = param_bones.get_list(); - - static const Real precision = 0.000000001; - int segments_count = 64; - Real segment_angle = 2*PI/(Real)segments_count; - - mask.clear(); - for(std::vector::const_iterator i = list.begin(); i != list.end(); ++i) - { - if (!i->same_type_as(BonePair())) continue; - const BonePair &bonePair = i->get(BonePair()); - const Bone &bone = bonePair.first; - Matrix matrix = bone.get_animated_matrix(); - Vector origin = matrix.get_transformed(Vector(0.0, 0.0)); - Vector direction = matrix.get_transformed(Vector(1.0, 0.0), false).norm(); - Real length = bone.get_length() * bone.get_scalelx(); - - if (length < 0) { - length *= -1; - direction *= -1; - } - - const Vector &p0 = origin; - const Vector p1 = origin + direction * length; - - Real r0 = fabs(bone.get_width()); - Real r1 = fabs(bone.get_tipwidth()); - Real direction_angle = atan2(direction[1], direction[0]); - - Real angle0_base = length - precision > fabs(r1 - r0) - ? acos((r0 - r1)/length) - : (r0 > r1 ? 0.0 : PI); - Real angle1_base = PI - angle0_base; - - int segments_count0 = (int)round(2*angle1_base / segment_angle); - Real segment_angle0 = 2*angle1_base / (Real)segments_count0; - - int segments_count1 = (int)round(2*angle0_base / segment_angle); - Real segment_angle1 = 2*angle0_base / (Real)segments_count1; - - // add vertices - int first = (int)mask.vertices.size(); - mask.vertices.reserve(first + segments_count0 + segments_count1 + 2); - - int j = 0; - Real angle = direction_angle + angle0_base; - while(true) - { - mask.vertices.push_back( Point(r0*cos(angle) + p0[0], r0*sin(angle) + p0[1]) ); - if (j++ >= segments_count0) break; else angle += segment_angle0; - } - j = 0; - while(true) - { - mask.vertices.push_back( Point(r1*cos(angle) + p1[0], r1*sin(angle) + p1[1]) ); - if (j++ >= segments_count1) break; else angle += segment_angle1; - } - - // add triangles - for(int i = first+2; i < (int)mask.vertices.size(); ++i) - mask.triangles.push_back(Polygon::Triangle(first, i-1, i)); - } -} - -struct Layer_SkeletonDeformation::GridPoint { - Vector initial_position; - Vector summary_position; - Real summary_depth; - Real summary_weight; - Real average_depth; - bool used; - - inline GridPoint(): - summary_depth(0.0), summary_weight(0.0), average_depth(0.0), used(false) { } - inline explicit GridPoint(const Vector &initial_position): - initial_position(initial_position), summary_depth(0.0), summary_weight(0.0), average_depth(0.0), used(false) { } - static bool compare_triagles(const std::pair &a, const std::pair &b) - { - return a.first < b.first ? false - : b.first < a.first ? true - : a.second.vertices[0] < b.second.vertices[0] ? true - : b.second.vertices[0] < a.second.vertices[0] ? false - : a.second.vertices[1] < b.second.vertices[1] ? true - : b.second.vertices[1] < a.second.vertices[1] ? false - : a.second.vertices[2] < b.second.vertices[2]; - } -}; - -Real Layer_SkeletonDeformation::distance_to_line(const Vector &p0, const Vector &p1, const Vector &x) -{ - const Real epsilon = 1e-10; - - Real distance_to_p0 = (x - p0).mag(); - Real distance_to_p1 = (x - p1).mag(); - Real distance_to_line = INFINITY; - - Vector line = p1 - p0; - Real line_length = line.mag(); - if (line_length > epsilon) - { - Real dist = fabs((x - p0) * line.perp() / line_length); - Real pos = (x - p0) * line / line_length; - if (pos > 0.0 && pos < line_length) - distance_to_line = dist; - } - - return std::min(distance_to_line, std::min(distance_to_p0, distance_to_p1) ); -} - -void -Layer_SkeletonDeformation::prepare_mesh() -{ - static const Real precision = 1e-10; - - mesh.clear(); - - // TODO: build grid with dynamic size - - const Point grid_p0 = param_point1.get(Point()); - const Point grid_p1 = param_point2.get(Point()); - const int grid_side_count_x = std::max(1, param_x_subdivisions.get(int())) + 1; - const int grid_side_count_y = std::max(1, param_y_subdivisions.get(int())) + 1; - - const Real grid_step_x = (grid_p1[0] - grid_p0[0]) / (Real)(grid_side_count_x - 1); - const Real grid_step_y = (grid_p1[1] - grid_p0[1]) / (Real)(grid_side_count_y - 1); - const Real grid_step_diagonal = sqrt(grid_step_x*grid_step_x + grid_step_y*grid_step_y); - - // build grid - std::vector grid; - grid.reserve(grid_side_count_x * grid_side_count_y); - for(int j = 0; j < grid_side_count_y; ++j) - for(int i = 0; i < grid_side_count_x; ++i) - grid.push_back(GridPoint(Vector( - grid_p0[0] + i*grid_step_x, - grid_p0[1] + j*grid_step_y ))); - - // apply deformation - if (param_bones.can_get(ValueBase::List())) - { - const ValueBase::List &bones = param_bones.get_list(); - for(ValueBase::List::const_iterator i = bones.begin(); i != bones.end(); ++i) - { - if (i->can_get(BonePair())) - { - const BonePair &bone_pair = i->get(BonePair()); - Bone::Shape shape0 = bone_pair.first.get_shape(); - Bone::Shape shape1 = bone_pair.second.get_shape(); - Bone::Shape expandedShape0 = shape0; - expandedShape0.r0 += 2.0*grid_step_diagonal; - expandedShape0.r1 += 2.0*grid_step_diagonal; - Real depth = bone_pair.second.get_depth(); - - Matrix into_bone( - shape0.p1[0] - shape0.p0[0], shape0.p1[1] - shape0.p0[1], 0.0, - shape0.p0[1] - shape0.p1[1], shape0.p1[0] - shape0.p0[0], 0.0, - shape0.p0[0], shape0.p0[1], 1.0 - ); - into_bone.invert(); - Matrix from_bone( - shape1.p1[0] - shape1.p0[0], shape1.p1[1] - shape1.p0[1], 0.0, - shape1.p0[1] - shape1.p1[1], shape1.p1[0] - shape1.p0[0], 0.0, - shape1.p0[0], shape1.p0[1], 1.0 - ); - Matrix matrix = into_bone * from_bone; - - for(std::vector::iterator j = grid.begin(); j != grid.end(); ++j) - { - Real percent = Bone::distance_to_shape_center_percent(expandedShape0, j->initial_position); - if (percent > precision) { - Real distance = distance_to_line(shape0.p0, shape0.p1, j->initial_position); - if (distance < precision) distance = precision; - Real weight = - percent/(distance*distance); - // 1.0/distance; - // 1.0/(distance*distance); - // 1.0/(distance*distance*distance); - // exp(-4.0*distance); - j->summary_position += matrix.get_transformed(j->initial_position) * weight; - j->summary_depth += depth * weight; - j->summary_weight += weight; - j->used = true; - } - } - } - } - } - - // build vertices - mesh.vertices.reserve(grid.size()); - for(std::vector::iterator i = grid.begin(); i != grid.end(); ++i) { - Vector average_position = i->summary_weight > precision ? i->summary_position/i->summary_weight : i->initial_position; - i->average_depth = i->summary_weight > precision ? i->summary_depth/i->summary_weight : 0.0; - mesh.vertices.push_back(Mesh::Vertex(average_position, i->initial_position)); - } - - // build triangles - std::vector< std::pair > triangles; - triangles.reserve(2*(grid_side_count_x-1)*(grid_side_count_y-1)); - for(int j = 1; j < grid_side_count_y; ++j) - { - for(int i = 1; i < grid_side_count_x; ++i) - { - int v[] = { - (j-1)*grid_side_count_x + (i-1), - (j-1)*grid_side_count_x + i, - j *grid_side_count_x + i, - j *grid_side_count_x + (i-1), - }; - if (grid[v[0]].used && grid[v[1]].used && grid[v[2]].used && grid[v[3]].used) - { - Real depth = 0.25*(grid[v[0]].average_depth - + grid[v[1]].average_depth - + grid[v[2]].average_depth - + grid[v[3]].average_depth); - triangles.push_back(std::make_pair(depth, Mesh::Triangle(v[0], v[1], v[3]))); - triangles.push_back(std::make_pair(depth, Mesh::Triangle(v[1], v[2], v[3]))); - } - } - } - - // sort triangles - std::sort(triangles.begin(), triangles.end(), GridPoint::compare_triagles); - mesh.triangles.reserve(triangles.size()); - for(std::vector< std::pair >::iterator i = triangles.begin(); i != triangles.end(); ++i) - mesh.triangles.push_back(i->second); - - prepare_mask(); - update_mesh_and_mask(); -} - -bool -Layer_SkeletonDeformation::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE_PLUS(param_bones, prepare_mesh()); - IMPORT_VALUE_PLUS(param_point1, prepare_mesh()); - IMPORT_VALUE_PLUS(param_point2, prepare_mesh()); - IMPORT_VALUE_PLUS(param_x_subdivisions, prepare_mesh()); - IMPORT_VALUE_PLUS(param_y_subdivisions, prepare_mesh()); - return Layer_MeshTransform::set_param(param,value); -} - -ValueBase -Layer_SkeletonDeformation::get_param(const String& param)const -{ - EXPORT_VALUE(param_bones); - EXPORT_VALUE(param_point1); - EXPORT_VALUE(param_point2); - EXPORT_VALUE(param_x_subdivisions); - EXPORT_VALUE(param_y_subdivisions); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_MeshTransform::get_param(param); -} - diff --git a/synfig-core/src/synfig/layer_skeletondeformation.h b/synfig-core/src/synfig/layer_skeletondeformation.h deleted file mode 100644 index a92a482..0000000 --- a/synfig-core/src/synfig/layer_skeletondeformation.h +++ /dev/null @@ -1,89 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_skeletondeformation.h -** \brief SkeletonDeformation layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_SKELETONDEFORMATION_H -#define __SYNFIG_LAYER_SKELETONDEFORMATION_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_meshtransform.h" -#include "pair.h" -#include "bone.h" -#include "polygon.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { -/*! \class Layer_SkeletonDeformation -** \brief Class of the SkeletonDeformation layer. -*/ -class Layer_SkeletonDeformation : public Layer_MeshTransform -{ - //! Layer module: defines the needed members to belong to a layer's factory. - SYNFIG_LAYER_MODULE_EXT -private: - //! Parameter: (list) Bones - ValueBase param_bones; - //! Parameter: (Point) - synfig::ValueBase param_point1; - //! Parameter: (Point) - synfig::ValueBase param_point2; - //! Parameter: (Integer) - synfig::ValueBase param_x_subdivisions; - //! Parameter: (Integer) - synfig::ValueBase param_y_subdivisions; - - struct GridPoint; - static Real distance_to_line(const Vector &p0, const Vector &p1, const Vector &x); - void prepare_mask(); - -public: - typedef std::pair BonePair; - - //! Default constructor - Layer_SkeletonDeformation(); - //! Destructor - virtual ~Layer_SkeletonDeformation(); - //! Returns a string with the localized name of this layer - virtual String get_local_name()const; - - //! Sets the parameter described by \a param to \a value. \see Layer::set_param - virtual bool set_param(const String & param, const synfig::ValueBase &value); - //! Get the value of the specified parameter. \see Layer::get_param - virtual ValueBase get_param(const String & param)const; - //! Gets the parameter vocabulary - virtual Vocab get_param_vocab()const; - - void prepare_mesh(); -}; // END of class SkeletonDeformation - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_solidcolor.cpp b/synfig-core/src/synfig/layer_solidcolor.cpp deleted file mode 100644 index 7a30649..0000000 --- a/synfig-core/src/synfig/layer_solidcolor.cpp +++ /dev/null @@ -1,238 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_solidcolor.cpp -** \brief Implementation of the "Solid Color" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2007, 2008 Chris Moore -** Copyright (c) 2011-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_solidcolor.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "renddesc.h" -#include "surface.h" -#include "value.h" -#include "valuenode.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_SolidColor); -SYNFIG_LAYER_SET_NAME(Layer_SolidColor,"SolidColor"); // todo: use solid_color -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_SolidColor,N_("Solid Color")); -SYNFIG_LAYER_SET_CATEGORY(Layer_SolidColor,N_("Geometry")); -SYNFIG_LAYER_SET_VERSION(Layer_SolidColor,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_SolidColor,"$Id$"); - -/* === P R O C E D U R E S ================================================= */ - -/* === M E T H O D S ======================================================= */ - -/* === E N T R Y P O I N T ================================================= */ - -Layer_SolidColor::Layer_SolidColor(): - Layer_Composite(1.0,Color::BLEND_COMPOSITE), - param_color(ValueBase(Color::black())) -{ - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -bool -Layer_SolidColor::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE_PLUS(param_color, - { - Color color=param_color.get(Color()); - if (color.get_a() == 0) - { - if (converted_blend_) - { - set_blend_method(Color::BLEND_ALPHA_OVER); - color.set_a(1); - param_color.set(color); - } - else transparent_color_ = true; - } - } - ); - - return Layer_Composite::set_param(param,value); -} - -ValueBase -Layer_SolidColor::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_color); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_Composite::get_param(param); -} - -Layer::Vocab -Layer_SolidColor::get_param_vocab()const -{ - Layer::Vocab ret(Layer_Composite::get_param_vocab()); - - ret.push_back(ParamDesc("color") - .set_local_name(_("Color")) - .set_description(_("Fill color of the layer")) - ); - - return ret; -} - -synfig::Layer::Handle -Layer_SolidColor::hit_check(synfig::Context context, const synfig::Point &point)const -{ - Color color=param_color.get(Color()); - if(get_blend_method()==Color::BLEND_STRAIGHT && get_amount()>=0.5) - return const_cast(this); - else - if(get_blend_method()==Color::BLEND_COMPOSITE && get_amount()*color.get_a()>=0.5) - return const_cast(this); - - Layer::Handle layer(context.hit_check(point)); - - return layer?layer:const_cast(this); -} - -Color -Layer_SolidColor::get_color(Context context, const Point &pos)const -{ - Color color=param_color.get(Color()); - if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT) - return color; - else - return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method()); -} - -bool -Layer_SolidColor::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - Color color=param_color.get(Color()); - if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT) - { - // Mark our progress as starting - if(cb && !cb->amount_complete(0,1000)) - return false; - - surface->set_wh(renddesc.get_w(),renddesc.get_h()); - surface->fill(color); - - // Mark our progress as finished - if(cb && !cb->amount_complete(1000,1000)) - return false; - - return true; - } - - SuperCallback supercb(cb,0,9500,10000); - - if(!context.accelerated_render(surface,quality,renddesc,&supercb)) - return false; - - int x,y; - - Surface::alpha_pen apen(surface->begin()); - - apen.set_value(color); - apen.set_alpha(get_amount()); - apen.set_blend_method(get_blend_method()); - - for(y=0;yamount_complete(10000,10000)) - return false; - - return true; -} - -////// - -bool -Layer_SolidColor::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const -{ - Color color=param_color.get(Color()); - float r(color.get_r()), - g(color.get_g()), - b(color.get_b()), - a(color.get_a()); - - if((get_amount()==1.f && get_blend_method()==Color::BLEND_STRAIGHT) - || - (get_amount()==1.f && color.get_a()==1.f && get_blend_method()==Color::BLEND_COMPOSITE) - ) - { - // Mark our progress as starting - if(cb && !cb->amount_complete(0,1000)) - return false; - cairo_save(cr); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); - cairo_paint(cr); - cairo_restore(cr); - // Mark our progress as finished - if(cb && !cb->amount_complete(1000,1000)) - return false; - return true; - } - - SuperCallback supercb(cb,0,9500,10000); - - if(!context.accelerated_cairorender(cr,quality,renddesc,&supercb)) - return false; - - cairo_save(cr); - cairo_reset_clip(cr); - cairo_set_source_rgba(cr, r, g, b, a); - cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); - cairo_restore(cr); - - // Mark our progress as finished - if(cb && !cb->amount_complete(10000,10000)) - return false; - - return true; -} - -////// diff --git a/synfig-core/src/synfig/layer_solidcolor.h b/synfig-core/src/synfig/layer_solidcolor.h deleted file mode 100644 index 5578788..0000000 --- a/synfig-core/src/synfig/layer_solidcolor.h +++ /dev/null @@ -1,73 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_solidcolor.h -** \brief Header file for implementation of the "Solid Color" layer -** -** $Id$ -** -** \legal -** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley -** Copyright (c) 2012-2013 Carlos López -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_SOLIDCOLOR_H -#define __SYNFIG_LAYER_SOLIDCOLOR_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_composite.h" -#include "color.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -class Layer_SolidColor : public Layer_Composite, public Layer_NoDeform -{ - SYNFIG_LAYER_MODULE_EXT - -private: - - //!Parameter: (Color) color of the solid - ValueBase param_color; - -public: - - Layer_SolidColor(); - - virtual bool set_param(const String & param, const synfig::ValueBase &value); - - virtual ValueBase get_param(const String & param)const; - - virtual Color get_color(Context context, const Point &pos)const; - - virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; - virtual Vocab get_param_vocab()const; - - virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; - -}; // END of class Layer_SolidColor - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_sound.cpp b/synfig-core/src/synfig/layer_sound.cpp deleted file mode 100644 index c151703..0000000 --- a/synfig-core/src/synfig/layer_sound.cpp +++ /dev/null @@ -1,131 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_sound.cpp -** \brief Implementation of the "Sound" layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_sound.h" -#include "string.h" -#include "time.h" -#include "real.h" -#include "value.h" -#include "soundprocessor.h" - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Sound); -SYNFIG_LAYER_SET_NAME(Layer_Sound,"sound"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Sound,N_("Sound")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Sound,N_("Other")); -SYNFIG_LAYER_SET_VERSION(Layer_Sound,"0.1"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Sound,"$Id$"); - -/* === P R O C E D U R E S ================================================= */ - -/* === M E T H O D S ======================================================= */ - -/* === E N T R Y P O I N T ================================================= */ - -Layer_Sound::Layer_Sound(): - Layer_Composite(0.0), - param_filename(String()), - param_delay(Time()), - param_volume(Real(1.0)) -{ - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -bool -Layer_Sound::set_param(const String ¶m, const ValueBase &value) -{ - IMPORT_VALUE(param_filename); - IMPORT_VALUE(param_delay); - IMPORT_VALUE(param_volume); - - return Layer::set_param(param,value); -} - -ValueBase -Layer_Sound::get_param(const String ¶m)const -{ - EXPORT_VALUE(param_filename); - EXPORT_VALUE(param_delay); - EXPORT_VALUE(param_volume); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer::get_param(param); -} - -Layer::Vocab -Layer_Sound::get_param_vocab()const -{ - Layer::Vocab ret(Layer::get_param_vocab()); - - ret.push_back(ParamDesc("filename") - .set_local_name(_("Filename")) - .set_description(_("Path to sound file")) - .set_static(true) - .set_hint("filename") - ); - - ret.push_back(ParamDesc("delay") - .set_local_name(_("Delay")) - .set_description(_("Delay before play")) - .set_static(true) - ); - - ret.push_back(ParamDesc("volume") - .set_local_name(_("Volume")) - .set_description(_("Volume of sound")) - .set_static(true) - ); - - return ret; -} - -void -Layer_Sound::fill_sound_processor(SoundProcessor &soundProcessor) const -{ - String filename = param_filename.get(String()); - Time delay = param_delay.get(Time()); - Real volume = param_volume.get(Real()); - if (!filename.empty()) - soundProcessor.addSound(SoundProcessor::PlayOptions(delay, volume), SoundProcessor::Sound(filename)); -} - diff --git a/synfig-core/src/synfig/layer_sound.h b/synfig-core/src/synfig/layer_sound.h deleted file mode 100644 index 1cf401a..0000000 --- a/synfig-core/src/synfig/layer_sound.h +++ /dev/null @@ -1,61 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_sound.h -** \brief Header file for implementation of the "Sound" layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_SOUND_H -#define __SYNFIG_LAYER_SOUND_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_composite.h" -#include "color.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { - -class Layer_Sound : public Layer_Composite, public Layer_NoDeform -{ - SYNFIG_LAYER_MODULE_EXT -private: - ValueBase param_filename; - ValueBase param_delay; - ValueBase param_volume; - -public: - Layer_Sound(); - virtual bool set_param(const String & param, const synfig::ValueBase &value); - virtual ValueBase get_param(const String & param)const; - virtual Vocab get_param_vocab()const; - virtual void fill_sound_processor(SoundProcessor &soundProcessor) const; -}; // END of class Layer_SolidColor - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layer_switch.cpp b/synfig-core/src/synfig/layer_switch.cpp deleted file mode 100644 index 93a2191..0000000 --- a/synfig-core/src/synfig/layer_switch.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_switch.cpp -** \brief Implementation of the "Switch" layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === H E A D E R S ======================================================= */ - -#ifdef USING_PCH -# include "pch.h" -#else -#ifdef HAVE_CONFIG_H -# include -#endif - -#include "layer_switch.h" -#include "string.h" -#include "time.h" -#include "context.h" -#include "paramdesc.h" -#include "value.h" -#include "valuenode.h" -#include "canvas.h" - - -#endif - -/* === U S I N G =========================================================== */ - -using namespace etl; -using namespace std; -using namespace synfig; - -/* === M A C R O S ========================================================= */ - -/* === C L A S S E S ======================================================= */ - -/* === G L O B A L S ======================================================= */ - -SYNFIG_LAYER_INIT(Layer_Switch); -SYNFIG_LAYER_SET_NAME(Layer_Switch,"switch"); -SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Switch,N_("Switch")); -SYNFIG_LAYER_SET_CATEGORY(Layer_Switch,N_("Other")); -SYNFIG_LAYER_SET_VERSION(Layer_Switch,"0.0"); -SYNFIG_LAYER_SET_CVS_ID(Layer_Switch,"$Id$"); - -/* === M E T H O D S ======================================================= */ - -Layer_Switch::Layer_Switch() -{ - param_layer_name=ValueBase(String()); - set_param("children_lock",ValueBase(true)); - - SET_INTERPOLATION_DEFAULTS(); - SET_STATIC_DEFAULTS(); -} - -Layer_Switch::~Layer_Switch() -{ -} - -String -Layer_Switch::get_local_name()const -{ - String s = Layer_PasteCanvas::get_local_name(); - return s.empty() ? _("Switch") : _("Switch") + (" [" + s + ']'); -} - -Layer::Vocab -Layer_Switch::get_param_vocab()const -{ - Layer::Vocab ret(Layer_PasteCanvas::get_param_vocab()); - - ret.push_back(ParamDesc("layer_name") - .set_local_name(_("Active Layer Name")) - .set_description(_("Only layer with specified name are visible")) - ); - - return ret; -} - -bool -Layer_Switch::set_param(const String & param, const ValueBase &value) -{ - IMPORT_VALUE(param_layer_name); - return Layer_PasteCanvas::set_param(param,value); -} - -ValueBase -Layer_Switch::get_param(const String& param)const -{ - EXPORT_VALUE(param_layer_name); - - EXPORT_NAME(); - EXPORT_VERSION(); - - return Layer_PasteCanvas::get_param(param); -} - -Layer::Handle -Layer_Switch::get_current_layer()const -{ - Canvas::Handle canvas = get_sub_canvas(); - String n = param_layer_name.get(String()); - if (canvas) - for(IndependentContext i = canvas->get_independent_context(); *i; i++) - if ((*i)->get_description() == n) - return *i; - return NULL; -} - - -void -Layer_Switch::apply_z_range_to_params(ContextParams &cp)const -{ - if (optimized()) return; // z_range already applied while optimizxation - - Layer::Handle layer = get_current_layer(); - if (layer) { - cp.z_range=true; - cp.z_range_position=layer->get_depth(); - cp.z_range_depth=0; - cp.z_range_blur=0; - return; - } - - cp.z_range=true; - cp.z_range_position=0; - cp.z_range_depth=-1; - cp.z_range_blur=0; -} diff --git a/synfig-core/src/synfig/layer_switch.h b/synfig-core/src/synfig/layer_switch.h deleted file mode 100644 index 978ed78..0000000 --- a/synfig-core/src/synfig/layer_switch.h +++ /dev/null @@ -1,75 +0,0 @@ -/* === S Y N F I G ========================================================= */ -/*! \file layer_switch.h -** \brief Header file for implementation of the "Switch" layer -** -** $Id$ -** -** \legal -** ......... ... 2014 Ivan Mahonin -** -** This package is free software; you can redistribute it and/or -** modify it under the terms of the GNU General Public License as -** published by the Free Software Foundation; either version 2 of -** the License, or (at your option) any later version. -** -** This package is distributed in the hope that it will be useful, -** but WITHOUT ANY WARRANTY; without even the implied warranty of -** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -** General Public License for more details. -** \endlegal -*/ -/* ========================================================================= */ - -/* === S T A R T =========================================================== */ - -#ifndef __SYNFIG_LAYER_SWITCH_H -#define __SYNFIG_LAYER_SWITCH_H - -/* === H E A D E R S ======================================================= */ - -#include "layer_pastecanvas.h" - -/* === M A C R O S ========================================================= */ - -/* === T Y P E D E F S ===================================================== */ - -/* === C L A S S E S & S T R U C T S ======================================= */ - -namespace synfig { -/*! \class Layer_Switch -** \brief Class of the Switch layer. -*/ -class Layer_Switch : public Layer_PasteCanvas -{ - //! Layer module: defines the needed members to belong to a layer's factory. - SYNFIG_LAYER_MODULE_EXT -private: - //! Parameter: (String) Active Layer Name - ValueBase param_layer_name; - -public: - //! Default constructor - Layer_Switch(); - //! Destructor - virtual ~Layer_Switch(); - //! Returns a string with the localized name of this layer - virtual String get_local_name()const; - - //! Sets the parameter described by \a param to \a value. \see Layer::set_param - virtual bool set_param(const String & param, const synfig::ValueBase &value); - //! Get the value of the specified parameter. \see Layer::get_param - virtual ValueBase get_param(const String & param)const; - //! Gets the parameter vocabulary - virtual Vocab get_param_vocab()const; - - Layer::Handle get_current_layer()const; - - //! Sets z_range* fields of specified ContextParams \a cp - virtual void apply_z_range_to_params(ContextParams &cp)const; -}; // END of class Layer_Switch - -}; // END of namespace synfig - -/* === E N D =============================================================== */ - -#endif diff --git a/synfig-core/src/synfig/layers/Makefile_insert b/synfig-core/src/synfig/layers/Makefile_insert new file mode 100644 index 0000000..128cc43 --- /dev/null +++ b/synfig-core/src/synfig/layers/Makefile_insert @@ -0,0 +1,41 @@ +LAYERS_HH = \ + layers/layer_bitmap.h \ + layers/layer_composite.h \ + layers/layer_duplicate.h \ + layers/layer_group.h \ + layers/layer_meshtransform.h \ + layers/layer_mime.h \ + layers/layer_motionblur.h \ + layers/layer_pastecanvas.h \ + layers/layer_polygon.h \ + layers/layer_shape.h \ + layers/layer_solidcolor.h \ + layers/layer_sound.h \ + layers/layer_skeleton.h \ + layers/layer_skeletondeformation.h \ + layers/layer_switch.h + +LAYERS_CC = \ + layers/layer_bitmap.cpp \ + layers/layer_composite.cpp \ + layers/layer_duplicate.cpp \ + layers/layer_group.cpp \ + layers/layer_meshtransform.cpp \ + layers/layer_mime.cpp \ + layers/layer_motionblur.cpp \ + layers/layer_pastecanvas.cpp \ + layers/layer_polygon.cpp \ + layers/layer_shape.cpp \ + layers/layer_solidcolor.cpp \ + layers/layer_sound.cpp \ + layers/layer_skeleton.cpp \ + layers/layer_skeletondeformation.cpp \ + layers/layer_switch.cpp + +libsynfig_include_HH += \ + $(LAYERS_HH) + +libsynfig_src += \ + $(LAYERS_HH) \ + $(LAYERS_CC) + diff --git a/synfig-core/src/synfig/layers/layer_bitmap.cpp b/synfig-core/src/synfig/layers/layer_bitmap.cpp new file mode 100644 index 0000000..ffa4ede --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_bitmap.cpp @@ -0,0 +1,824 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_bitmap.cpp +** \brief Template Header +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2012-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_bitmap.h" +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace synfig; +using namespace std; +using namespace etl; + +/* === G L O B A L S ======================================================= */ + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +synfig::Layer_Bitmap::Layer_Bitmap(): + Layer_Composite (1.0,Color::BLEND_COMPOSITE), + method (SOFTWARE), + param_tl (Point(-0.5,0.5)), + param_br (Point(0.5,-0.5)), + param_c (int(1)), + param_gamma_adjust (Real(1.0)), + surface (128,128), + trimmed (false) +{ + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +bool +synfig::Layer_Bitmap::set_param(const String & param, const ValueBase & value) +{ + IMPORT_VALUE(param_tl); + IMPORT_VALUE(param_br); + IMPORT_VALUE(param_c); + IMPORT_VALUE_PLUS(param_gamma_adjust, + if(param=="gamma_adjust"&& value.get_type()==type_real) + { + param_gamma_adjust.set(Real(1.0/value.get(Real()))); + return true; + } + ); + + return Layer_Composite::set_param(param,value); +} + +ValueBase +synfig::Layer_Bitmap::get_param(const String & param)const +{ + EXPORT_VALUE(param_tl); + EXPORT_VALUE(param_br); + EXPORT_VALUE(param_c); + if(param=="gamma_adjust") + { + ValueBase ret=param_gamma_adjust; + ret.set(1.0/param_gamma_adjust.get(Real())); + return ret; + } + + if(param=="_width") + { + ValueBase ret1(type_integer); + ret1=int(width); + ValueBase ret2(type_integer); + switch (method) + { + case SOFTWARE: + ret2=int(surface.get_w()); + break; + case CAIRO: + default: + ret2=int(csurface.get_w()); + break; + } + if (trimmed) return ret1; + return ret2; + } + if(param=="_height") + { + ValueBase ret1(type_integer); + ret1=int(height); + ValueBase ret2(type_integer); + switch (method) + { + case SOFTWARE: + ret2=int(surface.get_h()); + break; + case CAIRO: + default: + ret2=int(csurface.get_h()); + break; + } + if (trimmed) return ret1; + return ret2; + } + + return Layer_Composite::get_param(param); +} + + +Layer::Vocab +Layer_Bitmap::get_param_vocab()const +{ + Layer::Vocab ret(Layer_Composite::get_param_vocab()); + + ret.push_back(ParamDesc("tl") + .set_local_name(_("Top-Left")) + .set_description(_("Upper left-hand Corner of image")) + ); + + ret.push_back(ParamDesc("br") + .set_local_name(_("Bottom-Right")) + .set_description(_("Lower right-hand Corner of image")) + ); + + ret.push_back(ParamDesc("c") + .set_local_name(_("Interpolation")) + .set_description(_("What type of interpolation to use")) + .set_hint("enum") + .add_enum_value(0,"nearest",_("Nearest Neighbor")) + .add_enum_value(1,"linear",_("Linear")) + .add_enum_value(2,"cosine",_("Cosine")) + .add_enum_value(3,"cubic",_("Cubic")) + .set_static(true) + ); + + ret.push_back(ParamDesc("gamma_adjust") + .set_local_name(_("Gamma Adjustment")) + ); + + return ret; +} + +synfig::Layer::Handle +Layer_Bitmap::hit_check(synfig::Context context, const synfig::Point &pos)const +{ + Point tl(param_tl.get(Point())); + Point br(param_br.get(Point())); + Point surface_pos; + surface_pos=pos-tl; + + surface_pos[0]/=br[0]-tl[0]; + if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0) + { + surface_pos[1]/=br[1]-tl[1]; + if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0) + { + return const_cast(this); + } + } + + return context.hit_check(pos); +} + +void +synfig::Layer_Bitmap::set_render_method(Context context, RenderMethod x) +{ + set_method(x); + context.set_render_method(x); +} + +inline +const Color& +synfig::Layer_Bitmap::filter(Color& x)const +{ + Real gamma_adjust(param_gamma_adjust.get(Real())); + if(gamma_adjust!=1.0) + { + x.set_r(powf((float)x.get_r(),gamma_adjust)); + x.set_g(powf((float)x.get_g(),gamma_adjust)); + x.set_b(powf((float)x.get_b(),gamma_adjust)); + } + return x; +} + +inline +const CairoColor& +synfig::Layer_Bitmap::filter(CairoColor& x)const +{ + Real gamma_adjust(param_gamma_adjust.get(Real())); + if(gamma_adjust!=1.0) + { + x.set_r(powf((float)(x.get_r()/CairoColor::range),gamma_adjust)*CairoColor::range); + x.set_g(powf((float)(x.get_g()/CairoColor::range),gamma_adjust)*CairoColor::range); + x.set_b(powf((float)(x.get_b()/CairoColor::range),gamma_adjust)*CairoColor::range); + } + return x; +} + + +Color +synfig::Layer_Bitmap::get_color(Context context, const Point &pos)const +{ + Point tl(param_tl.get(Point())); + Point br(param_br.get(Point())); + int c(param_c.get(int())); + + Point surface_pos; + + if(!get_amount()) + return context.get_color(pos); + + surface_pos=pos-tl; + + surface_pos[0]/=br[0]-tl[0]; + if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0) + { + surface_pos[1]/=br[1]-tl[1]; + if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0) + { + Mutex::Lock lock(mutex); + + if (trimmed) + { + surface_pos[0]*=width; + surface_pos[1]*=height; + + if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top) + return context.get_color(pos); + + surface_pos[0] -= left; + surface_pos[1] -= top; + } + else + { + surface_pos[0]*=surface.get_w(); + surface_pos[1]*=surface.get_h(); + } + + Color ret(Color::alpha()); + + switch(c) + { + case 6: // Undefined + case 5: // Undefined + case 4: // Undefined + case 3: // Cubic + ret=surface.cubic_sample(surface_pos[0],surface_pos[1]); + break; + + case 2: // Cosine + ret=surface.cosine_sample(surface_pos[0],surface_pos[1]); + break; + case 1: // Linear + ret=surface.linear_sample(surface_pos[0],surface_pos[1]); + break; + case 0: // Nearest Neighbor + default: + { + int x(min(surface.get_w()-1,max(0,round_to_int(surface_pos[0])))); + int y(min(surface.get_h()-1,max(0,round_to_int(surface_pos[1])))); + ret= surface[y][x]; + } + break; + } + + ret=filter(ret); + + if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT) + return ret; + else + return Color::blend(ret,context.get_color(pos),get_amount(),get_blend_method()); + } + } + + return context.get_color(pos); +} + + +CairoColor +synfig::Layer_Bitmap::get_cairocolor(Context context, const Point &pos)const +{ + Point tl(param_tl.get(Point())); + Point br(param_br.get(Point())); + int c(param_c.get(int())); + + Point surface_pos; + + if(!get_amount()) + return context.get_cairocolor(pos); + + surface_pos=pos-tl; + + surface_pos[0]/=br[0]-tl[0]; + if(surface_pos[0]<=1.0 && surface_pos[0]>=0.0) + { + surface_pos[1]/=br[1]-tl[1]; + if(surface_pos[1]<=1.0 && surface_pos[1]>=0.0) + { + Mutex::Lock lock(mutex); + + if (trimmed) + { + surface_pos[0]*=width; + surface_pos[1]*=height; + + if (surface_pos[0] > left+surface.get_w() || surface_pos[0] < left || surface_pos[1] > top+surface.get_h() || surface_pos[1] < top) + return context.get_cairocolor(pos); + + surface_pos[0] -= left; + surface_pos[1] -= top; + } + else + { + surface_pos[0]*=csurface.get_w(); + surface_pos[1]*=csurface.get_h(); + } + + CairoColor ret(CairoColor::alpha()); + + switch(c) + { + case 6: // Undefined + case 5: // Undefined + case 4: // Undefined + case 3: // Cubic + ret=csurface.cubic_sample_cooked(surface_pos[0],surface_pos[1]); + break; + + case 2: // Cosine + ret=csurface.cosine_sample_cooked(surface_pos[0],surface_pos[1]); + break; + case 1: // Linear + ret=csurface.linear_sample_cooked(surface_pos[0],surface_pos[1]); + break; + case 0: // Nearest Neighbor + default: + { + int x(min(csurface.get_w()-1,max(0,round_to_int(surface_pos[0])))); + int y(min(csurface.get_h()-1,max(0,round_to_int(surface_pos[1])))); + ret= csurface[y][x]; + } + break; + } + ret=ret.demult_alpha(); + ret=filter(ret); + + if(get_amount()==1 && get_blend_method()==Color::BLEND_STRAIGHT) + return ret; + else + return CairoColor::blend(ret,context.get_cairocolor(pos),get_amount(),get_blend_method()); + } + } + return context.get_cairocolor(pos); +} + + +bool +Layer_Bitmap::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const +{ + RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) + + Mutex::Lock lock(mutex); + + Point tl(param_tl.get(Point())); + Point br(param_br.get(Point())); + int c(param_c.get(int())); + Real gamma_adjust(param_gamma_adjust.get(Real())); + + int interp=c; + if(quality>=10) + interp=0; + else if(quality>=5 && interp>1) + interp=1; + + // We can only handle NN and Linear at the moment + //if(interp>1) + // return Layer_Composite::accelerated_render(context,surface,quality,renddesc,cb); + + //if we don't actually have a valid surface just skip us + if(!this->surface.is_valid()) + { + // Render what is behind us + return context.accelerated_render(surface,quality,renddesc,cb); + } + + SuperCallback subcb(cb,1,10000,10001+renddesc.get_h()); + + if( get_amount()==1 && + get_blend_method()==Color::BLEND_STRAIGHT && + !trimmed && + renddesc.get_tl()==tl && + renddesc.get_br()==br) + { + // Check for the trivial case + if(this->surface.get_w()==renddesc.get_w() && this->surface.get_h()==renddesc.get_h() && gamma_adjust==1.0f) + { + if(cb && !cb->amount_complete(0,100)) return false; + *surface=this->surface; + if(cb && !cb->amount_complete(100,100)) return false; + return true; + } + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + } + else + { + // Render what is behind us + if(!context.accelerated_render(surface,quality,renddesc,&subcb)) + return false; + } + + if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false; + + Point obr = renddesc.get_br(), + otl = renddesc.get_tl(); + + //Vector::value_type pw=renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]); + //Vector::value_type ph=renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]); + + //A = representation of input (just tl,br) //just a scaling right now + //B = representation of output (just tl,br) //just a scaling right now + //sa = scaling for input (0,1) -> (0,w/h) + //sb = scaling for output (0,1) -> (0,w/h) + + float outwf = obr[0] - otl[0]; + float outhf = obr[1] - otl[1]; + + int inw = this->surface.get_w(); + int inh = this->surface.get_h(); + + int outw = renddesc.get_w(); + int outh = renddesc.get_h(); + + float inwf, inhf; + Point itl, ibr; + + if (trimmed) + { + inwf = (br[0] - tl[0])*this->surface.get_w()/width; + inhf = (br[1] - tl[1])*this->surface.get_h()/height; + itl = Point(tl[0] + (br[0]-tl[0])*left/width, + tl[1] + (br[1]-tl[1])*top/height); + ibr = Point(tl[0] + (br[0]-tl[0])*(left+inw)/width, + tl[1] + (br[1]-tl[1])*(top+inh)/height); + } + else + { + inwf = br[0] - tl[0]; + inhf = br[1] - tl[1]; + itl = tl; + ibr = br; + } + + //need to get the input coords in output space, so we can clip + + //get the desired corners of the bitmap (in increasing order) in integers + //floating point corners + float x1f = (itl[0] - otl[0])*outw/outwf; + float x2f = (ibr[0] - otl[0])*outw/outwf; + float y1f = (itl[1] - otl[1])*outh/outhf; + float y2f = (ibr[1] - otl[1])*outh/outhf; + + if(x1f > x2f) swap(x1f,x2f); + if(y1f > y2f) swap(y1f,y2f); + + int x_start = max(0,(int)floor(x1f)); //probably floor + int x_end = min(outw,(int)ceil(x2f)); //probably ceil + int y_start = max(0,(int)floor(y1f)); //probably floor + int y_end = min(outh,(int)ceil(y2f)); //probably ceil + + //need to get the x,y,dx,dy values from output space to input, so we can do fast interpolation + + //get the starting position in input space... for interpolating + + // in int -> out float: + // Sb(B^-1)A(Sa^-1) x + float inx_start = (((x_start/*+0.5f*/)*outwf/outw + otl[0]) - itl[0])*inw/inwf; //may want to bias this (center of pixel)??? + float iny_start = (((y_start/*+0.5f*/)*outhf/outh + otl[1]) - itl[1])*inh/inhf; //may want to bias this (center of pixel)??? + + //calculate the delta values in input space for one pixel movement in output space + //same matrix but with a vector instead of a point... + float indx = outwf*(inw)/((outw)*inwf); //translations died + float indy = outhf*(inh)/((outh)*inhf); //translations died + + //perhaps use a DDA algorithm... if faster... + // will still want pixel fractions to be floating point since colors are + + //synfig::info("xstart:%d ystart:%d xend:%d yend:%d",x_start,y_start,x_end,y_end); + + //start drawing at the start of the bitmap (either origin or corner of input...) + //and get other info + Surface::alpha_pen pen(surface->get_pen(x_start,y_start)); + pen.set_alpha(get_amount()); + pen.set_blend_method(get_blend_method()); + + //check if we should use the downscale filtering + if(quality <= 7) + { + //the stride of the value should be inverted because we want to downsample + //when the stride is small, not big + //int multw = (int)ceil(indx); + //int multh = (int)ceil(indy); + + if(indx > 1.7 || indy > 1.7) + { + /*synfig::info("Decided to downsample? ratios - (%f,%f) -> (%d,%d)", + indx, indy, multw, multh); */ + + //use sample rect here... + + float iny, inx; + int x,y; + + //Point sample - truncate + iny = iny_start;//+0.5f; + for(y = y_start; y < y_end; ++y, pen.inc_y(), iny += indy) + { + inx = inx_start;//+0.5f; + for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) + { + Color rc = this->surface.sample_rect_clip(inx,iny,inx+indx,iny+indy); + pen.put_value(filter(rc)); + } + pen.dec_x(x_end-x_start); + } + + //Color c = (*surface)[0][0]; + //synfig::info("ValueBase of first pixel = (%f,%f,%f,%f)",c.get_r(),c.get_g(),c.get_b(),c.get_a()); + + return true; + } + } + + //perform normal interpolation + if(interp==0) + { + //synfig::info("Decided to do nearest neighbor"); + float iny, inx; + int x,y; + + //Point sample - truncate + iny = iny_start;//+0.5f; + for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) + { + inx = inx_start;//+0.5f; + int yclamp = min(inh-1, max(0, round_to_int(iny))); + for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) + { + int xclamp = min(inw-1, max(0, round_to_int(inx))); + Color c = filter(this->surface[yclamp][xclamp]); + pen.put_value(c); //must get rid of the clip + } + pen.dec_x(x_end-x_start); + } + } + else + if(interp==1) + { + //bilinear filtering + + //float xmf,xpf,ymf,ypf; + //int xm,xp,ym,yp; + float inx,iny; + int x,y; + + //can probably buffer for x values... + + //loop and based on inx,iny sample input image + iny = iny_start; + for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) + { + inx = inx_start; + for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) + { + Color col(this->surface.linear_sample(inx,iny)); + pen.put_value(filter(col)); + } + pen.dec_x(x_end-x_start); + + } + } + else + if(interp==2) + { + //cosine filtering + + //float xmf,xpf,ymf,ypf; + //int xm,xp,ym,yp; + float inx,iny; + int x,y; + + //can probably buffer for x values... + + //loop and based on inx,iny sample input image + iny = iny_start; + for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) + { + inx = inx_start; + for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) + { + Color col(this->surface.cosine_sample(inx,iny)); + pen.put_value(filter(col)); + } + pen.dec_x(x_end-x_start); + + } + } + else + { + //cubic filtering + + //float xmf,xpf,ymf,ypf; + //int xm,xp,ym,yp; + float inx,iny; + int x,y; + + //can probably buffer for x values... + + //loop and based on inx,iny sample input image + iny = iny_start; + for(y = y_start; y < y_end; y++, pen.inc_y(), iny += indy) + { + inx = inx_start; + for(x = x_start; x < x_end; x++, pen.inc_x(), inx += indx) + { + Color col(this->surface.cubic_sample(inx,iny)); + pen.put_value(filter(col)); + } + pen.dec_x(x_end-x_start); + + } + } + + return true; +} + +///// +///// + +bool +Layer_Bitmap::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb) const +{ + Mutex::Lock lock(mutex); + + Point tl(param_tl.get(Point())); + Point br(param_br.get(Point())); + int c(param_c.get(int())); + Real gamma_adjust(param_gamma_adjust.get(Real())); + + int interp=c; + if(quality>=10) + interp=0; + else if(quality>=5 && interp>1) + interp=1; + + //if we don't actually have a valid surface just skip us + if(!csurface.is_mapped()) + { + // Render what is behind us + return context.accelerated_cairorender(cr,quality,renddesc,cb); + } + + cairo_surface_t* cs=csurface.get_cairo_image_surface(); + + if(cairo_surface_status(cs) || cairo_surface_get_type(cs)!=CAIRO_SURFACE_TYPE_IMAGE) + { + // Render what is behind us + return context.accelerated_cairorender(cr,quality,renddesc,cb); + } + + SuperCallback subcb(cb,1,10000,10001+renddesc.get_h()); + + Point obr = renddesc.get_br(); + Point otl = renddesc.get_tl(); + + int outw = renddesc.get_w(); + int outh = renddesc.get_h(); + + int inw = cairo_image_surface_get_width(cs); + int inh = cairo_image_surface_get_height(cs); + + + if( get_amount()==1 && // our bitmap is full opaque + get_blend_method()==Color::BLEND_STRAIGHT && // and it doesn't draw the context + otl==tl && + obr==br) // and the tl and br are the same ... + { + // Check for the trivial case: the Bitmap and the destiny surface have same dimensions and there is not gamma adjust + if(inw==outw && inh==outh && gamma_adjust==1.0f) + { + if(cb && !cb->amount_complete(0,100)) return false; + { + cairo_save(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); // set operator to ignore destiny + cairo_set_source_surface(cr, cs, 0, 0); // set the source our cairosurface + cairo_paint(cr); // paint on the destiny + cairo_restore(cr); + } + if(cb && !cb->amount_complete(100,100)) return false; + return true; + } + } + else // It is not the trivial case + { + // Render what is behind us... + if(!context.accelerated_cairorender(cr,quality,renddesc,&subcb)) + return false; + } + + if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false; + + + // Calculate the width and height in pixels of the bitmap in the output surface + float wp=(br[0]-tl[0])/renddesc.get_pw(); + float hp=(br[1]-tl[1])/renddesc.get_ph(); + // So we need to scale the bitmap by wp/inw in horizontal and hp/inh in vertical. + float scalex=wp/inw; + float scaley=hp/inh; + // Now let's calculate the displacement of the image in the output surface. + Point disp=tl-otl; + // Calculate the cairo interpolation to do by the interpolation parameter c + cairo_filter_t filter; + switch(c) + { + case 3: // Cubic + filter=CAIRO_FILTER_BEST; + break; + case 2: // Cosine + filter=CAIRO_FILTER_GOOD; + break; + case 1: // Linear + filter=CAIRO_FILTER_FAST; + break; + case 0: // Nearest Neighbor + default: + filter=CAIRO_FILTER_NEAREST; + break; + } + // TODO: filter the image with gamma_adjust!! + cairo_save(cr); + // Need to scale down to user coordinates before pass to cr + cairo_translate(cr, renddesc.get_tl()[0], renddesc.get_tl()[1]); + cairo_scale(cr, renddesc.get_pw(), renddesc.get_ph()); + // Apply the bitmap scale and tanslate + cairo_translate(cr, disp[0]/renddesc.get_pw(), disp[1]/renddesc.get_ph()); + cairo_scale(cr, scalex, scaley); + // set the surface, filter, and paint + cairo_pattern_set_filter(cairo_get_source(cr), filter); + cairo_set_source_surface(cr, cs, 0,0); + cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); + // we don't need cs anymore + cairo_surface_destroy(cs); + cairo_restore(cr); + + return true; +} + +///// + + +Rect +Layer_Bitmap::get_bounding_rect()const +{ + Point tl(param_tl.get(Point())); + Point br(param_br.get(Point())); + + return Rect(tl,br); +} + + +void +Layer_Bitmap::set_cairo_surface(cairo_surface_t *cs) +{ + if(cs==NULL) + { + synfig::error("Layer_Bitmap received a NULL cairo_surface_t"); + return; + } + if(cairo_surface_status(cs)) + { + synfig::error("Layer_Bitmap received a non valid cairo_surface_t"); + return; + } + csurface.set_cairo_surface(cs); + csurface.map_cairo_image(); +} diff --git a/synfig-core/src/synfig/layers/layer_bitmap.h b/synfig-core/src/synfig/layers/layer_bitmap.h new file mode 100644 index 0000000..0562eb5 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_bitmap.h @@ -0,0 +1,98 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_bitmap.h +** \brief Template Header +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2012-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_BITMAP_H +#define __SYNFIG_LAYER_BITMAP_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_composite.h" +#include +#include // for RenderMethod + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +/*! \class Layer_Bitmap +** \todo writeme +*/ +class Layer_Bitmap : public Layer_Composite, public Layer_NoDeform +{ + const Color& filter(Color& c)const; + const CairoColor& filter(CairoColor& c)const; + RenderMethod method; +public: + typedef etl::handle Handle; + + ValueBase param_tl; + ValueBase param_br; + ValueBase param_c; + ValueBase param_gamma_adjust; + + mutable synfig::Mutex mutex; + mutable Surface surface; + mutable CairoSurface csurface; + mutable bool trimmed; + mutable unsigned int width, height, top, left; + + + Layer_Bitmap(); + ~Layer_Bitmap() { + if(csurface.is_mapped()) csurface.unmap_cairo_image(); } + + virtual bool set_param(const String & param, const ValueBase & value); + + virtual ValueBase get_param(const String & param)const; + + virtual Color get_color(Context context, const Point &pos)const; + virtual CairoColor get_cairocolor(Context context, const Point &pos)const; + + virtual Vocab get_param_vocab()const; + + virtual Rect get_bounding_rect()const; + + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + + virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; + + virtual void set_render_method(Context context, RenderMethod x); + void set_method(RenderMethod x) { method=x;} + RenderMethod get_method()const { return method;} + + void set_cairo_surface(cairo_surface_t* cs); + +}; // END of class Layer_Bitmap + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_composite.cpp b/synfig-core/src/synfig/layers/layer_composite.cpp new file mode 100644 index 0000000..ceb7bfa --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_composite.cpp @@ -0,0 +1,316 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_composite.cpp +** \brief Template File +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2008 Chris Moore +** Copyright (c) 2011-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_composite.h" +#include "layer_pastecanvas.h" +#include +#include +#include +#include +#include +#include + +#include "layer_bitmap.h" + +#include +#include +#include +#include + + +#endif + +/* === U S I N G =========================================================== */ + +using namespace std; +using namespace etl; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +/* === G L O B A L S ======================================================= */ + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ +Layer_Composite::Layer_Composite(Real a, Color::BlendMethod bm): + param_amount (a), + param_blend_method ((int)Color::BlendMethod(bm)), + converted_blend_ (false), + transparent_color_ (false) + { + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); + } + +bool +Layer_Composite::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb) const +{ + RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) + + Real amount(param_amount.get(Real())); + if(!amount) + return context.accelerated_render(surface,quality,renddesc,cb); + + CanvasBase image; + + SuperCallback stageone(cb,0,50000,100000); + SuperCallback stagetwo(cb,50000,100000,100000); + + Layer_Bitmap::Handle surfacelayer(new class Layer_Bitmap()); + + Context iter; + + for(iter=context;*iter;iter++) + image.push_back(*iter); + + image.push_front(surfacelayer.get()); + + // We want to go ahead and schedule any other + // layers... +// while(dynamic_cast(context->get())) +// while(context->get() && +// &context->get()->AcceleratedRender== +// &Layer_Composite::AcceleratedRender) +// image.push_back(*(context++)); + + image.push_back(0); // Alpha black + + // Render the backdrop on the surface layer's surface. + if(!context.accelerated_render(&surfacelayer->surface,quality,renddesc,&stageone)) + return false; + // Sets up the interpolation of the context (now the surface layer is the first one) + // depending on the quality + if(quality<=4)surfacelayer->set_param("c", 3);else + if(quality<=5)surfacelayer->set_param("c", 2); + else if(quality<=6)surfacelayer->set_param("c", 1); + else surfacelayer->set_param("c",0); + surfacelayer->set_param("tl",renddesc.get_tl()); + surfacelayer->set_param("br",renddesc.get_br()); + // Sets the blend method to straight. See below + surfacelayer->set_blend_method(Color::BLEND_STRAIGHT); + // Push this layer on the image. The blending result is only this layer + // adn the surface layer. The rest of the context is ignored by the straight + // blend method of surface layer + image.push_front(const_cast(this)); + + // Set up a surface target + Target_Scanline::Handle target(surface_target(surface)); + + if(!target) + { + if(cb)cb->error(_("Unable to create surface target")); + return false; + } + + RendDesc desc(renddesc); + + target->set_rend_desc(&desc); + + // Render the scene + return render(Context(image.begin(),context),target,desc,&stagetwo); + //return render_threaded(Context(image.begin()),target,desc,&stagetwo,2); +} + + +///// +bool +Layer_Composite::accelerated_cairorender(Context context,cairo_t *cr, int quality, const RendDesc &renddesc_, ProgressCallback *cb) const +{ + RendDesc renddesc(renddesc_); + Real amount(param_amount.get(Real())); + + if(!amount) + return context.accelerated_cairorender(cr,quality,renddesc,cb); + + // Untransform the render desc + if(!cairo_renddesc_untransform(cr, renddesc)) + return false; + const Real pw(renddesc.get_pw()),ph(renddesc.get_ph()); + const Point tl(renddesc.get_tl()); + const int w(renddesc.get_w()); + const int h(renddesc.get_h()); + + CanvasBase image; + + SuperCallback stageone(cb,0,50000,100000); + SuperCallback stagetwo(cb,50000,100000,100000); + + Layer_Bitmap::Handle surfacelayer(new class Layer_Bitmap()); + + Context iter; + + for(iter=context;*iter;iter++) + image.push_back(*iter); + + // Add one Bitmap Layer on top + image.push_front(surfacelayer.get()); + + image.push_back(0); // and Alpha black at end + + // Render the backdrop on the surface layer's surface. + cairo_surface_t* cs=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + cairo_surface_t* result=cairo_image_surface_create(CAIRO_FORMAT_ARGB32, w, h); + cairo_t* cr_cs=cairo_create(cs); + cairo_scale(cr_cs, 1/pw, 1/ph); + cairo_translate(cr_cs, -tl[0], -tl[1]); + if(!context.accelerated_cairorender(cr_cs,quality,renddesc,&stageone)) + { + cairo_surface_destroy(cs); + cairo_destroy(cr_cs); + return false; + } + cairo_destroy(cr_cs); + surfacelayer->set_cairo_surface(cs); + cairo_surface_destroy(cs); + // Sets up the interpolation of the context (now the surface layer is the first one) + // depending on the quality + if(quality<=4)surfacelayer->set_param("c", 3);else + if(quality<=5)surfacelayer->set_param("c", 2); + else if(quality<=6)surfacelayer->set_param("c", 1); + else surfacelayer->set_param("c",0); + surfacelayer->set_param("tl",renddesc.get_tl()); + surfacelayer->set_param("br",renddesc.get_br()); + // Sets the blend method to straight. See below + surfacelayer->set_blend_method(Color::BLEND_STRAIGHT); + surfacelayer->set_render_method(context, CAIRO); + // Push this layer on the image. The blending result is only this layer + // and the surface layer. The rest of the context is ignored by the straight + // blend method of surface layer + image.push_front(const_cast(this)); + + // Render the scene + if(!cairorender(Context(image.begin(),context),result,renddesc,&stagetwo)) + { + cairo_surface_destroy(result); + return false; + } + // Put the result on the cairo context + cairo_save(cr); + cairo_translate(cr, tl[0], tl[1]); + cairo_scale(cr, pw, ph); + cairo_set_source_surface(cr, result, 0, 0); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_restore(cr); + + cairo_surface_destroy(result); + // Mark our progress as finished + if(cb && !cb->amount_complete(10000,10000)) + return false; + return true; +} + + +Rect +Layer_Composite::get_full_bounding_rect(Context context)const +{ + if(is_disabled() || Color::is_onto(get_blend_method())) + return context.get_full_bounding_rect(); + + return context.get_full_bounding_rect()|get_bounding_rect(); +} + +Layer::Vocab +Layer_Composite::get_param_vocab()const +{ + //! First fills the returning vocabulary with the ancestor class + Layer::Vocab ret(Layer::get_param_vocab()); + //! Now inserts the two parameters that this layer knows. + ret.push_back(ParamDesc(param_amount,"amount") + .set_local_name(_("Amount")) + .set_description(_("Alpha channel of the layer")) + ); + ret.push_back(ParamDesc(param_blend_method,"blend_method") + .set_local_name(_("Blend Method")) + .set_description(_("The blending method used to composite on the layers below")) + .set_static(true) + ); + + return ret; +} + +bool +Layer_Composite::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE(param_amount) + IMPORT_VALUE_PLUS(param_blend_method, + Color::BlendMethod blend_method = static_cast(value.get(int())); + if (blend_method < 0 || blend_method >= Color::BLEND_END) + { + warning("illegal value (%d) for blend_method - using Composite instead", blend_method); + param_blend_method.set((int)Color::BLEND_COMPOSITE); + return false; + } + + if (blend_method == Color::BLEND_STRAIGHT && !reads_context()) + { + Canvas::Handle canvas(get_canvas()); + if (canvas) + { + String version(canvas->get_version()); + + if (version == "0.1" || version == "0.2") + { + if (dynamic_cast(this) != NULL) + warning("loaded a version %s canvas with a 'Straight' blended PasteCanvas (%s) - check it renders OK", + version.c_str(), get_non_empty_description().c_str()); + else + { + param_blend_method.set(int(Color::BLEND_COMPOSITE)); + converted_blend_ = true; + + // if this layer has a transparent color, go back and set the color again + // now that we know we are converting the blend method as well. that will + // make the color non-transparent, and change the blend method to alpha over + if (transparent_color_) + set_param("color", get_param("color")); + } + } + } + } + ); + + return Layer::set_param(param,value); +} + +ValueBase +Layer_Composite::get_param(const String & param)const +{ + + EXPORT_VALUE(param_amount) + EXPORT_VALUE(param_blend_method) + //! If it is unknown then call the ancestor's get param member + //! to see if it can handle that parameter's string. + return Layer::get_param(param); +} diff --git a/synfig-core/src/synfig/layers/layer_composite.h b/synfig-core/src/synfig/layers/layer_composite.h new file mode 100644 index 0000000..1791fa5 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_composite.h @@ -0,0 +1,100 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_composite.h +** \brief Composite Layer Class Implementation +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_COMPOSITE_H +#define __SYNFIG_LAYER_COMPOSITE_H + +/* === H E A D E R S ======================================================= */ + +#include +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +class Layer_NoDeform {}; + + +/*! \class Layer_Composite +** \brief Base class for layers that put stuff on top of lower layers +*/ +class Layer_Composite : public Layer +{ +private: + //! The amount of composite + ValueBase param_amount; + //! The blend method for the composition + ValueBase param_blend_method; + +protected: + //! Default constructor. Not used directly. + Layer_Composite(Real amount=1.0, Color::BlendMethod blend_method=Color::BLEND_COMPOSITE); + + //! Converted blend is used to check if an old version of canvas + //! is used in the composition. Old Straight was used as new Composite + //! \todo verify this + bool converted_blend_; + //! Transparent color is used for old canvas versions. + //!Old Straight plus transparent color seems to be the same new than alpha over. + bool transparent_color_; + +public: + //! Gets the amount of the layer + float get_amount()const { return param_amount.get(Real()); } + //! Sets the amount of the layer and returns this layer + Layer_Composite& set_amount(float x) { param_amount.set(x); return *this; } + //! Gets the blend method of the layer + Color::BlendMethod get_blend_method()const { return Color::BlendMethod((param_blend_method.get(int()))); } + //! Sets the blend method of the layer and returns this layer + Layer_Composite& set_blend_method(Color::BlendMethod x) { param_blend_method.set(int(x)); return *this; } + //! Returns true is amount is 1 and blend method is straight + virtual bool is_solid_color()const { return param_amount.get(Real())==1.0f && param_blend_method.get(int())==Color::BLEND_STRAIGHT; } + //! Returns true if the amount is zero. + bool is_disabled()const { return param_amount.get(Real())==0.0f; } + //! Gets the parameter vocabulary. To be overrided by the derived. + virtual Vocab get_param_vocab()const; + //! Sets the value for the given parameter. + virtual bool set_param(const String ¶m, const ValueBase &value); + //! Gets the value of the given parameter + virtual ValueBase get_param(const String ¶m)const; + //!Returns the rectangle that includes the context of the layer and + //! the intersection of the layer in case it is active and not onto + virtual Rect get_full_bounding_rect(Context context)const; + //! Renders the layer composited on the context and puts it on the target surface. + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; +}; // END of class Layer_Composite + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_duplicate.cpp b/synfig-core/src/synfig/layers/layer_duplicate.cpp new file mode 100644 index 0000000..2d86828 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_duplicate.cpp @@ -0,0 +1,265 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_duplicate.cpp +** \brief Implementation of the "Duplicate" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "layer_duplicate.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace synfig; +using namespace etl; +using namespace std; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Duplicate); +SYNFIG_LAYER_SET_NAME(Layer_Duplicate,"duplicate"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Duplicate,N_("Duplicate")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Duplicate,N_("Other")); +SYNFIG_LAYER_SET_VERSION(Layer_Duplicate,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Duplicate,"$Id$"); + +/* === M E M B E R S ======================================================= */ + +Layer_Duplicate::Layer_Duplicate(): + Layer_Composite(1.0,Color::BLEND_COMPOSITE) +{ + LinkableValueNode* index_value_node = ValueNode_Duplicate::create(Real(3)); + connect_dynamic_param("index", index_value_node); + + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer::Handle +Layer_Duplicate::clone(Canvas::LooseHandle canvas, const GUID& deriv_guid)const +{ + Layer::Handle ret = (Layer::Handle)Layer_Composite::clone(canvas, deriv_guid); + + const DynamicParamList &dpl = dynamic_param_list(); + DynamicParamList::const_iterator iter = dpl.find("index"); + + // if we have a dynamic "index" parameter, make a new one in the clone + // it's not good to have two references to the same index valuenode, + // or nested duplications cause an infinite loop + if (iter != dpl.end()) + ret->connect_dynamic_param(iter->first,iter->second->clone(canvas, deriv_guid)); + + return ret; +} + +bool +Layer_Duplicate::set_param(const String ¶m, const ValueBase &value) +{ + IMPORT_VALUE(param_index); + return Layer_Composite::set_param(param,value); +} + +ValueBase +Layer_Duplicate::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_index); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Composite::get_param(param); +} + +void +Layer_Duplicate::set_time(IndependentContext context, Time time)const +{ + context.set_time(time); + time_cur=time; +} + +void +Layer_Duplicate::set_time(IndependentContext context, Time time, const Point &pos)const +{ + context.set_time(time,pos); + time_cur=time; +} + +Color +Layer_Duplicate::get_color(Context context, const Point &pos)const +{ + handle duplicate_param = get_duplicate_param(); + if (!duplicate_param) return context.get_color(pos); + + Color::BlendMethod blend_method(get_blend_method()); + float amount(get_amount()); + Color color; + + Mutex::Lock lock(mutex); + duplicate_param->reset_index(time_cur); + do + { + context.set_time(time_cur+1); + context.set_time(time_cur); + color = Color::blend(context.get_color(pos),color,amount,blend_method); + } while (duplicate_param->step(time_cur)); + + return color; +} + +Layer::Vocab +Layer_Duplicate::get_param_vocab()const +{ + Layer::Vocab ret; + ret=Layer_Composite::get_param_vocab(); + + ret.push_back(ParamDesc("index") + .set_local_name(_("Index")) + .set_description(_("Copy Index")) + ); + + return ret; +} + +ValueNode_Duplicate::Handle +Layer_Duplicate::get_duplicate_param()const +{ + const DynamicParamList &dpl = dynamic_param_list(); + DynamicParamList::const_iterator iter = dpl.find("index"); + if (iter == dpl.end()) return NULL; + etl::rhandle param(iter->second); + return ValueNode_Duplicate::Handle::cast_dynamic(param); +} + +bool +Layer_Duplicate::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) + + if(quality == 10) + return context.accelerated_render(surface,quality,renddesc,cb); + + if(context->empty()) + { + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + surface->clear(); + return true; + } + + SuperCallback subimagecb; + Surface tmp; + int i = 0; + + handle duplicate_param = get_duplicate_param(); + if (!duplicate_param) return context.accelerated_render(surface,quality,renddesc,cb); + + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + surface->clear(); + + Color::BlendMethod blend_method(get_blend_method()); + int steps = duplicate_param->count_steps(time_cur); + + Mutex::Lock lock(mutex); + duplicate_param->reset_index(time_cur); + do + { + subimagecb=SuperCallback(cb,i*(5000/steps),(i+1)*(5000/steps),5000); + // \todo can we force a re-evaluation of all the variables without changing the time twice? + context.set_time(time_cur+1); + context.set_time(time_cur); + if(!context.accelerated_render(&tmp,quality,renddesc,&subimagecb)) return false; + + Surface::alpha_pen apen(surface->begin()); + apen.set_alpha(get_amount()); + // \todo have a checkbox allowing use of 'behind' to reverse the order? + apen.set_blend_method(i ? blend_method : Color::BLEND_COMPOSITE); + tmp.blit_to(apen); + i++; + } while (duplicate_param->step(time_cur)); + + return true; +} + +///// +bool +Layer_Duplicate::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + if(quality == 10) + return context.accelerated_cairorender(cr,quality,renddesc,cb); + + if(context->empty()) + { + cairo_save(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_paint(cr); + cairo_restore(cr); + return true; + } + + SuperCallback subimagecb; + + int i = 0; + + handle duplicate_param = get_duplicate_param(); + if (!duplicate_param) return context.accelerated_cairorender(cr,quality,renddesc,cb); + + Color::BlendMethod blend_method(get_blend_method()); + int steps = duplicate_param->count_steps(time_cur); + + Mutex::Lock lock(mutex); + duplicate_param->reset_index(time_cur); + cairo_save(cr); + do + { + subimagecb=SuperCallback(cb,i*(5000/steps),(i+1)*(5000/steps),5000); + // \todo can we force a re-evaluation of all the variables without changing the time twice? + context.set_time(time_cur+1); + context.set_time(time_cur); + cairo_push_group(cr); + if(!context.accelerated_cairorender(cr,quality,renddesc,&subimagecb)) + { + cairo_pop_group(cr); + return false; + } + cairo_pop_group_to_source(cr);; + // \todo have a checkbox allowing use of 'behind' to reverse the order? + cairo_paint_with_alpha_operator(cr, get_amount(), i ? blend_method : Color::BLEND_COMPOSITE); + i++; + } while (duplicate_param->step(time_cur)); + cairo_restore(cr); + return true; +} diff --git a/synfig-core/src/synfig/layers/layer_duplicate.h b/synfig-core/src/synfig/layers/layer_duplicate.h new file mode 100644 index 0000000..55b7fd3 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_duplicate.h @@ -0,0 +1,70 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_duplicate.h +** \brief Header file for implementation of the "Duplicate" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2008 Chris Moore +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_DUPLICATE_H__ +#define __SYNFIG_LAYER_DUPLICATE_H__ + +/* === H E A D E R S ======================================================= */ + +#include +#include "layer_composite.h" +#include + +/* === S T R U C T S & C L A S S E S ======================================= */ + +namespace synfig { + +class Layer_Duplicate : public synfig::Layer_Composite +{ + SYNFIG_LAYER_MODULE_EXT + +private: + mutable ValueBase param_index; + mutable Time time_cur; + mutable synfig::Mutex mutex; + +public: + + Layer_Duplicate(); + + //! Duplicates the Layer + virtual Layer::Handle clone(etl::loose_handle canvas, const GUID& deriv_guid=GUID())const; + virtual bool set_param(const String & param, const synfig::ValueBase &value); + virtual ValueBase get_param(const String & param)const; + virtual Color get_color(Context context, const Point &pos)const; + virtual void set_time(IndependentContext context, Time time)const; + virtual void set_time(IndependentContext context, Time time, const Point &point)const; + virtual ValueNode_Duplicate::Handle get_duplicate_param()const; + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual Vocab get_param_vocab()const; + virtual bool reads_context()const { return true; } +}; // END of class Layer_Duplicate + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_group.cpp b/synfig-core/src/synfig/layers/layer_group.cpp new file mode 100644 index 0000000..d211641 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_group.cpp @@ -0,0 +1,150 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_group.cpp +** \brief Implementation of the "Group" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2011-2013 Carlos López +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_group.h" +#include +#include +#include +#include +#include +#include +#include + + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +/* === C L A S S E S ======================================================= */ + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Group); +SYNFIG_LAYER_SET_NAME(Layer_Group,"group"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Group,N_("Group")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Group,N_("Other")); +SYNFIG_LAYER_SET_VERSION(Layer_Group,"0.2"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Group,"$Id$"); + +/* === M E T H O D S ======================================================= */ + +Layer_Group::Layer_Group() +{ + param_z_range=ValueBase(bool(false)); + param_z_range_position=ValueBase(Real(0.0)); + param_z_range_depth=ValueBase(Real(0.0)); + param_z_range_blur=ValueBase(Real(0.0)); + + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer_Group::~Layer_Group() +{ +} + +String +Layer_Group::get_local_name()const +{ + String s = Layer_PasteCanvas::get_local_name(); + return s.empty() ? _("Group") : '[' + s + ']'; +} + +Layer::Vocab +Layer_Group::get_param_vocab()const +{ + Layer::Vocab ret(Layer_PasteCanvas::get_param_vocab()); + + ret.push_back(ParamDesc("z_range") + .set_local_name(_("Z Range")) + .set_description(_("When checked, only layers inside range are visible")) + .set_static(true) + ); + ret.push_back(ParamDesc("z_range_position") + .set_local_name(_("Z Range Position")) + .set_description(_("Starting position where layers are visible")) + ); + ret.push_back(ParamDesc("z_range_depth") + .set_local_name(_("Z Range Depth")) + .set_description(_("Depth where layers are visible in range")) + ); + ret.push_back(ParamDesc("z_range_blur") + .set_local_name(_("Z Range Blur")) + .set_description(_("Area where layers inside are partially visible")) + ); + + return ret; +} + +bool +Layer_Group::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE(param_z_range); + IMPORT_VALUE(param_z_range_position); + IMPORT_VALUE(param_z_range_depth); + IMPORT_VALUE(param_z_range_blur); + return Layer_PasteCanvas::set_param(param,value); +} + +ValueBase +Layer_Group::get_param(const String& param)const +{ + EXPORT_VALUE(param_z_range); + EXPORT_VALUE(param_z_range_position); + EXPORT_VALUE(param_z_range_depth); + EXPORT_VALUE(param_z_range_blur); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_PasteCanvas::get_param(param); +} + + +void +Layer_Group::apply_z_range_to_params(ContextParams &cp)const +{ + if (optimized()) return; // z_range already applied while optimizxation + + cp.z_range=param_z_range.get(bool()); + cp.z_range_position=param_z_range_position.get(Real()); + cp.z_range_depth=param_z_range_depth.get(Real()); + cp.z_range_blur=param_z_range_blur.get(Real()); +} diff --git a/synfig-core/src/synfig/layers/layer_group.h b/synfig-core/src/synfig/layers/layer_group.h new file mode 100644 index 0000000..ddc8ad1 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_group.h @@ -0,0 +1,82 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_group.h +** \brief Header file for implementation of the "Group" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2012-2013 Carlos López +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_GROUP_H +#define __SYNFIG_LAYER_GROUP_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_pastecanvas.h" + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { +/*! \class Layer_Group +** \brief Class of the Group layer. +*/ +class Layer_Group : public Layer_PasteCanvas +{ + //! Layer module: defines the needed members to belong to a layer's factory. + SYNFIG_LAYER_MODULE_EXT +private: + //! Parameter: (bool) Z_Depth Range is active + ValueBase param_z_range; + //! Parameter: (Real) Z_Depth Range position + ValueBase param_z_range_position; + //! Parameter: (Real) Z_Depth Range depth + ValueBase param_z_range_depth; + //! Parameter: (Real) Z_Depth Range transition + ValueBase param_z_range_blur; + +public: + //! Default constructor + Layer_Group(); + //! Destructor + virtual ~Layer_Group(); + //! Returns a string with the localized name of this layer + virtual String get_local_name()const; + + //! Sets the parameter described by \a param to \a value. \see Layer::set_param + virtual bool set_param(const String & param, const synfig::ValueBase &value); + //! Get the value of the specified parameter. \see Layer::get_param + virtual ValueBase get_param(const String & param)const; + //! Gets the parameter vocabulary + virtual Vocab get_param_vocab()const; + + //! Sets z_range* fields of specified ContextParams \a cp + virtual void apply_z_range_to_params(ContextParams &cp)const; +}; // END of class Layer_Group + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_meshtransform.cpp b/synfig-core/src/synfig/layers/layer_meshtransform.cpp new file mode 100644 index 0000000..26687b2 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_meshtransform.cpp @@ -0,0 +1,292 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_meshtransform.cpp +** \brief Implementation of the "MeshTransform" layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_meshtransform.h" +#include +#include +#include +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +/* === C L A S S E S ======================================================= */ + +class synfig::Mesh_Trans : public Transform +{ + etl::handle layer; +public: + Mesh_Trans(const Layer_MeshTransform* x):Transform(x->get_guid()),layer(x) { } + + synfig::Vector perform(const synfig::Vector& x)const + { + Vector v(INFINITY, INFINITY); + layer->mesh.transform_coord_texture_to_world(x, v); + return v; + } + + synfig::Vector unperform(const synfig::Vector& x)const + { + Vector v(INFINITY, INFINITY); + layer->mesh.transform_coord_world_to_texture(x, v); + return v; + } + + synfig::String get_string()const + { + return "mesh"; + } +}; + +/* === G L O B A L S ======================================================= */ + +/* === M E T H O D S ======================================================= */ + +Layer_MeshTransform::Layer_MeshTransform(): + max_texture_size(4096), + max_texture_scale(INFINITY), + world_bounds(Rect::zero()), + texture_bounds(Rect::zero()) +{ + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer_MeshTransform::~Layer_MeshTransform() +{ +} + +void +Layer_MeshTransform::update_mesh_and_mask() +{ + // TODO: check mask to calculate bounds + + texture_scale_dependency_from_x = Vector::zero(); + texture_scale_dependency_from_y = Vector::zero(); + + if (mesh.vertices.empty()) + { + world_bounds = Rect::zero(); + texture_bounds = Rect::zero(); + } + else + { + Mesh::VertexList::const_iterator i = mesh.vertices.begin(); + world_bounds.set_point(i->position); + texture_bounds.set_point(i->tex_coords); + for(++i; i != mesh.vertices.end(); ++i) + { + world_bounds.expand(i->position); + texture_bounds.expand(i->position); + } + + const Real epsilon = 1e-10; + for(Mesh::TriangleList::const_iterator i = mesh.triangles.begin(); i != mesh.triangles.end(); ++i) + { + for(int j = 0; j < 3; ++j) + { + const Mesh::Vertex &v0 = mesh.vertices[i->vertices[j]]; + const Mesh::Vertex &v1 = mesh.vertices[i->vertices[(j+1)%3]]; + Vector wd( fabs(v1.position[0] - v0.position[0]), + fabs(v1.position[1] - v0.position[1]) ); + Vector td( fabs(v1.tex_coords[0] - v0.tex_coords[0]), + fabs(v1.tex_coords[1] - v0.tex_coords[1]) ); + if (td[0] > epsilon) + { + Vector dep(wd[0]/td[0], wd[1]/td[0]); + if (dep[0] > texture_scale_dependency_from_x[0]) + texture_scale_dependency_from_x[0] = dep[0]; + if (dep[1] > texture_scale_dependency_from_y[0]) + texture_scale_dependency_from_y[0] = dep[1]; + } + if (td[1] > epsilon) + { + Vector dep(wd[0]/td[1], wd[1]/td[1]); + if (dep[0] > texture_scale_dependency_from_x[1]) + texture_scale_dependency_from_x[1] = dep[0]; + if (dep[1] > texture_scale_dependency_from_y[1]) + texture_scale_dependency_from_y[1] = dep[1]; + } + } + } + + if (max_texture_scale > 0.0) + { + if (texture_scale_dependency_from_x[0] > max_texture_scale) + texture_scale_dependency_from_x[0] = max_texture_scale; + if (texture_scale_dependency_from_x[1] > max_texture_scale) + texture_scale_dependency_from_x[1] = max_texture_scale; + if (texture_scale_dependency_from_y[0] > max_texture_scale) + texture_scale_dependency_from_y[0] = max_texture_scale; + if (texture_scale_dependency_from_y[1] > max_texture_scale) + texture_scale_dependency_from_y[1] = max_texture_scale; + } + } +} + +Layer::Handle +Layer_MeshTransform::hit_check(synfig::Context context, const synfig::Point &point)const +{ + // TODO: check mask + Vector v; + return mesh.transform_coord_world_to_texture(point, v) + ? context.hit_check(v) + : Layer::Handle(); +} + +Color +Layer_MeshTransform::get_color(Context context, const Point &pos)const +{ + // TODO: check mask + Vector v; + return mesh.transform_coord_world_to_texture(pos, v) + ? context.get_color(v) + : Color(); +} + +Rect +Layer_MeshTransform::get_full_bounding_rect(Context /* context */)const +{ + return world_bounds; +} + +etl::handle +Layer_MeshTransform::get_transform()const +{ + return new Mesh_Trans(this); +} + +bool +Layer_MeshTransform::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + const Real epsilon = 1e-10; + + // initialize surface + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + surface->clear(); + + // calculate texture size + RendDesc texture_renddesc(renddesc); + texture_renddesc.set_transformation_matrix(Matrix()); + texture_renddesc.set_tl(texture_bounds.get_min()); + texture_renddesc.set_br(texture_bounds.get_max()); + { + int texture_width, texture_height; + Real pw = fabs(renddesc.get_pw()); + Real ph = fabs(renddesc.get_ph()); + if (pw < epsilon || pw < epsilon) return true; + pw = 1.0/pw; + ph = 1.0/ph; + Vector texture_size = texture_bounds.get_max() - texture_bounds.get_min(); + Real texture_pw = std::max( + texture_scale_dependency_from_x[0]*pw, + texture_scale_dependency_from_y[0]*ph ); + Real texture_ph = std::max( + texture_scale_dependency_from_x[1]*pw, + texture_scale_dependency_from_y[1]*ph ); + texture_width = std::max(1, (int)roundf(texture_pw*texture_size[0])); + texture_height = std::max(1, (int)roundf(texture_ph*texture_size[1])); + if (max_texture_size > 0) + { + if (texture_width > max_texture_size) texture_width = max_texture_size; + if (texture_height > max_texture_size) texture_height = max_texture_size; + } + texture_renddesc.set_w(texture_width); + texture_renddesc.set_h(texture_height); + } + + // render texture + Surface texture; + if(!context.accelerated_render(&texture,quality,texture_renddesc,cb)) + { + if(cb)cb->error(strprintf(__FILE__"%d: Accelerated Renderer Failure",__LINE__)); + return false; + } + + { // render mask + Surface maskSurface; + maskSurface.set_wh(texture.get_w(), texture.get_h()); + maskSurface.fill(Color::alpha()); + RendererSoftware::render_polygon( + maskSurface, + mask, + texture_renddesc.get_transformation_matrix() + * texture_renddesc.get_world_to_pixels_matrix(), + Color::white(), + Color::BLEND_COMPOSITE ); + + // apply mask + Surface::pen a(texture.get_pen(0, 0)); + Surface::pen b(maskSurface.get_pen(0, 0)); + for(int i = 0; i < texture.get_h(); ++i) + { + for(int j = 0; j < texture.get_w(); ++j) + { + a.put_value(a.get_value()*b.get_value().get_a()); + a.inc_x(); + b.inc_x(); + } + a.dec_x(texture.get_w()); + b.dec_x(texture.get_w()); + a.inc_y(); + b.inc_y(); + } + } + + // prepare transformation matrices + Matrix world_to_pixels_matrix = + renddesc.get_transformation_matrix() + * renddesc.get_world_to_pixels_matrix(); + Matrix texture_to_texels_matrix = + texture_renddesc.get_world_to_pixels_matrix(); + + // render mesh + RendererSoftware::render_mesh( + *surface, + mesh, + texture, + world_to_pixels_matrix, + texture_to_texels_matrix, + 1.0, + Color::BLEND_COMPOSITE + ); + + return true; +} diff --git a/synfig-core/src/synfig/layers/layer_meshtransform.h b/synfig-core/src/synfig/layers/layer_meshtransform.h new file mode 100644 index 0000000..0ae5d9c --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_meshtransform.h @@ -0,0 +1,78 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_meshtransform.h +** \brief Header file for implementation of the "MeshTransform" layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_MESHTRANSFORM_H +#define __SYNFIG_LAYER_MESHTRANSFORM_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_composite.h" +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { +class Mesh_Trans; +class Layer_MeshTransform : public Layer_Composite +{ +protected: + friend class Mesh_Trans; + Mesh mesh; + Polygon mask; + + int max_texture_size; + Real max_texture_scale; + +private: + Vector texture_scale_dependency_from_x; + Vector texture_scale_dependency_from_y; + Rect world_bounds; + Rect texture_bounds; + +protected: + void update_mesh_and_mask(); + +public: + //! Default constructor + Layer_MeshTransform(); + //! Destructor + virtual ~Layer_MeshTransform(); + + synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; + virtual Color get_color(Context context, const Point &pos)const; + virtual Rect get_full_bounding_rect(Context context)const; + virtual etl::handle get_transform()const; + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; +}; // END of class Layer_MeshTransform + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_mime.cpp b/synfig-core/src/synfig/layers/layer_mime.cpp new file mode 100644 index 0000000..4d2a730 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_mime.cpp @@ -0,0 +1,148 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_mime.cpp +** \brief Template File +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_mime.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace std; +using namespace etl; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +/* === G L O B A L S ======================================================= */ + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +Layer_Mime::Layer_Mime(String x):name(x) +{ + // Throw a bogus default version onto the parameter list. + param_list["Version"]=(const char*)"9"; +} + +String +Layer_Mime::get_version()const +{ + return get_param("Version").get(String()); +} + +bool +Layer_Mime::set_version(const String &ver) +{ + return set_param("Version",ver); +} + +String +Layer_Mime::get_local_name()const +{ + return _("[MIME]")+get_name(); +} + +bool +Layer_Mime::set_param(const String ¶m, const ValueBase &value) +{ + // Don't try to set the name + if(param=="name" || param=="Name" || param=="name__") + return false; + + // Otherwise, remember this parameter's value + param_list[param]=value; + return true; +} + +ValueBase +Layer_Mime::get_param(const String ¶m)const +{ + // If they are requesting the name of + // the layer, just return it + if(param=="name" || param=="Name" || param=="name__") + return ValueBase(name); + + // Otherwise, return the stored parameter value + map::const_iterator iter=param_list.find(param); + if(iter!=param_list.end()) + return iter->second; + return ValueBase(); +} + +Color +Layer_Mime::get_color(Context context, const Point &pos)const +{ + // A Layer_Mime layer should do nothing at all. + return context.get_color(pos); +} + +bool +Layer_Mime::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + // A Layer_Mime layer should do nothing at all. + return context.accelerated_render(surface,quality,renddesc,cb); +} + +Layer::Vocab +Layer_Mime::get_param_vocab()const +{ + Layer::Vocab ret; + map::const_iterator iter; + + // Construct the vocabulary from the stored + // parameters + for(iter=param_list.begin();iter!=param_list.end();iter++) + { + // Make sure that we don't add the version + // into the vocabulary + if(iter->first!="Version") + ret.push_back(ParamDesc(iter->first)); + } + + // ... and return it + return ret; +} diff --git a/synfig-core/src/synfig/layers/layer_mime.h b/synfig-core/src/synfig/layers/layer_mime.h new file mode 100644 index 0000000..081467e --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_mime.h @@ -0,0 +1,75 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_mime.h +** \brief Template Header +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_MIME_H +#define __SYNFIG_LAYER_MIME_H + +/* === H E A D E R S ======================================================= */ + +#include +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +/*! \class Layer_Mime +** The mime layer is a layer that is used when an unknown +** layer type is requested. This allows people without +** all of the correct layers installed to still work with +** that composition. +*/ +class Layer_Mime : public Layer +{ + std::map param_list; + String name; +public: + Layer_Mime(String name); + + virtual String get_version()const; + + virtual bool set_version(const String &ver); + + virtual bool set_param(const String ¶m, const ValueBase &value); + + virtual ValueBase get_param(const String ¶m)const; + + virtual Color get_color(Context context, const Point &pos)const; + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + + virtual Vocab get_param_vocab()const; + virtual String get_local_name()const; + +}; + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_motionblur.cpp b/synfig-core/src/synfig/layers/layer_motionblur.cpp new file mode 100644 index 0000000..9fda34e --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_motionblur.cpp @@ -0,0 +1,413 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_motionblur.cpp +** \brief Implementation of the "Motion Blur" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "layer_motionblur.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace synfig; +using namespace etl; +using namespace std; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_MotionBlur); +SYNFIG_LAYER_SET_NAME(Layer_MotionBlur,"MotionBlur"); // todo: use motion_blur +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_MotionBlur,N_("Motion Blur")); +SYNFIG_LAYER_SET_CATEGORY(Layer_MotionBlur,N_("Blurs")); +SYNFIG_LAYER_SET_VERSION(Layer_MotionBlur,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_MotionBlur,"$Id$"); + +/* === M E M B E R S ======================================================= */ + +Layer_MotionBlur::Layer_MotionBlur(): + Layer_Composite (1.0,Color::BLEND_STRAIGHT), + param_aperture (ValueBase(Time(0))), + param_subsamples_factor (ValueBase(Real(1.0))), + param_subsampling_type (ValueBase(int(SUBSAMPLING_HYPERBOLIC))), + param_subsample_start (ValueBase(Real(0.0))), + param_subsample_end (ValueBase(Real(1.0))) +{ + +} + +bool +Layer_MotionBlur::set_param(const String ¶m, const ValueBase &value) +{ + + IMPORT_VALUE(param_aperture); + IMPORT_VALUE(param_subsamples_factor); + IMPORT_VALUE(param_subsampling_type); + IMPORT_VALUE(param_subsample_start); + IMPORT_VALUE(param_subsample_end); + return Layer_Composite::set_param(param,value); +} + +ValueBase +Layer_MotionBlur::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_aperture); + EXPORT_VALUE(param_subsamples_factor); + EXPORT_VALUE(param_subsampling_type); + EXPORT_VALUE(param_subsample_start); + EXPORT_VALUE(param_subsample_end); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Composite::get_param(param); +} + +void +Layer_MotionBlur::set_time(IndependentContext context, Time time)const +{ + context.set_time(time); + time_cur=time; +} + +void +Layer_MotionBlur::set_time(IndependentContext context, Time time, const Point &pos)const +{ + context.set_time(time,pos); + time_cur=time; +} + +Color +Layer_MotionBlur::get_color(Context context, const Point &pos)const +{ +/* if(aperture) + { + Time time(time_cur); + time+=(Vector::value_type)( (signed)(RAND_MAX/2)-(signed)rand() )/(Vector::value_type)(RAND_MAX) *aperture -aperture*0.5; + context.set_time(time, pos); + } +*/ + return context.get_color(pos); +} + +Layer::Vocab +Layer_MotionBlur::get_param_vocab()const +{ + Layer::Vocab ret; + //ret=Layer_Composite::get_param_vocab(); + + ret.push_back(ParamDesc("aperture") + .set_local_name(_("Aperture")) + .set_description(_("Shutter Time")) + ); + + ret.push_back(ParamDesc("subsamples_factor") + .set_local_name(_("Subsamples Factor")) + .set_description(_("Multiplies The Number Of Subsamples Rendered")) + ); + + ret.push_back(ParamDesc("subsampling_type") + .set_local_name(_("Subsampling Type")) + .set_description(_("Curve Type For Weighting Subsamples")) + .set_hint("enum") + .add_enum_value(SUBSAMPLING_CONSTANT,"constant",_("Constant")) + .add_enum_value(SUBSAMPLING_LINEAR,"linear",_("Linear")) + .add_enum_value(SUBSAMPLING_HYPERBOLIC,"hyperbolic",_("Hyperbolic")) + ); + + ret.push_back(ParamDesc("subsample_start") + .set_local_name(_("Subsample Start Amount")) + .set_description(_("Relative Amount Of The First Subsample, For Linear Weighting")) + ); + + ret.push_back(ParamDesc("subsample_end") + .set_local_name(_("Subsample End Amount")) + .set_description(_("Relative Amount Of The Last Subsample, For Linear Weighting")) + ); + + return ret; +} + +bool +Layer_MotionBlur::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + RENDER_TRANSFORMED_IF_NEED(__FILE__, __LINE__) + + Time aperture=param_aperture.get(Time()); + Real subsamples_factor=param_subsamples_factor.get(Real()); + SubsamplingType subsampling_type=(SubsamplingType)param_subsampling_type.get(int()); + Real subsample_start=param_subsample_start.get(Real()); + Real subsample_end=param_subsample_end.get(Real()); + + if(aperture && quality<=10) + { + //int x, y; + SuperCallback subimagecb; + int samples=1; + switch(quality) + { + case 1: // Production Quality + samples=32; + break; + case 2: // Excellent Quality + samples=24; + break; + case 3: // Good Quality + samples=16; + break; + case 4: // Moderate Quality + samples=12; + break; + case 5: // Draft Quality + samples=7; + break; + case 6: + samples=6; + break; + case 7: + samples=5; + break; + case 8: + samples=3; + break; + case 9: + samples=2; + break; + case 10: // Rough Quality + default: + samples=1; + break; + + } + + samples *= subsamples_factor; + + if (samples <= 1) return context.accelerated_render(surface,quality,renddesc,cb); + + // Only in modes where subsample_start/end matters... + if(subsampling_type == SUBSAMPLING_LINEAR) + { + // We won't render when the scale==0, so we'll use those samples elsewhere + if(subsample_start == 0) samples++; + if(subsample_end == 0) samples++; + } + + Surface tmp; + int i; + float scale, divisor = 0; + + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + surface->clear(); + + // Render subsamples from time_cur-aperture to time_cur + for(i=0;i + +/* === S T R U C T S & C L A S S E S ======================================= */ + +namespace synfig { + +class Layer_MotionBlur : public synfig::Layer_Composite +{ + SYNFIG_LAYER_MODULE_EXT + + enum SubsamplingType + { + SUBSAMPLING_CONSTANT=0, //!< weight each subsample equally + SUBSAMPLING_LINEAR=1, //!< fade in subsamples linearly + SUBSAMPLING_HYPERBOLIC=2, //!< fade in subsamples by a hyperbolic curve (default style of 0.62 and previous) + + SUBSAMPLING_END=2 //!< \internal + }; + +private: + ValueBase param_aperture; + ValueBase param_subsamples_factor; + ValueBase param_subsampling_type; + ValueBase param_subsample_start; + ValueBase param_subsample_end; + mutable Time time_cur; + +public: + Layer_MotionBlur(); + virtual bool set_param(const String & param, const synfig::ValueBase &value); + virtual ValueBase get_param(const String & param)const; + virtual Color get_color(Context context, const Point &pos)const; + virtual void set_time(IndependentContext context, Time time)const; + virtual void set_time(IndependentContext context, Time time, const Point &point)const; + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual Vocab get_param_vocab()const; + virtual bool reads_context()const { return true; } +}; // END of class Layer_MotionBlur + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_pastecanvas.cpp b/synfig-core/src/synfig/layers/layer_pastecanvas.cpp new file mode 100644 index 0000000..cde910d --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_pastecanvas.cpp @@ -0,0 +1,674 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_pastecanvas.cpp +** \brief Implementation of the "Paste Canvas" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2011-2013 Carlos López +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_pastecanvas.h" +#include "string.h" +#include "time.h" +#include "context.h" +#include "paramdesc.h" +#include "renddesc.h" +#include "surface.h" +#include "value.h" +#include "valuenode.h" +#include "canvas.h" +#include "cairo_renddesc.h" + + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +#define MAX_DEPTH 10 + +// if this isn't defined, the 'dead heads' in examples/pirates.sifz don't render properly +#define SYNFIG_CLIP_PASTECANVAS + +//#ifdef __APPLE__ +//#undef SYNFIG_CLIP_PASTECANVAS +//#endif + +/* === C L A S S E S ======================================================= */ + +class depth_counter // Makes our recursive depth counter exception-safe +{ + int *depth; +public: + depth_counter(int &x):depth(&x) { (*depth)++; } + ~depth_counter() { (*depth)--; } +}; + +/* === G L O B A L S ======================================================= */ + +/* === M E T H O D S ======================================================= */ + +Layer_PasteCanvas::Layer_PasteCanvas(): + param_origin(Point()), + param_transformation(Transformation()), + param_time_offset (Time(0)), + depth(0), + extra_reference(false) +{ + param_children_lock=ValueBase(bool(false)); + param_outline_grow=ValueBase(Real(0)); + param_curr_time=ValueBase(Time::begin()); + + muck_with_time_=true; + + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer_PasteCanvas::~Layer_PasteCanvas() +{ +/* if(canvas) + canvas->parent_set.erase(this); +*/ + + //if(canvas)DEBUGINFO(strprintf("%d",canvas->count())); + + set_sub_canvas(0); + + //if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root())) + //if(extra_reference) + // canvas->unref(); +} + +String +Layer_PasteCanvas::get_local_name()const +{ + if(!canvas || canvas->is_inline()) return String(); + if(canvas->get_root()==get_canvas()->get_root()) return canvas->get_id(); + return canvas->get_file_name(); +} + +Layer::Vocab +Layer_PasteCanvas::get_param_vocab()const +{ + Layer::Vocab ret(Layer_Composite::get_param_vocab()); + + ret.push_back(ParamDesc("origin") + .set_local_name(_("Origin")) + .set_description(_("Position offset")) + ); + + ret.push_back(ParamDesc("transformation") + .set_local_name(_("Transformation")) + .set_description(_("Position, rotation, skew and scale")) + ); + + ret.push_back(ParamDesc("canvas") + .set_local_name(_("Canvas")) + .set_description(_("Group content")) + ); + + ret.push_back(ParamDesc("time_offset") + .set_local_name(_("Time Offset")) + .set_description(_("Time Offset to apply to the context")) + ); + + ret.push_back(ParamDesc("children_lock") + .set_local_name(_("Lock Selection")) + .set_description(_("When checked prevents to select the children using the mouse click")) + .set_static(true) + ); + + ret.push_back(ParamDesc("outline_grow") + .set_local_name(_("Outline Grow")) + .set_description(_("Exponential value to grow children Outline layers width")) + ); + if(canvas && !(canvas->is_inline())) + { + ret.back().hidden(); + } + + // optimize_layers() in canvas.cpp makes a new PasteCanvas layer + // and copies over the parameters of the old layer. the + // 'curr_time' member wasn't being copied, so I've added it as a + // hidden, non critical parameter, and now it will be. this + // allows a single exported subcanvas to be used more than once at + // a time, with different time offets in each. see bug #1896557. + ret.push_back(ParamDesc("curr_time") + .set_local_name(_("Current Time")) + .not_critical() + .hidden() + ); + + return ret; +} + +bool +Layer_PasteCanvas::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE(param_origin); + IMPORT_VALUE(param_transformation); + + // IMPORT(canvas); + if(param=="canvas" && value.can_get(Canvas::Handle())) + { + set_sub_canvas(value.get(Canvas::Handle())); + return true; + } + //! \todo this introduces bug 1844764 if enabled; it was introduced in r954. + // http://synfig.org/images/3/3d/Moving-waypoints.sifz is an + // example of an animation that has its waypoints displayed + // incorrectly without this fix; select the outer layer and drag + // the time slider. The linear waypoints don't take effect until + // 5s, but the time slider appears to pass the first one at 3s. +#if 0 + if (param=="time_offset" && value.same_type_as(time_offset)) + { + if (time_offset != value.get(Time())) + { + value.put(&time_offset); + // notify that the time_offset has changed so we can update the + // waypoint positions in parent layers + changed(); + } + return true; + } +#else + IMPORT_VALUE(param_time_offset); +#endif + + IMPORT_VALUE(param_children_lock); + IMPORT_VALUE(param_outline_grow); + IMPORT_VALUE(param_curr_time); + return Layer_Composite::set_param(param,value); +} + +void +Layer_PasteCanvas::set_sub_canvas(etl::handle x) +{ + if(canvas && muck_with_time_) + remove_child(canvas.get()); + + // if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root())) + if (extra_reference) + canvas->unref(); + + child_changed_connection.disconnect(); + + if (canvas != x) signal_subcanvas_changed()(); + + canvas=x; + + /*if(canvas) + child_changed_connection=canvas->signal_changed().connect( + sigc::mem_fun( + *this, + &Layer_PasteCanvas::changed + ) + ); + */ + + if(canvas && muck_with_time_) + add_child(canvas.get()); + + if(canvas && (canvas->is_inline() || !get_canvas() || get_canvas()->get_root()!=canvas->get_root())) + { + canvas->ref(); + extra_reference = true; + } + else + extra_reference = false; + + if(canvas) + on_canvas_set(); +} + +// when a pastecanvas that contains another pastecanvas is copy/pasted +// from one document to another, only the outermost pastecanvas was +// getting its renddesc set to match that of its new parent. this +// function is used to recurse through the pastecanvas copying its +// renddesc to any pastecanvases it contains (bug #2116947, svn r2200) +void +Layer_PasteCanvas::update_renddesc() +{ + if(!get_canvas() || !canvas || !canvas->is_inline()) return; + + canvas->rend_desc()=get_canvas()->rend_desc(); + for (IndependentContext iter = canvas->get_independent_context(); !iter->empty(); iter++) + { + etl::handle paste = etl::handle::cast_dynamic(*iter); + if (paste) paste->update_renddesc(); + } +} + +// This is called whenever the parent canvas gets set/changed +void +Layer_PasteCanvas::on_canvas_set() +{ + if(get_canvas() && canvas && canvas->is_inline() && canvas->parent()!=get_canvas()) + { + canvas->set_inline(get_canvas()); + } +} + +ValueBase +Layer_PasteCanvas::get_param(const String& param)const +{ + EXPORT_VALUE(param_origin); + EXPORT_VALUE(param_transformation); + if (param=="canvas") + { + synfig::ValueBase ret(canvas); + return ret; + } + EXPORT_VALUE(param_time_offset); + EXPORT_VALUE(param_children_lock); + EXPORT_VALUE(param_curr_time); + EXPORT_VALUE(param_outline_grow); + + return Layer_Composite::get_param(param); +} + +void +Layer_PasteCanvas::set_time(IndependentContext context, Time time)const +{ + Time time_offset=param_time_offset.get(Time()); + + if(depth==MAX_DEPTH)return;depth_counter counter(depth); + param_curr_time.set(time); + + context.set_time(time); + if(canvas) + canvas->set_time(time+time_offset); +} + +void +Layer_PasteCanvas::apply_z_range_to_params(ContextParams &/*cp*/)const +{ +} + +synfig::Layer::Handle +Layer_PasteCanvas::hit_check(synfig::Context context, const synfig::Point &pos)const +{ + if(depth==MAX_DEPTH)return 0;depth_counter counter(depth); + + Transformation transformation(get_summary_transformation()); + + bool children_lock=param_children_lock.get(bool(true)); + ContextParams cp(context.get_params()); + apply_z_range_to_params(cp); + if (canvas) { + Point target_pos = transformation.back_transform(pos); + + if(canvas && get_amount() && canvas->get_context(cp).get_color(target_pos).get_a()>=0.25) + { + if(!children_lock) + { + return canvas->get_context(cp).hit_check(target_pos); + } + return const_cast(this); + } + } + return context.hit_check(pos); +} + +Color +Layer_PasteCanvas::get_color(Context context, const Point &pos)const +{ + Transformation transformation(get_summary_transformation()); + + ContextParams cp(context.get_params()); + apply_z_range_to_params(cp); + if(!canvas || !get_amount()) + return context.get_color(pos); + + if(depth==MAX_DEPTH)return Color::alpha();depth_counter counter(depth); + + Point target_pos = transformation.back_transform(pos); + + return Color::blend(canvas->get_context(cp).get_color(target_pos),context.get_color(pos),get_amount(),get_blend_method()); +} + +Rect +Layer_PasteCanvas::get_bounding_rect_context_dependent(const ContextParams &context_params)const +{ + if (canvas) + { + ContextParams cp(context_params); + apply_z_range_to_params(cp); + + return get_summary_transformation() + .transform_bounds( + canvas->get_context(cp).get_full_bounding_rect() ); + } + return Rect::zero(); +} + +Rect +Layer_PasteCanvas::get_full_bounding_rect(Context context)const +{ + if(is_disabled() || Color::is_onto(get_blend_method())) + return context.get_full_bounding_rect(); + + return context.get_full_bounding_rect()|get_bounding_rect_context_dependent(context.get_params()); +} + +bool +Layer_PasteCanvas::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + Transformation transformation( + get_summary_transformation().get_matrix() + * renddesc.get_transformation_matrix() ); + + Real outline_grow=param_outline_grow.get(Real()); + Time time_offset=param_time_offset.get(Time()); + Time curr_time=param_curr_time.get(Time()); + + if(cb && !cb->amount_complete(0,10000)) return false; + + if(depth==MAX_DEPTH) + // if we are at the extent of our depth, + // then we should just return whatever is under us. + return context.accelerated_render(surface,quality,renddesc,cb); + + depth_counter counter(depth); + + if(!canvas || !get_amount()) + return context.accelerated_render(surface,quality,renddesc,cb); + + SuperCallback stageone(cb,0,4500,10000); + SuperCallback stagetwo(cb,4500,9000,10000); + SuperCallback stagethree(cb,9000,9999,10000); + + Context canvasContext = canvas->get_context(context); + + if (is_solid_color()) + { + RendDesc intermediate_desc(renddesc); + intermediate_desc.clear_flags(); + intermediate_desc.set_transformation_matrix(transformation.get_matrix()); + return canvasContext.accelerated_render(surface,quality,intermediate_desc,&stagetwo); + } + else + if (!context.accelerated_render(surface,quality,renddesc,&stageone)) + return false; + + Real grow_value(get_parent_canvas_grow_value()); + canvas->set_grow_value(outline_grow+grow_value); + + if(muck_with_time_ && curr_time!=Time::begin() /*&& canvas->get_time()!=curr_time+time_offset*/) + canvas->set_time(curr_time+time_offset); + + Color::BlendMethod blend_method(get_blend_method()); + const Rect full_bounding_rect(canvasContext.get_full_bounding_rect()); + + Rect inner_bounds( + full_bounding_rect.get_min(), + full_bounding_rect.get_max() + ); + inner_bounds &= transformation.back_transform_bounds(renddesc.get_rect()); + Rect outer_bounds(transformation.transform_bounds(inner_bounds)); + outer_bounds &= renddesc.get_rect(); + if (!outer_bounds.is_valid()) + return true; + + Rect next_bounds( Transformation::transform_bounds(renddesc.get_transformation_matrix(), context.get_full_bounding_rect()) ); + + // sometimes the user changes the parameters while we're + // rendering, causing our pasted canvas' bounding box to shrink + // and no longer overlap with our tile. if that has happened, + // let's just stop now - we'll be refreshing soon anyway + //! \todo shouldn't a mutex ensure this isn't needed? + // http://synfig.org/images/d/d2/Bbox-change.sifz is an example + // that shows this happening - open the encapsulation, select the + // 'shade', and toggle the 'invert' parameter quickly. + // Occasionally you'll see: + // error: Context::accelerated_render(): Layer "shade" threw a bad_alloc exception! + // where the shade layer tries to allocate itself a canvas of + // negative proportions, due to changing bounding boxes. + if (!inner_bounds.is_valid()) + { + warning("%s:%d bounding box shrank while rendering?", __FILE__, __LINE__); + return true; + } + + bool blend_using_straight = false; // use 'straight' just for the central blit + + if (!etl::intersect(next_bounds,outer_bounds)) + { + // if there's no intersection between the context and our + // surface, and we're rendering 'onto', then we're done + if (Color::is_onto(blend_method) && !Color::is_straight(blend_method)) + return true; + + /* 'straight' is faster than 'composite' and has the same + * effect if the affected area of the lower layer is + * transparent; however, if we're not clipping the blit to + * just the bounding rectangle, the affected area is the whole + * tile, so we can't use this optimisation. if we are + * clipping, then we can use 'straight' to blit the clipped + * rectangle, but we shouldn't set blend_method to 'straight', + * or the surrounding areas will be blanked, which we don't + * want. + */ +#ifdef SYNFIG_CLIP_PASTECANVAS + if (blend_method==Color::BLEND_COMPOSITE) blend_using_straight = true; +#endif // SYNFIG_CLIP_PASTECANVAS + } + + int w = renddesc.get_w(); + int h = renddesc.get_h(); + Vector tl = renddesc.get_tl(); + Vector br = renddesc.get_br(); + Vector size = br - tl; + Real rx0 = (outer_bounds.minx - tl[0])/size[0]*w; + Real rx1 = (outer_bounds.maxx - tl[0])/size[0]*w; + Real ry0 = (outer_bounds.miny - tl[1])/size[1]*h; + Real ry1 = (outer_bounds.maxy - tl[1])/size[1]*h; + if (rx1 < rx0) { Real rx = rx0; rx0 = rx1; rx1 = rx; } + if (ry1 < ry0) { Real ry = ry0; ry0 = ry1; ry1 = ry; } + int x0((floor(rx0))); + int x1((ceil(rx1))); + int y0((floor(ry0))); + int y1((ceil(ry1))); + + if (x0 < 0) x0 = 0; else if (x0 > w) x0 = w; + if (x1 < 0) x1 = 0; else if (x1 > w) x1 = w; + if (y0 < 0) y0 = 0; else if (y0 > h) y0 = h; + if (y1 < 0) y1 = 0; else if (y1 > h) y1 = h; + int intermediate_w = x1 - x0; + int intermediate_h = y1 - y0; + Vector pixel_aligned_tl( + (Real)x0/(Real)w*size[0] + tl[0], + (Real)y0/(Real)h*size[1] + tl[1] ); + Vector pixel_aligned_br( + (Real)x1/(Real)w*size[0] + tl[0], + (Real)y1/(Real)h*size[1] + tl[1] ); + + if (intermediate_w > 0 && intermediate_h > 0) { + RendDesc intermediate_desc(renddesc); + intermediate_desc.clear_flags(); + intermediate_desc.set_transformation_matrix(transformation.get_matrix()); + intermediate_desc.set_wh(intermediate_w, intermediate_h); + intermediate_desc.set_tl(pixel_aligned_tl); + intermediate_desc.set_br(pixel_aligned_br); + Surface intermediate_surface; + if(!canvasContext.accelerated_render(&intermediate_surface,quality,intermediate_desc,&stagetwo)) + return false; + Surface::alpha_pen apen(surface->get_pen(x0, y0)); + apen.set_alpha(get_amount()); + apen.set_blend_method(blend_using_straight ? Color::BLEND_STRAIGHT : blend_method); + intermediate_surface.blit_to(apen); + } + + if(cb && !cb->amount_complete(10000,10000)) return false; + return true; +} + +/////// + +bool +Layer_PasteCanvas::accelerated_cairorender(Context context,cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + Transformation transformation(get_summary_transformation()); + + Real outline_grow=param_outline_grow.get(Real()); + Time time_offset=param_time_offset.get(Time()); + Time curr_time=param_curr_time.get(Time()); + + if(cb && !cb->amount_complete(0,10000)) return false; + + if(depth==MAX_DEPTH) + // if we are at the extent of our depth, + // then we should just return whatever is under us. + return context.accelerated_cairorender(cr,quality,renddesc,cb); + + depth_counter counter(depth); + + if(!canvas || !get_amount()) + return context.accelerated_cairorender(cr,quality,renddesc,cb); + + SuperCallback stageone(cb,0,4500,10000); + SuperCallback stagetwo(cb,4500,9000,10000); + SuperCallback stagethree(cb,9000,9999,10000); + + + Real grow_value(get_parent_canvas_grow_value()); + canvas->set_grow_value(outline_grow+grow_value); + + if(muck_with_time_ && curr_time!=Time::begin() /*&& canvas->get_time()!=curr_time+time_offset*/) + canvas->set_time(curr_time+time_offset); + + bool ret; + RendDesc workdesc(renddesc); + + // Render the background + ret=context.accelerated_cairorender(cr, quality, renddesc, &stagethree); + if(!ret) + return false; + + + // render the canvas to be pasted onto pastesurface + cairo_surface_t* pastesurface=cairo_surface_create_similar_image(cairo_get_target(cr), CAIRO_FORMAT_ARGB32, workdesc.get_w(), workdesc.get_h()); + cairo_t* subcr=cairo_create(pastesurface); + // apply the transformations form the current context + cairo_matrix_t matrix; + cairo_get_matrix(cr, &matrix); + + // apply the transformations form the (paste canvas) group layer + cairo_set_matrix(subcr, &matrix); + + cairo_matrix_t cairo_transformation_matrix; + Matrix transformation_matrix(transformation.get_matrix()); + cairo_matrix_init( + &cairo_transformation_matrix, + transformation_matrix.m00, + transformation_matrix.m01, + transformation_matrix.m10, + transformation_matrix.m11, + transformation_matrix.m20, + transformation_matrix.m21 ); + + cairo_transform(subcr, &cairo_transformation_matrix); + + // Effectively render the canvas content + ret=canvas->get_context(context).accelerated_cairorender(subcr, quality, workdesc, &stagetwo); + // we are done apply the result to the source + cairo_destroy(subcr); + + if(!ret) + return false; + // Let's paint the result with its alpha + cairo_save(cr); + + cairo_status_t status; + status=cairo_matrix_invert(&matrix); + if(status) // doh! the matrix can't be inverted! + { + synfig::error("Can't invert current Cairo matrix!"); + return false; + } + // apply the inverse of the transformation of the current context to + // compensate the pending transformations form cr to be applied. + cairo_transform(cr, &matrix); + cairo_set_source_surface(cr, pastesurface, 0, 0); + cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); + + cairo_restore(cr); + cairo_surface_destroy(pastesurface); + + if(cb && !cb->amount_complete(10000,10000)) return false; + + return true; +} +/////// + + +void Layer_PasteCanvas::get_times_vfunc(Node::time_set &set) const +{ + Time time_offset=param_time_offset.get(Time()); + + Node::time_set tset; + if(canvas) tset = canvas->get_times(); + + Node::time_set::iterator i = tset.begin(), end = tset.end(); + + //Make sure we offset the time... + //! \todo: SOMETHING STILL HAS TO BE DONE WITH THE OTHER DIRECTION + // (recursing down the tree needs to take this into account too...) + for(; i != end; ++i) + set.insert(*i +#ifdef ADJUST_WAYPOINTS_FOR_TIME_OFFSET // see node.h + - time_offset +#endif + ); + + Layer::get_times_vfunc(set); +} + + +void +Layer_PasteCanvas::set_render_method(Context context, RenderMethod x) +{ + if(canvas) // if there is a canvas pass down to it + canvas->get_context(context).set_render_method(x); + + // in any case pass it down + context.set_render_method(x); +} + +void +Layer_PasteCanvas::fill_sound_processor(SoundProcessor &soundProcessor) const +{ + if (active() && canvas) canvas->fill_sound_processor(soundProcessor); +} diff --git a/synfig-core/src/synfig/layers/layer_pastecanvas.h b/synfig-core/src/synfig/layers/layer_pastecanvas.h new file mode 100644 index 0000000..a218a50 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_pastecanvas.h @@ -0,0 +1,203 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_pastecanvas.h +** \brief Header file for implementation of the "Paste Canvas" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2012-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_PASTECANVAS_H +#define __SYNFIG_LAYER_PASTECANVAS_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_composite.h" +#include +#include +#include +#include +#include +#include +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { +/*! \class Layer_PasteCanvas +** \brief Class of the Pasted Canvas layer. +*/ +class Layer_PasteCanvas : public Layer_Composite, public Layer_NoDeform +{ +private: + //! Parameter: (Origin) Position offset + ValueBase param_origin; + //! Parameter: (Transfromation) Position, rotation and scale of the paste canvas layer + ValueBase param_transformation; + //! Parameter: (etl::loose_handle) The canvas parameter + etl::loose_handle canvas; + //! Parameter: (Time) Time offset of the paste canvas layer + ValueBase param_time_offset; + //! Parameter: (Real) The value to grow the children outline layers + ValueBase param_outline_grow; + //! Parameter: (bool) Value that avoid hit check to go depth into the children. + ValueBase param_children_lock; + //! Parameter: Current time of the paste canvas layer. \see set_time + mutable ValueBase param_curr_time; + + //! \todo writeme! + bool muck_with_time_; + //! Recursion depth counter. + mutable int depth; + + //! Boundaries of the paste canvas layer. It is the canvas's boundary + //! affected by the origin and transformation. + mutable Rect bounds; + //! signal connection for children. Seems to be used only here + sigc::connection child_changed_connection; + + // Nasty hack: Remember whether we called an extra ref() when + // setting the canvas, so we know whether to call an extra unref() + // when finished with the canvas. + // + // Here's the story: + // + // The root canvas is destructed first. That sets the + // Layer::canvas_ (the parent canvas) of any PasteCanvas layer it + // contains to nil, due to a call to Layer::set_canvas(0), + // triggered by the connection made when Layer::set_canvas + // originally set its canvas_ member to point to the root canvas. + // ~Canvas does begin_delete() which triggers that connection. + // + // After ~Canvas has run, the members of the root canvas are + // freed, including its children_ list. If this was the last + // reference to the child canvas that the pastecanvas uses, that + // child canvas will Layer_PasteCanvas::set_sub_canvas(0) on the + // PasteCanvas layer to set its canvas (the child, pasted canvas) + // not to refer to the soon-to-be destroys child canvas. But + // set_sub_canvas() originally looked at the value of + // Layer::canvas_ (the parent canvas, obtained via + // Layer::get_canvas()) to decide whether to do an extra ref() on + // canvas (the child canvas). We need to unref() it now if we + // did, but we've forgotten whether we did. So we use this + // 'extra_reference' member to store that decision. + bool extra_reference; + + /* + -- ** -- S I G N A L S ------------------------------------------------------- + */ + +private: + //! Signal used when the canvas parameter has changed. \see layertreestore.cpp + sigc::signal signal_subcanvas_changed_; + + /* + -- ** -- S I G N A L I N T E R F A C E ------------------------------------- + */ + +public: + //! Wrapper for the subcanvas changed signal + sigc::signal& signal_subcanvas_changed() { return signal_subcanvas_changed_; } + +public: + + //! Recursively update the Render Description for the inner inline only pasted canvases. + //! Used for copy and paste Paste Canvas Layers between compositions. + void update_renddesc(); + + //! Every time the Paste Canvas Layer parent canvas is changed, this + //! is called and it sets the parent of the canvas parameter to that canvas + //! if it is on line + virtual void on_canvas_set(); + //! Sets muck_with_time. + //! \todo writeme! + void set_muck_with_time(bool x=false) { muck_with_time_=x; } + + //! Gets the canvas parameter. It is called sub_canvas to avoid confusion + //! with the get_canvas from the Layer class. + etl::handle get_sub_canvas()const { return canvas; } + //! Sets the canvas parameter. + //! \see get_sub_canvas() + void set_sub_canvas(etl::handle x); + //! Gets time offset parameter + Time get_time_offset()const { return param_time_offset.get(Time()); } + + //! Get origin parameter + Point get_origin()const { return param_origin.get(Point()); } + //! Get transformation parameter + Transformation get_transformation()const { return param_transformation.get(Transformation()); } + //! Get summary transformation + Transformation get_summary_transformation()const + { + return get_transformation().transform( Transformation(-get_origin()) ); + } + + //! Default constructor + Layer_PasteCanvas(); + //! Destructor + virtual ~Layer_PasteCanvas(); + //! Returns a string with the localized name of this layer + virtual String get_local_name()const; + //! Sets the parameter described by \a param to \a value. \see Layer::set_param + virtual bool set_param(const String & param, const synfig::ValueBase &value); + //! Get the value of the specified parameter. \see Layer::get_param + virtual ValueBase get_param(const String & param)const; + //! Sets z_range* fields of specified ContextParams \a cp + virtual void apply_z_range_to_params(ContextParams &cp)const; + //! Gets the blend color of the Layer in the context at \a pos + virtual Color get_color(Context context, const Point &pos)const; + //! Sets the time of the Paste Canvas Layer and those under it + virtual void set_time(IndependentContext context, Time time)const; + //! Renders the Canvas to the given Surface in an accelerated manner + //! See Layer::accelerated_render + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + //! Bounding rect for this layer depends from context_params + Rect get_bounding_rect_context_dependent(const ContextParams &context_params)const; + //!Returns the rectangle that includes the context of the layer and + //! the intersection of the layer in case it is active and not onto + virtual Rect get_full_bounding_rect(Context context)const; + //! Gets the parameter vocabulary + virtual Vocab get_param_vocab()const; + //! Checks to see if a part of the Paste Canvas Layer is directly under \a point + virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; + virtual void set_render_method(Context context, RenderMethod x); + + virtual void fill_sound_processor(SoundProcessor &soundProcessor) const; + +protected: + //! Function to be overloaded that fills the Time Point Set with + //! all the children Time Points. In this case the children Time Points + //! are the canvas parameter children layers Time points and the Paste Canvas + //! Layer time points. \todo clarify all this comments. + virtual void get_times_vfunc(Node::time_set &set) const; + +}; // END of class Layer_PasteCanvas + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_polygon.cpp b/synfig-core/src/synfig/layers/layer_polygon.cpp new file mode 100644 index 0000000..81d3722 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_polygon.cpp @@ -0,0 +1,194 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_polygon.cpp +** \brief Implementation of the "Polygon" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007 Chris Moore +** Copyright (c) 2011-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_polygon.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +using std::deque; + +#endif + +/* === U S I N G =========================================================== */ + +using namespace synfig; +using namespace std; +using namespace etl; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Polygon); +SYNFIG_LAYER_SET_NAME(Layer_Polygon,"polygon"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Polygon,N_("Polygon")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Polygon,N_("Geometry")); +SYNFIG_LAYER_SET_VERSION(Layer_Polygon,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Polygon,"$Id$"); + +/* === C L A S S E S ======================================================= */ + +/* === M E T H O D S ======================================================= */ + +Layer_Polygon::Layer_Polygon(): + Layer_Shape(1.0,Color::BLEND_COMPOSITE), + param_vector_list(ValueBase(std::vector())) +{ + std::vector vector_list; + vector_list.push_back(Point(0,0.5)); + vector_list.push_back(Point(-0.333333,0)); + vector_list.push_back(Point(0.333333,0)); + param_vector_list.set_list_of(vector_list); + sync(); + + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer_Polygon::~Layer_Polygon() +{ +} + +void +Layer_Polygon::sync() +{ +/* + int i,pointcount=vector_list.size(); + + if(pointcount<3) + return; + + //Layer_Shape::clear(); + //clear(); + + // Build edge table + move_to(vector_list[0][0],vector_list[0][1]); + + for(i = 1;i < pointcount; i++) + { + if(isnan(vector_list[i][0]) || isnan(vector_list[i][1])) + break; + line_to(vector_list[i][0],vector_list[i][1]); + } + close(); + //endpath(); +*/ +} + +void +Layer_Polygon::add_polygon(const std::vector &point_list) +{ + int i,pointcount=point_list.size(); + + if(pointcount<3) + return; + + //Layer_Shape::clear(); + //clear(); + + // Build edge table + move_to(point_list[0][0],point_list[0][1]); + + for(i = 1;i < pointcount; i++) + { + if(isnan(point_list[i][0]) || isnan(point_list[i][1])) + break; + line_to(point_list[i][0],point_list[i][1]); + } + close(); + //endpath(); +} + +void +Layer_Polygon::upload_polygon(const std::vector &point_list) +{ + ValueBase::List vector_list; + vector_list.reserve(point_list.size()); + for(std::vector::const_iterator i = point_list.begin(); i != point_list.end(); ++i) + vector_list.push_back(*i); + param_vector_list.set(vector_list); +} + +void +Layer_Polygon::clear() +{ + Layer_Shape::clear(); + param_vector_list.set(ValueBase::List()); +} + +bool +Layer_Polygon::set_param(const String & param, const ValueBase &value) +{ + if( param=="vector_list" && param_vector_list.get_type()==value.get_type()) + { + param_vector_list=value; + Layer_Shape::clear(); + add_polygon(value.get_list_of(Vector())); + sync(); + return true; + } + + return Layer_Shape::set_param(param,value); +} + +ValueBase +Layer_Polygon::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_vector_list); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Shape::get_param(param); +} + +Layer::Vocab +Layer_Polygon::get_param_vocab()const +{ + Layer::Vocab ret(Layer_Shape::get_param_vocab()); + + ret.push_back(ParamDesc("vector_list") + .set_local_name(_("Vertices List")) + .set_description(_("Define the corners of the polygon")) + .set_origin("origin") + ); + + return ret; +} + diff --git a/synfig-core/src/synfig/layers/layer_polygon.h b/synfig-core/src/synfig/layers/layer_polygon.h new file mode 100644 index 0000000..6db9ab6 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_polygon.h @@ -0,0 +1,100 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_polygon.h +** \brief Header file for implementation of the "Polygon" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2011-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_POLYGON_H +#define __SYNFIG_LAYER_POLYGON_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_shape.h" +#include +#include +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +/*! \class Layer_Polygon +** \brief writeme +** \todo This layer needs to support multiple polygons */ +class Layer_Polygon : public Layer_Shape +{ + SYNFIG_LAYER_MODULE_EXT + +private: + + //! Parameter: (std::vector) + ValueBase param_vector_list; + +protected: + + Layer_Polygon(); + +public: + + ~Layer_Polygon(); + + //! Adds a polygon to the layer + /*! The edge data is automatically added to the + ** EdgeTable, so there is no need to call sync() + ** after adding a polygon using this function. + ** \param point_list A list containing the + ** points that define the polygon's parameter. + */ + void add_polygon(const std::vector &point_list); + + // Places the point_list on the vector_list, for later render as polygon. + void upload_polygon(const std::vector &point_list); + + //! Clears out any polygon data + /*! Also clears out the EdgeTable, so there is no + ** need to call sync() after using this function. + */ + void clear(); + + //! Updates EdgeTable so it will reflect the parameter data + void sync(); + + virtual bool set_param(const String & param, const synfig::ValueBase &value); + + virtual ValueBase get_param(const String & param)const; + + virtual Vocab get_param_vocab()const; +private: + class PolySpan; + bool render_polyspan(Surface *surface,PolySpan &polyspan)const; + +}; // END of Layer_Polygon + +}; // END of namespace synfig +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_shape.cpp b/synfig-core/src/synfig/layers/layer_shape.cpp new file mode 100644 index 0000000..910fe2c --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_shape.cpp @@ -0,0 +1,3566 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_shape.cpp +** \brief Implementation of the "Shape" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2012-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_shape.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include + +#include + +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace synfig; +using namespace std; +using namespace etl; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Shape); +SYNFIG_LAYER_SET_NAME(Layer_Shape,"shape"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Shape,N_("Shape")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Shape,N_("Internal")); +SYNFIG_LAYER_SET_VERSION(Layer_Shape,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Shape,"$Id$"); + +#define EPSILON 1e-12 + +template < class T > +inline bool IsZero(const T &n) +{ + return (n < EPSILON) && (n > -EPSILON); +} + +/* === C L A S S E S ======================================================= */ + +//Assumes 64 byte aligned structures if at all +struct Primitive +{ + int operation; + int number; + + //Point data[0]; + + enum Operations + { + NONE = -1, + MOVE_TO = 0, //(x,y)+ after first point treated as line_to + CLOSE, // NOT RUNLENGTH enabled + LINE_TO, //(x,y)+ continuous func + CONIC_TO, //(x1,y1,x,y)+ " " + CONIC_TO_SMOOTH, //(x,y)+ " " + CUBIC_TO, //(x1,y1,x2,y2,x,y)+ " " + CUBIC_TO_SMOOTH, //(x2,y2,x,y)+ " " + END + }; +}; + +//******** CURVE FUNCTIONS ***************** +const int MAX_SUBDIVISION_SIZE = 64; +const int MIN_SUBDIVISION_DRAW_LEVELS = 4; + +static void Subd_Conic_Stack(Point *arc) +{ + /* + + b0 + * 0+1 a + b1 b * 1+2*1+2 a + * 1+2 b * + b2 * + * + + 0.1.2 -> 0.1 2 3.4 + + */ + + Real a,b; + + + arc[4][0] = arc[2][0]; + b = arc[1][0]; + + a = arc[1][0] = (arc[0][0] + b)/2; + b = arc[3][0] = (arc[4][0] + b)/2; + arc[2][0] = (a + b)/2; + + + arc[4][1] = arc[2][1]; + b = arc[1][1]; + + a = arc[1][1] = (arc[0][1] + b)/2; + b = arc[3][1] = (arc[4][1] + b)/2; + arc[2][1] = (a + b)/2; + + /* //USING SIMD + + arc[4] = arc[2]; + + arc[3] = (arc[2] + arc[1])/2; + arc[1] = (arc[0] + arc[1])/2; + + arc[2] = (arc[1] + arc[3])/2; + + */ + +} + +static void Subd_Cubic_Stack(Point *arc) +{ + Real a,b,c; + + /* + + b0 + * 0+1 a + b1 b * 1+2*1+2 a + * 1+2 b * 0+3*1+3*2+3 + b2 c * 1+2*2+2 b * + * 2+3 c * + b3 * + * + + 0.1 2.3 -> 0.1 2 3 4 5.6 + + */ + + arc[6][0] = arc[3][0]; + + b = arc[1][0]; + c = arc[2][0]; + + a = arc[1][0] = (arc[0][0] + b)/2; + b = (b + c)/2; + c = arc[5][0] = (arc[6][0] + c)/2; + + a = arc[2][0] = (a + b)/2; + b = arc[4][0] = (b + c)/2; + + arc[3][0] = (a + b)/2; + + + arc[6][1] = arc[3][1]; + + b = arc[1][1]; + c = arc[2][1]; + + a = arc[1][1] = (arc[0][1] + b)/2; + b = (b + c)/2; + c = arc[5][1] = (arc[6][1] + c)/2; + + a = arc[2][1] = (a + b)/2; + b = arc[4][1] = (b + c)/2; + + arc[3][1] = (a + b)/2; + + /* //USING SIMD + temp + + arc[6] = arc[3]; + + //backwards to avoid overwriting + arc[5] = (arc[2] + arc[3])/2; + temp = (arc[1] + arc[2])/2; + arc[1] = (arc[0] + arc[1])/2; + + arc[4] = (temp + arc[5])/2; + arc[2] = (arc[1] + temp)/2; + + arc[3] = (arc[2] + arc[4])/2; + + */ +} + +//************** PARAMETRIC RENDERER SUPPORT STRUCTURES **************** + +// super segment +struct MonoSegment +{ + Rect aabb; + int ydir; + vector pointlist; + + MonoSegment(int dir = 0, Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0) + { + aabb.minx = x0; + aabb.maxx = x1; + aabb.miny = y0; + aabb.maxy = y1; + + ydir = dir; + } + + int intersect(Real x,Real y) const + { + if((y < aabb.miny+EPSILON) || (y > aabb.maxy) || (x < aabb.minx)) return 0; + if(x > aabb.maxx) return ydir; + + //int i = 0; + //int size = pointlist.size(); + //vector::const_iterator end = pointlist.end(); + vector::const_iterator p = pointlist.begin(); + + //assumes that the rect culled away anything that would be beyond the edges + if(ydir > 0) + { + while(y > (*++p)[1]) + ; + } + else + { + while(y < (*++p)[1]) + ; + } + + //for the loop to break there must have been a slope (straight line would do nothing) + //vector::const_iterator p1 = p-1; + Real dy = p[-1][1] - p[0][1]; + Real dx = p[-1][0] - p[0][0]; + + assert(dy != 0); + + Real xi = p[0][0] + (y - p[0][1]) * dx / dy; + return (x > xi)*ydir; + } +}; + +struct CurveArray +{ + Rect aabb; //not necessarily as effective - can only reject values + vector pointlist; //run length - p0, p1, p2, p3 = p10, p11, p12, p13 = p20 ... + vector degrees; + + CurveArray(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0) + { + aabb.set(x0,y0,x1,y1); + } + + void reset(Real x0 = 0, Real x1 = 0, Real y0 = 0, Real y1 = 0) + { + aabb.set(x0,y0,x1,y1); + pointlist.clear(); + degrees.clear(); + } + + int size () const + { + return degrees.size(); + } + + void Start(Point m) + { + reset(m[0],m[0],m[1],m[1]); + pointlist.push_back(m); + } + + void AddCubic(Point p1, Point p2, Point dest) + { + aabb.expand(p1[0],p1[1]); + aabb.expand(p2[0],p2[1]); + aabb.expand(dest[0],dest[1]); + + pointlist.push_back(p1); + pointlist.push_back(p2); + pointlist.push_back(dest); + + degrees.push_back(3); + } + + void AddConic(Point p1, Point dest) + { + aabb.expand(p1[0],p1[1]); + aabb.expand(dest[0],dest[1]); + + pointlist.push_back(p1); + pointlist.push_back(dest); + + degrees.push_back(2); + } + + static int intersect_conic(Real x, Real y, Point *p, int /*level*/ = 0) + { + Real ymin,ymax,xmin,xmax; + int intersects = 0; + + //sort the overall curve ys - degenerate detection + ymin = min(p[0][1],p[2][1]); + ymax = max(p[0][1],p[2][1]); + + xmin = min(min(p[0][0],p[1][0]),p[2][0]); + xmax = max(max(p[0][0],p[1][0]),p[2][0]); + + //to the left, to the right and out of range y, or completely out of range y + if( x < xmin ) return 0; + if( x > xmax && (y > ymax || y < ymin) ) return 0; + if( (y > ymax && y > p[1][1]) || (y < ymin && y < p[1][1]) ) return 0; + + //degenerate line max + if(ymin == ymax && ymax == p[1][1]) + return 0; + + //degenerate accept - to the right and crossing the base line + if(x > xmax) + { + return (y <= ymax && y >= ymin); + } + + //solve for curve = y + + //real roots: + //0 roots - 0 intersection + //1 root - get x, and figure out x + //2 roots (non-double root) - get 2 xs, and count xs to the left + + //for conic we can assume 1 intersection for monotonic curve + Real a = p[2][1] - 2*p[1][1] + p[0][1], + b = 2*p[1][1] - 2*p[0][1], + c = p[0][1] - y; + + Real t1 = -1, t2 = -1; + + if(a == 0) + { + //linear - easier :) + if(b == 0) return 0; //may not need this check + + t1 = - c / b; //bt + c = 0 solved + }else + { + //2 degree polynomial + Real b2_4ac = b*b - 4*a*c; + + //if there are double/no roots - no intersections (in real #s that is) + if(b2_4ac <= 0) + { + return 0; + } + + b2_4ac = sqrt(b2_4ac); + + t1 = (-b - b2_4ac) / 2*a, + t2 = (-b + b2_4ac) / 2*a; + } + + //calculate number of intersections + if(t1 >= 0 && t1 <= 1) + { + const Real t = t1; + const Real invt = 1 - t; + + //find x val and it counts if it's to the left of the point + const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0]; + const Real dy_t = 2*a*t + b; + + if(dy_t) + { + intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1); + } + } + + if(t2 >= 0 && t2 <= 1) + { + const Real t = t2; + const Real invt = 1 - t; + + //find x val and it counts if it's to the left of the point + const Real xi = invt*invt*p[0][0] + 2*t*invt*p[1][0] + t*t*p[2][0]; + const Real dy_t = 2*a*t + b; + + if(dy_t) + { + intersects += (x >= xi) * ( dy_t > 0 ? 1 : -1); + } + } + + return intersects; + } + + static int quadratic_eqn(Real a, Real b, Real c, Real *t0, Real *t1) + { + const Real b2_4ac = b*b - 4*a*c; + + //degenerate reject (can't take sqrt) + if(b2_4ac < 0) + { + return 0; + } + + const Real sqrtb2_4ac = sqrt(b2_4ac); + const Real signb = b < 0 ? -1 : 1; + const Real q = - 0.5 * (b + signb * sqrtb2_4ac); + + *t0 = q/a; + *t1 = c/q; + + return sqrtb2_4ac == 0 ? 1 : 2; + } + + /* TODO: function not finished - no return value. To remove? + //Newton-Raphson root polishing (we don't care about bounds, assumes very near the desired root) + static Real polish_cubicroot(Real a, Real b, Real c, Real d, Real t, Real *dpdt) + { + const Real cn[4] = {a,b,c,d}; + Real p,dp,newt,oldpmag=FLT_MAX; + + //eval cubic eqn and its derivative + for(;;) + { + p = cn[0]*t + cn[1]; + dp = cn[0]; + + for(int i = 2; i < 4; i++) + { + dp = p + dp*t; + p = cn[i] + p*t; + } + + if(dp == 0) + { + synfig::warning("polish_cubicroot: Derivative should not vanish!!!"); + return t; + } + + newt = t - p/dp; + + if(newt == t || fabs(p) >= oldpmag) + { + *dpdt = dp; + return t; + } + + t = newt; + oldpmag = fabs(p); + } + } + */ + + static int intersect_cubic(Real x, Real y, Point *p, int /*level*/ = 0) + { + const Real INVALIDROOT = -FLT_MAX; + Real ymin,ymax,xmin,xmax; + Real ymin2,ymax2,ymintot,ymaxtot; + int intersects = 0; + + //sort the overall curve ys and xs - degenerate detection + + //open span for the two end points + ymin = min(p[0][1],p[3][1]); + ymax = max(p[0][1],p[3][1]); + + //other points etc. + ymin2 = min(p[1][1],p[2][1]); + ymax2 = max(p[1][1],p[2][1]); + + ymintot = min(ymin,ymin2); + ymaxtot = max(ymax,ymax2); + + //the entire curve control polygon is in this x range + xmin = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0])); + xmax = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][0])); + + //outside all y boundaries (no intersect) + if( (y > ymaxtot) || (y < ymintot) ) return 0; + + //left of curve (no intersect) + if(x < xmin) return 0; + + //right of curve (and outside base range) + if( x > xmax ) + { + if( (y > ymax) || (y < ymin) ) return 0; + + //degenerate accept - to the right and inside the [ymin,ymax] range (already rejected if out of range) + const Real n = p[3][1] - p[0][1]; + + //extract the sign from the value (we need valid data) + return n < 0 ? -1 : 1; + } + + //degenerate horizontal line max -- doesn't happen enough to check for + if( ymintot == ymaxtot ) return 0; + + //calculate roots: + // can have 0,1,2, or 3 real roots + // if any of them are double then reject the two... + + // y-coefficients for f_y(t) - y = 0 + Real a = p[3][1] - 3*p[2][1] + 3*p[1][1] - p[0][1], + b = 3*p[2][1] - 6*p[1][1] + 3*p[0][1], + c = 3*p[1][1] - 3*p[0][1], + d = p[0][1] - y; + + Real ax = p[3][0] - 3*p[2][0] + 3*p[1][0] - p[0][0], + bx = 3*p[2][0] - 6*p[1][0] + 3*p[0][0], + cx = 3*p[1][0] - 3*p[0][0], + dx = p[0][0]; + + Real t1 = INVALIDROOT, t2 = INVALIDROOT, t3 = INVALIDROOT, t, dydt; + + if(a == 0) + { + //only 2nd degree + if(b == 0) + { + //linear + if(c == 0) return 0; + + t1 = - d / c; //equation devolved into: ct + d = 0 - solve... + }else + { + //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective) + if(quadratic_eqn(a,b,c,&t1,&t2) != 2) return 0; + } + }else + { + //cubic - sigh.... + + //algorithm courtesy of Numerical Recipes in C (algorithm copied from pg. 184/185) + Real an = b / a, + bn = c / a, + cn = d / a; + + //if cn is 0 (or really really close), then we can simplify this... + if(IsZero(cn)) + { + t3 = 0; + + //0 roots = 0 intersections, 1 root = 2 intersections at the same place (0 effective) + if(quadratic_eqn(a,b,c,&t1,&t2) != 2) + { + t1 = t2 = INVALIDROOT; + } + } + else + { + //otherwise run the normal cubic root equation + Real Q = (an*an - 3.0*bn) / 9.0; + Real R = ((2.0*an*an - 9.0*bn)*an + 27.0*cn)/54.0; + + if(R*R < Q*Q*Q) + { + Real theta = acos(R / sqrt(Q*Q*Q)); + + t1 = -2.0*sqrt(Q)*cos(theta/3) - an/3.0; + t2 = -2.0*sqrt(Q)*cos((theta+2*PI)/3.0) - an/3.0; + t3 = -2.0*sqrt(Q)*cos((theta-2*PI)/3.0) - an/3.0; + + //don't need to reorder,l just need to eliminate double/triple roots + //if(t3 == t2 && t1 == t2) t2 = t3 = INVALIDROOT; + if(t3 == t2) t2 = t3 = INVALIDROOT; + if(t1 == t2) t1 = t2 = INVALIDROOT; + if(t1 == t3) t1 = t3 = INVALIDROOT; + }else + { + Real signR = R < 0 ? -1 : 1; + Real A = - signR * pow(signR*R + sqrt(R*R - Q*Q*Q),1/3.0); + + Real B; + if(A == 0) B = 0; + else B = Q / A; + + //single real root in this case + t1 = (A + B) - an/3.0; + } + } + } + + //if(t1 != INVALIDROOT) + { + t = t1;//polish_cubicroot(a,b,c,d,t1,&dydt); + if(t >= 0 && t < 1) + { + //const Real invt = 1 - t; + + //find x val and it counts if it's to the left of the point + const Real xi = ((ax*t + bx)*t + cx)*t + dx; + dydt = (3*a*t + 2*b)*t + c; + + if(dydt) + { + intersects += (x >= xi) * ( dydt > 0 ? 1 : -1); + } + } + } + + //if(t2 != INVALIDROOT) + { + t = t2;//polish_cubicroot(a,b,c,d,t2,&dydt); + if(t >= 0 && t < 1) + { + //const Real invt = 1 - t; + + //find x val and it counts if it's to the left of the point + const Real xi = ((ax*t + bx)*t + cx)*t + dx; + dydt = (3*a*t + 2*b)*t + c; + + if(dydt) + { + intersects += (x >= xi) * ( dydt > 0 ? 1 : -1); + } + } + } + + //if(t3 != INVALIDROOT) + { + t = t3;//polish_cubicroot(a,b,c,d,t3,&dydt); + if(t >= 0 && t < 1) + { + //const Real invt = 1 - t; + + //find x val and it counts if it's to the left of the point + const Real xi = ((ax*t + bx)*t + cx)*t + dx; + dydt = (3*a*t + 2*b)*t + c; + + if(dydt) + { + intersects += (x >= xi) * ( dydt > 0 ? 1 : -1); + } + } + } + + return intersects; + } + + int intersect(Real x,Real y, Point *table) const + { + if((y < aabb.miny) || (y > aabb.maxy) || (x < aabb.minx)) return 0; + + int i, curdeg, intersects = 0; + const int numcurves = degrees.size(); + + vector::const_iterator p = pointlist.begin(); + + for(i=0; i < numcurves; i++) + { + curdeg = degrees[i]; + + switch(curdeg) + { + case 2: + { + table[0] = *p++; + table[1] = *p++; + table[2] = *p; //we want to include the last point for the next curve + + intersects += intersect_conic(x,y,table); + + break; + } + + case 3: + { + table[0] = *p++; + table[1] = *p++; + table[2] = *p++; + table[3] = *p; //we want to include the last point for the next curve + + intersects += intersect_cubic(x,y,table); + + break; + } + + default: + { + warning("Invalid degree (%d) inserted into the list (index: %d)\n", curdeg, i); + return 0; + } + } + } + + return intersects; + } +}; + +struct Layer_Shape::Intersector +{ + Rect aabb; + + //! true iff aabb hasn't been initialized yet + bool initaabb; + + int flags; + + enum IntersectorFlags + { + NotClosed = 0x8000 + }; + + enum PrimitiveType + { + TYPE_NONE = 0, + TYPE_LINE, + TYPE_CURVE + }; + + Real cur_x,cur_y; + Real close_x,close_y; + + vector segs; //monotonically increasing + vector curves; //big array of consecutive curves + + int prim; + Vector tangent; + + Intersector() + { + clear(); + } + + bool notclosed() + { + return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y); + } + + void move_to(Real x, Real y) + { + close(); + + close_x = cur_x = x; + close_y = cur_y = y; + + tangent[0] = tangent[1] = 0; + + if(initaabb) + { + aabb.set_point(x,y); + initaabb = false; + }else aabb.expand(x,y); + + prim = TYPE_NONE; + } + + void line_to(Real x, Real y) + { + int dir = (y > cur_y)*1 + (-1)*(y < cur_y); + + //check for context (if not line start a new segment) + //if we're not in line mode (covers 0 set case), or if directions are different (not valid for 0 direction) + if(prim != TYPE_LINE || (dir && segs.back().ydir != dir)) + { + MonoSegment seg(dir,x,x,y,y); + + seg.aabb.expand(cur_x,cur_y); + seg.pointlist.push_back(Point(cur_x,cur_y)); + seg.pointlist.push_back(Point(x,y)); + segs.push_back(seg); + } + //add to the last segment, because it works + else + { + segs.back().pointlist.push_back(Point(x,y)); + segs.back().aabb.expand(x,y); + } + + + + cur_x = x; + cur_y = y; + aabb.expand(x,y); //expand the entire thing's bounding box + + tangent[0] = x - cur_x; + tangent[1] = x - cur_y; + + flags |= NotClosed; + prim = TYPE_LINE; + } + + void conic_to_smooth(Real x, Real y) + { + const Real x1 = tangent[0]/2.0 + cur_x; + const Real y1 = tangent[1]/2.0 + cur_y; + + conic_to(x1,y1,x,y); + } + + void conic_to(Real x1, Real y1, Real x, Real y) + { + //if we're not already a curve start one + if(prim != TYPE_CURVE) + { + CurveArray c; + + c.Start(Point(cur_x,cur_y)); + c.AddConic(Point(x1,y1),Point(x,y)); + + curves.push_back(c); + }else + { + curves.back().AddConic(Point(x1,y1),Point(x,y)); + } + + cur_x = x; + cur_y = y; + + aabb.expand(x1,y1); + aabb.expand(x,y); + + tangent[0] = 2*(x - x1); + tangent[1] = 2*(y - y1); + + flags |= NotClosed; + prim = TYPE_CURVE; + } + + void curve_to_smooth(Real x2, Real y2, Real x, Real y) + { + Real x1 = tangent[0]/3.0 + cur_x; + Real y1 = tangent[1]/3.0 + cur_y; + + curve_to(x1,y1,x2,y2,x,y); + } + + void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y) + { + //if we're not already a curve start one + if(prim != TYPE_CURVE) + { + CurveArray c; + + c.Start(Point(cur_x,cur_y)); + c.AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y)); + + curves.push_back(c); + }else + { + curves.back().AddCubic(Point(x1,y1),Point(x2,y2),Point(x,y)); + } + + cur_x = x; + cur_y = y; + + //expand bounding box around ALL of it + aabb.expand(x1,y1); + aabb.expand(x2,y2); + aabb.expand(x,y); + + tangent[0] = 3*(x - x2); + tangent[1] = 3*(y - y2); + + flags |= NotClosed; + prim = TYPE_CURVE; + } + + void close() + { + if(flags & NotClosed) + { + if(cur_x != close_x || cur_y != close_y) + { + line_to(close_x,close_y); + } + + flags &= ~NotClosed; + } + } + + //assumes the line to count the intersections with is (-1,0) + int intersect (Real x, Real y) const + { + int inter = 0; + unsigned int i; + vector::const_iterator s = segs.begin(); + vector::const_iterator c = curves.begin(); + + Point memory[3*MAX_SUBDIVISION_SIZE + 1]; + + for(i = 0; i < segs.size(); i++,s++) + { + inter += s->intersect(x,y); + } + + for(i=0; i < curves.size(); i++,c++) + inter += c->intersect(x,y,memory); + + return inter; + } + + //intersect an arbitrary line + //int intersect (Real x, Real y, Real vx, Real vy) {return 0;} + + void clear() + { + segs.clear(); + curves.clear(); + + flags = 0; + cur_x = cur_y = close_x = close_y = 0; + prim = TYPE_NONE; + tangent[0] = tangent[1] = 0; + initaabb = true; + } +}; + +//*********** SCANLINE RENDERER SUPPORT STRUCTURES *************** +struct PenMark +{ + int y,x; + Real cover,area; + + PenMark(): y(), x(), cover(), area() {} + PenMark(int xin, int yin, Real c, Real a) + :y(yin),x(xin),cover(c),area(a) {} + + void set(int xin, int yin, Real c, Real a) { y = yin; x = xin; cover = c; area = a; } + + void setcoord(int xin, int yin) { y = yin; x = xin; } + + void setcover(Real c, Real a) { cover = c; area = a; } + void addcover(Real c, Real a) { cover += c; area += a; } + + bool operator<(const PenMark &rhs) const + { + return y == rhs.y ? x < rhs.x : y < rhs.y; + } +}; + +typedef rect ContextRect; + +class Layer_Shape::PolySpan +{ +public: + typedef vector cover_array; + + Point arc[3*MAX_SUBDIVISION_SIZE + 1]; + + cover_array covers; + PenMark current; + + int open_index; + + //ending position of last primitive + Real cur_x; + Real cur_y; + + //starting position of current primitive list + Real close_x; + Real close_y; + + //flags for the current segment + int flags; + + //the window that will be drawn (used for clipping) + ContextRect window; + + //for assignment to flags value + enum PolySpanFlags + { + NotSorted = 0x8000, + NotClosed = 0x4000 + }; + + //default constructor - 0 everything + PolySpan() :current(0,0,0,0),flags(NotSorted) + { + cur_x = cur_y = close_x = close_y = 0; + open_index = 0; + } + + bool notclosed() const + { + return (flags & NotClosed) || (cur_x != close_x) || (cur_y != close_y); + } + + //0 out all the variables involved in processing + void clear() + { + covers.clear(); + cur_x = cur_y = close_x = close_y = 0; + open_index = 0; + current.set(0,0,0,0); + flags = NotSorted; + } + + //add the current cell, but only if there is information to add + void addcurrent() + { + if(current.cover || current.area) + { + if (covers.size() == covers.capacity()) + covers.reserve(covers.size() + 1024*1024); + covers.push_back(current); + } + } + + //move to the next cell (cover values 0 initially), keeping the current if necessary + void move_pen(int x, int y) + { + if(y != current.y || x != current.x) + { + addcurrent(); + current.set(x,y,0,0); + } + } + + //close the primitives with a line (or rendering will not work as expected) + void close() + { + if(flags & NotClosed) + { + if(cur_x != close_x || cur_y != close_y) + { + line_to(close_x,close_y); + addcurrent(); + current.setcover(0,0); + } + flags &= ~NotClosed; + } + } + + // Not recommended - destroys any separation of spans currently held + void merge_all() + { + sort(covers.begin(),covers.end()); + open_index = 0; + } + + //will sort the marks if they are not sorted + void sort_marks() + { + if(flags & NotSorted) + { + //only sort the open index + addcurrent(); + current.setcover(0,0); + + sort(covers.begin() + open_index,covers.end()); + flags &= ~NotSorted; + } + } + + //encapsulate the current sublist of marks (used for drawing) + void encapsulate_current() + { + //sort the current list then reposition the open list section + sort_marks(); + open_index = covers.size(); + } + + //move to start a new primitive list (enclose the last primitive if need be) + void move_to(Real x, Real y) + { + close(); + if(isnan(x))x=0; + if(isnan(y))y=0; + move_pen((int)floor(x),(int)floor(y)); + close_y = cur_y = y; + close_x = cur_x = x; + } + + //primitive_to functions + void line_to(Real x, Real y); + void conic_to(Real x1, Real y1, Real x, Real y); + void cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y); + + void draw_scanline(int y, Real x1, Real y1, Real x2, Real y2); + void draw_line(Real x1, Real y1, Real x2, Real y2); + + Real ExtractAlpha(Real area, WindingStyle winding_style) + { + if (area < 0) + area = -area; + + if (winding_style == WINDING_NON_ZERO) + { + // non-zero winding style + if (area > 1) + return 1; + } + else // if (winding_style == WINDING_EVEN_ODD) + { + // even-odd winding style + while (area > 1) + area -= 2; + + // want pyramid like thing + if (area < 0) + area = -area; + } + + return area; + } +}; + +/* === M E T H O D S ======================================================= */ + +Layer_Shape::Layer_Shape(const Real &a, const Color::BlendMethod m): + Layer_Composite (a,m), + edge_table (new Intersector), + param_color (Color::black()), + param_origin (Vector(0,0)), + param_invert (bool(false)), + param_antialias (bool(true)), + param_blurtype (int(Blur::FASTGAUSSIAN)), + param_feather (Real(0.0)), + param_winding_style (int(WINDING_NON_ZERO)), + bytestream (0), + lastbyteop (Primitive::NONE), + lastoppos (-1) +{ +} + +Layer_Shape::~Layer_Shape() +{ + delete edge_table; +} + +void +Layer_Shape::clear() +{ + edge_table->clear(); + bytestream.clear(); +} + +bool +Layer_Shape::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE_PLUS(param_color, + { + Color color=param_color.get(Color()); + if (color.get_a() == 0) + { + if (converted_blend_) + { + set_blend_method(Color::BLEND_ALPHA_OVER); + color.set_a(1); + } + else + transparent_color_ = true; + } + param_color.set(color); + } + ); + IMPORT_VALUE(param_origin); + IMPORT_VALUE(param_invert); + IMPORT_VALUE(param_antialias); + IMPORT_VALUE_PLUS(param_feather, + { + Real feather=param_feather.get(Real()); + if(feather<0) + { + feather=0; + param_feather.set(feather); + } + } + ); + + IMPORT_VALUE(param_blurtype); + IMPORT_VALUE(param_winding_style); + + if(param=="offset" && param_origin.get_type() == value.get_type()) + { + param_origin=value; + return true; + } + return Layer_Composite::set_param(param,value); +} + +ValueBase +Layer_Shape::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_color); + EXPORT_VALUE(param_origin); + EXPORT_VALUE(param_invert); + EXPORT_VALUE(param_antialias); + EXPORT_VALUE(param_feather); + EXPORT_VALUE(param_blurtype); + EXPORT_VALUE(param_winding_style); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Composite::get_param(param); +} + +Layer::Vocab +Layer_Shape::get_param_vocab()const +{ + Layer::Vocab ret(Layer_Composite::get_param_vocab()); + + ret.push_back(ParamDesc("color") + .set_local_name(_("Color")) + .set_description(_("Layer_Shape Color")) + ); + ret.push_back(ParamDesc("origin") + .set_local_name(_("Origin")) + ); + ret.push_back(ParamDesc("invert") + .set_local_name(_("Invert")) + ); + ret.push_back(ParamDesc("antialias") + .set_local_name(_("Antialiasing")) + ); + ret.push_back(ParamDesc("feather") + .set_local_name(_("Feather")) + .set_is_distance() + ); + ret.push_back(ParamDesc("blurtype") + .set_local_name(_("Type of Feather")) + .set_description(_("Type of feathering to use")) + .set_hint("enum") + .add_enum_value(Blur::BOX,"box",_("Box Blur")) + .add_enum_value(Blur::FASTGAUSSIAN,"fastgaussian",_("Fast Gaussian Blur")) + .add_enum_value(Blur::CROSS,"cross",_("Cross-Hatch Blur")) + .add_enum_value(Blur::GAUSSIAN,"gaussian",_("Gaussian Blur")) + .add_enum_value(Blur::DISC,"disc",_("Disc Blur")) + ); + ret.push_back(ParamDesc("winding_style") + .set_local_name(_("Winding Style")) + .set_description(_("Winding style to use")) + .set_hint("enum") + .add_enum_value(WINDING_NON_ZERO,"nonzero",_("Non Zero")) + .add_enum_value(WINDING_EVEN_ODD,"evenodd",_("Even/Odd")) + ); + + return ret; +} + +synfig::Layer::Handle +Layer_Shape::hit_check(synfig::Context context, const synfig::Point &p)const +{ + Color color=param_color.get(Color()); + Point origin=param_origin.get(Point()); + bool invert =param_invert.get(bool(true)); + + Point pos(p-origin); + + int intercepts = edge_table->intersect(pos[0],pos[1]); + + // If we have an odd number of intercepts, we are inside. + // If we have an even number of intercepts, we are outside. + bool intersect = ((!!intercepts) ^ invert); + + if(get_amount() == 0 || get_blend_method() == Color::BLEND_ALPHA_OVER) + { + intersect = false; + } + + if(intersect) + { + synfig::Layer::Handle tmp; + if(get_blend_method()==Color::BLEND_BEHIND && (tmp=context.hit_check(p))) + return tmp; + if(Color::is_onto(get_blend_method())) + { + //if there's something in the lower layer then we're set... + if(!context.hit_check(p).empty()) + return const_cast(this); + }else if(get_blend_method() == Color::BLEND_ALPHA_OVER) + { + synfig::info("layer_shape::hit_check - we've got alphaover"); + //if there's something in the lower layer then we're set... + if(color.get_a() < 0.1 && get_amount() > .9) + { + synfig::info("layer_shape::hit_check - can see through us... so nothing"); + return Handle(); + }else return context.hit_check(p); + }else + return const_cast(this); + } + + return context.hit_check(p); +} + +Color +Layer_Shape::get_color(Context context, const Point &p)const +{ + Color color=param_color.get(Color()); + Point origin=param_origin.get(Point()); + bool invert =param_invert.get(bool(true)); + int blurtype=param_blurtype.get(int()); + Real feather=param_feather.get(Real()); + + Point pp = p; + + if(feather) + pp = Blur(feather,feather,blurtype)(p); + + Point pos(pp-origin); + + int intercepts = edge_table->intersect(pos[0],pos[1]); + + // If we have an odd number of intercepts, we are inside. + // If we have an even number of intercepts, we are outside. + bool intersect = ((!!intercepts) ^ invert); + + if(!intersect) + return Color::blend(Color::alpha(),context.get_color(pp),get_amount(),get_blend_method()); + + //Ok, we're inside... bummmm ba bum buM... + if(get_blend_method() == Color::BLEND_STRAIGHT && get_amount() == 1) + return color; + else + return Color::blend(color,context.get_color(p),get_amount(),get_blend_method()); +} + +//************** SCANLINE RENDERING ********************* +void Layer_Shape::PolySpan::line_to(Real x, Real y) +{ + Real n[4] = {0,0,0,0}; + bool afterx = false; + + const Real xin(x), yin(y); + + Real dx = x - cur_x; + Real dy = y - cur_y; + + //CLIP IT!!!! + try { + //outside y - ignore entirely + if( (cur_y >= window.maxy && y >= window.maxy) + ||(cur_y < window.miny && y < window.miny) ) + { + cur_x = x; + cur_y = y; + } + else //not degenerate - more complicated + { + if(dy > 0) //be sure it's not tooooo small + { + // cur_y ... window.miny ... window.maxy ... y + + //initial degenerate - initial clip + if(cur_y < window.miny) + { + //new clipped start point (must also move pen) + n[2] = cur_x + (window.miny - cur_y) * dx / dy; + + cur_x = n[2]; + cur_y = window.miny; + move_pen((int)floor(cur_x),window.miny); + } + + //generate data for the ending clipped info + if(y > window.maxy) + { + //initial line to intersection (and degenerate) + n[2] = x + (window.maxy - y) * dx / dy; + + //intersect coords + x = n[2]; + y = window.maxy; + } + } + else + { + //initial degenerate - initial clip + if(cur_y > window.maxy) + { + //new clipped start point (must also move pen) + n[2] = cur_x + (window.maxy - cur_y) * dx / dy; + + cur_x = n[2]; + cur_y = window.maxy; + move_pen((int)floor(cur_x),window.maxy); + } + + //generate data for the ending clipped info + if(y < window.miny) + { + //initial line to intersection (and degenerate) + n[2] = x + (window.miny - y) * dx / dy; + + //intersect coords + x = n[2]; + y = window.miny; + } + } + + //all degenerate - but require bounded clipped values + if( (cur_x >= window.maxx && x >= window.maxx) + ||(cur_x < window.minx && x < window.minx) ) + { + //clip both vertices - but only needed in the x direction + cur_x = max(cur_x, (Real)window.minx); + cur_x = min(cur_x, (Real)window.maxx); + + //clip the dest values - y is already clipped + x = max(x,(Real)window.minx); + x = min(x,(Real)window.maxx); + + //must start at new point... + move_pen((int)floor(cur_x),(int)floor(cur_y)); + + draw_line(cur_x,cur_y,x,y); + + cur_x = xin; + cur_y = yin; + } + else + { + //clip x + if(dx > 0) + { + //initial degenerate - initial clip + if(cur_x < window.minx) + { + //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty + n[2] = cur_y + (window.minx - cur_x) * dy / dx; + + move_pen(window.minx,(int)floor(cur_y)); + draw_line(window.minx,cur_y,window.minx,n[2]); + + cur_x = window.minx; + cur_y = n[2]; + } + + //generate data for the ending clipped info + if(x > window.maxx) + { + //initial line to intersection (and degenerate) + n[2] = y + (window.maxx - x) * dy / dx; + + n[0] = window.maxx; + n[1] = y; + + //intersect coords + x = window.maxx; + y = n[2]; + afterx = true; + } + }else + { + //initial degenerate - initial clip + if(cur_x > window.maxx) + { + //need to draw an initial segment from clippedx,cur_y to clippedx,intersecty + n[2] = cur_y + (window.maxx - cur_x) * dy / dx; + + move_pen(window.maxx,(int)floor(cur_y)); + draw_line(window.maxx,cur_y,window.maxx,n[2]); + + cur_x = window.maxx; + cur_y = n[2]; + } + + //generate data for the ending clipped info + if(x < window.minx) + { + //initial line to intersection (and degenerate) + n[2] = y + (window.minx - x) * dy / dx; + + n[0] = window.minx; + n[1] = y; + + //intersect coords + x = window.minx; + y = n[2]; + afterx = true; + } + } + + move_pen((int)floor(cur_x),(int)floor(cur_y)); + //draw the relevant line (clipped) + draw_line(cur_x,cur_y,x,y); + + if(afterx) + { + draw_line(x,y,n[0],n[1]); + } + + cur_x = xin; + cur_y = yin; + } + } + } catch(...) { synfig::error("line_to: cur_x=%f, cur_y=%f, x=%f, y=%f", cur_x, cur_y, x, y); throw; } + + flags |= NotClosed|NotSorted; +} + +static inline bool clip_conic(const Point *const p, const ContextRect &r) +{ + const Real minx = min(min(p[0][0],p[1][0]),p[2][0]); + const Real miny = min(min(p[0][1],p[1][1]),p[2][1]); + const Real maxx = max(max(p[0][0],p[1][0]),p[2][0]); + const Real maxy = max(max(p[0][1],p[1][1]),p[2][1]); + + return (minx > r.maxx) || + (maxx < r.minx) || + (miny > r.maxy) || + (maxy < r.miny); +} + +static inline bool clip_cubic(const Point *const p, const ContextRect &r) +{ + /*const Real minx = min(min(p[0][0],p[1][0]),min(p[2][0],p[3][0])); + const Real miny = min(min(p[0][1],p[1][1]),min(p[2][1],p[3][1])); + const Real maxx = max(max(p[0][0],p[1][0]),max(p[2][0],p[3][1])); + const Real maxy = max(max(p[0][1],p[1][1]),max(p[2][1],p[3][1])); + + return (minx > r.maxx) || + (maxx < r.minx) || + (miny > r.maxy) || + (maxy < r.miny);*/ + + return ((p[0][0] > r.maxx) && (p[1][0] > r.maxx) && (p[2][0] > r.maxx) && (p[3][0] > r.maxx)) || + ((p[0][0] < r.minx) && (p[1][0] < r.minx) && (p[2][0] < r.minx) && (p[3][0] < r.minx)) || + ((p[0][1] > r.maxy) && (p[1][1] > r.maxy) && (p[2][1] > r.maxy) && (p[3][1] > r.maxy)) || + ((p[0][1] < r.miny) && (p[1][1] < r.miny) && (p[2][1] < r.miny) && (p[3][1] < r.miny)); +} + +static inline Real max_edges_cubic(const Point *const p) +{ + const Real x1 = p[1][0] - p[0][0]; + const Real y1 = p[1][1] - p[0][1]; + + const Real x2 = p[2][0] - p[1][0]; + const Real y2 = p[2][1] - p[1][1]; + + const Real x3 = p[3][0] - p[2][0]; + const Real y3 = p[3][1] - p[2][1]; + + const Real d1 = x1*x1 + y1*y1; + const Real d2 = x2*x2 + y2*y2; + const Real d3 = x3*x3 + y3*y3; + + return max(max(d1,d2),d3); +} + +static inline Real max_edges_conic(const Point *const p) +{ + const Real x1 = p[1][0] - p[0][0]; + const Real y1 = p[1][1] - p[0][1]; + + const Real x2 = p[2][0] - p[1][0]; + const Real y2 = p[2][1] - p[1][1]; + + const Real d1 = x1*x1 + y1*y1; + const Real d2 = x2*x2 + y2*y2; + + return max(d1,d2); +} + +void Layer_Shape::PolySpan::conic_to(Real x1, Real y1, Real x, Real y) +{ + Point *current = arc; + int level = 0; + int num = 0; + bool onsecond = false; + + arc[0] = Point(x,y); + arc[1] = Point(x1,y1); + arc[2] = Point(cur_x,cur_y); + + //just draw the line if it's outside + if(clip_conic(arc,window)) + { + line_to(x,y); + return; + } + + //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first) + while(current >= arc) + { + if(num >= MAX_SUBDIVISION_SIZE) + { + warning("Curve subdivision somehow ran out of space while tessellating!"); + + //do something... + assert(0); + return; + }else + //if the curve is clipping then draw degenerate + if(clip_conic(current,window)) + { + line_to(current[0][0],current[0][1]); //backwards so front is destination + current -= 2; + if(onsecond) level--; + onsecond = true; + num--; + continue; + }else + //if we are not at the level minimum + if(level < MIN_SUBDIVISION_DRAW_LEVELS) + { + Subd_Conic_Stack(current); + current += 2; //cursor on second curve + level ++; + num ++; + onsecond = false; + continue; + }else + //split it again, if it's too big + if(max_edges_conic(current) > 0.25) //distance of .5 (cover no more than half the pixel) + { + Subd_Conic_Stack(current); + current += 2; //cursor on second curve + level ++; + num ++; + onsecond = false; + } + else //NOT TOO BIG? RENDER!!! + { + //cur_x,cur_y = current[2], so we need to go 1,0 + line_to(current[1][0],current[1][1]); + line_to(current[0][0],current[0][1]); + + current -= 2; + if(onsecond) level--; + num--; + onsecond = true; + } + } +} + +void Layer_Shape::PolySpan::cubic_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y) +{ + Point *current = arc; + int num = 0; + int level = 0; + bool onsecond = false; + + arc[0] = Point(x,y); + arc[1] = Point(x2,y2); + arc[2] = Point(x1,y1); + arc[3] = Point(cur_x,cur_y); + + //just draw the line if it's outside + if(clip_cubic(arc,window)) + { + line_to(x,y); + return; + } + + //Ok so it's not super degenerate, subdivide and draw (run through minimum subdivision levels first) + while(current >= arc) //once current goes below arc, there are no more curves left + { + if(num >= MAX_SUBDIVISION_SIZE) + { + warning("Curve subdivision somehow ran out of space while tessellating!"); + + //do something... + assert(0); + return; + }else + + //if we are not at the level minimum + if(level < MIN_SUBDIVISION_DRAW_LEVELS) + { + Subd_Cubic_Stack(current); + current += 3; //cursor on second curve + level ++; + num ++; + onsecond = false; + continue; + }else + //if the curve is clipping then draw degenerate + if(clip_cubic(current,window)) + { + line_to(current[0][0],current[0][1]); //backwards so front is destination + current -= 3; + if(onsecond) level--; + onsecond = true; + num --; + continue; + } + else + //split it again, if it's too big + if(max_edges_cubic(current) > 0.25) //could use max_edges<3> + { + Subd_Cubic_Stack(current); + current += 3; //cursor on second curve + level ++; + num ++; + onsecond = false; + } + else //NOT TOO BIG? RENDER!!! + { + //cur_x,cur_y = current[3], so we need to go 2,1,0 + line_to(current[2][0],current[2][1]); + line_to(current[1][0],current[1][1]); + line_to(current[0][0],current[0][1]); + + current -= 3; + if(onsecond) level--; + num --; + onsecond = true; + } + } +} + +//******************** LINE ALGORITHMS **************************** +// THESE CALCULATE THE AREA AND THE COVER FOR THE MARKS, TO THEN SCAN CONVERT +// - BROKEN UP INTO SCANLINES (draw_line - y intersections), +// THEN THE COVER AND AREA PER TOUCHED PIXEL IS CALCULATED (draw_scanline - x intersections) +void Layer_Shape::PolySpan::draw_scanline(int y, Real x1, Real fy1, Real x2, Real fy2) +{ + int ix1 = (int)floor(x1); + int ix2 = (int)floor(x2); + Real fx1 = x1 - ix1; + Real fx2 = x2 - ix2; + + Real dx,dy,dydx,mult; + + dx = x2 - x1; + dy = fy2 - fy1; + + //case horizontal line + if(fy1 == fy2) + { + move_pen(ix2,y); //pen needs to be at the last coord + return; + } + + //case all in same pixel + if(ix1 == ix2) //impossible for degenerate case (covered by the previous cases) + { + current.addcover(dy,(fx1 + fx2)*dy/2); //horizontal trapezoid area + return; + } + + if(dx > 0) + { + // ----> fx1...1 0...1 ... 0...1 0...fx2 + dydx = dy / dx; + + //set initial values + //Iterate through the covered pixels + mult = (1 - fx1)*dydx; //next y intersection diff value (at 1) + + //first pixel + current.addcover(mult,(1 + fx1)*mult/2); // fx1,fy1,1,fy@1 - starting trapezoidal area + + //move to the next pixel + fy1 += mult; + ix1++; + + move_pen(ix1,y); + + //set up for whole ones + while(ix1 != ix2) + { + //trapezoid(0,y1,1,y1+dydx); + current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover + + //move to next pixel (+1) + ix1++; + fy1 += dydx; + move_pen(ix1,y); + } + + //last pixel + //final y-pos - last intersect pos + mult = fx2 * dydx; + current.addcover(mult,(0+fx2)*mult/2); + }else + { + // fx2...1 0...1 ... 0...1 0...fx1 <---- + //mult = (0 - fx1) * dy / dx; + //neg sign sucked into dydx + dydx = -dy / dx; + + //set initial values + //Iterate through the covered pixels + mult = fx1*dydx; //next y intersection diff value + + //first pixel + current.addcover(mult,fx1*mult/2); // fx1,fy1,0,fy@0 - starting trapezoidal area + + //move to next pixel + fy1 += mult; + ix1--; + + move_pen(ix1,y); + + //set up for whole ones + while(ix1 != ix2) + { + //trapezoid(0,y1,1,y1+dydx); + current.addcover(dydx,dydx/2); //accumulated area 1/2 the cover + + //move to next pixel (-1) + fy1 += dydx; + ix1--; + move_pen(ix1,y); + } + + //last pixel + mult = fy2 - fy1; //final y-pos - last intersect pos + + current.addcover(mult,(fx2+1)*mult/2); + } +} + +void Layer_Shape::PolySpan::draw_line(Real x1, Real y1, Real x2, Real y2) +{ + int iy1 = (int)floor(y1); + int iy2 = (int)floor(y2); + Real fy1 = y1 - iy1; + Real fy2 = y2 - iy2; + + assert(!isnan(fy1)); + assert(!isnan(fy2)); + + Real dx,dy,dxdy,mult,x_from,x_to; + + const Real SLOPE_EPSILON = 1e-10; + + //case all one scanline + if(iy1 == iy2) + { + draw_scanline(iy1,x1,y1,x2,y2); + return; + } + + //difference values + dy = y2 - y1; + dx = x2 - x1; + + //case vertical line + if(dx < SLOPE_EPSILON && dx > -SLOPE_EPSILON) + { + //calc area and cover on vertical line + if(dy > 0) + { + // ----> fx1...1 0...1 ... 0...1 0...fx2 + Real sub; + + int ix1 = (int)floor(x1); + Real fx1 = x1 - ix1; + + //current pixel + sub = 1 - fy1; + + current.addcover(sub,fx1*sub); + + //next pixel + iy1++; + + //move pen to next pixel + move_pen(ix1,iy1); + + while(iy1 != iy2) + { + //accumulate cover + current.addcover(1,fx1); + + //next pixel + iy1++; + move_pen(ix1,iy1); + } + + //last pixel + current.addcover(fy2,fy2*fx1); + }else + { + Real sub; + + int ix1 = (int)floor(x1); + Real fx1 = x1 - ix1; + + //current pixel + sub = 0 - fy1; + + current.addcover(sub,fx1*sub); + + //next pixel + iy1--; + + move_pen(ix1,iy1); + + while(iy1 != iy2) + { + //accumulate in current pixel + current.addcover(-1,-fx1); + + //move to next + iy1--; + move_pen(ix1,iy1); + } + + current.addcover(fy2-1,(fy2-1)*fx1); + } + return; + } + + //case normal line - guaranteed dx != 0 && dy != 0 + + //calculate the initial intersection with "next" scanline + if(dy > 0) + { + dxdy = dx / dy; + + mult = (1 - fy1) * dxdy; + + //x intersect scanline + x_from = x1 + mult; + draw_scanline(iy1,x1,fy1,x_from,1); + + //move to next line + iy1++; + + move_pen((int)floor(x_from),iy1); + + while(iy1 != iy2) + { + //keep up on the x axis, and render the current scanline + x_to = x_from + dxdy; + draw_scanline(iy1,x_from,0,x_to,1); + x_from = x_to; + + //move to next pixel + iy1++; + move_pen((int)floor(x_from),iy1); + } + + //draw the last one, fractional + draw_scanline(iy2,x_from,0,x2,fy2); + + }else + { + dxdy = -dx / dy; + + mult = fy1 * dxdy; + + //x intersect scanline + x_from = x1 + mult; + draw_scanline(iy1,x1,fy1,x_from,0); + + //each line after + iy1--; + + move_pen((int)floor(x_from),iy1); + + while(iy1 != iy2) + { + x_to = x_from + dxdy; + draw_scanline(iy1,x_from,1,x_to,0); + x_from = x_to; + + iy1--; + move_pen((int)floor(x_from),iy1); + } + //draw the last one, fractional + draw_scanline(iy2,x_from,1,x2,fy2); + } +} + +//****** LAYER PEN OPERATIONS (move_to, line_to, etc.) ****** +void Layer_Shape::move_to(Real x, Real y) +{ + //const int sizeblock = sizeof(Primitive)+sizeof(Point); + Primitive op; + Point p(x,y); + + op.operation = Primitive::MOVE_TO; + op.number = 1; //one point for now + + if(lastbyteop == Primitive::MOVE_TO) + { + char *ptr = &bytestream[lastoppos]; + memcpy(ptr,&op,sizeof(op)); + memcpy(ptr+sizeof(op),&p,sizeof(p)); + } + else //make a new op + { + lastbyteop = Primitive::MOVE_TO; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data + } + + edge_table->move_to(x,y); +} + +void Layer_Shape::close() +{ + Primitive op; + + op.operation = Primitive::CLOSE; + op.number = 0; + + if(lastbyteop == Primitive::CLOSE) + { + }else + { + lastbyteop = Primitive::CLOSE; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert header + } + + edge_table->close(); + //should not affect the bounding box since it would just be returning to old point... +} + +void Layer_Shape::endpath() +{ + Primitive op; + + op.operation = Primitive::END; + op.number = 0; + + if(lastbyteop == Primitive::END || lastbyteop == Primitive::NONE) + { + }else + { + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); + } + //should not affect the bounding box since it would just be returning to old point... if at all +} + +void Layer_Shape::line_to(Real x, Real y) +{ + assert(!isnan(x)); + assert(!isnan(y)); + + //const int sizeblock = sizeof(Primitive)+sizeof(Point); + Primitive op; + Point p(x,y); + + op.operation = Primitive::LINE_TO; + op.number = 1; //one point for now + + if(lastbyteop == Primitive::MOVE_TO || lastbyteop == Primitive::LINE_TO) + { + //only need to insert the point + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); + + Primitive * prim = (Primitive *)&bytestream[lastoppos]; + prim->number++; //increment number of points in the list + }else + { + lastbyteop = Primitive::LINE_TO; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data + } + + edge_table->line_to(x,y); +} + +void Layer_Shape::conic_to(Real x1, Real y1, Real x, Real y) +{ + //const int sizeblock = sizeof(Primitive)+sizeof(Point)*2; + Primitive op; + Point p(x,y); + Point p1(x1,y1); + + op.operation = Primitive::CONIC_TO; + op.number = 2; //2 points for now + + if(lastbyteop == Primitive::CONIC_TO) + { + //only need to insert the new points + bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); + + Primitive * prim = (Primitive *)&bytestream[lastoppos]; + prim->number += 2; //increment number of points in the list + }else + { + lastbyteop = Primitive::CONIC_TO; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header + bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data + } + + edge_table->conic_to(x1,y1,x,y); +} + +void Layer_Shape::conic_to_smooth(Real x, Real y) //x1,y1 derived from current tangent +{ + //const int sizeblock = sizeof(Primitive)+sizeof(Point); + Primitive op; + Point p(x,y); + + op.operation = Primitive::CONIC_TO_SMOOTH; + op.number = 1; //2 points for now + + if(lastbyteop == Primitive::CONIC_TO_SMOOTH) + { + //only need to insert the new point + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); + + Primitive * prim = (Primitive *)&bytestream[lastoppos]; + prim->number += 1; //increment number of points in the list + }else + { + lastbyteop = Primitive::CONIC_TO_SMOOTH; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data + } + + edge_table->conic_to_smooth(x,y); +} + +void Layer_Shape::curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y) +{ + //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3; + Primitive op; + Point p(x,y); + Point p1(x1,y1); + Point p2(x2,y2); + + op.operation = Primitive::CUBIC_TO; + op.number = 3; //3 points for now + + if(lastbyteop == Primitive::CUBIC_TO) + { + //only need to insert the new points + bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); + bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); + + Primitive * prim = (Primitive *)&bytestream[lastoppos]; + prim->number += 3; //increment number of points in the list + }else + { + lastbyteop = Primitive::CUBIC_TO; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header + bytestream.insert(bytestream.end(),(char*)&p1,(char*)(&p1+1)); //insert the bytes for data + bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data + } + + edge_table->curve_to(x1,y1,x2,y2,x,y); +} + +void Layer_Shape::curve_to_smooth(Real x2, Real y2, Real x, Real y) //x1,y1 derived from current tangent +{ + //const int sizeblock = sizeof(Primitive)+sizeof(Point)*3; + Primitive op; + Point p(x,y); + Point p2(x2,y2); + + op.operation = Primitive::CUBIC_TO_SMOOTH; + op.number = 2; //3 points for now + + if(lastbyteop == Primitive::CUBIC_TO_SMOOTH) + { + //only need to insert the new points + bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); + + Primitive * prim = (Primitive *)&bytestream[lastoppos]; + prim->number += 2; //increment number of points in the list + }else + { + lastbyteop = Primitive::CUBIC_TO_SMOOTH; + lastoppos = bytestream.size(); + + bytestream.insert(bytestream.end(),(char*)&op,(char*)(&op+1)); //insert the bytes for the header + bytestream.insert(bytestream.end(),(char*)&p2,(char*)(&p2+1)); //insert the bytes for data + bytestream.insert(bytestream.end(),(char*)&p,(char*)(&p+1)); //insert the bytes for data + } +} + +// ACCELERATED RENDER FUNCTION - TRANSLATE BYTE CODE INTO FUNCTION CALLS + +bool Layer_Shape::render_polyspan( + Surface *surface, + PolySpan &polyspan, + Color::value_type amount, + Color::BlendMethod blend_method, + const Color &color, + bool invert, + bool antialias, + WindingStyle winding_style ) const +{ + Surface::alpha_pen p(surface->begin(), amount, blend_method); + PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin(); + PolySpan::cover_array::iterator end_mark = polyspan.covers.end(); + + Real cover,area,alpha; + + int y,x; + + p.set_value(color); + cover = 0; + + if(cur_mark == end_mark) + { + //no marks at all + if(invert) + { + p.move_to(polyspan.window.minx,polyspan.window.miny); + p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx); + } + return true; + } + + //fill initial rect / line + if(invert) + { + //fill all the area above the first vertex + p.move_to(polyspan.window.minx,polyspan.window.miny); + y = polyspan.window.miny; + int l = polyspan.window.maxx - polyspan.window.minx; + + p.put_block(cur_mark->y - polyspan.window.miny,l); + + //fill the area to the left of the first vertex on that line + l = cur_mark->x - polyspan.window.minx; + p.move_to(polyspan.window.minx,cur_mark->y); + if(l) p.put_hline(l); + } + + for(;;) + { + y = cur_mark->y; + x = cur_mark->x; + + p.move_to(x,y); + + area = cur_mark->area; + cover += cur_mark->cover; + + //accumulate for the current pixel + while(++cur_mark != polyspan.covers.end()) + { + if(y != cur_mark->y || x != cur_mark->x) + break; + + area += cur_mark->area; + cover += cur_mark->cover; + } + + //draw pixel - based on covered area + if(area) //if we're ok, draw the current pixel + { + alpha = polyspan.ExtractAlpha(cover - area, winding_style); + if(invert) alpha = 1 - alpha; + + if(!antialias) + { + if(alpha >= .5) p.put_value(); + } + else if(alpha) p.put_value_alpha(alpha); + + p.inc_x(); + x++; + } + + //if we're done, don't use iterator and exit + if(cur_mark == end_mark) break; + + //if there is no more live pixels on this line, goto next + if(y != cur_mark->y) + { + if(invert) + { + //fill the area at the end of the line + p.put_hline(polyspan.window.maxx - x); + + //fill area at the beginning of the next line + p.move_to(polyspan.window.minx,cur_mark->y); + p.put_hline(cur_mark->x - polyspan.window.minx); + } + + cover = 0; + + continue; + } + + //draw span to next pixel - based on total amount of pixel cover + if(x < cur_mark->x) + { + alpha = polyspan.ExtractAlpha(cover, winding_style); + if(invert) alpha = 1 - alpha; + + if(!antialias) + { + if(alpha >= .5) p.put_hline(cur_mark->x - x); + } + else if(alpha) p.put_hline(cur_mark->x - x,alpha); + } + } + + //fill the after stuff + if(invert) + { + //fill the area at the end of the line + p.put_hline(polyspan.window.maxx - x); + + //fill area at the beginning of the next line + p.move_to(polyspan.window.minx,y+1); + p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx); + } + + return true; +} + +bool Layer_Shape::render_polyspan(etl::surface *surface, PolySpan &polyspan) const +{ + bool invert =param_invert.get(bool(true)); + bool antialias =param_antialias.get(bool(true)); + WindingStyle winding_style=(WindingStyle)param_winding_style.get(int()); + + etl::surface::pen p(surface->begin()); + PolySpan::cover_array::iterator cur_mark = polyspan.covers.begin(); + PolySpan::cover_array::iterator end_mark = polyspan.covers.end(); + + Real cover,area,alpha; + + int y,x; + + cover = 0; + + //the pen always writes 1 (unless told to do otherwise) + p.set_value(1); + + if(cur_mark == end_mark) + { + //no marks at all + if(invert) + { + p.move_to(polyspan.window.minx,polyspan.window.miny); + p.put_block(polyspan.window.maxy - polyspan.window.miny,polyspan.window.maxx - polyspan.window.minx); + } + return true; + } + + //fill initial rect / line + if(invert) + { + //fill all the area above the first vertex + p.move_to(polyspan.window.minx,polyspan.window.miny); + y = polyspan.window.miny; + int l = polyspan.window.maxx - polyspan.window.minx; + + p.put_block(cur_mark->y - polyspan.window.miny,l); + + //fill the area to the left of the first vertex on that line + l = cur_mark->x - polyspan.window.minx; + p.move_to(polyspan.window.minx,cur_mark->y); + if(l) p.put_hline(l); + + for(;;) + { + y = cur_mark->y; + x = cur_mark->x; + + p.move_to(x,y); + + area = cur_mark->area; + cover += cur_mark->cover; + + //accumulate for the current pixel + while(++cur_mark != polyspan.covers.end()) + { + if(y != cur_mark->y || x != cur_mark->x) + break; + + area += cur_mark->area; + cover += cur_mark->cover; + } + + //draw pixel - based on covered area + if(area) //if we're ok, draw the current pixel + { + alpha = 1 - polyspan.ExtractAlpha(cover - area, winding_style); + if(!antialias) + { + if(alpha >= .5) p.put_value(); + } + else if(alpha) p.put_value(alpha); + + p.inc_x(); + x++; + } + + //if we're done, don't use iterator and exit + if(cur_mark == end_mark) break; + + //if there is no more live pixels on this line, goto next + if(y != cur_mark->y) + { + //fill the area at the end of the line + p.put_hline(polyspan.window.maxx - x); + + //fill area at the beginning of the next line + p.move_to(polyspan.window.minx,cur_mark->y); + p.put_hline(cur_mark->x - polyspan.window.minx); + + cover = 0; + + continue; + } + + //draw span to next pixel - based on total amount of pixel cover + if(x < cur_mark->x) + { + alpha = 1 - polyspan.ExtractAlpha(cover, winding_style); + if(!antialias) + { + if(alpha >= .5) p.put_hline(cur_mark->x - x); + } + else if(alpha) p.put_hline(cur_mark->x - x,alpha); + } + } + + //fill the area at the end of the line + p.put_hline(polyspan.window.maxx - x); + + //fill area at the beginning of the next line + p.move_to(polyspan.window.minx,y+1); + p.put_block(polyspan.window.maxy - y - 1,polyspan.window.maxx - polyspan.window.minx); + }else + { + for(;;) + { + y = cur_mark->y; + x = cur_mark->x; + + p.move_to(x,y); + + area = cur_mark->area; + cover += cur_mark->cover; + + //accumulate for the current pixel + while(++cur_mark != polyspan.covers.end()) + { + if(y != cur_mark->y || x != cur_mark->x) + break; + + area += cur_mark->area; + cover += cur_mark->cover; + } + + //draw pixel - based on covered area + if(area) //if we're ok, draw the current pixel + { + alpha = polyspan.ExtractAlpha(cover - area, winding_style); + if(!antialias) + { + if(alpha >= .5) p.put_value(); + } + else if(alpha) p.put_value(alpha); + + p.inc_x(); + x++; + } + + //if we're done, don't use iterator and exit + if(cur_mark == end_mark) break; + + //if there is no more live pixels on this line, goto next + if(y != cur_mark->y) + { + cover = 0; + + continue; + } + + //draw span to next pixel - based on total amount of pixel cover + if(x < cur_mark->x) + { + alpha = polyspan.ExtractAlpha(cover, winding_style); + if(!antialias) + { + if(alpha >= .5) p.put_hline(cur_mark->x - x); + } + else if(alpha) p.put_hline(cur_mark->x - x,alpha); + } + } + } + + return true; +} + +bool +Layer_Shape::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + Color color=param_color.get(Color()); + Point origin=param_origin.get(Point()); + bool invert =param_invert.get(bool(true)); + int blurtype=param_blurtype.get(int()); + Real feather=param_feather.get(Real()); + + const unsigned int w = renddesc.get_w(); + const unsigned int h = renddesc.get_h(); + + const Real pw = abs(renddesc.get_pw()); + const Real ph = abs(renddesc.get_ph()); + + //const Real OFFSET_EPSILON = 1e-8; + SuperCallback stageone(cb,1,10000,15001+renddesc.get_h()); + SuperCallback stagetwo(cb,10000,10001+renddesc.get_h(),15001+renddesc.get_h()); + SuperCallback stagethree(cb,10001+renddesc.get_h(),15001+renddesc.get_h(),15001+renddesc.get_h()); + + // Render what is behind us + + //clip if it satisfies the invert solid thing + if(is_solid_color() && invert) + { + Rect aabb = edge_table->aabb; + Point tl = renddesc.get_tl() - origin; + + Real pw = renddesc.get_pw(), + ph = renddesc.get_ph(); + + Rect nrect; + + Real pixelfeatherx = quality == 10 ? 0 : abs(feather/pw), + pixelfeathery = quality == 10 ? 0 : abs(feather/ph); + + nrect.set_point((aabb.minx - tl[0])/pw,(aabb.miny - tl[1])/ph); + nrect.expand((aabb.maxx - tl[0])/pw,(aabb.maxy - tl[1])/ph); + + RendDesc optdesc(renddesc); + + //make sure to expand so we gain subpixels rather than lose them + nrect.minx = floor(nrect.minx-pixelfeatherx); nrect.miny = floor(nrect.miny-pixelfeathery); + nrect.maxx = ceil(nrect.maxx+pixelfeatherx); nrect.maxy = ceil(nrect.maxy+pixelfeathery); + + //make sure the subwindow is clipped with our tile window (minimize useless drawing) + set_intersect(nrect,nrect,Rect(0,0,renddesc.get_w(),renddesc.get_h())); + + //must resize the surface first + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + surface->clear(); + + //only render anything if it's visible from our current tile + if(nrect.valid()) + { + //set the subwindow to the viewable pixels and render it to the subsurface + optdesc.set_subwindow((int)nrect.minx, (int)nrect.miny, + (int)(nrect.maxx - nrect.minx), (int)(nrect.maxy - nrect.miny)); + + Surface optimizedbacksurf; + if(!context.accelerated_render(&optimizedbacksurf,quality,optdesc,&stageone)) + return false; + + //blit that onto the original surface so we can pretend that nothing ever happened + Surface::pen p = surface->get_pen((int)nrect.minx,(int)nrect.miny); + optimizedbacksurf.blit_to(p); + } + }else + { + if(!context.accelerated_render(surface,quality,renddesc,&stageone)) + return false; + } + + if(cb && !cb->amount_complete(10000,10001+renddesc.get_h())) return false; + + if(feather && quality != 10) + { + //we have to blur rather than be crappy + + //so make a separate surface + RendDesc workdesc(renddesc); + + etl::surface shapesurface; + + //the expanded size = 1/2 the size in each direction rounded up + int halfsizex = (int) (abs(feather*.5/pw) + 3), + halfsizey = (int) (abs(feather*.5/ph) + 3); + + //expand by 1/2 size in each direction on either side + switch(blurtype) + { + case Blur::DISC: + case Blur::BOX: + case Blur::CROSS: + { + workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); + break; + } + case Blur::FASTGAUSSIAN: + { + if(quality < 4) + { + halfsizex*=2; + halfsizey*=2; + } + workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); + break; + } + case Blur::GAUSSIAN: + { + #define GAUSSIAN_ADJUSTMENT (0.05) + Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]); + Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]); + + pw=pw*pw; + ph=ph*ph; + + halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5); + halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5); + + halfsizex = (halfsizex + 1)/2; + halfsizey = (halfsizey + 1)/2; + workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey ); + + break; + } + } + + shapesurface.set_wh(workdesc.get_w(),workdesc.get_h()); + shapesurface.clear(); + + //render the shape + if(!render_shape(&shapesurface,quality,workdesc,&stagetwo))return false; + + //blur the image + Blur(feather,feather,blurtype,&stagethree)(shapesurface,workdesc.get_br()-workdesc.get_tl(),shapesurface); + + //blend with stuff below it... + unsigned int u = halfsizex, v = halfsizey, x = 0, y = 0; + for(y = 0; y < h; y++,v++) + { + u = halfsizex; + for(x = 0; x < w; x++,u++) + { + float a = shapesurface[v][u]; + if(a) + { + //a = floor(a*255+0.5f)/255; + (*surface)[y][x]=Color::blend(color,(*surface)[y][x],a*get_amount(),get_blend_method()); + } + //else (*surface)[y][x] = worksurface[v][u]; + } + } + + //we are done + if(cb && !cb->amount_complete(100,100)) + { + synfig::warning("Layer_Shape: could not set amount complete"); + return false; + } + + return true; + }else + { + //might take out to reduce code size + return render_shape(surface,true,quality,renddesc,&stagetwo); + } + +} + +//// +bool +Layer_Shape::accelerated_cairorender(Context context,cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + Color color=param_color.get(Color()); + Point origin=param_origin.get(Point()); + bool invert =param_invert.get(bool(true)); + bool antialias =param_antialias.get(bool(true)); + int blurtype=param_blurtype.get(int()); + Real feather=param_feather.get(Real()); + WindingStyle winding_style=(WindingStyle)param_winding_style.get(int()); + + // Grab the rgba values + const float r(color.get_r()); + const float g(color.get_g()); + const float b(color.get_b()); + const float a(color.get_a()); + + // First render the context + if(!is_solid_color()) + if(!context.accelerated_cairorender(cr,quality,renddesc,cb)) + { + if(cb) + cb->error(strprintf(__FILE__"%d: Accelerated Cairo Renderer Failure",__LINE__)); + return false; + } + + if(feather && quality != 10) + { + cairo_surface_t* subimage; + RendDesc workdesc(renddesc); + + // Untransform the render desc + if(!cairo_renddesc_untransform(cr, workdesc)) + return false; + + int halfsizex(0), halfsizey(0); + + int w=workdesc.get_w(), h=workdesc.get_h(); + const double wpw=(workdesc.get_br()[0]-workdesc.get_tl()[0])/w; + const double wph=(workdesc.get_br()[1]-workdesc.get_tl()[1])/h; + //the expanded size = 1/2 the size in each direction rounded up + halfsizex = (int) (abs(feather*.5/wpw) + 3), + halfsizey = (int) (abs(feather*.5/wph) + 3); + + //expand by 1/2 size in each direction on either side + switch(blurtype) + { + case Blur::DISC: + case Blur::BOX: + case Blur::CROSS: + { + workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); + break; + } + case Blur::FASTGAUSSIAN: + { + if(quality < 4) + { + halfsizex*=2; + halfsizey*=2; + } + workdesc.set_subwindow(-max(1,halfsizex),-max(1,halfsizey),w+2*max(1,halfsizex),h+2*max(1,halfsizey)); + break; + } + case Blur::GAUSSIAN: + { +#define GAUSSIAN_ADJUSTMENT (0.05) + Real pw = (Real)workdesc.get_w()/(workdesc.get_br()[0]-workdesc.get_tl()[0]); + Real ph = (Real)workdesc.get_h()/(workdesc.get_br()[1]-workdesc.get_tl()[1]); + + pw=pw*pw; + ph=ph*ph; + + halfsizex = (int)(abs(pw)*feather*GAUSSIAN_ADJUSTMENT+0.5); + halfsizey = (int)(abs(ph)*feather*GAUSSIAN_ADJUSTMENT+0.5); + + halfsizex = (halfsizex + 1)/2; + halfsizey = (halfsizey + 1)/2; + workdesc.set_subwindow( -halfsizex, -halfsizey, w+2*halfsizex, h+2*halfsizey ); + break; +#undef GAUSSIAN_ADJUSTMENT + } + } + + // New expanded workdesc values + const int ww=workdesc.get_w(); + const int wh=workdesc.get_h(); + const double wtlx=workdesc.get_tl()[0]; + const double wtly=workdesc.get_tl()[1]; + subimage=cairo_surface_create_similar(cairo_get_target(cr), CAIRO_CONTENT_COLOR_ALPHA, ww, wh); + cairo_t* subcr=cairo_create(subimage); + cairo_scale(subcr, 1/wpw, 1/wph); + cairo_translate(subcr, -wtlx, -wtly); + cairo_translate(subcr, origin[0], origin[1]); + switch(winding_style) + { + case WINDING_NON_ZERO: + cairo_set_fill_rule(subcr, CAIRO_FILL_RULE_WINDING); + break; + default: + cairo_set_fill_rule(subcr, CAIRO_FILL_RULE_EVEN_ODD); + break; + } + + cairo_set_source_rgba(subcr, r, g, b, a); + if(invert) + cairo_paint(subcr); + // Draw the shape + if(!antialias) + cairo_set_antialias(subcr, CAIRO_ANTIALIAS_NONE); + if(invert) + cairo_set_operator(subcr, CAIRO_OPERATOR_CLEAR); + else + cairo_set_operator(subcr, CAIRO_OPERATOR_OVER); + + Layer_Shape::shape_to_cairo(subcr); + cairo_clip(subcr); + cairo_paint(subcr); + + if(!feather_cairo_surface(subimage, workdesc, quality)) + { + cairo_surface_destroy(subimage); + cairo_destroy(subcr); + return false; + } + cairo_destroy(subcr); + + cairo_save(cr); + cairo_translate(cr, wtlx, wtly); + cairo_scale(cr, wpw, wph); + cairo_set_source_surface(cr, subimage, 0, 0); + cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); + cairo_restore(cr); + cairo_surface_destroy(subimage); + return true; + } + cairo_save(cr); + cairo_translate(cr, origin[0], origin[1]); + cairo_set_source_rgba(cr, r, g, b, a); + switch(winding_style) + { + case WINDING_NON_ZERO: + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_WINDING); + break; + default: + cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD); + break; + } + if(!antialias) + cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE); + if(invert) + { + cairo_push_group(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_set_source_rgba(cr, r, g, b, a); + cairo_paint(cr); + Layer_Shape::shape_to_cairo(cr); + cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR); + cairo_clip(cr); + cairo_paint(cr); + cairo_pop_group_to_source(cr); + cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); + } + else + { + Layer_Shape::shape_to_cairo(cr); + cairo_clip(cr); + cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); + } + cairo_restore(cr); + return true; +} +//// + + +// +bool +Layer_Shape::shape_to_cairo(cairo_t *cr)const +{ + int tmp(0); + //pointers for processing the bytestream + const char *current = &bytestream[0]; + const char *end = &bytestream[bytestream.size()]; + int operation = Primitive::NONE; + int number = 0; + int curnum; + + Primitive *curprim; + Point *data; + + Real x,y/*,x1,y1,x2,y2*/; + while(current < end) + { + tmp++; + + try { + + //get the op code safely + curprim = (Primitive *)current; + + //advance past indices + current += sizeof(Primitive); + if(current > end) + { + warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration"); + return false; + } + + //get the relevant data + operation = curprim->operation; + number = curprim->number; + + if(operation == Primitive::END) + break; + + if(operation == Primitive::CLOSE) + { + + cairo_close_path(cr); + continue; + } + + data = (Point*)current; + current += sizeof(Point)*number; + + //check data positioning + if(current > end) + { + warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points"); + return false; + } + + } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; } + + //transfer all the data - RLE optimized + for(curnum=0; curnum < number;) + { + switch(operation) + { + case Primitive::MOVE_TO: + { + x = data[curnum][0]; + y = data[curnum][1]; + + if(curnum == 0) + { + cairo_move_to(cr, x, y); + } + else + { + cairo_line_to(cr, x, y); + } + + curnum++; //only advance one point + + break; + } + + case Primitive::LINE_TO: + { + x = data[curnum][0]; + y = data[curnum][1]; + + cairo_line_to(cr, x, y); + synfig::info("line to x,y = %f, %f", x, y); + + curnum++; + break; + } +// +// case Primitive::CONIC_TO: +// { +// x = data[curnum+1][0]; +// x = (x - tl[0] + origin[0])*pw; +// y = data[curnum+1][1]; +// y = (y - tl[1] + origin[1])*ph; +// +// x1 = data[curnum][0]; +// x1 = (x1 - tl[0] + origin[0])*pw; +// y1 = data[curnum][1]; +// y1 = (y1 - tl[1] + origin[1])*ph; +// +// tangent[0] = 2*(x - x1); +// tangent[1] = 2*(y - y1); +// +// span.conic_to(x1,y1,x,y); +// curnum += 2; +// break; +// } +// +// case Primitive::CONIC_TO_SMOOTH: +// { +// x = data[curnum][0]; +// x = (x - tl[0] + origin[0])*pw; +// y = data[curnum][1]; +// y = (y - tl[1] + origin[1])*ph; +// +// x1 = span.cur_x + tangent[0]/2; +// y1 = span.cur_y + tangent[1]/2; +// +// tangent[0] = 2*(x - x1); +// tangent[1] = 2*(y - y1); +// +// span.conic_to(x1,y1,x,y); +// curnum ++; +// +// break; +// } +// +// case Primitive::CUBIC_TO: +// { +// x = data[curnum+2][0]; +// x = (x - tl[0] + origin[0])*pw; +// y = data[curnum+2][1]; +// y = (y - tl[1] + origin[1])*ph; +// +// x2 = data[curnum+1][0]; +// x2 = (x2 - tl[0] + origin[0])*pw; +// y2 = data[curnum+1][1]; +// y2 = (y2 - tl[1] + origin[1])*ph; +// +// x1 = data[curnum][0]; +// x1 = (x1 - tl[0] + origin[0])*pw; +// y1 = data[curnum][1]; +// y1 = (y1 - tl[1] + origin[1])*ph; +// +// tangent[0] = 2*(x - x2); +// tangent[1] = 2*(y - y2); +// +// span.cubic_to(x1,y1,x2,y2,x,y); +// curnum += 3; +// +// break; +// } +// +// case Primitive::CUBIC_TO_SMOOTH: +// { +// x = data[curnum+1][0]; +// x = (x - tl[0] + origin[0])*pw; +// y = data[curnum+1][1]; +// y = (y - tl[1] + origin[1])*ph; +// +// x2 = data[curnum][0]; +// x2 = (x2 - tl[0] + origin[0])*pw; +// y2 = data[curnum][1]; +// y2 = (y2 - tl[1] + origin[1])*ph; +// +// x1 = span.cur_x + tangent[0]/3.0; +// y1 = span.cur_y + tangent[1]/3.0; +// +// tangent[0] = 2*(x - x2); +// tangent[1] = 2*(y - y2); +// +// span.cubic_to(x1,y1,x2,y2,x,y); +// curnum += 2; +// +// break; +// } + } // switch + } // for + } // while + + return true; +} +// + +bool +Layer_Shape::feather_cairo_surface(cairo_surface_t* surface, RendDesc renddesc, int quality)const +{ + Color color=param_color.get(Color()); + int blurtype=param_blurtype.get(int()); + Real feather=param_feather.get(Real()); + + if(feather && quality!=10) + { + etl::surface shapesurface; + shapesurface.set_wh(renddesc.get_w(),renddesc.get_h()); + shapesurface.clear(); + + CairoSurface cairosurface(surface); + if(!cairosurface.map_cairo_image()) + { + synfig::info("map cairo image failed"); + return false; + } + // Extract the alpha values: + int x, y; + int h(renddesc.get_h()), w(renddesc.get_w()); + float div=1.0/((float)(CairoColor::ceil)); + for(y=0; y end) + { + warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration"); + return false; + } + + //get the relevant data + operation = curprim->operation; + number = curprim->number; + + if(operation == Primitive::END) + break; + + if(operation == Primitive::CLOSE) + { + if(span.notclosed()) + { + tangent[0] = span.close_x - span.cur_x; + tangent[1] = span.close_y - span.cur_y; + span.close(); + } + continue; + } + + data = (Point*)current; + current += sizeof(Point)*number; + + //check data positioning + if(current > end) + { + warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points"); + return false; + } + + } catch(...) { synfig::error("Layer_Shape::render_shape()1: Caught an exception after %d loops, rethrowing...", tmp); throw; } + + //transfer all the data - RLE optimized + for(curnum=0; curnum < number;) + { + switch(operation) + { + case Primitive::MOVE_TO: + { + matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); + + if(curnum == 0) + { + span.move_to(x,y); + + tangent[0] = 0; + tangent[1] = 0; + } + else + { + tangent[0] = x - span.cur_x; + tangent[1] = y - span.cur_y; + + span.line_to(x,y); + } + + curnum++; //only advance one point + + break; + } + + case Primitive::LINE_TO: + { + matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); + + tangent[0] = x - span.cur_x; + tangent[1] = y - span.cur_y; + + span.line_to(x,y); + curnum++; + break; + } + + case Primitive::CONIC_TO: + { + matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); + matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); + + tangent[0] = 2*(x - x1); + tangent[1] = 2*(y - y1); + + span.conic_to(x1,y1,x,y); + curnum += 2; + break; + } + + case Primitive::CONIC_TO_SMOOTH: + { + matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); + + x1 = span.cur_x + tangent[0]/2; + y1 = span.cur_y + tangent[1]/2; + + tangent[0] = 2*(x - x1); + tangent[1] = 2*(y - y1); + + span.conic_to(x1,y1,x,y); + curnum ++; + + break; + } + + case Primitive::CUBIC_TO: + { + matrix.get_transformed(x, y, data[curnum+2][0], data[curnum+2][1]); + matrix.get_transformed(x2, y2, data[curnum+1][0], data[curnum+1][1]); + matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); + + tangent[0] = 2*(x - x2); + tangent[1] = 2*(y - y2); + + span.cubic_to(x1,y1,x2,y2,x,y); + curnum += 3; + + break; + } + + case Primitive::CUBIC_TO_SMOOTH: + { + matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); + matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); + + x1 = span.cur_x + tangent[0]/3.0; + y1 = span.cur_y + tangent[1]/3.0; + + tangent[0] = 2*(x - x2); + tangent[1] = 2*(y - y2); + + span.cubic_to(x1,y1,x2,y2,x,y); + curnum += 2; + + break; + } + } + } + } + + //sort the bastards so we can render everything + span.sort_marks(); + + Color::value_type amount = useblend ? get_amount() : 1.0; + Color::BlendMethod blend_method = useblend ? get_blend_method() : Color::BLEND_STRAIGHT; + Color color = param_color.get(Color()); + bool invert = param_invert.get(bool(true)); + bool antialias = param_antialias.get(bool(true)); + WindingStyle winding_style = (WindingStyle)param_winding_style.get(int()); + + if (useblend && get_blend_method() == Color::BLEND_STRAIGHT_ONTO) + { + Surface s; + s.set_wh(surface->get_w(), surface->get_h()); + s.clear(); + bool result = render_polyspan( + &s, + span, + 1.0, + Color::BLEND_STRAIGHT, + color, + invert, + antialias, + winding_style ); + + Surface::alpha_pen p(surface->begin(), amount, Color::BLEND_STRAIGHT_ONTO); + s.blit_to(p, 0, 0, surface->get_w(), surface->get_h()); + + return result; + } + + return render_polyspan( + surface, + span, + amount, + blend_method, + color, + invert, + antialias, + winding_style ); +} + +bool +Layer_Shape::render_shape(etl::surface *surface,int /*quality*/, + const RendDesc &renddesc, ProgressCallback */*cb*/)const +{ + // If our amount is set to zero, no need to render anything + if(!get_amount()) + return true; + + const Real pw = renddesc.get_w()/(renddesc.get_br()[0]-renddesc.get_tl()[0]); + const Real ph = renddesc.get_h()/(renddesc.get_br()[1]-renddesc.get_tl()[1]); + + // if the pixels are zero sized then we're too zoomed out to see anything + if (pw == 0 || ph == 0) + return true; + + Matrix matrix( + Matrix().set_translate(param_origin.get(Point())) + * renddesc.get_transformation_matrix() + * Matrix().set_translate(-renddesc.get_tl()) + * Matrix().set_scale(pw, ph) + ); + + //test new polygon renderer + // Build edge table + // Width and Height of a pixel + const int w = renddesc.get_w(); + const int h = renddesc.get_h(); + + Vector tangent (0,0); + + PolySpan span; + + //optimization for tessellating only inside tiles + span.window.minx = 0; + span.window.miny = 0; + span.window.maxx = w; + span.window.maxy = h; + + //pointers for processing the bytestream + const char *current = &bytestream[0]; + const char *end = &bytestream[bytestream.size()]; + + int operation = Primitive::NONE; + int number = 0; + int curnum; + + Primitive *curprim; + Point *data; + + Real x,y,x1,y1,x2,y2; + + while(current < end) + { + //get the op code safely + curprim = (Primitive *)current; + + //advance past indices + current += sizeof(Primitive); + if(current > end) + { + warning("Layer_Shape::accelerated_render - Error in the byte stream, not enough space for next declaration"); + return false; + } + + //get the relevant data + operation = curprim->operation; + number = curprim->number; + + if(operation == Primitive::END) + break; + + if(operation == Primitive::CLOSE) + { + if(span.notclosed()) + { + tangent[0] = span.close_x - span.cur_x; + tangent[1] = span.close_y - span.cur_y; + span.close(); + } + continue; + } + + data = (Point*)current; + current += sizeof(Point)*number; + + //check data positioning + if(current > end) + { + warning("Layer_Shape::accelerated_render - Error in the byte stream, in sufficient data space for declared number of points"); + return false; + } + + //transfer all the data + for(curnum=0; curnum < number;) + { + switch(operation) + { + case Primitive::MOVE_TO: + { + matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); + + if(curnum == 0) + { + span.move_to(x,y); + + tangent[0] = 0; + tangent[1] = 0; + } + else + { + tangent[0] = x - span.cur_x; + tangent[1] = y - span.cur_y; + + span.line_to(x,y); + } + + curnum++; //only advance one point + + break; + } + + case Primitive::LINE_TO: + { + matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); + + tangent[0] = x - span.cur_x; + tangent[1] = y - span.cur_y; + + span.line_to(x,y); + curnum++; + break; + } + + case Primitive::CONIC_TO: + { + matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); + matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); + + tangent[0] = 2*(x - x1); + tangent[1] = 2*(y - y1); + + span.conic_to(x1,y1,x,y); + curnum += 2; + break; + } + + case Primitive::CONIC_TO_SMOOTH: + { + matrix.get_transformed(x, y, data[curnum][0], data[curnum][1]); + + x1 = span.cur_x + tangent[0]/2; + y1 = span.cur_y + tangent[1]/2; + + tangent[0] = 2*(x - x1); + tangent[1] = 2*(y - y1); + + span.conic_to(x1,y1,x,y); + curnum ++; + + break; + } + + case Primitive::CUBIC_TO: + { + matrix.get_transformed(x, y, data[curnum+2][0], data[curnum+2][1]); + matrix.get_transformed(x2, y2, data[curnum+1][0], data[curnum+1][1]); + matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); + + tangent[0] = 2*(x - x2); + tangent[1] = 2*(y - y2); + + span.cubic_to(x1,y1,x2,y2,x,y); + curnum += 3; + + break; + } + + case Primitive::CUBIC_TO_SMOOTH: + { + matrix.get_transformed(x, y, data[curnum+1][0], data[curnum+1][1]); + matrix.get_transformed(x1, y1, data[curnum][0], data[curnum][1]); + + x1 = span.cur_x + tangent[0]/3.0; + y1 = span.cur_y + tangent[1]/3.0; + + tangent[0] = 2*(x - x2); + tangent[1] = 2*(y - y2); + + span.cubic_to(x1,y1,x2,y2,x,y); + curnum += 2; + + break; + } + } + } + } + + //sort the bastards so we can render everything + span.sort_marks(); + + return render_polyspan(surface, span); +} + +Rect +Layer_Shape::get_bounding_rect()const +{ + Point origin=param_origin.get(Point()); + bool invert =param_invert.get(bool(true)); + Real feather=param_feather.get(Real()); + + if(invert) + return Rect::full_plane(); + + if (edge_table->initaabb) + return Rect::zero(); + + Rect bounds(edge_table->aabb+origin); + bounds.expand(max((bounds.get_min() - bounds.get_max()).mag()*0.01, + feather)); + + return bounds; +} diff --git a/synfig-core/src/synfig/layers/layer_shape.h b/synfig-core/src/synfig/layers/layer_shape.h new file mode 100644 index 0000000..54abf90 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_shape.h @@ -0,0 +1,144 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_shape.h +** \brief Header file for implementation of the "Shape" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007-2008 Chris Moore +** Copyright (c) 2012-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_SHAPE_H +#define __SYNFIG_LAYER_SHAPE_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_composite.h" +#include +#include +#include + +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +/*! \class Layer_Shape +** \brief writeme */ +class Layer_Shape : public Layer_Composite, public Layer_NoDeform +{ + SYNFIG_LAYER_MODULE_EXT + + enum WindingStyle + { + WINDING_NON_ZERO=0, //!< less than -1 --> 1; -1 --> 1; 0 --> 0; 1 --> 1; greater than 1 --> 1 + WINDING_EVEN_ODD=1, //!< add or subtract multiples of 2 to get into range -1:1, then as above + + WINDING_END=2 //!< \internal + }; + +private: + + //internal caching + struct Intersector; + Intersector *edge_table; +protected: + //!Parameter: (Color) Color of the shape + ValueBase param_color; + //!Parameter: (Point) Origin of the shape definition + ValueBase param_origin; + //!Parameter: (bool) Whether the shape is inverted or not + ValueBase param_invert; + //!Parameter: (bool) Whether the shape has antialiased edge + ValueBase param_antialias; + //!Parameter: (Blur::Type) The type of blur used for the feather + ValueBase param_blurtype; + //!Parameter: (Real) Amount of feather of the shape + ValueBase param_feather; + //!Parameter: (WindingStyle) How shape is rendered when crosses it self + ValueBase param_winding_style; +private: + std::vector< char > bytestream; + + //for use in creating the bytestream + int lastbyteop; + int lastoppos; + +protected: + + Layer_Shape(const Real &a = 1.0, const Color::BlendMethod m = Color::BLEND_COMPOSITE); + +public: + + ~Layer_Shape(); + + //! Clears out any data + /*! Also clears out the Intersector + */ + void clear(); + //void sync(); + + void move_to(Real x, Real y); + void line_to(Real x, Real y); + void conic_to(Real x1, Real y1, Real x, Real y); + void conic_to_smooth(Real x, Real y); //x1,y1 derived from current tangent + void curve_to(Real x1, Real y1, Real x2, Real y2, Real x, Real y); + void curve_to_smooth(Real x2, Real y2, Real x, Real y); //x1,y1 derived from current tangent + void close(); + void endpath(); + + virtual bool set_param(const String & param, const synfig::ValueBase &value); + virtual ValueBase get_param(const String & param)const; + + virtual Vocab get_param_vocab()const; + + virtual Color get_color(Context context, const Point &pos)const; + virtual bool accelerated_render(Context context, Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; + virtual Rect get_bounding_rect()const; + //This function translates Shape primitives to Cairo primitives. Currently only supported move_to and line_to. + bool shape_to_cairo(cairo_t* cr)const; + bool feather_cairo_surface(cairo_surface_t* surface, RendDesc renddesc, int quality)const; + +private: + class PolySpan; + bool render_polyspan( + Surface *surface, + PolySpan &polyspan, + Color::value_type amount, + Color::BlendMethod blend_method, + const Color &color, + bool invert, + bool antialias, + WindingStyle winding_style) const; + bool render_polyspan(etl::surface *surface,PolySpan &polyspan)const; + virtual bool render_shape(Surface *surface,bool useblend,int quality,const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool render_shape(etl::surface *surface,int quality,const RendDesc &renddesc, ProgressCallback *cb)const; +}; // END of Layer_Shape + +}; // END of namespace synfig +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_skeleton.cpp b/synfig-core/src/synfig/layers/layer_skeleton.cpp new file mode 100644 index 0000000..71b0822 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_skeleton.cpp @@ -0,0 +1,227 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_skeleton.cpp +** \brief Implementation of the "Layer_Skeleton" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2008 Chris Moore +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include "layer_skeleton.h" +#include +#include +#include +#include +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Skeleton); +SYNFIG_LAYER_SET_NAME(Layer_Skeleton,"skeleton"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Skeleton,N_("Skeleton")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Skeleton,N_("Other")); +SYNFIG_LAYER_SET_VERSION(Layer_Skeleton,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Skeleton,"$Id$"); + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +/* === E N T R Y P O I N T ================================================= */ + +Layer_Skeleton::Layer_Skeleton(): + param_name(ValueBase((const char*)"skeleton")) +{ + std::vector bones; + int bone_count = 1; + if (getenv("SYNFIG_NUMBER_OF_BONES_IN_SKELETON")) + bone_count = atoi(getenv("SYNFIG_NUMBER_OF_BONES_IN_SKELETON")); + if (bone_count < 1) bone_count = 1; + else if (bone_count > 10) bone_count = 10; + + while (bone_count--) + bones.push_back(Bone()); + + param_bones.set_list_of(bones); + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); + + set_exclude_from_rendering(true); + Layer_Polygon::set_param("color", ValueBase(Color(0.5, 0.5, 1.0, 1.0))); + Layer_Polygon::set_param("amount", ValueBase(Real(0.5))); +} + +#ifdef _DEBUG +Layer_Skeleton::~Layer_Skeleton() +{ + if (getenv("SYNFIG_DEBUG_DESTRUCTORS")) + printf("%s:%d ~Layer_Skeleton()\n", __FILE__, __LINE__); +} +#endif + +bool +Layer_Skeleton::set_param(const String & param, const ValueBase &value) +{ + // lock color param + if (param == "color") return false; + + IMPORT_VALUE(param_name); + + if (param=="bones" && param_bones.get_type()==value.get_type()) + { + param_bones = value; + sync(); + return true; + } + + return Layer_Polygon::set_param(param,value); +} + +ValueBase +Layer_Skeleton::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_name); + EXPORT_VALUE(param_bones); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Polygon::get_param(param); +} + +Layer::Vocab +Layer_Skeleton::get_param_vocab()const +{ + Layer::Vocab ret(Layer::get_param_vocab()); + + // Params from layer Layer_Shape + //ret.push_back(ParamDesc("color") + // .set_local_name(_("Color")) + //); + + ret.push_back(ParamDesc("amount") + .set_local_name(_("Amount")) + .set_description(_("Alpha channel of the layer")) + ); + + // Self params + ret.push_back(ParamDesc("name") + .set_local_name(_("Name")) + ); + ret.push_back(ParamDesc("bones") + .set_local_name(_("Bones")) + ); + + return ret; +} + +void +Layer_Skeleton::set_time(IndependentContext context, Time time)const +{ + const_cast(this)->sync(); + context.set_time(time); +} + +void +Layer_Skeleton::set_time(IndependentContext context, Time time, const Point &pos)const +{ + const_cast(this)->sync(); + context.set_time(time,pos); +} + +void +Layer_Skeleton::sync() +{ + const std::vector &list = param_bones.get_list(); + + static const Real precision = 0.000000001; + int segments_count = 64; + Real segment_angle = 2*PI/(Real)segments_count; + + clear(); + for(std::vector::const_iterator i = list.begin(); i != list.end(); ++i) + { + if (!i->same_type_as(Bone())) continue; + const Bone &bone = i->get(Bone()); + Matrix matrix = bone.get_animated_matrix(); + Vector origin = matrix.get_transformed(Vector(0.0, 0.0)); + Vector direction = matrix.get_transformed(Vector(1.0, 0.0), false).norm(); + Real length = bone.get_length() * bone.get_scalelx(); + + if (length < 0) { + length *= -1; + direction *= -1; + } + + const Vector &p0 = origin; + const Vector p1 = origin + direction * length; + + Real r0 = fabs(bone.get_width()); + Real r1 = fabs(bone.get_tipwidth()); + Real direction_angle = atan2(direction[1], direction[0]); + + Real angle0_base = length - precision > fabs(r1 - r0) + ? acos((r0 - r1)/length) + : (r0 > r1 ? 0.0 : PI); + Real angle1_base = PI - angle0_base; + + int segments_count0 = (int)round(2*angle1_base / segment_angle); + Real segment_angle0 = 2*angle1_base / (Real)segments_count0; + + int segments_count1 = (int)round(2*angle0_base / segment_angle); + Real segment_angle1 = 2*angle0_base / (Real)segments_count1; + + std::vector list; + list.reserve(segments_count0 + segments_count1 + 2); + + int j = 0; + Real angle = direction_angle + angle0_base; + while(true) + { + list.push_back( Point(r0*cos(angle) + p0[0], r0*sin(angle) + p0[1]) ); + if (j++ >= segments_count0) break; else angle += segment_angle0; + } + j = 0; + while(true) + { + list.push_back( Point(r1*cos(angle) + p1[0], r1*sin(angle) + p1[1]) ); + if (j++ >= segments_count1) break; else angle += segment_angle1; + } + + add_polygon(list); + upload_polygon(list); + } +} diff --git a/synfig-core/src/synfig/layers/layer_skeleton.h b/synfig-core/src/synfig/layers/layer_skeleton.h new file mode 100644 index 0000000..a7732af --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_skeleton.h @@ -0,0 +1,77 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_skeleton.h +** \brief Header file for implementation of the "Layer_Skeleton" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_SKELETON_H +#define __SYNFIG_LAYER_SKELETON_H + +/* === H E A D E R S ======================================================= */ + +#include +#include "layer_polygon.h" +// #include +// #include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +class Layer_Skeleton : public Layer_Polygon +{ + SYNFIG_LAYER_MODULE_EXT +private: + + //!Parameter: (std::vector) Bones list of the skeleton + ValueBase param_bones; + //!Parameter: (synfig::String) Name of the skeleton + ValueBase param_name; + +public: + + Layer_Skeleton(); + +#ifdef _DEBUG + ~Layer_Skeleton(); +#endif + + virtual bool set_param(const synfig::String & param, const synfig::ValueBase &value); + + virtual synfig::ValueBase get_param(const synfig::String & param)const; + + virtual Vocab get_param_vocab()const; + + //! Updates the polygon data to match the parameters. + virtual void sync(); + virtual void set_time(IndependentContext context, Time time)const; + virtual void set_time(IndependentContext context, Time time, const Point &pos)const; +}; // END of class Layer_Skeleton + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_skeletondeformation.cpp b/synfig-core/src/synfig/layers/layer_skeletondeformation.cpp new file mode 100644 index 0000000..b60fe1f --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_skeletondeformation.cpp @@ -0,0 +1,385 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_skeletondeformation.cpp +** \brief SkeletonDeformation layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_skeletondeformation.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +/* === C L A S S E S ======================================================= */ + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_SkeletonDeformation); +SYNFIG_LAYER_SET_NAME(Layer_SkeletonDeformation,"skeleton_deformation"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_SkeletonDeformation,N_("Skeleton Deformation")); +SYNFIG_LAYER_SET_CATEGORY(Layer_SkeletonDeformation,N_("Distortions")); +SYNFIG_LAYER_SET_VERSION(Layer_SkeletonDeformation,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_SkeletonDeformation,"$Id$"); + +/* === M E T H O D S ======================================================= */ + +Layer_SkeletonDeformation::Layer_SkeletonDeformation(): + param_point1(ValueBase(Point(-4,4))), + param_point2(ValueBase(Point(4,-4))), + param_x_subdivisions(32), + param_y_subdivisions(32) +{ + max_texture_scale = 1.f; + param_bones.set_list_of(std::vector(1)); + + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer_SkeletonDeformation::~Layer_SkeletonDeformation() +{ +} + +String +Layer_SkeletonDeformation::get_local_name()const +{ + String s = Layer_MeshTransform::get_local_name(); + return s.empty() ? _("Skeleton Deformation") : '[' + s + ']'; +} + +Layer::Vocab +Layer_SkeletonDeformation::get_param_vocab()const +{ + Layer::Vocab ret(Layer_MeshTransform::get_param_vocab()); + + ret.push_back(ParamDesc("bones") + .set_local_name(_("Bones")) + .set_description(_("List of bones")) + .set_static(true) + ); + + ret.push_back(ParamDesc("point1") + .set_local_name(_("Point 1")) + .set_box("point2") + .set_description(_("First corner of the bounds rectangle")) + ); + + ret.push_back(ParamDesc("point2") + .set_local_name(_("Point 2")) + .set_description(_("Second corner of the bounds rectangle")) + ); + + ret.push_back(ParamDesc("x_subdivisions") + .set_local_name(_("Horizontal subdivisions")) + .set_description(_("Count of horizontal subdivisions of the transformation grid")) + ); + + ret.push_back(ParamDesc("y_subdivisions") + .set_local_name(_("Vertical subdivisions")) + .set_description(_("Count of vertical subdivisions of the transformation grid")) + ); + + return ret; +} + +void +Layer_SkeletonDeformation::prepare_mask() +{ + const std::vector &list = param_bones.get_list(); + + static const Real precision = 0.000000001; + int segments_count = 64; + Real segment_angle = 2*PI/(Real)segments_count; + + mask.clear(); + for(std::vector::const_iterator i = list.begin(); i != list.end(); ++i) + { + if (!i->same_type_as(BonePair())) continue; + const BonePair &bonePair = i->get(BonePair()); + const Bone &bone = bonePair.first; + Matrix matrix = bone.get_animated_matrix(); + Vector origin = matrix.get_transformed(Vector(0.0, 0.0)); + Vector direction = matrix.get_transformed(Vector(1.0, 0.0), false).norm(); + Real length = bone.get_length() * bone.get_scalelx(); + + if (length < 0) { + length *= -1; + direction *= -1; + } + + const Vector &p0 = origin; + const Vector p1 = origin + direction * length; + + Real r0 = fabs(bone.get_width()); + Real r1 = fabs(bone.get_tipwidth()); + Real direction_angle = atan2(direction[1], direction[0]); + + Real angle0_base = length - precision > fabs(r1 - r0) + ? acos((r0 - r1)/length) + : (r0 > r1 ? 0.0 : PI); + Real angle1_base = PI - angle0_base; + + int segments_count0 = (int)round(2*angle1_base / segment_angle); + Real segment_angle0 = 2*angle1_base / (Real)segments_count0; + + int segments_count1 = (int)round(2*angle0_base / segment_angle); + Real segment_angle1 = 2*angle0_base / (Real)segments_count1; + + // add vertices + int first = (int)mask.vertices.size(); + mask.vertices.reserve(first + segments_count0 + segments_count1 + 2); + + int j = 0; + Real angle = direction_angle + angle0_base; + while(true) + { + mask.vertices.push_back( Point(r0*cos(angle) + p0[0], r0*sin(angle) + p0[1]) ); + if (j++ >= segments_count0) break; else angle += segment_angle0; + } + j = 0; + while(true) + { + mask.vertices.push_back( Point(r1*cos(angle) + p1[0], r1*sin(angle) + p1[1]) ); + if (j++ >= segments_count1) break; else angle += segment_angle1; + } + + // add triangles + for(int i = first+2; i < (int)mask.vertices.size(); ++i) + mask.triangles.push_back(Polygon::Triangle(first, i-1, i)); + } +} + +struct Layer_SkeletonDeformation::GridPoint { + Vector initial_position; + Vector summary_position; + Real summary_depth; + Real summary_weight; + Real average_depth; + bool used; + + inline GridPoint(): + summary_depth(0.0), summary_weight(0.0), average_depth(0.0), used(false) { } + inline explicit GridPoint(const Vector &initial_position): + initial_position(initial_position), summary_depth(0.0), summary_weight(0.0), average_depth(0.0), used(false) { } + static bool compare_triagles(const std::pair &a, const std::pair &b) + { + return a.first < b.first ? false + : b.first < a.first ? true + : a.second.vertices[0] < b.second.vertices[0] ? true + : b.second.vertices[0] < a.second.vertices[0] ? false + : a.second.vertices[1] < b.second.vertices[1] ? true + : b.second.vertices[1] < a.second.vertices[1] ? false + : a.second.vertices[2] < b.second.vertices[2]; + } +}; + +Real Layer_SkeletonDeformation::distance_to_line(const Vector &p0, const Vector &p1, const Vector &x) +{ + const Real epsilon = 1e-10; + + Real distance_to_p0 = (x - p0).mag(); + Real distance_to_p1 = (x - p1).mag(); + Real distance_to_line = INFINITY; + + Vector line = p1 - p0; + Real line_length = line.mag(); + if (line_length > epsilon) + { + Real dist = fabs((x - p0) * line.perp() / line_length); + Real pos = (x - p0) * line / line_length; + if (pos > 0.0 && pos < line_length) + distance_to_line = dist; + } + + return std::min(distance_to_line, std::min(distance_to_p0, distance_to_p1) ); +} + +void +Layer_SkeletonDeformation::prepare_mesh() +{ + static const Real precision = 1e-10; + + mesh.clear(); + + // TODO: build grid with dynamic size + + const Point grid_p0 = param_point1.get(Point()); + const Point grid_p1 = param_point2.get(Point()); + const int grid_side_count_x = std::max(1, param_x_subdivisions.get(int())) + 1; + const int grid_side_count_y = std::max(1, param_y_subdivisions.get(int())) + 1; + + const Real grid_step_x = (grid_p1[0] - grid_p0[0]) / (Real)(grid_side_count_x - 1); + const Real grid_step_y = (grid_p1[1] - grid_p0[1]) / (Real)(grid_side_count_y - 1); + const Real grid_step_diagonal = sqrt(grid_step_x*grid_step_x + grid_step_y*grid_step_y); + + // build grid + std::vector grid; + grid.reserve(grid_side_count_x * grid_side_count_y); + for(int j = 0; j < grid_side_count_y; ++j) + for(int i = 0; i < grid_side_count_x; ++i) + grid.push_back(GridPoint(Vector( + grid_p0[0] + i*grid_step_x, + grid_p0[1] + j*grid_step_y ))); + + // apply deformation + if (param_bones.can_get(ValueBase::List())) + { + const ValueBase::List &bones = param_bones.get_list(); + for(ValueBase::List::const_iterator i = bones.begin(); i != bones.end(); ++i) + { + if (i->can_get(BonePair())) + { + const BonePair &bone_pair = i->get(BonePair()); + Bone::Shape shape0 = bone_pair.first.get_shape(); + Bone::Shape shape1 = bone_pair.second.get_shape(); + Bone::Shape expandedShape0 = shape0; + expandedShape0.r0 += 2.0*grid_step_diagonal; + expandedShape0.r1 += 2.0*grid_step_diagonal; + Real depth = bone_pair.second.get_depth(); + + Matrix into_bone( + shape0.p1[0] - shape0.p0[0], shape0.p1[1] - shape0.p0[1], 0.0, + shape0.p0[1] - shape0.p1[1], shape0.p1[0] - shape0.p0[0], 0.0, + shape0.p0[0], shape0.p0[1], 1.0 + ); + into_bone.invert(); + Matrix from_bone( + shape1.p1[0] - shape1.p0[0], shape1.p1[1] - shape1.p0[1], 0.0, + shape1.p0[1] - shape1.p1[1], shape1.p1[0] - shape1.p0[0], 0.0, + shape1.p0[0], shape1.p0[1], 1.0 + ); + Matrix matrix = into_bone * from_bone; + + for(std::vector::iterator j = grid.begin(); j != grid.end(); ++j) + { + Real percent = Bone::distance_to_shape_center_percent(expandedShape0, j->initial_position); + if (percent > precision) { + Real distance = distance_to_line(shape0.p0, shape0.p1, j->initial_position); + if (distance < precision) distance = precision; + Real weight = + percent/(distance*distance); + // 1.0/distance; + // 1.0/(distance*distance); + // 1.0/(distance*distance*distance); + // exp(-4.0*distance); + j->summary_position += matrix.get_transformed(j->initial_position) * weight; + j->summary_depth += depth * weight; + j->summary_weight += weight; + j->used = true; + } + } + } + } + } + + // build vertices + mesh.vertices.reserve(grid.size()); + for(std::vector::iterator i = grid.begin(); i != grid.end(); ++i) { + Vector average_position = i->summary_weight > precision ? i->summary_position/i->summary_weight : i->initial_position; + i->average_depth = i->summary_weight > precision ? i->summary_depth/i->summary_weight : 0.0; + mesh.vertices.push_back(Mesh::Vertex(average_position, i->initial_position)); + } + + // build triangles + std::vector< std::pair > triangles; + triangles.reserve(2*(grid_side_count_x-1)*(grid_side_count_y-1)); + for(int j = 1; j < grid_side_count_y; ++j) + { + for(int i = 1; i < grid_side_count_x; ++i) + { + int v[] = { + (j-1)*grid_side_count_x + (i-1), + (j-1)*grid_side_count_x + i, + j *grid_side_count_x + i, + j *grid_side_count_x + (i-1), + }; + if (grid[v[0]].used && grid[v[1]].used && grid[v[2]].used && grid[v[3]].used) + { + Real depth = 0.25*(grid[v[0]].average_depth + + grid[v[1]].average_depth + + grid[v[2]].average_depth + + grid[v[3]].average_depth); + triangles.push_back(std::make_pair(depth, Mesh::Triangle(v[0], v[1], v[3]))); + triangles.push_back(std::make_pair(depth, Mesh::Triangle(v[1], v[2], v[3]))); + } + } + } + + // sort triangles + std::sort(triangles.begin(), triangles.end(), GridPoint::compare_triagles); + mesh.triangles.reserve(triangles.size()); + for(std::vector< std::pair >::iterator i = triangles.begin(); i != triangles.end(); ++i) + mesh.triangles.push_back(i->second); + + prepare_mask(); + update_mesh_and_mask(); +} + +bool +Layer_SkeletonDeformation::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE_PLUS(param_bones, prepare_mesh()); + IMPORT_VALUE_PLUS(param_point1, prepare_mesh()); + IMPORT_VALUE_PLUS(param_point2, prepare_mesh()); + IMPORT_VALUE_PLUS(param_x_subdivisions, prepare_mesh()); + IMPORT_VALUE_PLUS(param_y_subdivisions, prepare_mesh()); + return Layer_MeshTransform::set_param(param,value); +} + +ValueBase +Layer_SkeletonDeformation::get_param(const String& param)const +{ + EXPORT_VALUE(param_bones); + EXPORT_VALUE(param_point1); + EXPORT_VALUE(param_point2); + EXPORT_VALUE(param_x_subdivisions); + EXPORT_VALUE(param_y_subdivisions); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_MeshTransform::get_param(param); +} + diff --git a/synfig-core/src/synfig/layers/layer_skeletondeformation.h b/synfig-core/src/synfig/layers/layer_skeletondeformation.h new file mode 100644 index 0000000..2134a02 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_skeletondeformation.h @@ -0,0 +1,89 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_skeletondeformation.h +** \brief SkeletonDeformation layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_SKELETONDEFORMATION_H +#define __SYNFIG_LAYER_SKELETONDEFORMATION_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_meshtransform.h" +#include +#include +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { +/*! \class Layer_SkeletonDeformation +** \brief Class of the SkeletonDeformation layer. +*/ +class Layer_SkeletonDeformation : public Layer_MeshTransform +{ + //! Layer module: defines the needed members to belong to a layer's factory. + SYNFIG_LAYER_MODULE_EXT +private: + //! Parameter: (list) Bones + ValueBase param_bones; + //! Parameter: (Point) + synfig::ValueBase param_point1; + //! Parameter: (Point) + synfig::ValueBase param_point2; + //! Parameter: (Integer) + synfig::ValueBase param_x_subdivisions; + //! Parameter: (Integer) + synfig::ValueBase param_y_subdivisions; + + struct GridPoint; + static Real distance_to_line(const Vector &p0, const Vector &p1, const Vector &x); + void prepare_mask(); + +public: + typedef std::pair BonePair; + + //! Default constructor + Layer_SkeletonDeformation(); + //! Destructor + virtual ~Layer_SkeletonDeformation(); + //! Returns a string with the localized name of this layer + virtual String get_local_name()const; + + //! Sets the parameter described by \a param to \a value. \see Layer::set_param + virtual bool set_param(const String & param, const synfig::ValueBase &value); + //! Get the value of the specified parameter. \see Layer::get_param + virtual ValueBase get_param(const String & param)const; + //! Gets the parameter vocabulary + virtual Vocab get_param_vocab()const; + + void prepare_mesh(); +}; // END of class SkeletonDeformation + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_solidcolor.cpp b/synfig-core/src/synfig/layers/layer_solidcolor.cpp new file mode 100644 index 0000000..787e9b9 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_solidcolor.cpp @@ -0,0 +1,238 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_solidcolor.cpp +** \brief Implementation of the "Solid Color" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2007, 2008 Chris Moore +** Copyright (c) 2011-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_solidcolor.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_SolidColor); +SYNFIG_LAYER_SET_NAME(Layer_SolidColor,"SolidColor"); // todo: use solid_color +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_SolidColor,N_("Solid Color")); +SYNFIG_LAYER_SET_CATEGORY(Layer_SolidColor,N_("Geometry")); +SYNFIG_LAYER_SET_VERSION(Layer_SolidColor,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_SolidColor,"$Id$"); + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +/* === E N T R Y P O I N T ================================================= */ + +Layer_SolidColor::Layer_SolidColor(): + Layer_Composite(1.0,Color::BLEND_COMPOSITE), + param_color(ValueBase(Color::black())) +{ + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +bool +Layer_SolidColor::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE_PLUS(param_color, + { + Color color=param_color.get(Color()); + if (color.get_a() == 0) + { + if (converted_blend_) + { + set_blend_method(Color::BLEND_ALPHA_OVER); + color.set_a(1); + param_color.set(color); + } + else transparent_color_ = true; + } + } + ); + + return Layer_Composite::set_param(param,value); +} + +ValueBase +Layer_SolidColor::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_color); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_Composite::get_param(param); +} + +Layer::Vocab +Layer_SolidColor::get_param_vocab()const +{ + Layer::Vocab ret(Layer_Composite::get_param_vocab()); + + ret.push_back(ParamDesc("color") + .set_local_name(_("Color")) + .set_description(_("Fill color of the layer")) + ); + + return ret; +} + +synfig::Layer::Handle +Layer_SolidColor::hit_check(synfig::Context context, const synfig::Point &point)const +{ + Color color=param_color.get(Color()); + if(get_blend_method()==Color::BLEND_STRAIGHT && get_amount()>=0.5) + return const_cast(this); + else + if(get_blend_method()==Color::BLEND_COMPOSITE && get_amount()*color.get_a()>=0.5) + return const_cast(this); + + Layer::Handle layer(context.hit_check(point)); + + return layer?layer:const_cast(this); +} + +Color +Layer_SolidColor::get_color(Context context, const Point &pos)const +{ + Color color=param_color.get(Color()); + if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT) + return color; + else + return Color::blend(color,context.get_color(pos),get_amount(),get_blend_method()); +} + +bool +Layer_SolidColor::accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + Color color=param_color.get(Color()); + if(get_amount()==1.0 && get_blend_method()==Color::BLEND_STRAIGHT) + { + // Mark our progress as starting + if(cb && !cb->amount_complete(0,1000)) + return false; + + surface->set_wh(renddesc.get_w(),renddesc.get_h()); + surface->fill(color); + + // Mark our progress as finished + if(cb && !cb->amount_complete(1000,1000)) + return false; + + return true; + } + + SuperCallback supercb(cb,0,9500,10000); + + if(!context.accelerated_render(surface,quality,renddesc,&supercb)) + return false; + + int x,y; + + Surface::alpha_pen apen(surface->begin()); + + apen.set_value(color); + apen.set_alpha(get_amount()); + apen.set_blend_method(get_blend_method()); + + for(y=0;yamount_complete(10000,10000)) + return false; + + return true; +} + +////// + +bool +Layer_SolidColor::accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const +{ + Color color=param_color.get(Color()); + float r(color.get_r()), + g(color.get_g()), + b(color.get_b()), + a(color.get_a()); + + if((get_amount()==1.f && get_blend_method()==Color::BLEND_STRAIGHT) + || + (get_amount()==1.f && color.get_a()==1.f && get_blend_method()==Color::BLEND_COMPOSITE) + ) + { + // Mark our progress as starting + if(cb && !cb->amount_complete(0,1000)) + return false; + cairo_save(cr); + cairo_set_source_rgba(cr, r, g, b, a); + cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE); + cairo_paint(cr); + cairo_restore(cr); + // Mark our progress as finished + if(cb && !cb->amount_complete(1000,1000)) + return false; + return true; + } + + SuperCallback supercb(cb,0,9500,10000); + + if(!context.accelerated_cairorender(cr,quality,renddesc,&supercb)) + return false; + + cairo_save(cr); + cairo_reset_clip(cr); + cairo_set_source_rgba(cr, r, g, b, a); + cairo_paint_with_alpha_operator(cr, get_amount(), get_blend_method()); + cairo_restore(cr); + + // Mark our progress as finished + if(cb && !cb->amount_complete(10000,10000)) + return false; + + return true; +} + +////// diff --git a/synfig-core/src/synfig/layers/layer_solidcolor.h b/synfig-core/src/synfig/layers/layer_solidcolor.h new file mode 100644 index 0000000..c1ffea8 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_solidcolor.h @@ -0,0 +1,73 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_solidcolor.h +** \brief Header file for implementation of the "Solid Color" layer +** +** $Id$ +** +** \legal +** Copyright (c) 2002-2005 Robert B. Quattlebaum Jr., Adrian Bentley +** Copyright (c) 2012-2013 Carlos López +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_SOLIDCOLOR_H +#define __SYNFIG_LAYER_SOLIDCOLOR_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_composite.h" +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +class Layer_SolidColor : public Layer_Composite, public Layer_NoDeform +{ + SYNFIG_LAYER_MODULE_EXT + +private: + + //!Parameter: (Color) color of the solid + ValueBase param_color; + +public: + + Layer_SolidColor(); + + virtual bool set_param(const String & param, const synfig::ValueBase &value); + + virtual ValueBase get_param(const String & param)const; + + virtual Color get_color(Context context, const Point &pos)const; + + virtual bool accelerated_render(Context context,Surface *surface,int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual bool accelerated_cairorender(Context context, cairo_t *cr, int quality, const RendDesc &renddesc, ProgressCallback *cb)const; + virtual Vocab get_param_vocab()const; + + virtual synfig::Layer::Handle hit_check(synfig::Context context, const synfig::Point &point)const; + +}; // END of class Layer_SolidColor + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_sound.cpp b/synfig-core/src/synfig/layers/layer_sound.cpp new file mode 100644 index 0000000..4403548 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_sound.cpp @@ -0,0 +1,131 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_sound.cpp +** \brief Implementation of the "Sound" layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_sound.h" +#include +#include +#include +#include +#include + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Sound); +SYNFIG_LAYER_SET_NAME(Layer_Sound,"sound"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Sound,N_("Sound")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Sound,N_("Other")); +SYNFIG_LAYER_SET_VERSION(Layer_Sound,"0.1"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Sound,"$Id$"); + +/* === P R O C E D U R E S ================================================= */ + +/* === M E T H O D S ======================================================= */ + +/* === E N T R Y P O I N T ================================================= */ + +Layer_Sound::Layer_Sound(): + Layer_Composite(0.0), + param_filename(String()), + param_delay(Time()), + param_volume(Real(1.0)) +{ + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +bool +Layer_Sound::set_param(const String ¶m, const ValueBase &value) +{ + IMPORT_VALUE(param_filename); + IMPORT_VALUE(param_delay); + IMPORT_VALUE(param_volume); + + return Layer::set_param(param,value); +} + +ValueBase +Layer_Sound::get_param(const String ¶m)const +{ + EXPORT_VALUE(param_filename); + EXPORT_VALUE(param_delay); + EXPORT_VALUE(param_volume); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer::get_param(param); +} + +Layer::Vocab +Layer_Sound::get_param_vocab()const +{ + Layer::Vocab ret(Layer::get_param_vocab()); + + ret.push_back(ParamDesc("filename") + .set_local_name(_("Filename")) + .set_description(_("Path to sound file")) + .set_static(true) + .set_hint("filename") + ); + + ret.push_back(ParamDesc("delay") + .set_local_name(_("Delay")) + .set_description(_("Delay before play")) + .set_static(true) + ); + + ret.push_back(ParamDesc("volume") + .set_local_name(_("Volume")) + .set_description(_("Volume of sound")) + .set_static(true) + ); + + return ret; +} + +void +Layer_Sound::fill_sound_processor(SoundProcessor &soundProcessor) const +{ + String filename = param_filename.get(String()); + Time delay = param_delay.get(Time()); + Real volume = param_volume.get(Real()); + if (!filename.empty()) + soundProcessor.addSound(SoundProcessor::PlayOptions(delay, volume), SoundProcessor::Sound(filename)); +} + diff --git a/synfig-core/src/synfig/layers/layer_sound.h b/synfig-core/src/synfig/layers/layer_sound.h new file mode 100644 index 0000000..cfd1e30 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_sound.h @@ -0,0 +1,61 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_sound.h +** \brief Header file for implementation of the "Sound" layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_SOUND_H +#define __SYNFIG_LAYER_SOUND_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_composite.h" +#include + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { + +class Layer_Sound : public Layer_Composite, public Layer_NoDeform +{ + SYNFIG_LAYER_MODULE_EXT +private: + ValueBase param_filename; + ValueBase param_delay; + ValueBase param_volume; + +public: + Layer_Sound(); + virtual bool set_param(const String & param, const synfig::ValueBase &value); + virtual ValueBase get_param(const String & param)const; + virtual Vocab get_param_vocab()const; + virtual void fill_sound_processor(SoundProcessor &soundProcessor) const; +}; // END of class Layer_SolidColor + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/layers/layer_switch.cpp b/synfig-core/src/synfig/layers/layer_switch.cpp new file mode 100644 index 0000000..220bea3 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_switch.cpp @@ -0,0 +1,147 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_switch.cpp +** \brief Implementation of the "Switch" layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === H E A D E R S ======================================================= */ + +#ifdef USING_PCH +# include "pch.h" +#else +#ifdef HAVE_CONFIG_H +# include +#endif + +#include "layer_switch.h" +#include +#include +#include +#include +#include +#include +#include + + +#endif + +/* === U S I N G =========================================================== */ + +using namespace etl; +using namespace std; +using namespace synfig; + +/* === M A C R O S ========================================================= */ + +/* === C L A S S E S ======================================================= */ + +/* === G L O B A L S ======================================================= */ + +SYNFIG_LAYER_INIT(Layer_Switch); +SYNFIG_LAYER_SET_NAME(Layer_Switch,"switch"); +SYNFIG_LAYER_SET_LOCAL_NAME(Layer_Switch,N_("Switch")); +SYNFIG_LAYER_SET_CATEGORY(Layer_Switch,N_("Other")); +SYNFIG_LAYER_SET_VERSION(Layer_Switch,"0.0"); +SYNFIG_LAYER_SET_CVS_ID(Layer_Switch,"$Id$"); + +/* === M E T H O D S ======================================================= */ + +Layer_Switch::Layer_Switch() +{ + param_layer_name=ValueBase(String()); + set_param("children_lock",ValueBase(true)); + + SET_INTERPOLATION_DEFAULTS(); + SET_STATIC_DEFAULTS(); +} + +Layer_Switch::~Layer_Switch() +{ +} + +String +Layer_Switch::get_local_name()const +{ + String s = Layer_PasteCanvas::get_local_name(); + return s.empty() ? _("Switch") : _("Switch") + (" [" + s + ']'); +} + +Layer::Vocab +Layer_Switch::get_param_vocab()const +{ + Layer::Vocab ret(Layer_PasteCanvas::get_param_vocab()); + + ret.push_back(ParamDesc("layer_name") + .set_local_name(_("Active Layer Name")) + .set_description(_("Only layer with specified name are visible")) + ); + + return ret; +} + +bool +Layer_Switch::set_param(const String & param, const ValueBase &value) +{ + IMPORT_VALUE(param_layer_name); + return Layer_PasteCanvas::set_param(param,value); +} + +ValueBase +Layer_Switch::get_param(const String& param)const +{ + EXPORT_VALUE(param_layer_name); + + EXPORT_NAME(); + EXPORT_VERSION(); + + return Layer_PasteCanvas::get_param(param); +} + +Layer::Handle +Layer_Switch::get_current_layer()const +{ + Canvas::Handle canvas = get_sub_canvas(); + String n = param_layer_name.get(String()); + if (canvas) + for(IndependentContext i = canvas->get_independent_context(); *i; i++) + if ((*i)->get_description() == n) + return *i; + return NULL; +} + + +void +Layer_Switch::apply_z_range_to_params(ContextParams &cp)const +{ + if (optimized()) return; // z_range already applied while optimizxation + + Layer::Handle layer = get_current_layer(); + if (layer) { + cp.z_range=true; + cp.z_range_position=layer->get_depth(); + cp.z_range_depth=0; + cp.z_range_blur=0; + return; + } + + cp.z_range=true; + cp.z_range_position=0; + cp.z_range_depth=-1; + cp.z_range_blur=0; +} diff --git a/synfig-core/src/synfig/layers/layer_switch.h b/synfig-core/src/synfig/layers/layer_switch.h new file mode 100644 index 0000000..978ed78 --- /dev/null +++ b/synfig-core/src/synfig/layers/layer_switch.h @@ -0,0 +1,75 @@ +/* === S Y N F I G ========================================================= */ +/*! \file layer_switch.h +** \brief Header file for implementation of the "Switch" layer +** +** $Id$ +** +** \legal +** ......... ... 2014 Ivan Mahonin +** +** This package is free software; you can redistribute it and/or +** modify it under the terms of the GNU General Public License as +** published by the Free Software Foundation; either version 2 of +** the License, or (at your option) any later version. +** +** This package is distributed in the hope that it will be useful, +** but WITHOUT ANY WARRANTY; without even the implied warranty of +** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +** General Public License for more details. +** \endlegal +*/ +/* ========================================================================= */ + +/* === S T A R T =========================================================== */ + +#ifndef __SYNFIG_LAYER_SWITCH_H +#define __SYNFIG_LAYER_SWITCH_H + +/* === H E A D E R S ======================================================= */ + +#include "layer_pastecanvas.h" + +/* === M A C R O S ========================================================= */ + +/* === T Y P E D E F S ===================================================== */ + +/* === C L A S S E S & S T R U C T S ======================================= */ + +namespace synfig { +/*! \class Layer_Switch +** \brief Class of the Switch layer. +*/ +class Layer_Switch : public Layer_PasteCanvas +{ + //! Layer module: defines the needed members to belong to a layer's factory. + SYNFIG_LAYER_MODULE_EXT +private: + //! Parameter: (String) Active Layer Name + ValueBase param_layer_name; + +public: + //! Default constructor + Layer_Switch(); + //! Destructor + virtual ~Layer_Switch(); + //! Returns a string with the localized name of this layer + virtual String get_local_name()const; + + //! Sets the parameter described by \a param to \a value. \see Layer::set_param + virtual bool set_param(const String & param, const synfig::ValueBase &value); + //! Get the value of the specified parameter. \see Layer::get_param + virtual ValueBase get_param(const String & param)const; + //! Gets the parameter vocabulary + virtual Vocab get_param_vocab()const; + + Layer::Handle get_current_layer()const; + + //! Sets z_range* fields of specified ContextParams \a cp + virtual void apply_z_range_to_params(ContextParams &cp)const; +}; // END of class Layer_Switch + +}; // END of namespace synfig + +/* === E N D =============================================================== */ + +#endif diff --git a/synfig-core/src/synfig/loadcanvas.cpp b/synfig-core/src/synfig/loadcanvas.cpp index 52f42db..62d6ae6 100644 --- a/synfig-core/src/synfig/loadcanvas.cpp +++ b/synfig-core/src/synfig/loadcanvas.cpp @@ -43,7 +43,7 @@ #include #include -#include "layer_group.h" +#include #include "loadcanvas.h" #include "valuenode.h" #include "boneweightpair.h" diff --git a/synfig-core/src/synfig/timepointcollect.cpp b/synfig-core/src/synfig/timepointcollect.cpp index a60fd46..d02d7b1 100644 --- a/synfig-core/src/synfig/timepointcollect.cpp +++ b/synfig-core/src/synfig/timepointcollect.cpp @@ -31,8 +31,8 @@ #endif #include "timepointcollect.h" -#include "valuenodes/valuenode_animated.h" -#include "layer_pastecanvas.h" +#include +#include #include "layer.h" #include "canvas.h" #include "value.h" diff --git a/synfig-studio/src/gui/actionmanagers/layeractionmanager.cpp b/synfig-studio/src/gui/actionmanagers/layeractionmanager.cpp index 505243d..b1e69c5 100644 --- a/synfig-studio/src/gui/actionmanagers/layeractionmanager.cpp +++ b/synfig-studio/src/gui/actionmanagers/layeractionmanager.cpp @@ -34,7 +34,7 @@ #include "layeractionmanager.h" #include "trees/layertree.h" #include -#include +#include #include #include "instance.h" #include diff --git a/synfig-studio/src/gui/canvasview.cpp b/synfig-studio/src/gui/canvasview.cpp index 379cfb1..f913420 100644 --- a/synfig-studio/src/gui/canvasview.cpp +++ b/synfig-studio/src/gui/canvasview.cpp @@ -82,7 +82,7 @@ #include #include #include -#include +#include #include #include diff --git a/synfig-studio/src/gui/cellrenderer/cellrenderer_timetrack.cpp b/synfig-studio/src/gui/cellrenderer/cellrenderer_timetrack.cpp index 59d7af6..e328333 100644 --- a/synfig-studio/src/gui/cellrenderer/cellrenderer_timetrack.cpp +++ b/synfig-studio/src/gui/cellrenderer/cellrenderer_timetrack.cpp @@ -47,7 +47,7 @@ #include "general.h" -#include +#include #endif diff --git a/synfig-studio/src/gui/duckmatic.cpp b/synfig-studio/src/gui/duckmatic.cpp index 7e7e6d4..c709897 100644 --- a/synfig-studio/src/gui/duckmatic.cpp +++ b/synfig-studio/src/gui/duckmatic.cpp @@ -64,7 +64,7 @@ #include #include -#include +#include #include #include diff --git a/synfig-studio/src/gui/states/state_brush.cpp b/synfig-studio/src/gui/states/state_brush.cpp index 0766449..51dc260 100644 --- a/synfig-studio/src/gui/states/state_brush.cpp +++ b/synfig-studio/src/gui/states/state_brush.cpp @@ -37,7 +37,7 @@ #include #include -#include +#include #include "state_brush.h" #include "state_normal.h" diff --git a/synfig-studio/src/gui/trees/layertreestore.cpp b/synfig-studio/src/gui/trees/layertreestore.cpp index f2e1636..262413a 100644 --- a/synfig-studio/src/gui/trees/layertreestore.cpp +++ b/synfig-studio/src/gui/trees/layertreestore.cpp @@ -40,7 +40,7 @@ #include #include "app.h" #include "instance.h" -#include +#include #include #include diff --git a/synfig-studio/src/synfigapp/actions/layeradd.cpp b/synfig-studio/src/synfigapp/actions/layeradd.cpp index c701391..d53d21d 100644 --- a/synfig-studio/src/synfigapp/actions/layeradd.cpp +++ b/synfig-studio/src/synfigapp/actions/layeradd.cpp @@ -33,7 +33,7 @@ #include "layeradd.h" #include #include -#include +#include #include #endif diff --git a/synfig-studio/src/synfigapp/actions/layeraddframe.h b/synfig-studio/src/synfigapp/actions/layeraddframe.h index e7a5bb6..0b68523 100644 --- a/synfig-studio/src/synfigapp/actions/layeraddframe.h +++ b/synfig-studio/src/synfigapp/actions/layeraddframe.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ #include -#include +#include #include #include #include diff --git a/synfig-studio/src/synfigapp/actions/layercopy.cpp b/synfig-studio/src/synfigapp/actions/layercopy.cpp index d7bb5fc..343706e 100644 --- a/synfig-studio/src/synfigapp/actions/layercopy.cpp +++ b/synfig-studio/src/synfigapp/actions/layercopy.cpp @@ -35,7 +35,7 @@ #include #include #include -#include +#include #endif diff --git a/synfig-studio/src/synfigapp/actions/layerembed.cpp b/synfig-studio/src/synfigapp/actions/layerembed.cpp index c48f3bf..96df9d3 100644 --- a/synfig-studio/src/synfigapp/actions/layerembed.cpp +++ b/synfig-studio/src/synfigapp/actions/layerembed.cpp @@ -31,7 +31,7 @@ #include "layerembed.h" -#include +#include #include #include diff --git a/synfig-studio/src/synfigapp/actions/layerembed.h b/synfig-studio/src/synfigapp/actions/layerembed.h index 99bb7a0..97ef07f 100644 --- a/synfig-studio/src/synfigapp/actions/layerembed.h +++ b/synfig-studio/src/synfigapp/actions/layerembed.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ #include -#include +#include #include /* === M A C R O S ========================================================= */ diff --git a/synfig-studio/src/synfigapp/actions/layerextract.h b/synfig-studio/src/synfigapp/actions/layerextract.h index ab5e1d9..6b46449 100644 --- a/synfig-studio/src/synfigapp/actions/layerextract.h +++ b/synfig-studio/src/synfigapp/actions/layerextract.h @@ -28,7 +28,7 @@ /* === H E A D E R S ======================================================= */ #include -#include +#include #include /* === M A C R O S ========================================================= */ diff --git a/synfig-studio/src/synfigapp/actions/layerpaint.cpp b/synfig-studio/src/synfigapp/actions/layerpaint.cpp index 3b1c41f..8c28f22 100644 --- a/synfig-studio/src/synfigapp/actions/layerpaint.cpp +++ b/synfig-studio/src/synfigapp/actions/layerpaint.cpp @@ -33,7 +33,7 @@ #include #include #include -#include +#include #include #endif diff --git a/synfig-studio/src/synfigapp/actions/layerpaint.h b/synfig-studio/src/synfigapp/actions/layerpaint.h index 3013c3a..c0da416 100644 --- a/synfig-studio/src/synfigapp/actions/layerpaint.h +++ b/synfig-studio/src/synfigapp/actions/layerpaint.h @@ -27,7 +27,7 @@ /* === H E A D E R S ======================================================= */ -#include +#include #include #include diff --git a/synfig-studio/src/synfigapp/actions/layerzdepthrangeset.cpp b/synfig-studio/src/synfigapp/actions/layerzdepthrangeset.cpp index eb808b8..660394a 100644 --- a/synfig-studio/src/synfigapp/actions/layerzdepthrangeset.cpp +++ b/synfig-studio/src/synfigapp/actions/layerzdepthrangeset.cpp @@ -37,7 +37,7 @@ #include -#include +#include #endif diff --git a/synfig-studio/src/synfigapp/actions/timepointscopy.cpp b/synfig-studio/src/synfigapp/actions/timepointscopy.cpp index b1276a7..8546624 100644 --- a/synfig-studio/src/synfigapp/actions/timepointscopy.cpp +++ b/synfig-studio/src/synfigapp/actions/timepointscopy.cpp @@ -30,7 +30,7 @@ #endif #include "timepointscopy.h" -#include +#include #include #include #include diff --git a/synfig-studio/src/synfigapp/actions/timepointsdelete.cpp b/synfig-studio/src/synfigapp/actions/timepointsdelete.cpp index da8a258..6ded4ee 100644 --- a/synfig-studio/src/synfigapp/actions/timepointsdelete.cpp +++ b/synfig-studio/src/synfigapp/actions/timepointsdelete.cpp @@ -30,7 +30,7 @@ #endif #include "timepointsdelete.h" -#include +#include #include #include #include diff --git a/synfig-studio/src/synfigapp/actions/timepointsmove.cpp b/synfig-studio/src/synfigapp/actions/timepointsmove.cpp index 7fdca0e..10f84a1 100644 --- a/synfig-studio/src/synfigapp/actions/timepointsmove.cpp +++ b/synfig-studio/src/synfigapp/actions/timepointsmove.cpp @@ -30,7 +30,7 @@ #endif #include "timepointsmove.h" -#include +#include #include #include #include diff --git a/synfig-studio/src/synfigapp/actions/valuedesccreatechildbone.h b/synfig-studio/src/synfigapp/actions/valuedesccreatechildbone.h index 0702fad..df98e5b 100644 --- a/synfig-studio/src/synfigapp/actions/valuedesccreatechildbone.h +++ b/synfig-studio/src/synfigapp/actions/valuedesccreatechildbone.h @@ -30,7 +30,7 @@ #include #include #include -#include +#include #include #include diff --git a/synfig-studio/src/synfigapp/actions/valuedescresetpose.h b/synfig-studio/src/synfigapp/actions/valuedescresetpose.h index 05c0bbc..4ef982a 100644 --- a/synfig-studio/src/synfigapp/actions/valuedescresetpose.h +++ b/synfig-studio/src/synfigapp/actions/valuedescresetpose.h @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include diff --git a/synfig-studio/src/synfigapp/instance.cpp b/synfig-studio/src/synfigapp/instance.cpp index e022cbd..9d78c0a 100644 --- a/synfig-studio/src/synfigapp/instance.cpp +++ b/synfig-studio/src/synfigapp/instance.cpp @@ -54,8 +54,8 @@ #include #include #include -#include -#include +#include +#include #include #include "actions/valuedescexport.h" #include "actions/layerparamset.h" diff --git a/synfig-studio/src/synfigapp/timegather.cpp b/synfig-studio/src/synfigapp/timegather.cpp index 5b71201..042db89 100644 --- a/synfig-studio/src/synfigapp/timegather.cpp +++ b/synfig-studio/src/synfigapp/timegather.cpp @@ -33,7 +33,7 @@ #include "timegather.h" #include "value_desc.h" -#include +#include #include "general.h"