<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
		<id>https://www.wiki.synfig.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dooglus</id>
		<title>Synfig Studio :: Documentation - User contributions [en]</title>
		<link rel="self" type="application/atom+xml" href="https://www.wiki.synfig.org/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Dooglus"/>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/Special:Contributions/Dooglus"/>
		<updated>2026-04-30T19:11:44Z</updated>
		<subtitle>User contributions</subtitle>
		<generator>MediaWiki 1.26.3</generator>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Build_Instructions&amp;diff=8678</id>
		<title>Dev:Build Instructions</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Build_Instructions&amp;diff=8678"/>
				<updated>2009-05-26T10:46:04Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* synfig */ line was 625 not 622 for me&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Building]]&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
If you are using the released versions instead of SVN, none of the libtoolize or autoreconf steps are necessary. For released versions, &amp;quot;./configure &amp;amp;&amp;amp; make &amp;amp;&amp;amp; sudo make install&amp;quot; should be enough.&lt;br /&gt;
&lt;br /&gt;
If you are using packages for synfig's dependencies, you want the '''development packages''' not the main packages. Check below for your distribution's packages.&lt;br /&gt;
&lt;br /&gt;
Please read the [[Source code|source code]] page to check out the latest code. Please also check the [[Download|download page]] and the [[FAQ]] to find out about any issues that you may run into along the way.&lt;br /&gt;
&lt;br /&gt;
Some Linux/BSD distros have a pkg-config that doesn't look in /usr/local/lib/pkgconfig by default. So if you are installing in anywhere other than the system pkg-config path, please run &amp;quot;export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig&amp;quot; or similar before building or installing anything.&lt;br /&gt;
&lt;br /&gt;
Don't use automake 1.4, there are problems with it.&lt;br /&gt;
&lt;br /&gt;
Using automake 1.9, 'make install' seems to re-link and re-install all the synfig core modules every time whether they have changed or not.  [http://dooglus.rincevent.net/synfig/automake.html here] is an ugly workaround - it's only worth using if you intend to rebuild synfig repeatedly&lt;br /&gt;
&lt;br /&gt;
The instructions below result in 3 separate subversion working directories being created.  This is inconvenient to work with - you'll need to 'svn commit' in 3 different places to send changes, 'svn update' in 3 different places to get the latest updates, etc.  [[Subversion|This page]] shows how to arrange for the code to be checked out into a single working directory. You can also download a daily updated tarball that uses this from the [[Source code|source code]] page.&lt;br /&gt;
&lt;br /&gt;
The CVS requirement is only because the autopoint program run by autoreconf needs CVS. You can avoid the need for CVS by disabling the translation/gettext stuff in configure.ac.&lt;br /&gt;
&lt;br /&gt;
If you don't want to install to a system-wide directory using sudo, run something like these commands before starting:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PREFIX=&amp;quot;$HOME/opt&amp;quot;&lt;br /&gt;
export PKG_CONFIG_PATH=&amp;quot;$PKG_CONFIG_PATH:$PREFIX/lib/pkgconfig&amp;quot;&lt;br /&gt;
export PATH=&amp;quot;$PATH:$PREFIX/bin&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And when you run ./configure, run it with --prefix=&amp;quot;$PREFIX&amp;quot; and don't use sudo when you do make install.&lt;br /&gt;
&lt;br /&gt;
=== Automatic build/update script ===&lt;br /&gt;
&lt;br /&gt;
You can use [http://zelgadis.profusehost.net/files/synfig/synfigstudio-svn-build this] script to quickly build/update synfigstudio from SVN (software installed in ~/synfig-svn by default).&lt;br /&gt;
&lt;br /&gt;
To use the script just execute following single command in terminal: &lt;br /&gt;
&amp;lt;pre&amp;gt;cd &amp;amp;&amp;amp; \&lt;br /&gt;
wget http://zelgadis.profusehost.net/files/synfig/synfigstudio-svn-build &amp;amp;&amp;amp; \&lt;br /&gt;
chmod +x synfigstudio-svn-build &amp;amp;&amp;amp; \&lt;br /&gt;
./synfigstudio-svn-build initialize&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Your system must satisfy synfig's build requiments, the sript won't do it for you.&lt;br /&gt;
&lt;br /&gt;
=== System-specific instructions ===&lt;br /&gt;
&lt;br /&gt;
* Gentoo: SVN [[Gentoo Ebuilds|ebuilds]] are available&lt;br /&gt;
* MacOS X: [[Building_On_Mac_OS_X|instructions for building]] with the GTK+ Aqua port are available.&lt;br /&gt;
* PCLinuxOS: [[PCLinuxOS build instructions|build instructions]]&lt;br /&gt;
* Windows: [[Windows build instructions|instructions for building]] in [[Mingw_installation|mingw]] are available.&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
&lt;br /&gt;
ETL is a template library, there is nothing to build really, it just needed to be installed.&lt;br /&gt;
&lt;br /&gt;
Requires: autoconf automake&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: build-essential autoconf automake&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''ETL:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== synfig ==&lt;br /&gt;
&lt;br /&gt;
Requires: ETL (etl-dev, already installed if you successfully built etl), libxml++, libsigc++, libltdl, libtool, gettext, cvs&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: etl-dev libxml++2.6-dev libsigc++-2.0-dev libltdl3-dev libtool gettext cvs&lt;br /&gt;
* Gentoo: virtual/ETL dev-cpp/libxmlpp dev-libs/libsigc++ dev-util/cvs&lt;br /&gt;
** If you are using ./configure --prefix=&amp;quot;$PREFIX&amp;quot; to configure synfig, do not install virtual/ETL.&lt;br /&gt;
&lt;br /&gt;
Note: libpng isn't required to build synfig, but if you build synfig without PNG support and go on to build synfigstudio, that step will fail (because the build process for synfigstudio uses synfig to create .png icon files).  The package is  libpng12-dev on Debian or media-libs/libpng on Gentoo.&lt;br /&gt;
&lt;br /&gt;
Note: the 'configure.ac' file in the synfig-core directory doesn't work with libtool version 2, as shipped with ubuntu 8.10.  To work around the problem until a proper fix is found, comment out line 622 or thereabouts (it says &amp;quot;AC_CONFIG_SUBDIRS(libltdl)&amp;quot;) by putting a &amp;quot;#&amp;quot; at the front of the line.  The line is required for older versions of libtool, as shipped with other distributions.&lt;br /&gt;
&lt;br /&gt;
Optional: libpng, libmng, libjpeg, libfreetype, libfontconfig, libopenexr, libavcodec, libmagick++, vimage (MacOS only, proprietary)&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: libpng12-dev libmng-dev libjpeg62-dev libfreetype6-dev libfontconfig1-dev libopenexr-dev libavcodec-dev libavformat-dev libswscale-dev libmagick++9-dev&lt;br /&gt;
* Gentoo: sys-devel/libtool media-libs/libpng media-libs/libmng media-libs/jpeg media-libs/freetype media-libs/fontconfig media-libs/openexr media-libs/libavcodec&lt;br /&gt;
*Ubuntu (since Jaunty): Same libraries as Debian but do not use libmagick++9-dev, use graphicsmagick-libmagick-dev-compat instead.&lt;br /&gt;
Runtime: encodedv (from libdv), ffmpeg, convert (from imagemagick)&lt;br /&gt;
* Debian: libdv-bin ffmpeg imagemagick&lt;br /&gt;
* Gentoo: media-libs/libdv media-video/ffmpeg media-gfx/imagemagick&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''synfig-core:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ libtoolize --ltdl --copy --force&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ make&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Don't use --enable-half, it is slow.&lt;br /&gt;
&lt;br /&gt;
== synfigstudio ==&lt;br /&gt;
&lt;br /&gt;
Requires: ETL (etl-dev, already installed if you successfully built etl), synfig (libsynfig-dev, already installed if you successfully built synfig), gtkmm &amp;gt;= 2.4, gtk &amp;gt;= 2.0, glibmm, libsigc++, libltdl, libtool, gettext, cvs&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: etl-dev libsynfig-dev libgtkmm-2.4-dev libgtk2.0-dev libglibmm-2.4-dev libsigc++-2.0-dev libltdl3-dev libtool gettext cvs&lt;br /&gt;
* Gentoo: virtual/ETL virtual/synfig dev-cpp/gtkmm-2.4 dev-libs/libsigc++ sys-devel/libtool&lt;br /&gt;
** If you are using ./configure --prefix=&amp;quot;$PREFIX&amp;quot; to configure synfigstudio, do not install virtual/ETL or virtual/synfig.&lt;br /&gt;
Optional: fonts (for the images), [http://www.fmod.org FMOD] (version 3.x, proprietary)&lt;br /&gt;
* Debian: ttf-freefont ttf-dejavu ttf-dustin&lt;br /&gt;
* Gentoo: freefonts dejavu&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''synfig-studio:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ make&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
== synfig-docs ==&lt;br /&gt;
&lt;br /&gt;
(This step isn't required to run synfig or synfigstudio, and the documents it gets you are really quite out of date)&lt;br /&gt;
&lt;br /&gt;
This is basically a copy of what is on this wiki.&lt;br /&gt;
&lt;br /&gt;
Requires: sgml processor, ldp docbook stylesheets, db2ps, db2pdf&lt;br /&gt;
* Debian: openjade ldp-docbook-dsssl docbook-utils&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make multiple-html&lt;br /&gt;
make ps&lt;br /&gt;
make pdf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== finalizing ==&lt;br /&gt;
&lt;br /&gt;
Depending on where you installed synfig to, you might have to tell your system where the libraries can be found.  That can be done via the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ sudo ldconfig&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=File:Tree3.gif&amp;diff=8304</id>
		<title>File:Tree3.gif</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=File:Tree3.gif&amp;diff=8304"/>
				<updated>2008-12-19T11:13:59Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: an example of the bones work in progress&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;an example of the bones work in progress&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Convert&amp;diff=8303</id>
		<title>Convert</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Convert&amp;diff=8303"/>
				<updated>2008-12-18T22:15:02Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Random */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Right-clicking on a value in the Parameters dialog brings up a context menu which has a sub-menu called &amp;quot;Convert&amp;quot;.  The &amp;quot;Convert&amp;quot; menu allows you to specify that the parameter should be controlled automatically in various ways.  Depending on the type of the parameter the Convert menu will contain different options.&lt;br /&gt;
&lt;br /&gt;
To convert the value back to its original type, select &amp;quot;Disconnect&amp;quot; from its context menu.&lt;br /&gt;
&lt;br /&gt;
== Convert Types ==&lt;br /&gt;
&lt;br /&gt;
=== Add ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Add&amp;quot; adds three sub-parameters, the first two of which are the same type as the parameter itself:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;LHS&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;RHS&amp;quot;&lt;br /&gt;
* real &amp;quot;Scalar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Add&amp;quot; conversion can be used with parameters of type [[Convert#Angle|angle]], [[Convert#Color|color]], [[Convert#Gradient|gradient]], [[Convert#Integer|integer]], [[Convert#Real|real]], [[Convert#Time|time]], and [[Convert#Vector|vector]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   (LHS + RHS) * Scalar&lt;br /&gt;
&lt;br /&gt;
=== Angle String ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#String|string]]-valued parameter to &amp;quot;Angle String&amp;quot; adds four sub-parameters:&lt;br /&gt;
* angle &amp;quot;Angle&amp;quot;&lt;br /&gt;
* integer &amp;quot;Width&amp;quot;&lt;br /&gt;
* integer &amp;quot;Precision&amp;quot;&lt;br /&gt;
* bool &amp;quot;Zero Padded&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value a string containing the value of &amp;quot;Angle&amp;quot; (in degrees) formatted as a string with a minimum width &amp;quot;Width&amp;quot;, with &amp;quot;Precision&amp;quot; decimal places.  If &amp;quot;Zero Padded&amp;quot; is true, it will be left-padded with &amp;quot;0&amp;quot; characters.&lt;br /&gt;
&lt;br /&gt;
=== aTan2 ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]]-valued parameter to &amp;quot;aTan2&amp;quot; adds two sub-parameters:&lt;br /&gt;
* real &amp;quot;X&amp;quot;&lt;br /&gt;
* real &amp;quot;Y&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   atan2(y,x)&lt;br /&gt;
&lt;br /&gt;
ie. atan(y/x) but without an error when x is 0.  The value is the angle between the x axis and the vector (x,y).&lt;br /&gt;
&lt;br /&gt;
=== BLine ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#List|list]] parameter to &amp;quot;BLine&amp;quot; doesn't seem to change anything.  Perhaps that's the default type for lists of vertices, such as are found in outlines and regions?&lt;br /&gt;
&lt;br /&gt;
=== BLine Tangent ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Angle|angle]], [[Convert#Real|real]] (since SVN r1862), or [[Convert#Vector|vector]] parameter to &amp;quot;BLine Tangent&amp;quot; adds six sub-parameters:&lt;br /&gt;
* bline &amp;quot;BLine&amp;quot;&lt;br /&gt;
* bool &amp;quot;Loop&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
* angle &amp;quot;Offset&amp;quot; (since SVN r1863)&lt;br /&gt;
* real &amp;quot;Scale&amp;quot; (since SVN r1863)&lt;br /&gt;
* bool &amp;quot;Fixed Length&amp;quot; (since SVN r1863)&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given bline.  The resulting value for the whole parameter is the tangent to the bline, at the given point along the bline, optionally rotated and scaled according to the &amp;quot;Offset&amp;quot;, &amp;quot;Scale&amp;quot;, and &amp;quot;Fixed Length&amp;quot; parameters.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Offset&amp;quot; is an angle used to give the tangent an extra rotation before returning it.  If &amp;quot;Fixed Length&amp;quot; is true, the tangent is then scaled to have a length equal to &amp;quot;Scale&amp;quot;.  Otherwise the tangent is multiplied by &amp;quot;Scale&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If a vector was converted the result is the tangent itself.  If an angle was converted, the result is the angle of the tangent to the horizontal, and if a real was converted, the result is the length of the tangent.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This [[Following a BLine|tutorial]] gives an example of the use of this convert type.&lt;br /&gt;
&lt;br /&gt;
=== BLine Vertex ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;BLine Vertex&amp;quot; adds three sub-parameters:&lt;br /&gt;
* bline &amp;quot;BLine&amp;quot;&lt;br /&gt;
* bool &amp;quot;Loop&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given bline.  The resulting value for the whole parameter is a vector giving the position of the given point along the bline.&lt;br /&gt;
&lt;br /&gt;
This [[Following a BLine|tutorial]] gives an example of the use of this convert type.&lt;br /&gt;
&lt;br /&gt;
=== BLine Width ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] parameter to &amp;quot;BLine Width&amp;quot; adds three sub-parameters:&lt;br /&gt;
* bline &amp;quot;BLine&amp;quot;&lt;br /&gt;
* bool &amp;quot;Loop&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
* real &amp;quot;Scale&amp;quot; (since SVN r1872)&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given bline.  The resulting value for the whole parameter is the width of the bline at the given point along it, multiplied by the &amp;quot;Scale&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
=== Composite ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#BLinePoint|blinepoint]] parameter to &amp;quot;Composite&amp;quot; adds six sub-parameters:&lt;br /&gt;
* vector &amp;quot;Vertex&amp;quot;&lt;br /&gt;
* real &amp;quot;Width&amp;quot;&lt;br /&gt;
* real &amp;quot;Origin&amp;quot;&lt;br /&gt;
* bool &amp;quot;Split Tangents&amp;quot;&lt;br /&gt;
* vector &amp;quot;Tangent 1&amp;quot;&lt;br /&gt;
* vector &amp;quot;Tangent 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] parameter to &amp;quot;Composite&amp;quot; adds four real-valued sub-parameters:&lt;br /&gt;
* real &amp;quot;Red&amp;quot;&lt;br /&gt;
* real &amp;quot;Green&amp;quot;&lt;br /&gt;
* real &amp;quot;Blue&amp;quot;&lt;br /&gt;
* real &amp;quot;Alpha&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Segment|segment]] parameter to &amp;quot;Composite&amp;quot; adds four vertex sub-parameters:&lt;br /&gt;
* vertex &amp;quot;Vertex 1&amp;quot;&lt;br /&gt;
* vertex &amp;quot;Tangent 1&amp;quot;&lt;br /&gt;
* vertex &amp;quot;Vertex 2&amp;quot;&lt;br /&gt;
* vertex &amp;quot;Tangent 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;Composite&amp;quot; adds two real-valued sub-parameters:&lt;br /&gt;
* real &amp;quot;X-Axis&amp;quot;&lt;br /&gt;
* real &amp;quot;Y-Axis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a blinepoint, color, segment, or vector made by combining the component parts.&lt;br /&gt;
&lt;br /&gt;
=== Cos ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Cos&amp;quot; adds two sub-parameters:&lt;br /&gt;
* angle &amp;quot;Angle&amp;quot;&lt;br /&gt;
* real &amp;quot;Amplitude&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Amplitude * cos(Angle)&lt;br /&gt;
&lt;br /&gt;
=== Dot Product ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] or [[Convert#Angle|angle]] parameter to a &amp;quot;Dot Product&amp;quot; adds two sub-parameters:&lt;br /&gt;
* vector &amp;quot;LHS&amp;quot;&lt;br /&gt;
* vector &amp;quot;RHS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the converted value is an angle, the return value is the angle between the two vectors:&lt;br /&gt;
&lt;br /&gt;
 return = acos((LHS · RHS) / (|LHS| * |RHS|))&lt;br /&gt;
&lt;br /&gt;
If the converted value is a real, the result value is the dot product of the two vectors:&lt;br /&gt;
&lt;br /&gt;
 return = LHS · RHS = |LHS| * |RHS| * cos(alpha)&lt;br /&gt;
&lt;br /&gt;
(where alpha is the angle between LHS and RHS).&lt;br /&gt;
&lt;br /&gt;
=== Duplicate ===&lt;br /&gt;
&lt;br /&gt;
This ValueNode type is only used by the [[Duplicate Layer]].  It never appears in the Convert menu.  It is used to control the range of the Index in the Duplicate Layer (q.v.).&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Duplicate&amp;quot; ValueNode type has 3 real-valued sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;From&amp;quot;&lt;br /&gt;
* real &amp;quot;To&amp;quot;&lt;br /&gt;
* real &amp;quot;Step&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The value of the ValueNode varies from the value of &amp;quot;From&amp;quot; to the value of &amp;quot;To&amp;quot; in steps of size &amp;quot;Step&amp;quot;.   The sign of &amp;quot;Step&amp;quot; is ignored.  If From&amp;lt;To the steps are positive, else they're negative.&lt;br /&gt;
&lt;br /&gt;
=== Dynamic List ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#List|list]] parameter to &amp;quot;Dynamic List&amp;quot; seems to replace each of the &amp;quot;Vertex NNN&amp;quot; sub-parameters with &amp;quot;Item NNN&amp;quot; parameters which can't be expanded, but can be exported.&lt;br /&gt;
&lt;br /&gt;
=== Exponential ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] parameter to &amp;quot;Exponential&amp;quot; adds two sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;Exponent&amp;quot;&lt;br /&gt;
* real &amp;quot;Scale&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the result raising the [http://en.wikipedia.org/wiki/E_%28mathematical_constant%29 mathematical constant 'e'] to the power of Exponent, and scaling the result by Scale.  That is, it returns:&lt;br /&gt;
  Scale * e^Exponent&lt;br /&gt;
&lt;br /&gt;
This is useful for tracking layers which have been zoomed, since the Zoom layer scales by e^(zoom factor).&lt;br /&gt;
&lt;br /&gt;
See [http://youtube.com/watch?v=GAWtndOHkUw this video] for an example of the use of this convert type.&lt;br /&gt;
&lt;br /&gt;
=== From Integer ===&lt;br /&gt;
&lt;br /&gt;
This is currently disabled.  It converts an integer to one of several types.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Color ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] parameter to &amp;quot;Gradient Color&amp;quot; adds two sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* gradient &amp;quot;Gradient&amp;quot;&lt;br /&gt;
* real &amp;quot;Index&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a color taken from the gradient at the given index position.  Index 0 corresponds to the left of the gradient; index 1 corresponds to the right of the gradient.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Rotate ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] parameter to &amp;quot;Gradient Rotate&amp;quot; adds two sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* gradient &amp;quot;Gradient&amp;quot;&lt;br /&gt;
* real &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a gradient based on the &amp;quot;Gradient&amp;quot; parameter, but shifted left (for negative values) or right, according to the value of the &amp;quot;Offset&amp;quot; parameter.  An offset of 1.0 will shift the gradient by its entire visible width.  Values shifted off the left or right edge aren't lost - they aren't visible in the gradient as it's displayed in the parameters dialog, but they will still be used when rendering (depending on parameters such as 'Loop' and 'Zigzag', which can cause gradients to be looped between their their left and right edges, rather than using the non-displayed parts).&lt;br /&gt;
&lt;br /&gt;
=== Int String ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#String|string]]-valued parameter to &amp;quot;Int String&amp;quot; adds three sub-parameters:&lt;br /&gt;
* integer &amp;quot;Int&amp;quot;&lt;br /&gt;
* integer &amp;quot;Width&amp;quot;&lt;br /&gt;
* bool &amp;quot;Zero Padded&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value a string containing &amp;quot;Int&amp;quot; formatted as a string with a minimum width &amp;quot;Width&amp;quot;.  If &amp;quot;Zero Padded&amp;quot; is true, it will be left-padded with &amp;quot;0&amp;quot; characters.&lt;br /&gt;
&lt;br /&gt;
=== Joined List ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#String|string]] parameter to be 'Joined List' adds four sub-parameters:&lt;br /&gt;
* list &amp;quot;Strings&amp;quot;&lt;br /&gt;
* string &amp;quot;Before&amp;quot;&lt;br /&gt;
* string &amp;quot;Separator&amp;quot;&lt;br /&gt;
* string &amp;quot;After&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The result is a string containing the value of &amp;quot;Before&amp;quot;, followed by all the strings in the &amp;quot;Strings&amp;quot; list, with the value of &amp;quot;Separator&amp;quot; between each pair, followed by the value of &amp;quot;After&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Linear ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]] parameter to be 'Linear' adds two angle sub-parameters:&lt;br /&gt;
* angle &amp;quot;Rate&amp;quot;&lt;br /&gt;
* angle &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] parameter to be 'Linear' adds two angle sub-parameters (since svn r617):&lt;br /&gt;
* color &amp;quot;Rate&amp;quot;&lt;br /&gt;
* color &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Integer|integer]] parameter to be 'Linear' adds two angle sub-parameters (since svn r617):&lt;br /&gt;
* integer &amp;quot;Rate&amp;quot;&lt;br /&gt;
* integer &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] parameter to be 'Linear' adds two real-valued sub-parameters:&lt;br /&gt;
* real &amp;quot;Rate&amp;quot;&lt;br /&gt;
* real &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Time|time]] parameter to be 'Linear' adds two time sub-parameters:&lt;br /&gt;
* time &amp;quot;Rate&amp;quot;&lt;br /&gt;
* time &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to be 'Linear' adds two vector sub-parameters:&lt;br /&gt;
* vector &amp;quot;Slope&amp;quot;&lt;br /&gt;
* vector &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The parameter's value will change linearly over time, starting with the value specified by &amp;quot;Offset&amp;quot; at time zero, and increasing by the value specified by &amp;quot;Rate&amp;quot; (or &amp;quot;Slope&amp;quot;, in the case of vector parameters) every second.&lt;br /&gt;
&lt;br /&gt;
The resulting value for vector parameters is:&lt;br /&gt;
   Offset + Slope*time&lt;br /&gt;
&lt;br /&gt;
and for the other 5 types of parameter it is:&lt;br /&gt;
   Offset + Rate*time&lt;br /&gt;
&lt;br /&gt;
=== Logarithm ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Logarithm&amp;quot; adds three sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Epsilon&amp;quot;.&lt;br /&gt;
* real &amp;quot;Infinite&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
&lt;br /&gt;
  Log(Link) (if Link &amp;gt;= Epsilon)&lt;br /&gt;
  -Infinite (if Link &amp;lt; Epsilon)&lt;br /&gt;
&lt;br /&gt;
The epsilon and infinite parameters are only needed to prevent logarithm of negative or zero numbers. For regular operation the resulting value is simply the natural logarithm of Link. In fact a logarithm of a negative number cannot be calculated in the space of Real numbers. This convert type returns -Infinite for simplicity.&lt;br /&gt;
&lt;br /&gt;
=== Radial Composite ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] to &amp;quot;Radial Composite&amp;quot; adds four sub-parameters:&lt;br /&gt;
* real &amp;quot;Luma&amp;quot;&lt;br /&gt;
* real &amp;quot;Saturation&amp;quot;&lt;br /&gt;
* angle &amp;quot;Hue&amp;quot;&lt;br /&gt;
* real &amp;quot;Alpha&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] to &amp;quot;Radial Composite&amp;quot; adds two sub-parameters:&lt;br /&gt;
* real &amp;quot;Radius&amp;quot;&lt;br /&gt;
* angle &amp;quot;Theta&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For color parameters, the resulting value is the color with the given lima, saturation, hue, and alpha amounts.&lt;br /&gt;
&lt;br /&gt;
For vector parameters, the resulting value is the point reached by traveling a distance &amp;quot;Radius&amp;quot; from the origin, in the distance given by the angle &amp;quot;Theta&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Random === &lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Random&amp;quot; adds five sub-parameters, the first of which is the same type as the converted parameter:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Radius&amp;quot;&lt;br /&gt;
* integer &amp;quot;Seed&amp;quot;&lt;br /&gt;
* real &amp;quot;Animation Speed&amp;quot;&lt;br /&gt;
* integer &amp;quot;Interpolation&amp;quot;&lt;br /&gt;
* real &amp;quot;Loop Time&amp;quot; (since SVN r2315)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Random&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Color|colors]], [[Convert#Integer|integers]], [[Convert#Real|reals]], [[Convert#Time|times]], and [[Convert#Vector|vectors]].&lt;br /&gt;
&lt;br /&gt;
It is used to cause a parameter's value to vary randomly over time, around a central value:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Link&amp;quot; provides the central value.&lt;br /&gt;
* &amp;quot;Radius&amp;quot; defines the maximum random difference.&lt;br /&gt;
* &amp;quot;Seed&amp;quot; seeds the random number generator&lt;br /&gt;
* &amp;quot;Animation Speed&amp;quot; defines how often a new random value is chosen (in choices per second)&lt;br /&gt;
* &amp;quot;Interpolation&amp;quot; determines how the value is interpolated from one random choice to the next.  Possible values are:&lt;br /&gt;
** 0 - no interpolation; the value jumps from one value to the next&lt;br /&gt;
** 1 - linear interpolation&lt;br /&gt;
** 2 - cosine&lt;br /&gt;
** 3 - spline&lt;br /&gt;
** 4 - cubic (the default); uses [http://www.gamedev.net/reference/articles/article1497.asp Catmull-Rom] spline interpolation&lt;br /&gt;
* &amp;quot;Loop Time&amp;quot; (added in SVN r2315) makes the random value repeat after the given time.  The value ends up the same at the given time as at time=0 so it's possible to make random looping animations without a nasty jump when the time wraps back to zero.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Interpolation&amp;quot; sub-parameter should really be a drop-down menu, rather than an integer field, but that isn't yet implemented.&lt;br /&gt;
&lt;br /&gt;
=== Range ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Range&amp;quot; adds three sub-parameters, all the same type as the parameter itself:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Min&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Max&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Range&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Integer|integers]], [[Convert#Real|reals]], and [[Convert#Time|times]].&lt;br /&gt;
&lt;br /&gt;
It is used to limit the value of the linked parameter to be between Min and Max.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Min (if Link &amp;lt; Min)&lt;br /&gt;
   Max (if Link &amp;gt; Max)&lt;br /&gt;
   Link (otherwise)&lt;br /&gt;
&lt;br /&gt;
=== Real String ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#String|string]] parameter to &amp;quot;Real String&amp;quot; adds four sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;Real&amp;quot;&lt;br /&gt;
* int &amp;quot;Width&amp;quot;&lt;br /&gt;
* int &amp;quot;Precision&amp;quot;&lt;br /&gt;
* bool &amp;quot;Zero Padded&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The result is a string formatted to contain the given value &amp;quot;Real&amp;quot;.  &amp;quot;Width&amp;quot; specifies the minimum field width, &amp;quot;Precision&amp;quot; specifies the number of decimal places and &amp;quot;Zero Padded&amp;quot; specifies whether to pad with zeros on the left hand side.&lt;br /&gt;
&lt;br /&gt;
For example, with Real=3.1415, Width=6, Precision=2, and ZeroPadded=true, we get:&lt;br /&gt;
  &amp;quot;003.14&amp;quot;&lt;br /&gt;
(6 characters long, 2 decimal places, and padded with zeros on the left).&lt;br /&gt;
&lt;br /&gt;
=== Reciprocal ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Reciprocal&amp;quot; adds three sub-parameters:&lt;br /&gt;
* real &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Epsilon&amp;quot;.&lt;br /&gt;
* real &amp;quot;Infinite&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   1/Link (Link &amp;lt;= -epsilon or epsilon &amp;lt;= Link)&lt;br /&gt;
   Infinite (if 0 &amp;lt;= Link &amp;lt; epsilon)&lt;br /&gt;
   -Infinite (if -epsilon &amp;lt; Link &amp;lt; 0)&lt;br /&gt;
&lt;br /&gt;
The epsilon and infinite parameters are only needed to prevent division by zero.  For regular operation the resulting value is simply the reciprocal of Link.&lt;br /&gt;
&lt;br /&gt;
=== Reference ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Reference&amp;quot; adds a single sub-parameter called &amp;quot;Link&amp;quot;.  The &amp;quot;Link&amp;quot; parameter is the same type as the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
It doesn't seem to do anything at all, other than adding an extra parameter.  Whatever value is put into &amp;quot;Link&amp;quot; becomes the value of the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
The only use for this conversion type I can think of is the following:&lt;br /&gt;
&lt;br /&gt;
* you know that point A should follow point B, so you export point B and connect point A to it&lt;br /&gt;
* you're not yet sure exactly how point B should move, so you experiment with different conversion types for point B&lt;br /&gt;
* changing the conversion type for point B breaks the connection you made in the first step&lt;br /&gt;
* converting point B to be a reference, and then experimenting with different conversions in its &amp;quot;Link&amp;quot; parameter allows point A to connect to point B and for the connection to remain in place while you experiment in the &amp;quot;Link&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Link&lt;br /&gt;
&lt;br /&gt;
=== Repeat Gradient ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] parameter to &amp;quot;Repeat Gradient&amp;quot; adds seven sub-parameters:&lt;br /&gt;
* gradient &amp;quot;Gradient&amp;quot;&lt;br /&gt;
* integer &amp;quot;Count&amp;quot;&lt;br /&gt;
* real &amp;quot;Width&amp;quot;&lt;br /&gt;
* bool &amp;quot;Specify Start&amp;quot;&lt;br /&gt;
* bool &amp;quot;Specify End&amp;quot;&lt;br /&gt;
* color &amp;quot;Start Color&amp;quot;&lt;br /&gt;
* color &amp;quot;End Color&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a gradient containing &amp;quot;Count&amp;quot; equally spaced, equally wide copies of gradient &amp;quot;Gradient&amp;quot;.  Each copy has &amp;quot;Gradient&amp;quot; going forwards and then backwards.  &amp;quot;Width&amp;quot; specifies relative width of the forward copy, with a width of 0 or less meaning only the backward copy is used, and a width of 1 or more meaning only the forward copy is used.  A value of 0.5 will result in the forward and reverse copies of &amp;quot;Gradient&amp;quot; being the same width.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Specify Start&amp;quot; is checked then &amp;quot;Start Color&amp;quot; will be inserted at the beginning of the new gradient, otherwise the beginning of &amp;quot;Gradient&amp;quot; will be used as the beginning of the new gradient.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Specify End&amp;quot; is checked then &amp;quot;End Color&amp;quot; will be appended to the end of the new gradient, otherwise the end of &amp;quot;Gradient&amp;quot; will be used as the end of the new gradient.&lt;br /&gt;
&lt;br /&gt;
Here's an example of a repeated gradient - the radiating green/yellow lines are a repeated gradient, applied to a perpendicular curve gradient.  This gradient was repeated with a width of 0.5, meaning it is used backwards and forwards the same amount:&lt;br /&gt;
&lt;br /&gt;
[[Image:Repeat-gradient-valuenode-gradient.png]]&lt;br /&gt;
&lt;br /&gt;
and here's the resulting image, along with the .sif file:&lt;br /&gt;
&lt;br /&gt;
[[Image:Repeat-gradient-valuenode.png]]&lt;br /&gt;
[[Image:Repeat-gradient-valuenode.sif]]&lt;br /&gt;
&lt;br /&gt;
=== Reverse Tangent ===&lt;br /&gt;
&lt;br /&gt;
Converting a blinepoint parameter to &amp;quot;Reverse Tangent&amp;quot; adds two sub-parameters: one called &amp;quot;Reference&amp;quot; of type BLinePoint, and a boolean parameter called &amp;quot;Reverse&amp;quot;.&lt;br /&gt;
* BLinePoint &amp;quot;Reference&amp;quot;&lt;br /&gt;
* bool &amp;quot;Reverse&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Reverse Tangent&amp;quot; can only be used on [[Convert#BLinePoint|blinepoints]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is the same as the reference BLinePoint, but with its tangents switched over.  This is useful when attempting to link the verticies of a region to the vertices of an outline when the region and the outline were drawn in opposite directions, and so tangent1 of an outline vertex needs to be linked to tangent2 of the region vertex, and vice versa.&lt;br /&gt;
&lt;br /&gt;
=== Scale ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Scale&amp;quot; adds two sub-parameters: one called &amp;quot;Link&amp;quot;, of the same type as the parameter itself, and a real-valued parameter called &amp;quot;Scalar&amp;quot;.&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Scalar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Scale&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Color|colors]], [[Convert#Integer|integers]], [[Convert#Real|reals]], [[Convert#Time|times]], and [[Convert#Vector|vectors]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Link * Scalar&lt;br /&gt;
&lt;br /&gt;
=== Segment Tangent ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;Segment Tangent&amp;quot; adds two sub-parameters:&lt;br /&gt;
* segment &amp;quot;Segment&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given segment.  The resulting value for the whole parameter is the tangent to the segment, at the given point along the segment.&lt;br /&gt;
&lt;br /&gt;
=== Segment Vertex ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;Segment Vertex&amp;quot; adds two sub-parameters:&lt;br /&gt;
* segment &amp;quot;Segment&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given segment.  The resulting value is the vertex at the given point along the segment.&lt;br /&gt;
&lt;br /&gt;
=== Sine ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Sine&amp;quot; adds two sub-parameters:&lt;br /&gt;
* angle &amp;quot;Angle&amp;quot;&lt;br /&gt;
* real &amp;quot;Amplitude&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Amplitude * sin(Angle)&lt;br /&gt;
&lt;br /&gt;
=== Step ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]], [[Convert#Color|color]], [[Convert#Integer|integer]], [[Convert#Real|real]], [[Convert#Time|time]], or [[Convert#Vector|vector]] parameter to be 'Step' adds four sub-parameters:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* time &amp;quot;Duration&amp;quot;&lt;br /&gt;
* time &amp;quot;Start Time&amp;quot;&lt;br /&gt;
* real &amp;quot;Intersection&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The parameter's value will change in steps.  Each step is &amp;quot;Duration&amp;quot; seconds long.  The steps start at times &amp;quot;Start Time&amp;quot;, &amp;quot;Start Time&amp;quot;+&amp;quot;Duration&amp;quot;, etc.  The value of the valuenode is the value of &amp;quot;Link&amp;quot; at some time.  &amp;quot;Intersection&amp;quot; determines which time is used.  An &amp;quot;Intersection&amp;quot; of 0.0 means that the value of &amp;quot;Link&amp;quot; at the start of the step should be used.  An &amp;quot;Intersection&amp;quot; of 0.5 (the default) means to use the value of &amp;quot;Link&amp;quot; at the middle of the step, etc.&lt;br /&gt;
&lt;br /&gt;
The resulting value at time &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; is:&lt;br /&gt;
   &amp;lt;math&amp;gt;Link \Bigg ( \Bigg ( Duration \cdot \left ( \left \lfloor \frac{T - Start\ Time}{Duration} \right \rfloor + Intersection \right ) \Bigg ) + Start \ Time \Bigg )&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Link&amp;quot; is a sine wave.  &amp;quot;Duration&amp;quot; is 10f (the frame rate is 24 fps).  &amp;quot;Start Time&amp;quot; is 1s.&lt;br /&gt;
&lt;br /&gt;
So one step starts at 1s, and others start at 0s 14f, 0s 4f, 1s 10f, etc.&lt;br /&gt;
&lt;br /&gt;
This is the sine wave:&lt;br /&gt;
&lt;br /&gt;
[[Image:Smooth-sine.png]]&lt;br /&gt;
&lt;br /&gt;
And this is the effect of the Step valuenode on it, with an &amp;quot;Intersection&amp;quot; of 0.0.  Notice that at time 0s, the step has a negative value -- that step runs from -6f to 4f, and so its value is the value of Link at time -6f.  ''These images were created in [http://www.gimp.org/ The Gimp] - it's not currently possible to view two curves at the same time in Synfig Studio.''&lt;br /&gt;
&lt;br /&gt;
[[Image:Stepped-sine-0.0.png]]&lt;br /&gt;
&lt;br /&gt;
Here it is with an &amp;quot;Intersection&amp;quot; of 0.5:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stepped-sine-0.5.png]]&lt;br /&gt;
&lt;br /&gt;
and here, with an &amp;quot;Intersection&amp;quot; of 1.0:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stepped-sine-1.0.png]]&lt;br /&gt;
&lt;br /&gt;
=== Stripes ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] parameter to &amp;quot;Stripes&amp;quot; adds four sub-parameters:&lt;br /&gt;
* color &amp;quot;Color 1&amp;quot;&lt;br /&gt;
* color &amp;quot;Color 2&amp;quot;&lt;br /&gt;
* integer &amp;quot;Stripe Count&amp;quot;&lt;br /&gt;
* real &amp;quot;Width&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a gradient containing &amp;quot;Stripe Count&amp;quot; equally spaced, equally wide stripes of color &amp;quot;Color 2&amp;quot; with a background of &amp;quot;Color 1&amp;quot;.  &amp;quot;Width&amp;quot; specifies the width of the stripes, with a width of 0 or less meaning they are invisible, and a width of 1 or more meaning the whole gradient is of &amp;quot;Color 2&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Subtract ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Subtract&amp;quot; adds three sub-parameters, the first two of which are the same type as the parameter itself:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;LHS&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;RHS&amp;quot;&lt;br /&gt;
* real &amp;quot;Scalar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Subtract&amp;quot; conversion can be used with parameters of type [[Convert#Angle|angle]], [[Convert#Color|color]], [[Convert#Gradient|gradient]], [[Convert#Integer|integer]], [[Convert#Real|real]], [[Convert#Time|time]], and [[Convert#Vector|vector]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   (LHS - RHS) * Scalar&lt;br /&gt;
&lt;br /&gt;
=== Switch ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Switch&amp;quot; adds three sub-parameters:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link Off&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link On&amp;quot;&lt;br /&gt;
* bool &amp;quot;Switch&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Link Off&amp;quot; and &amp;quot;Link On&amp;quot; are the same type as the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
The resulting value is the value of &amp;quot;Link Off&amp;quot; when &amp;quot;Switch&amp;quot; is off, and &amp;quot;Link On&amp;quot; when &amp;quot;Switch&amp;quot; is on.&lt;br /&gt;
&lt;br /&gt;
This conversion can be used on all value types.&lt;br /&gt;
&lt;br /&gt;
=== Time Loop ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Time Loop&amp;quot; adds four sub-parameters: one called &amp;quot;Link&amp;quot;, of the same type as the parameter itself, and three time parameters:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* time &amp;quot;Link Time&amp;quot; &lt;br /&gt;
* time &amp;quot;Local Time&amp;quot;&lt;br /&gt;
* time &amp;quot;Duration&amp;quot;&lt;br /&gt;
&lt;br /&gt;
It works similarly to the [[Time Loop Layer]] but affects only a single parameter.&lt;br /&gt;
&lt;br /&gt;
For any integer value n, from &amp;quot;Local Time + abs(Duration)*n&amp;quot; to &amp;quot;Local Time + abs(Duration)*(n+1)&amp;quot;, the resulting value of the parameter is the same as that of the &amp;quot;Link&amp;quot; parameter from &amp;quot;Link Time&amp;quot; to &amp;quot;Link Time + Duration&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In other words, &amp;quot;Duration&amp;quot; seconds of values of the parameter &amp;quot;Link&amp;quot; starting from time &amp;quot;Link Time&amp;quot; onwards are looped over and over, with the value of the &amp;quot;Link&amp;quot;ed parameter at time &amp;quot;Link Time&amp;quot; corresponding to the resulting value at time &amp;quot;Local Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As an example, suppose the &amp;quot;Link&amp;quot; parameter has a value of time the current time.  At 0s the value is 0, at 10s the value is 20.&lt;br /&gt;
&lt;br /&gt;
If we set:&lt;br /&gt;
* Link Time = 5s&lt;br /&gt;
* Local Time = 2s&lt;br /&gt;
* Duration = 4s&lt;br /&gt;
then from 2s to 6s and from 6s to 10s, etc., the resulting value is the value of &amp;quot;Link&amp;quot; from 5s to 9s, as follows:&lt;br /&gt;
&lt;br /&gt;
Then the resulting values will be:&lt;br /&gt;
* 0s -&amp;gt; &amp;quot;Link&amp;quot; value at 7s = 14&lt;br /&gt;
* 1s -&amp;gt; &amp;quot;Link&amp;quot; value at 8s = 16&lt;br /&gt;
* 2s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (at &amp;quot;Link Time&amp;quot; = 2s, result is the value of &amp;quot;Link&amp;quot; at &amp;quot;Link Time&amp;quot; = 5s = 10)&lt;br /&gt;
* 3s -&amp;gt; &amp;quot;Link&amp;quot; value at 6s = 12&lt;br /&gt;
* 4s -&amp;gt; &amp;quot;Link&amp;quot; value at 7s = 14&lt;br /&gt;
* 5s -&amp;gt; &amp;quot;Link&amp;quot; value at 8s = 16&lt;br /&gt;
* 6s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (&amp;quot;Duration&amp;quot; = 4s later, the value is the same as at 2s)&lt;br /&gt;
* 7s -&amp;gt; &amp;quot;Link&amp;quot; value at 6s = 12&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Duration&amp;quot; is zero, the resulting value is whatever the value of the &amp;quot;Link&amp;quot; parameter is at time &amp;quot;Link Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Duration&amp;quot; is negative, the resulting value at &amp;quot;Local Time&amp;quot; still matches the value of &amp;quot;Link&amp;quot; at &amp;quot;Link Time&amp;quot;, but the animation goes in the opposite direction.   For example:&lt;br /&gt;
&lt;br /&gt;
If we set:&lt;br /&gt;
* Link Time = 5s&lt;br /&gt;
* Local Time = 2s&lt;br /&gt;
* Duration = -4s&lt;br /&gt;
then from 2s to 6s and from 6s to 10s, etc., the resulting value is the value of &amp;quot;Link&amp;quot; from 5s to 1s, as follows:&lt;br /&gt;
&lt;br /&gt;
Then the resulting values will be:&lt;br /&gt;
* 0s -&amp;gt; &amp;quot;Link&amp;quot; value at 3s = 6&lt;br /&gt;
* 1s -&amp;gt; &amp;quot;Link&amp;quot; value at 2s = 4&lt;br /&gt;
* 2s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (at &amp;quot;Link Time&amp;quot; = 2s, result is the value of &amp;quot;Link&amp;quot; at &amp;quot;Link Time&amp;quot; = 5s = 10)&lt;br /&gt;
* 3s -&amp;gt; &amp;quot;Link&amp;quot; value at 4s = 8&lt;br /&gt;
* 4s -&amp;gt; &amp;quot;Link&amp;quot; value at 3s = 6&lt;br /&gt;
* 5s -&amp;gt; &amp;quot;Link&amp;quot; value at 2s = 4&lt;br /&gt;
* 6s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (4s later, the value is the same as at &amp;quot;Link Time&amp;quot; = 2s)&lt;br /&gt;
* 7s -&amp;gt; &amp;quot;Link&amp;quot; value at 4s = 8&lt;br /&gt;
&lt;br /&gt;
This conversion can be used on all value types.&lt;br /&gt;
&lt;br /&gt;
=== Time String ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#String|string]] parameter to &amp;quot;Time String&amp;quot; adds one sub-parameter called &amp;quot;Time&amp;quot;, of type time:&lt;br /&gt;
&lt;br /&gt;
* time &amp;quot;Time&amp;quot; &lt;br /&gt;
&lt;br /&gt;
The result is a string containing the given time.&lt;br /&gt;
&lt;br /&gt;
=== Timed Swap ===&lt;br /&gt;
&lt;br /&gt;
This convert type was disabled in Synfig 0.61.06 and earlier because it didn't work.&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Timed Swap&amp;quot; adds four sub-parameters:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Before&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;After&amp;quot;&lt;br /&gt;
* time &amp;quot;Swap Time&amp;quot;&lt;br /&gt;
* time &amp;quot;Swap Duration&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Before&amp;quot; and &amp;quot;After&amp;quot; are the same type as the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
This conversion type linearly switches from &amp;quot;Before&amp;quot; to &amp;quot;After&amp;quot;, taking &amp;quot;Swap Duration&amp;quot; seconds to do so, and completing the swap at &amp;quot;Swap Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note that this doesn't give us anything that we can't achieve using the &amp;quot;[[Convert#Linear|Linear]]&amp;quot; conversion type and a few waypoints.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Timed Swap&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Color|colors]], [[Convert#Integer|integers]], [[Convert#Real|reals]], [[Convert#Time|times]], and [[Convert#Vector|vectors]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   if time &amp;gt; &amp;quot;Swap Time&amp;quot; then &amp;quot;After&amp;quot;&lt;br /&gt;
   else if time &amp;lt; (&amp;quot;Swap Time&amp;quot; - &amp;quot;Swap Duration&amp;quot;) then &amp;quot;Before&amp;quot;&lt;br /&gt;
   else interpolate between &amp;quot;Before&amp;quot; and &amp;quot;After&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Two-Tone ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] to &amp;quot;Two-Tone&amp;quot; adds two color-valued sub-parameters:&lt;br /&gt;
* color &amp;quot;Color1&amp;quot;&lt;br /&gt;
* color &amp;quot;Color2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting gradient has two CPoints, one at each end, starting with &amp;quot;Color1&amp;quot; and ending with &amp;quot;Color2&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
These color parameters can be animated, giving us the ability to have the gradient change color over time.  This can be used as a workaround for [http://sourceforge.net/tracker/index.php?func=detail&amp;amp;aid=1568818&amp;amp;group_id=144022&amp;amp;atid=757416 this bug].&lt;br /&gt;
&lt;br /&gt;
=== Vector Angle ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]] to &amp;quot;Vector Angle&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the angle between the vector and the X axis.&lt;br /&gt;
&lt;br /&gt;
=== Vector Length ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] to &amp;quot;Vector Length&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the length of the vector.&lt;br /&gt;
&lt;br /&gt;
=== Vector X ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] to &amp;quot;Vector X&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the X component of the vector.&lt;br /&gt;
&lt;br /&gt;
=== Vector Y ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] to &amp;quot;Vector Y&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the Y component of the vector.&lt;br /&gt;
&lt;br /&gt;
== Which Value Types can use which Convert Types? ==&lt;br /&gt;
&lt;br /&gt;
There are 13 different types of value in Synfig.  Each of these types has a different set of convert types available to it, as follows:&lt;br /&gt;
&lt;br /&gt;
=== Angle ===&lt;br /&gt;
&lt;br /&gt;
[[Image:angle_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Angle parameters can be converted to [[Convert#Add|Add]], [[Convert#aTan2|aTan2]], [[Convert#BLine Tangent|BLine Tangent]], [[Convert#Dot Product|Dot Product]], [[Convert#Linear|Linear]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], [[Convert#Vector Angle|Vector Angle]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== BLinePoint ===&lt;br /&gt;
[[Image:blinepoint_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* BLinePoint parameters can be converted to [[Convert#Composite|Composite]], [[Convert#Reverse Tangent|Reverse Tangent]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Bool ===&lt;br /&gt;
[[Image:bool_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Bool parameters can only be converted to the [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Canvas ===&lt;br /&gt;
[[Image:canvas_pointer_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Canvas parameters can be converted to the [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] type.&lt;br /&gt;
&lt;br /&gt;
=== Color ===&lt;br /&gt;
[[Image:color_icon.png|32px]]&lt;br /&gt;
* Color parameters can be converted to [[Convert#Add|Add]], [[Convert#Composite|Composite]], [[Convert#Gradient Color|Gradient Color]], [[Convert#Linear|Linear]], [[Convert#Radial Composite|Radial Composite]], [[Convert#Random|Random]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Gradient ===&lt;br /&gt;
[[Image:gradient_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Gradient parameters can be converted to [[Convert#Add|Add]], [[Convert#Gradient Rotate|Gradient Rotate]], [[Convert#Repeat Gradient|Repeat Gradient]], [[Convert#Stripes|Stripes]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Two-Tone|Two-Tone]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Integer ===&lt;br /&gt;
[[Image:Integer_icon.png|32px]]&lt;br /&gt;
* Integer parameters can be converted to [[Convert#Add|Add]], [[Convert#Linear|Linear]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== List ===&lt;br /&gt;
[[Image:list_icon.png|32px]]&lt;br /&gt;
* List parameters can be converted to [[Convert#BLine|BLine]], [[Convert#Dynamic List|Dynamic List]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Real ===&lt;br /&gt;
[[Image:real_icon.png|32px]]&lt;br /&gt;
* Real parameters can be converted to [[Convert#Add|Add]], [[Convert#BLine Width|BLine Width]], [[Convert#Cos|Cos]], [[Convert#Dot Product|Dot Product]], [[Convert#Exponential|Exponential]], [[Convert#Linear|Linear]], [[Convert#Logarithm|Logarithm]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Reciprocal|Reciprocal]], [[Convert#Scale|Scale]], [[Convert#Sine|Sine]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], [[Convert#Vector Length|Vector Length]], [[Convert#Vector X|Vector X]], [[Convert#Vector Y|Vector Y]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Segment ===&lt;br /&gt;
[[Image:segment_icon.png|32px]]&lt;br /&gt;
* Segment parameters can be converted to the [[Convert#Composite|Composite]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== String ===&lt;br /&gt;
[[Image:string_icon.png|32px]]&lt;br /&gt;
* String parameters can be converted to the [[Convert#Angle String|Angle String]], [[Convert#Int String|Int String]], [[Convert#Joined List|Joined List]], [[Convert#Real String|Real String]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Time String|Time String]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Time ===&lt;br /&gt;
[[Image:time_icon.png|32px]]&lt;br /&gt;
* Time parameters can be converted to the [[Convert#Add|Add]], [[Convert#Linear|Linear]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Vector ===&lt;br /&gt;
[[Image:vector_icon.png|32px]]&lt;br /&gt;
* Vector parameters can be converted to [[Convert#Add|Add]], [[Convert#BLine Tangent|BLine Tangent]], [[Convert#BLine Vertex|BLine Vertex]], [[Convert#Composite|Composite]], [[Convert#Linear|Linear]], [[Convert#Radial Composite|Radial Composite]], [[Convert#Random|Random]], [[Convert#Scale|Scale]], [[Convert#Segment Tangent|Segment Tangent]], [[Convert#Segment Vertex|Segment Vertex]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
When a new ValueNode type is added to Synfig, the .sif file format is extended to include a way of writing the new type.  This extension won't be able to be read by any older version of Synfig.  Here's a list of the ValueNode types that have been added, along with the subversion revision number in which they first appeared:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| style=&amp;quot;width:55%&amp;quot;&lt;br /&gt;
| '''Version''' || '''Revision''' || '''Convert'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.09)''' || not yet released || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2034 || [[#Logarithm|Logarithm]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2010 || [[#Int String|Int String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2010 || [[#Angle String|Angle String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2007 || [[#Joined List|Joined List]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2003 || [[#Real String|Real String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2000 || [[#Time String|Time String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1891 || [[#Dot Product|Dot Product]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1885 || [[#Gradient Color|Gradient Color]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1882 || [[#Vector X|Vector X]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1882 || [[#Vector Y|Vector Y]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1881 || [[#Vector Length|Vector Length]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1880 || [[#Vector Angle|Vector Angle]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.08)''' || 1839 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1694 || [[#BLine Width|BLine Width]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1690 || [[#Random|Random]] (for bools)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1691 || [[#Step|Step]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1354 || [[#Subtract|Subtract]] (for gradients)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1354 || [[#Add|Add]] (for gradients)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1267 || [[#From Integer|From Integer]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1267 || [[#Duplicate|Duplicate]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1238 || [[#Reciprocal|Reciprocal]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1226 || [[#Time Loop|Time Loop]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1162 || [[#Reverse Tangent|Reverse Tangent]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1132 || [[#aTan2|aTan2]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1111 || [[#Cos|Cos]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 923 || [[#Switch|Switch]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 907 || [[#Random|Random]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.07)''' || 878 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 776 || [[#Range|Range]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 744 || [[#BLine Vertex|BLine Vertex]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 744 || [[#BLine Tangent|BLine Tangent]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 742 || [[#Add|Add]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 739 || [[#Exponential|Exponential]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 666 || [[#Repeat Gradient|Repeat Gradient]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 610 || [[#Timed Swap|Timed Swap]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.06)''' || 536 || &amp;amp;nbsp;&lt;br /&gt;
|-|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Convert&amp;diff=8302</id>
		<title>Convert</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Convert&amp;diff=8302"/>
				<updated>2008-12-18T22:14:38Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Random */ add 'loop' param&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Right-clicking on a value in the Parameters dialog brings up a context menu which has a sub-menu called &amp;quot;Convert&amp;quot;.  The &amp;quot;Convert&amp;quot; menu allows you to specify that the parameter should be controlled automatically in various ways.  Depending on the type of the parameter the Convert menu will contain different options.&lt;br /&gt;
&lt;br /&gt;
To convert the value back to its original type, select &amp;quot;Disconnect&amp;quot; from its context menu.&lt;br /&gt;
&lt;br /&gt;
== Convert Types ==&lt;br /&gt;
&lt;br /&gt;
=== Add ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Add&amp;quot; adds three sub-parameters, the first two of which are the same type as the parameter itself:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;LHS&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;RHS&amp;quot;&lt;br /&gt;
* real &amp;quot;Scalar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Add&amp;quot; conversion can be used with parameters of type [[Convert#Angle|angle]], [[Convert#Color|color]], [[Convert#Gradient|gradient]], [[Convert#Integer|integer]], [[Convert#Real|real]], [[Convert#Time|time]], and [[Convert#Vector|vector]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   (LHS + RHS) * Scalar&lt;br /&gt;
&lt;br /&gt;
=== Angle String ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#String|string]]-valued parameter to &amp;quot;Angle String&amp;quot; adds four sub-parameters:&lt;br /&gt;
* angle &amp;quot;Angle&amp;quot;&lt;br /&gt;
* integer &amp;quot;Width&amp;quot;&lt;br /&gt;
* integer &amp;quot;Precision&amp;quot;&lt;br /&gt;
* bool &amp;quot;Zero Padded&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value a string containing the value of &amp;quot;Angle&amp;quot; (in degrees) formatted as a string with a minimum width &amp;quot;Width&amp;quot;, with &amp;quot;Precision&amp;quot; decimal places.  If &amp;quot;Zero Padded&amp;quot; is true, it will be left-padded with &amp;quot;0&amp;quot; characters.&lt;br /&gt;
&lt;br /&gt;
=== aTan2 ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]]-valued parameter to &amp;quot;aTan2&amp;quot; adds two sub-parameters:&lt;br /&gt;
* real &amp;quot;X&amp;quot;&lt;br /&gt;
* real &amp;quot;Y&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   atan2(y,x)&lt;br /&gt;
&lt;br /&gt;
ie. atan(y/x) but without an error when x is 0.  The value is the angle between the x axis and the vector (x,y).&lt;br /&gt;
&lt;br /&gt;
=== BLine ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#List|list]] parameter to &amp;quot;BLine&amp;quot; doesn't seem to change anything.  Perhaps that's the default type for lists of vertices, such as are found in outlines and regions?&lt;br /&gt;
&lt;br /&gt;
=== BLine Tangent ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Angle|angle]], [[Convert#Real|real]] (since SVN r1862), or [[Convert#Vector|vector]] parameter to &amp;quot;BLine Tangent&amp;quot; adds six sub-parameters:&lt;br /&gt;
* bline &amp;quot;BLine&amp;quot;&lt;br /&gt;
* bool &amp;quot;Loop&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
* angle &amp;quot;Offset&amp;quot; (since SVN r1863)&lt;br /&gt;
* real &amp;quot;Scale&amp;quot; (since SVN r1863)&lt;br /&gt;
* bool &amp;quot;Fixed Length&amp;quot; (since SVN r1863)&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given bline.  The resulting value for the whole parameter is the tangent to the bline, at the given point along the bline, optionally rotated and scaled according to the &amp;quot;Offset&amp;quot;, &amp;quot;Scale&amp;quot;, and &amp;quot;Fixed Length&amp;quot; parameters.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Offset&amp;quot; is an angle used to give the tangent an extra rotation before returning it.  If &amp;quot;Fixed Length&amp;quot; is true, the tangent is then scaled to have a length equal to &amp;quot;Scale&amp;quot;.  Otherwise the tangent is multiplied by &amp;quot;Scale&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If a vector was converted the result is the tangent itself.  If an angle was converted, the result is the angle of the tangent to the horizontal, and if a real was converted, the result is the length of the tangent.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
This [[Following a BLine|tutorial]] gives an example of the use of this convert type.&lt;br /&gt;
&lt;br /&gt;
=== BLine Vertex ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;BLine Vertex&amp;quot; adds three sub-parameters:&lt;br /&gt;
* bline &amp;quot;BLine&amp;quot;&lt;br /&gt;
* bool &amp;quot;Loop&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given bline.  The resulting value for the whole parameter is a vector giving the position of the given point along the bline.&lt;br /&gt;
&lt;br /&gt;
This [[Following a BLine|tutorial]] gives an example of the use of this convert type.&lt;br /&gt;
&lt;br /&gt;
=== BLine Width ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] parameter to &amp;quot;BLine Width&amp;quot; adds three sub-parameters:&lt;br /&gt;
* bline &amp;quot;BLine&amp;quot;&lt;br /&gt;
* bool &amp;quot;Loop&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
* real &amp;quot;Scale&amp;quot; (since SVN r1872)&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given bline.  The resulting value for the whole parameter is the width of the bline at the given point along it, multiplied by the &amp;quot;Scale&amp;quot; parameter.&lt;br /&gt;
&lt;br /&gt;
=== Composite ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#BLinePoint|blinepoint]] parameter to &amp;quot;Composite&amp;quot; adds six sub-parameters:&lt;br /&gt;
* vector &amp;quot;Vertex&amp;quot;&lt;br /&gt;
* real &amp;quot;Width&amp;quot;&lt;br /&gt;
* real &amp;quot;Origin&amp;quot;&lt;br /&gt;
* bool &amp;quot;Split Tangents&amp;quot;&lt;br /&gt;
* vector &amp;quot;Tangent 1&amp;quot;&lt;br /&gt;
* vector &amp;quot;Tangent 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] parameter to &amp;quot;Composite&amp;quot; adds four real-valued sub-parameters:&lt;br /&gt;
* real &amp;quot;Red&amp;quot;&lt;br /&gt;
* real &amp;quot;Green&amp;quot;&lt;br /&gt;
* real &amp;quot;Blue&amp;quot;&lt;br /&gt;
* real &amp;quot;Alpha&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Segment|segment]] parameter to &amp;quot;Composite&amp;quot; adds four vertex sub-parameters:&lt;br /&gt;
* vertex &amp;quot;Vertex 1&amp;quot;&lt;br /&gt;
* vertex &amp;quot;Tangent 1&amp;quot;&lt;br /&gt;
* vertex &amp;quot;Vertex 2&amp;quot;&lt;br /&gt;
* vertex &amp;quot;Tangent 2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;Composite&amp;quot; adds two real-valued sub-parameters:&lt;br /&gt;
* real &amp;quot;X-Axis&amp;quot;&lt;br /&gt;
* real &amp;quot;Y-Axis&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a blinepoint, color, segment, or vector made by combining the component parts.&lt;br /&gt;
&lt;br /&gt;
=== Cos ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Cos&amp;quot; adds two sub-parameters:&lt;br /&gt;
* angle &amp;quot;Angle&amp;quot;&lt;br /&gt;
* real &amp;quot;Amplitude&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Amplitude * cos(Angle)&lt;br /&gt;
&lt;br /&gt;
=== Dot Product ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] or [[Convert#Angle|angle]] parameter to a &amp;quot;Dot Product&amp;quot; adds two sub-parameters:&lt;br /&gt;
* vector &amp;quot;LHS&amp;quot;&lt;br /&gt;
* vector &amp;quot;RHS&amp;quot;&lt;br /&gt;
&lt;br /&gt;
If the converted value is an angle, the return value is the angle between the two vectors:&lt;br /&gt;
&lt;br /&gt;
 return = acos((LHS · RHS) / (|LHS| * |RHS|))&lt;br /&gt;
&lt;br /&gt;
If the converted value is a real, the result value is the dot product of the two vectors:&lt;br /&gt;
&lt;br /&gt;
 return = LHS · RHS = |LHS| * |RHS| * cos(alpha)&lt;br /&gt;
&lt;br /&gt;
(where alpha is the angle between LHS and RHS).&lt;br /&gt;
&lt;br /&gt;
=== Duplicate ===&lt;br /&gt;
&lt;br /&gt;
This ValueNode type is only used by the [[Duplicate Layer]].  It never appears in the Convert menu.  It is used to control the range of the Index in the Duplicate Layer (q.v.).&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Duplicate&amp;quot; ValueNode type has 3 real-valued sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;From&amp;quot;&lt;br /&gt;
* real &amp;quot;To&amp;quot;&lt;br /&gt;
* real &amp;quot;Step&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The value of the ValueNode varies from the value of &amp;quot;From&amp;quot; to the value of &amp;quot;To&amp;quot; in steps of size &amp;quot;Step&amp;quot;.   The sign of &amp;quot;Step&amp;quot; is ignored.  If From&amp;lt;To the steps are positive, else they're negative.&lt;br /&gt;
&lt;br /&gt;
=== Dynamic List ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#List|list]] parameter to &amp;quot;Dynamic List&amp;quot; seems to replace each of the &amp;quot;Vertex NNN&amp;quot; sub-parameters with &amp;quot;Item NNN&amp;quot; parameters which can't be expanded, but can be exported.&lt;br /&gt;
&lt;br /&gt;
=== Exponential ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] parameter to &amp;quot;Exponential&amp;quot; adds two sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;Exponent&amp;quot;&lt;br /&gt;
* real &amp;quot;Scale&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the result raising the [http://en.wikipedia.org/wiki/E_%28mathematical_constant%29 mathematical constant 'e'] to the power of Exponent, and scaling the result by Scale.  That is, it returns:&lt;br /&gt;
  Scale * e^Exponent&lt;br /&gt;
&lt;br /&gt;
This is useful for tracking layers which have been zoomed, since the Zoom layer scales by e^(zoom factor).&lt;br /&gt;
&lt;br /&gt;
See [http://youtube.com/watch?v=GAWtndOHkUw this video] for an example of the use of this convert type.&lt;br /&gt;
&lt;br /&gt;
=== From Integer ===&lt;br /&gt;
&lt;br /&gt;
This is currently disabled.  It converts an integer to one of several types.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Color ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] parameter to &amp;quot;Gradient Color&amp;quot; adds two sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* gradient &amp;quot;Gradient&amp;quot;&lt;br /&gt;
* real &amp;quot;Index&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a color taken from the gradient at the given index position.  Index 0 corresponds to the left of the gradient; index 1 corresponds to the right of the gradient.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Rotate ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] parameter to &amp;quot;Gradient Rotate&amp;quot; adds two sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* gradient &amp;quot;Gradient&amp;quot;&lt;br /&gt;
* real &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a gradient based on the &amp;quot;Gradient&amp;quot; parameter, but shifted left (for negative values) or right, according to the value of the &amp;quot;Offset&amp;quot; parameter.  An offset of 1.0 will shift the gradient by its entire visible width.  Values shifted off the left or right edge aren't lost - they aren't visible in the gradient as it's displayed in the parameters dialog, but they will still be used when rendering (depending on parameters such as 'Loop' and 'Zigzag', which can cause gradients to be looped between their their left and right edges, rather than using the non-displayed parts).&lt;br /&gt;
&lt;br /&gt;
=== Int String ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#String|string]]-valued parameter to &amp;quot;Int String&amp;quot; adds three sub-parameters:&lt;br /&gt;
* integer &amp;quot;Int&amp;quot;&lt;br /&gt;
* integer &amp;quot;Width&amp;quot;&lt;br /&gt;
* bool &amp;quot;Zero Padded&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value a string containing &amp;quot;Int&amp;quot; formatted as a string with a minimum width &amp;quot;Width&amp;quot;.  If &amp;quot;Zero Padded&amp;quot; is true, it will be left-padded with &amp;quot;0&amp;quot; characters.&lt;br /&gt;
&lt;br /&gt;
=== Joined List ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#String|string]] parameter to be 'Joined List' adds four sub-parameters:&lt;br /&gt;
* list &amp;quot;Strings&amp;quot;&lt;br /&gt;
* string &amp;quot;Before&amp;quot;&lt;br /&gt;
* string &amp;quot;Separator&amp;quot;&lt;br /&gt;
* string &amp;quot;After&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The result is a string containing the value of &amp;quot;Before&amp;quot;, followed by all the strings in the &amp;quot;Strings&amp;quot; list, with the value of &amp;quot;Separator&amp;quot; between each pair, followed by the value of &amp;quot;After&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Linear ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]] parameter to be 'Linear' adds two angle sub-parameters:&lt;br /&gt;
* angle &amp;quot;Rate&amp;quot;&lt;br /&gt;
* angle &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] parameter to be 'Linear' adds two angle sub-parameters (since svn r617):&lt;br /&gt;
* color &amp;quot;Rate&amp;quot;&lt;br /&gt;
* color &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Integer|integer]] parameter to be 'Linear' adds two angle sub-parameters (since svn r617):&lt;br /&gt;
* integer &amp;quot;Rate&amp;quot;&lt;br /&gt;
* integer &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] parameter to be 'Linear' adds two real-valued sub-parameters:&lt;br /&gt;
* real &amp;quot;Rate&amp;quot;&lt;br /&gt;
* real &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Time|time]] parameter to be 'Linear' adds two time sub-parameters:&lt;br /&gt;
* time &amp;quot;Rate&amp;quot;&lt;br /&gt;
* time &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to be 'Linear' adds two vector sub-parameters:&lt;br /&gt;
* vector &amp;quot;Slope&amp;quot;&lt;br /&gt;
* vector &amp;quot;Offset&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The parameter's value will change linearly over time, starting with the value specified by &amp;quot;Offset&amp;quot; at time zero, and increasing by the value specified by &amp;quot;Rate&amp;quot; (or &amp;quot;Slope&amp;quot;, in the case of vector parameters) every second.&lt;br /&gt;
&lt;br /&gt;
The resulting value for vector parameters is:&lt;br /&gt;
   Offset + Slope*time&lt;br /&gt;
&lt;br /&gt;
and for the other 5 types of parameter it is:&lt;br /&gt;
   Offset + Rate*time&lt;br /&gt;
&lt;br /&gt;
=== Logarithm ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Logarithm&amp;quot; adds three sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Epsilon&amp;quot;.&lt;br /&gt;
* real &amp;quot;Infinite&amp;quot;. &lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
&lt;br /&gt;
  Log(Link) (if Link &amp;gt;= Epsilon)&lt;br /&gt;
  -Infinite (if Link &amp;lt; Epsilon)&lt;br /&gt;
&lt;br /&gt;
The epsilon and infinite parameters are only needed to prevent logarithm of negative or zero numbers. For regular operation the resulting value is simply the natural logarithm of Link. In fact a logarithm of a negative number cannot be calculated in the space of Real numbers. This convert type returns -Infinite for simplicity.&lt;br /&gt;
&lt;br /&gt;
=== Radial Composite ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Color|color]] to &amp;quot;Radial Composite&amp;quot; adds four sub-parameters:&lt;br /&gt;
* real &amp;quot;Luma&amp;quot;&lt;br /&gt;
* real &amp;quot;Saturation&amp;quot;&lt;br /&gt;
* angle &amp;quot;Hue&amp;quot;&lt;br /&gt;
* real &amp;quot;Alpha&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] to &amp;quot;Radial Composite&amp;quot; adds two sub-parameters:&lt;br /&gt;
* real &amp;quot;Radius&amp;quot;&lt;br /&gt;
* angle &amp;quot;Theta&amp;quot;&lt;br /&gt;
&lt;br /&gt;
For color parameters, the resulting value is the color with the given lima, saturation, hue, and alpha amounts.&lt;br /&gt;
&lt;br /&gt;
For vector parameters, the resulting value is the point reached by traveling a distance &amp;quot;Radius&amp;quot; from the origin, in the distance given by the angle &amp;quot;Theta&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Random === &lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Random&amp;quot; adds five sub-parameters, the first of which is the same type as the converted parameter:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Radius&amp;quot;&lt;br /&gt;
* integer &amp;quot;Seed&amp;quot;&lt;br /&gt;
* real &amp;quot;Animation Speed&amp;quot;&lt;br /&gt;
* integer &amp;quot;Interpolation&amp;quot;&lt;br /&gt;
* real &amp;quot;Loop Time&amp;quot; (since SVN r2315)&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Random&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Color|colors]], [[Convert#Integer|integers]], [[Convert#Real|reals]], [[Convert#Time|times]], and [[Convert#Vector|vectors]].&lt;br /&gt;
&lt;br /&gt;
It is used to cause a parameter's value to vary randomly over time, around a central value:&lt;br /&gt;
&lt;br /&gt;
* &amp;quot;Link&amp;quot; provides the central value.&lt;br /&gt;
* &amp;quot;Radius&amp;quot; defines the maximum random difference.&lt;br /&gt;
* &amp;quot;Seed&amp;quot; seeds the random number generator&lt;br /&gt;
* &amp;quot;Animation Speed&amp;quot; defines how often a new random value is chosen (in choices per second)&lt;br /&gt;
* &amp;quot;Interpolation&amp;quot; determines how the value is interpolated from one random choice to the next.  Possible values are:&lt;br /&gt;
** 0 - no interpolation; the value jumps from one value to the next&lt;br /&gt;
** 1 - linear interpolation&lt;br /&gt;
** 2 - cosine&lt;br /&gt;
** 3 - spline&lt;br /&gt;
** 4 - cubic (the default); uses [http://www.gamedev.net/reference/articles/article1497.asp Catmull-Rom] spline interpolation&lt;br /&gt;
* &amp;quot;Loop Time&amp;quot; (adding in SVN r2315) makes the random value repeat after the given time.  The value ends up the same at the given time as at time=0 so it's possible to make random looping animations without a nasty jump when the time wraps back to zero.&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Interpolation&amp;quot; sub-parameter should really be a drop-down menu, rather than an integer field, but that isn't yet implemented.&lt;br /&gt;
&lt;br /&gt;
=== Range ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Range&amp;quot; adds three sub-parameters, all the same type as the parameter itself:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Min&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Max&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Range&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Integer|integers]], [[Convert#Real|reals]], and [[Convert#Time|times]].&lt;br /&gt;
&lt;br /&gt;
It is used to limit the value of the linked parameter to be between Min and Max.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Min (if Link &amp;lt; Min)&lt;br /&gt;
   Max (if Link &amp;gt; Max)&lt;br /&gt;
   Link (otherwise)&lt;br /&gt;
&lt;br /&gt;
=== Real String ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#String|string]] parameter to &amp;quot;Real String&amp;quot; adds four sub-parameters:&lt;br /&gt;
&lt;br /&gt;
* real &amp;quot;Real&amp;quot;&lt;br /&gt;
* int &amp;quot;Width&amp;quot;&lt;br /&gt;
* int &amp;quot;Precision&amp;quot;&lt;br /&gt;
* bool &amp;quot;Zero Padded&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The result is a string formatted to contain the given value &amp;quot;Real&amp;quot;.  &amp;quot;Width&amp;quot; specifies the minimum field width, &amp;quot;Precision&amp;quot; specifies the number of decimal places and &amp;quot;Zero Padded&amp;quot; specifies whether to pad with zeros on the left hand side.&lt;br /&gt;
&lt;br /&gt;
For example, with Real=3.1415, Width=6, Precision=2, and ZeroPadded=true, we get:&lt;br /&gt;
  &amp;quot;003.14&amp;quot;&lt;br /&gt;
(6 characters long, 2 decimal places, and padded with zeros on the left).&lt;br /&gt;
&lt;br /&gt;
=== Reciprocal ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Reciprocal&amp;quot; adds three sub-parameters:&lt;br /&gt;
* real &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Epsilon&amp;quot;.&lt;br /&gt;
* real &amp;quot;Infinite&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   1/Link (Link &amp;lt;= -epsilon or epsilon &amp;lt;= Link)&lt;br /&gt;
   Infinite (if 0 &amp;lt;= Link &amp;lt; epsilon)&lt;br /&gt;
   -Infinite (if -epsilon &amp;lt; Link &amp;lt; 0)&lt;br /&gt;
&lt;br /&gt;
The epsilon and infinite parameters are only needed to prevent division by zero.  For regular operation the resulting value is simply the reciprocal of Link.&lt;br /&gt;
&lt;br /&gt;
=== Reference ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Reference&amp;quot; adds a single sub-parameter called &amp;quot;Link&amp;quot;.  The &amp;quot;Link&amp;quot; parameter is the same type as the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
It doesn't seem to do anything at all, other than adding an extra parameter.  Whatever value is put into &amp;quot;Link&amp;quot; becomes the value of the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
The only use for this conversion type I can think of is the following:&lt;br /&gt;
&lt;br /&gt;
* you know that point A should follow point B, so you export point B and connect point A to it&lt;br /&gt;
* you're not yet sure exactly how point B should move, so you experiment with different conversion types for point B&lt;br /&gt;
* changing the conversion type for point B breaks the connection you made in the first step&lt;br /&gt;
* converting point B to be a reference, and then experimenting with different conversions in its &amp;quot;Link&amp;quot; parameter allows point A to connect to point B and for the connection to remain in place while you experiment in the &amp;quot;Link&amp;quot; parameter&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Link&lt;br /&gt;
&lt;br /&gt;
=== Repeat Gradient ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] parameter to &amp;quot;Repeat Gradient&amp;quot; adds seven sub-parameters:&lt;br /&gt;
* gradient &amp;quot;Gradient&amp;quot;&lt;br /&gt;
* integer &amp;quot;Count&amp;quot;&lt;br /&gt;
* real &amp;quot;Width&amp;quot;&lt;br /&gt;
* bool &amp;quot;Specify Start&amp;quot;&lt;br /&gt;
* bool &amp;quot;Specify End&amp;quot;&lt;br /&gt;
* color &amp;quot;Start Color&amp;quot;&lt;br /&gt;
* color &amp;quot;End Color&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a gradient containing &amp;quot;Count&amp;quot; equally spaced, equally wide copies of gradient &amp;quot;Gradient&amp;quot;.  Each copy has &amp;quot;Gradient&amp;quot; going forwards and then backwards.  &amp;quot;Width&amp;quot; specifies relative width of the forward copy, with a width of 0 or less meaning only the backward copy is used, and a width of 1 or more meaning only the forward copy is used.  A value of 0.5 will result in the forward and reverse copies of &amp;quot;Gradient&amp;quot; being the same width.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Specify Start&amp;quot; is checked then &amp;quot;Start Color&amp;quot; will be inserted at the beginning of the new gradient, otherwise the beginning of &amp;quot;Gradient&amp;quot; will be used as the beginning of the new gradient.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Specify End&amp;quot; is checked then &amp;quot;End Color&amp;quot; will be appended to the end of the new gradient, otherwise the end of &amp;quot;Gradient&amp;quot; will be used as the end of the new gradient.&lt;br /&gt;
&lt;br /&gt;
Here's an example of a repeated gradient - the radiating green/yellow lines are a repeated gradient, applied to a perpendicular curve gradient.  This gradient was repeated with a width of 0.5, meaning it is used backwards and forwards the same amount:&lt;br /&gt;
&lt;br /&gt;
[[Image:Repeat-gradient-valuenode-gradient.png]]&lt;br /&gt;
&lt;br /&gt;
and here's the resulting image, along with the .sif file:&lt;br /&gt;
&lt;br /&gt;
[[Image:Repeat-gradient-valuenode.png]]&lt;br /&gt;
[[Image:Repeat-gradient-valuenode.sif]]&lt;br /&gt;
&lt;br /&gt;
=== Reverse Tangent ===&lt;br /&gt;
&lt;br /&gt;
Converting a blinepoint parameter to &amp;quot;Reverse Tangent&amp;quot; adds two sub-parameters: one called &amp;quot;Reference&amp;quot; of type BLinePoint, and a boolean parameter called &amp;quot;Reverse&amp;quot;.&lt;br /&gt;
* BLinePoint &amp;quot;Reference&amp;quot;&lt;br /&gt;
* bool &amp;quot;Reverse&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Reverse Tangent&amp;quot; can only be used on [[Convert#BLinePoint|blinepoints]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is the same as the reference BLinePoint, but with its tangents switched over.  This is useful when attempting to link the verticies of a region to the vertices of an outline when the region and the outline were drawn in opposite directions, and so tangent1 of an outline vertex needs to be linked to tangent2 of the region vertex, and vice versa.&lt;br /&gt;
&lt;br /&gt;
=== Scale ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Scale&amp;quot; adds two sub-parameters: one called &amp;quot;Link&amp;quot;, of the same type as the parameter itself, and a real-valued parameter called &amp;quot;Scalar&amp;quot;.&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* real &amp;quot;Scalar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Scale&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Color|colors]], [[Convert#Integer|integers]], [[Convert#Real|reals]], [[Convert#Time|times]], and [[Convert#Vector|vectors]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Link * Scalar&lt;br /&gt;
&lt;br /&gt;
=== Segment Tangent ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;Segment Tangent&amp;quot; adds two sub-parameters:&lt;br /&gt;
* segment &amp;quot;Segment&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot;&lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given segment.  The resulting value for the whole parameter is the tangent to the segment, at the given point along the segment.&lt;br /&gt;
&lt;br /&gt;
=== Segment Vertex ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Vector|vector]] parameter to &amp;quot;Segment Vertex&amp;quot; adds two sub-parameters:&lt;br /&gt;
* segment &amp;quot;Segment&amp;quot;&lt;br /&gt;
* real &amp;quot;Amount&amp;quot; &lt;br /&gt;
&lt;br /&gt;
Amount is a number between 0 and 1, defining the distance along the given segment.  The resulting value is the vertex at the given point along the segment.&lt;br /&gt;
&lt;br /&gt;
=== Sine ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]]-valued parameter to &amp;quot;Sine&amp;quot; adds two sub-parameters:&lt;br /&gt;
* angle &amp;quot;Angle&amp;quot;&lt;br /&gt;
* real &amp;quot;Amplitude&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   Amplitude * sin(Angle)&lt;br /&gt;
&lt;br /&gt;
=== Step ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]], [[Convert#Color|color]], [[Convert#Integer|integer]], [[Convert#Real|real]], [[Convert#Time|time]], or [[Convert#Vector|vector]] parameter to be 'Step' adds four sub-parameters:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* time &amp;quot;Duration&amp;quot;&lt;br /&gt;
* time &amp;quot;Start Time&amp;quot;&lt;br /&gt;
* real &amp;quot;Intersection&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The parameter's value will change in steps.  Each step is &amp;quot;Duration&amp;quot; seconds long.  The steps start at times &amp;quot;Start Time&amp;quot;, &amp;quot;Start Time&amp;quot;+&amp;quot;Duration&amp;quot;, etc.  The value of the valuenode is the value of &amp;quot;Link&amp;quot; at some time.  &amp;quot;Intersection&amp;quot; determines which time is used.  An &amp;quot;Intersection&amp;quot; of 0.0 means that the value of &amp;quot;Link&amp;quot; at the start of the step should be used.  An &amp;quot;Intersection&amp;quot; of 0.5 (the default) means to use the value of &amp;quot;Link&amp;quot; at the middle of the step, etc.&lt;br /&gt;
&lt;br /&gt;
The resulting value at time &amp;lt;math&amp;gt;T&amp;lt;/math&amp;gt; is:&lt;br /&gt;
   &amp;lt;math&amp;gt;Link \Bigg ( \Bigg ( Duration \cdot \left ( \left \lfloor \frac{T - Start\ Time}{Duration} \right \rfloor + Intersection \right ) \Bigg ) + Start \ Time \Bigg )&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==== Example ====&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Link&amp;quot; is a sine wave.  &amp;quot;Duration&amp;quot; is 10f (the frame rate is 24 fps).  &amp;quot;Start Time&amp;quot; is 1s.&lt;br /&gt;
&lt;br /&gt;
So one step starts at 1s, and others start at 0s 14f, 0s 4f, 1s 10f, etc.&lt;br /&gt;
&lt;br /&gt;
This is the sine wave:&lt;br /&gt;
&lt;br /&gt;
[[Image:Smooth-sine.png]]&lt;br /&gt;
&lt;br /&gt;
And this is the effect of the Step valuenode on it, with an &amp;quot;Intersection&amp;quot; of 0.0.  Notice that at time 0s, the step has a negative value -- that step runs from -6f to 4f, and so its value is the value of Link at time -6f.  ''These images were created in [http://www.gimp.org/ The Gimp] - it's not currently possible to view two curves at the same time in Synfig Studio.''&lt;br /&gt;
&lt;br /&gt;
[[Image:Stepped-sine-0.0.png]]&lt;br /&gt;
&lt;br /&gt;
Here it is with an &amp;quot;Intersection&amp;quot; of 0.5:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stepped-sine-0.5.png]]&lt;br /&gt;
&lt;br /&gt;
and here, with an &amp;quot;Intersection&amp;quot; of 1.0:&lt;br /&gt;
&lt;br /&gt;
[[Image:Stepped-sine-1.0.png]]&lt;br /&gt;
&lt;br /&gt;
=== Stripes ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] parameter to &amp;quot;Stripes&amp;quot; adds four sub-parameters:&lt;br /&gt;
* color &amp;quot;Color 1&amp;quot;&lt;br /&gt;
* color &amp;quot;Color 2&amp;quot;&lt;br /&gt;
* integer &amp;quot;Stripe Count&amp;quot;&lt;br /&gt;
* real &amp;quot;Width&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is a gradient containing &amp;quot;Stripe Count&amp;quot; equally spaced, equally wide stripes of color &amp;quot;Color 2&amp;quot; with a background of &amp;quot;Color 1&amp;quot;.  &amp;quot;Width&amp;quot; specifies the width of the stripes, with a width of 0 or less meaning they are invisible, and a width of 1 or more meaning the whole gradient is of &amp;quot;Color 2&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
=== Subtract ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Subtract&amp;quot; adds three sub-parameters, the first two of which are the same type as the parameter itself:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;LHS&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;RHS&amp;quot;&lt;br /&gt;
* real &amp;quot;Scalar&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The &amp;quot;Subtract&amp;quot; conversion can be used with parameters of type [[Convert#Angle|angle]], [[Convert#Color|color]], [[Convert#Gradient|gradient]], [[Convert#Integer|integer]], [[Convert#Real|real]], [[Convert#Time|time]], and [[Convert#Vector|vector]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   (LHS - RHS) * Scalar&lt;br /&gt;
&lt;br /&gt;
=== Switch ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Switch&amp;quot; adds three sub-parameters:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link Off&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link On&amp;quot;&lt;br /&gt;
* bool &amp;quot;Switch&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Link Off&amp;quot; and &amp;quot;Link On&amp;quot; are the same type as the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
The resulting value is the value of &amp;quot;Link Off&amp;quot; when &amp;quot;Switch&amp;quot; is off, and &amp;quot;Link On&amp;quot; when &amp;quot;Switch&amp;quot; is on.&lt;br /&gt;
&lt;br /&gt;
This conversion can be used on all value types.&lt;br /&gt;
&lt;br /&gt;
=== Time Loop ===&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Time Loop&amp;quot; adds four sub-parameters: one called &amp;quot;Link&amp;quot;, of the same type as the parameter itself, and three time parameters:&lt;br /&gt;
&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Link&amp;quot;&lt;br /&gt;
* time &amp;quot;Link Time&amp;quot; &lt;br /&gt;
* time &amp;quot;Local Time&amp;quot;&lt;br /&gt;
* time &amp;quot;Duration&amp;quot;&lt;br /&gt;
&lt;br /&gt;
It works similarly to the [[Time Loop Layer]] but affects only a single parameter.&lt;br /&gt;
&lt;br /&gt;
For any integer value n, from &amp;quot;Local Time + abs(Duration)*n&amp;quot; to &amp;quot;Local Time + abs(Duration)*(n+1)&amp;quot;, the resulting value of the parameter is the same as that of the &amp;quot;Link&amp;quot; parameter from &amp;quot;Link Time&amp;quot; to &amp;quot;Link Time + Duration&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In other words, &amp;quot;Duration&amp;quot; seconds of values of the parameter &amp;quot;Link&amp;quot; starting from time &amp;quot;Link Time&amp;quot; onwards are looped over and over, with the value of the &amp;quot;Link&amp;quot;ed parameter at time &amp;quot;Link Time&amp;quot; corresponding to the resulting value at time &amp;quot;Local Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
As an example, suppose the &amp;quot;Link&amp;quot; parameter has a value of time the current time.  At 0s the value is 0, at 10s the value is 20.&lt;br /&gt;
&lt;br /&gt;
If we set:&lt;br /&gt;
* Link Time = 5s&lt;br /&gt;
* Local Time = 2s&lt;br /&gt;
* Duration = 4s&lt;br /&gt;
then from 2s to 6s and from 6s to 10s, etc., the resulting value is the value of &amp;quot;Link&amp;quot; from 5s to 9s, as follows:&lt;br /&gt;
&lt;br /&gt;
Then the resulting values will be:&lt;br /&gt;
* 0s -&amp;gt; &amp;quot;Link&amp;quot; value at 7s = 14&lt;br /&gt;
* 1s -&amp;gt; &amp;quot;Link&amp;quot; value at 8s = 16&lt;br /&gt;
* 2s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (at &amp;quot;Link Time&amp;quot; = 2s, result is the value of &amp;quot;Link&amp;quot; at &amp;quot;Link Time&amp;quot; = 5s = 10)&lt;br /&gt;
* 3s -&amp;gt; &amp;quot;Link&amp;quot; value at 6s = 12&lt;br /&gt;
* 4s -&amp;gt; &amp;quot;Link&amp;quot; value at 7s = 14&lt;br /&gt;
* 5s -&amp;gt; &amp;quot;Link&amp;quot; value at 8s = 16&lt;br /&gt;
* 6s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (&amp;quot;Duration&amp;quot; = 4s later, the value is the same as at 2s)&lt;br /&gt;
* 7s -&amp;gt; &amp;quot;Link&amp;quot; value at 6s = 12&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Duration&amp;quot; is zero, the resulting value is whatever the value of the &amp;quot;Link&amp;quot; parameter is at time &amp;quot;Link Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
If &amp;quot;Duration&amp;quot; is negative, the resulting value at &amp;quot;Local Time&amp;quot; still matches the value of &amp;quot;Link&amp;quot; at &amp;quot;Link Time&amp;quot;, but the animation goes in the opposite direction.   For example:&lt;br /&gt;
&lt;br /&gt;
If we set:&lt;br /&gt;
* Link Time = 5s&lt;br /&gt;
* Local Time = 2s&lt;br /&gt;
* Duration = -4s&lt;br /&gt;
then from 2s to 6s and from 6s to 10s, etc., the resulting value is the value of &amp;quot;Link&amp;quot; from 5s to 1s, as follows:&lt;br /&gt;
&lt;br /&gt;
Then the resulting values will be:&lt;br /&gt;
* 0s -&amp;gt; &amp;quot;Link&amp;quot; value at 3s = 6&lt;br /&gt;
* 1s -&amp;gt; &amp;quot;Link&amp;quot; value at 2s = 4&lt;br /&gt;
* 2s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (at &amp;quot;Link Time&amp;quot; = 2s, result is the value of &amp;quot;Link&amp;quot; at &amp;quot;Link Time&amp;quot; = 5s = 10)&lt;br /&gt;
* 3s -&amp;gt; &amp;quot;Link&amp;quot; value at 4s = 8&lt;br /&gt;
* 4s -&amp;gt; &amp;quot;Link&amp;quot; value at 3s = 6&lt;br /&gt;
* 5s -&amp;gt; &amp;quot;Link&amp;quot; value at 2s = 4&lt;br /&gt;
* 6s -&amp;gt; &amp;quot;Link&amp;quot; value at 5s = 10 (4s later, the value is the same as at &amp;quot;Link Time&amp;quot; = 2s)&lt;br /&gt;
* 7s -&amp;gt; &amp;quot;Link&amp;quot; value at 4s = 8&lt;br /&gt;
&lt;br /&gt;
This conversion can be used on all value types.&lt;br /&gt;
&lt;br /&gt;
=== Time String ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#String|string]] parameter to &amp;quot;Time String&amp;quot; adds one sub-parameter called &amp;quot;Time&amp;quot;, of type time:&lt;br /&gt;
&lt;br /&gt;
* time &amp;quot;Time&amp;quot; &lt;br /&gt;
&lt;br /&gt;
The result is a string containing the given time.&lt;br /&gt;
&lt;br /&gt;
=== Timed Swap ===&lt;br /&gt;
&lt;br /&gt;
This convert type was disabled in Synfig 0.61.06 and earlier because it didn't work.&lt;br /&gt;
&lt;br /&gt;
Converting a parameter to &amp;quot;Timed Swap&amp;quot; adds four sub-parameters:&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;Before&amp;quot;&lt;br /&gt;
* &amp;lt;param&amp;gt; &amp;quot;After&amp;quot;&lt;br /&gt;
* time &amp;quot;Swap Time&amp;quot;&lt;br /&gt;
* time &amp;quot;Swap Duration&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Before&amp;quot; and &amp;quot;After&amp;quot; are the same type as the parameter being converted.&lt;br /&gt;
&lt;br /&gt;
This conversion type linearly switches from &amp;quot;Before&amp;quot; to &amp;quot;After&amp;quot;, taking &amp;quot;Swap Duration&amp;quot; seconds to do so, and completing the swap at &amp;quot;Swap Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Note that this doesn't give us anything that we can't achieve using the &amp;quot;[[Convert#Linear|Linear]]&amp;quot; conversion type and a few waypoints.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Timed Swap&amp;quot; can be used on [[Convert#Angle|angles]], [[Convert#Color|colors]], [[Convert#Integer|integers]], [[Convert#Real|reals]], [[Convert#Time|times]], and [[Convert#Vector|vectors]].&lt;br /&gt;
&lt;br /&gt;
The resulting value is:&lt;br /&gt;
   if time &amp;gt; &amp;quot;Swap Time&amp;quot; then &amp;quot;After&amp;quot;&lt;br /&gt;
   else if time &amp;lt; (&amp;quot;Swap Time&amp;quot; - &amp;quot;Swap Duration&amp;quot;) then &amp;quot;Before&amp;quot;&lt;br /&gt;
   else interpolate between &amp;quot;Before&amp;quot; and &amp;quot;After&amp;quot;&lt;br /&gt;
&lt;br /&gt;
=== Two-Tone ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Gradient|gradient]] to &amp;quot;Two-Tone&amp;quot; adds two color-valued sub-parameters:&lt;br /&gt;
* color &amp;quot;Color1&amp;quot;&lt;br /&gt;
* color &amp;quot;Color2&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting gradient has two CPoints, one at each end, starting with &amp;quot;Color1&amp;quot; and ending with &amp;quot;Color2&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
These color parameters can be animated, giving us the ability to have the gradient change color over time.  This can be used as a workaround for [http://sourceforge.net/tracker/index.php?func=detail&amp;amp;aid=1568818&amp;amp;group_id=144022&amp;amp;atid=757416 this bug].&lt;br /&gt;
&lt;br /&gt;
=== Vector Angle ===&lt;br /&gt;
&lt;br /&gt;
Converting an [[Convert#Angle|angle]] to &amp;quot;Vector Angle&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the angle between the vector and the X axis.&lt;br /&gt;
&lt;br /&gt;
=== Vector Length ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] to &amp;quot;Vector Length&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the length of the vector.&lt;br /&gt;
&lt;br /&gt;
=== Vector X ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] to &amp;quot;Vector X&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the X component of the vector.&lt;br /&gt;
&lt;br /&gt;
=== Vector Y ===&lt;br /&gt;
&lt;br /&gt;
Converting a [[Convert#Real|real]] to &amp;quot;Vector Y&amp;quot; adds a vector sub-parameter:&lt;br /&gt;
* vector &amp;quot;Vector&amp;quot;&lt;br /&gt;
&lt;br /&gt;
The resulting value is the Y component of the vector.&lt;br /&gt;
&lt;br /&gt;
== Which Value Types can use which Convert Types? ==&lt;br /&gt;
&lt;br /&gt;
There are 13 different types of value in Synfig.  Each of these types has a different set of convert types available to it, as follows:&lt;br /&gt;
&lt;br /&gt;
=== Angle ===&lt;br /&gt;
&lt;br /&gt;
[[Image:angle_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Angle parameters can be converted to [[Convert#Add|Add]], [[Convert#aTan2|aTan2]], [[Convert#BLine Tangent|BLine Tangent]], [[Convert#Dot Product|Dot Product]], [[Convert#Linear|Linear]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], [[Convert#Vector Angle|Vector Angle]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== BLinePoint ===&lt;br /&gt;
[[Image:blinepoint_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* BLinePoint parameters can be converted to [[Convert#Composite|Composite]], [[Convert#Reverse Tangent|Reverse Tangent]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Bool ===&lt;br /&gt;
[[Image:bool_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Bool parameters can only be converted to the [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Canvas ===&lt;br /&gt;
[[Image:canvas_pointer_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Canvas parameters can be converted to the [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] type.&lt;br /&gt;
&lt;br /&gt;
=== Color ===&lt;br /&gt;
[[Image:color_icon.png|32px]]&lt;br /&gt;
* Color parameters can be converted to [[Convert#Add|Add]], [[Convert#Composite|Composite]], [[Convert#Gradient Color|Gradient Color]], [[Convert#Linear|Linear]], [[Convert#Radial Composite|Radial Composite]], [[Convert#Random|Random]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Gradient ===&lt;br /&gt;
[[Image:gradient_icon.png|32px]]&lt;br /&gt;
&lt;br /&gt;
* Gradient parameters can be converted to [[Convert#Add|Add]], [[Convert#Gradient Rotate|Gradient Rotate]], [[Convert#Repeat Gradient|Repeat Gradient]], [[Convert#Stripes|Stripes]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Two-Tone|Two-Tone]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Integer ===&lt;br /&gt;
[[Image:Integer_icon.png|32px]]&lt;br /&gt;
* Integer parameters can be converted to [[Convert#Add|Add]], [[Convert#Linear|Linear]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== List ===&lt;br /&gt;
[[Image:list_icon.png|32px]]&lt;br /&gt;
* List parameters can be converted to [[Convert#BLine|BLine]], [[Convert#Dynamic List|Dynamic List]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Real ===&lt;br /&gt;
[[Image:real_icon.png|32px]]&lt;br /&gt;
* Real parameters can be converted to [[Convert#Add|Add]], [[Convert#BLine Width|BLine Width]], [[Convert#Cos|Cos]], [[Convert#Dot Product|Dot Product]], [[Convert#Exponential|Exponential]], [[Convert#Linear|Linear]], [[Convert#Logarithm|Logarithm]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Reciprocal|Reciprocal]], [[Convert#Scale|Scale]], [[Convert#Sine|Sine]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], [[Convert#Vector Length|Vector Length]], [[Convert#Vector X|Vector X]], [[Convert#Vector Y|Vector Y]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Segment ===&lt;br /&gt;
[[Image:segment_icon.png|32px]]&lt;br /&gt;
* Segment parameters can be converted to the [[Convert#Composite|Composite]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== String ===&lt;br /&gt;
[[Image:string_icon.png|32px]]&lt;br /&gt;
* String parameters can be converted to the [[Convert#Angle String|Angle String]], [[Convert#Int String|Int String]], [[Convert#Joined List|Joined List]], [[Convert#Real String|Real String]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Time String|Time String]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Time ===&lt;br /&gt;
[[Image:time_icon.png|32px]]&lt;br /&gt;
* Time parameters can be converted to the [[Convert#Add|Add]], [[Convert#Linear|Linear]], [[Convert#Random|Random]], [[Convert#Range|Range]], [[Convert#Scale|Scale]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
=== Vector ===&lt;br /&gt;
[[Image:vector_icon.png|32px]]&lt;br /&gt;
* Vector parameters can be converted to [[Convert#Add|Add]], [[Convert#BLine Tangent|BLine Tangent]], [[Convert#BLine Vertex|BLine Vertex]], [[Convert#Composite|Composite]], [[Convert#Linear|Linear]], [[Convert#Radial Composite|Radial Composite]], [[Convert#Random|Random]], [[Convert#Scale|Scale]], [[Convert#Segment Tangent|Segment Tangent]], [[Convert#Segment Vertex|Segment Vertex]], [[Convert#Step|Step]], [[Convert#Subtract|Subtract]], [[Convert#Switch|Switch]], [[Convert#Time Loop|Time Loop]], [[Convert#Timed Swap|Timed Swap]], and [[Convert#Reference|Reference]] types.&lt;br /&gt;
&lt;br /&gt;
== Compatibility ==&lt;br /&gt;
&lt;br /&gt;
When a new ValueNode type is added to Synfig, the .sif file format is extended to include a way of writing the new type.  This extension won't be able to be read by any older version of Synfig.  Here's a list of the ValueNode types that have been added, along with the subversion revision number in which they first appeared:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;blockquote&amp;gt;&lt;br /&gt;
{| style=&amp;quot;width:55%&amp;quot;&lt;br /&gt;
| '''Version''' || '''Revision''' || '''Convert'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.09)''' || not yet released || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2034 || [[#Logarithm|Logarithm]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2010 || [[#Int String|Int String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2010 || [[#Angle String|Angle String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2007 || [[#Joined List|Joined List]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2003 || [[#Real String|Real String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 2000 || [[#Time String|Time String]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1891 || [[#Dot Product|Dot Product]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1885 || [[#Gradient Color|Gradient Color]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1882 || [[#Vector X|Vector X]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1882 || [[#Vector Y|Vector Y]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1881 || [[#Vector Length|Vector Length]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1880 || [[#Vector Angle|Vector Angle]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.08)''' || 1839 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1694 || [[#BLine Width|BLine Width]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1690 || [[#Random|Random]] (for bools)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1691 || [[#Step|Step]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1354 || [[#Subtract|Subtract]] (for gradients)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1354 || [[#Add|Add]] (for gradients)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1267 || [[#From Integer|From Integer]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1267 || [[#Duplicate|Duplicate]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1238 || [[#Reciprocal|Reciprocal]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1226 || [[#Time Loop|Time Loop]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1162 || [[#Reverse Tangent|Reverse Tangent]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1132 || [[#aTan2|aTan2]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 1111 || [[#Cos|Cos]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 923 || [[#Switch|Switch]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 907 || [[#Random|Random]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.07)''' || 878 || &amp;amp;nbsp;&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 776 || [[#Range|Range]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 744 || [[#BLine Vertex|BLine Vertex]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 744 || [[#BLine Tangent|BLine Tangent]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 742 || [[#Add|Add]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 739 || [[#Exponential|Exponential]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 666 || [[#Repeat Gradient|Repeat Gradient]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;amp;nbsp; || 610 || [[#Timed Swap|Timed Swap]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt; || &amp;lt;hr&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
| '''(0.61.06)''' || 536 || &amp;amp;nbsp;&lt;br /&gt;
|-|}&lt;br /&gt;
&amp;lt;/blockquote&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Time_Loop_Layer&amp;diff=8294</id>
		<title>Time Loop Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Time_Loop_Layer&amp;diff=8294"/>
				<updated>2008-12-13T11:51:20Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: add an 'otherwise' to show that the sentence only applies if the previous one doesn't&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;The Time Loop layer can be used to repeat an animation over and over.  It loops a section of the layers under it over and over.&lt;br /&gt;
&lt;br /&gt;
See also the [[Convert#Time_Loop|Time Loop ValueNode]] conversion, which can be used to loop the value of a single parameter, rather than an entire layer or group of layers.&lt;br /&gt;
&lt;br /&gt;
[Note: ''the Time Loop layer used to have parameters 'start time' and 'end time'.  Documentation for that old version of the layer [[Time Loop Layer (v0.1)|is available]]''.&lt;br /&gt;
&lt;br /&gt;
It has 6 parameters, as follows:&lt;br /&gt;
* real &amp;quot;Z Depth&amp;quot;&lt;br /&gt;
* time &amp;quot;Link Time&amp;quot;&lt;br /&gt;
* time &amp;quot;Local Time&amp;quot;&lt;br /&gt;
* time &amp;quot;Duration&amp;quot;&lt;br /&gt;
* bool &amp;quot;Only For Positive Duration&amp;quot;&lt;br /&gt;
* bool &amp;quot;Symmetrical&amp;quot;&lt;br /&gt;
&lt;br /&gt;
These parameters, like any other in Synfig can be animated, so that they change over time.  This can be confusing, so make sure you aren't in Animate Edit Mode when working with the Time Loop layer, unless you know what you're doing!&lt;br /&gt;
&lt;br /&gt;
If 'Only For Positive Duration' is checked, and 'Duration' is zero or negative, then the time loop layer is effectively disabled, and acts as if it wasn't there.&lt;br /&gt;
&lt;br /&gt;
Otherwise, when the Duration is zero, the Time Loop layer freezes the animation of the children layers at the value of &amp;quot;Link Time&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Otherwise, the Time Loop layer repeatedly loops through the 'Duration' seconds of its child layers, from 'Link Time' to 'Link Time' + 'Duration'.  'Local Time' is used to line up the offset of the time looping.  When the Time Loop layer is asked to set its time to 'Local Time', it sets the time in its child layers to be 'Link Time', ie. the start of the loop.&lt;br /&gt;
&lt;br /&gt;
If 'Symmetrical' isn't checked, and the current time is less than 'local time', then 'duration' is taken off the resulting time.  This is to provide compatibility with [[Time Loop Layer (v0.1)|version 0.1]] of the time loop layer.&lt;br /&gt;
&lt;br /&gt;
For example, suppose:&lt;br /&gt;
* Link Time is 5s&lt;br /&gt;
* Duration is 3s&lt;br /&gt;
* Local Time' is 4s&lt;br /&gt;
&lt;br /&gt;
And suppose that the Time Loop layer is applied over an existing animation.  The 'Link Time' and 'Duration' specify that the section from 5s to 8s in the children layers will be looped.  The 'Local Time' specifies that this loop will be at the beginning at 4s.  (And so also therefore at 1s, 7s, 10s, etc).&lt;br /&gt;
&lt;br /&gt;
This is how the mapping actually works:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|'''real time'''||'''child time&amp;lt;br/&amp;gt;(symmetrical = true)'''||'''child time&amp;lt;br/&amp;gt;(symmetrical = false)'''&lt;br /&gt;
|-&lt;br /&gt;
| 0 || 7 || 4&lt;br /&gt;
|-&lt;br /&gt;
| 1 || 5 || 2&lt;br /&gt;
|-&lt;br /&gt;
| 2 || 6 || 3&lt;br /&gt;
|-&lt;br /&gt;
| 3 || 7 || 4&lt;br /&gt;
|-&lt;br /&gt;
| 4 || 5 || 5 (local time = 4; link time = 5)&lt;br /&gt;
|-&lt;br /&gt;
| 5 || 6 || 6&lt;br /&gt;
|-&lt;br /&gt;
| 6 || 7 || 7&lt;br /&gt;
|-&lt;br /&gt;
| 7 || 5 || 5 (duration = 3, so loop repeats after 3 seconds)&lt;br /&gt;
|-&lt;br /&gt;
| 8 || 6 || 6&lt;br /&gt;
|-&lt;br /&gt;
| 9 || 7 || 7&lt;br /&gt;
|-&lt;br /&gt;
| 10 || 5 || 5&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Specifying a huge number for the Duration parameter effectively turns the Time Loop layer into a Time Shift layer.  The Link Time and Local Time parameters controls which time in the children lines up with which time in the Time Loop layer, giving the amount of the timeshift, with both positive and negative differences working as expected.&lt;br /&gt;
&lt;br /&gt;
== Contrived Example ==&lt;br /&gt;
&lt;br /&gt;
Download and examine this example file: [[Media:Time-loop-demo-0.2.sifz|Time-loop-demo-0.2.sifz]]&lt;br /&gt;
&lt;br /&gt;
It's a 10 second animation, and shows 2 circles.  The top one moves linearly from the left to the right.  Its position is marked by static text digits 0 through 10.&lt;br /&gt;
&lt;br /&gt;
The other circle is an identical copy of the first one, with the same waypoints, but it's inside an encapsulation layer.  The parameters are:&lt;br /&gt;
* Link Time: 5s&lt;br /&gt;
* Duration: 1.5s&lt;br /&gt;
* Local Time: 2s&lt;br /&gt;
* Symmetrical: true&lt;br /&gt;
&lt;br /&gt;
So as time=2s, the top circle is at position 2 (local time) and the bottom circle is at position 5 (link time):&lt;br /&gt;
&lt;br /&gt;
[[Image:Time-loop-demo-0.2-2s-0f.png]]&lt;br /&gt;
&lt;br /&gt;
The loop is 1.5s long, so the bottom circle is also at position 5 every 1.5 seconds before and after this point in time, for example at t=3.5s and at t=8s:&lt;br /&gt;
&lt;br /&gt;
[[Image:Time-loop-demo-0.2-3s-12f.png]]&lt;br /&gt;
[[Image:Time-loop-demo-0.2-8s-0f.png]]&lt;br /&gt;
&lt;br /&gt;
The following two images show the positions at t=0s and t=3s.  The loop starts at t=2s, so it's also at the start at t=0.5s.  So at t=0s it's half a second before finishing the previous loop.  And at t=3s the same is true, but 2 loops later on:&lt;br /&gt;
&lt;br /&gt;
[[Image:Time-loop-demo-0.2-0s-0f.png]]&lt;br /&gt;
[[Image:Time-loop-demo-0.2-3s-0f.png]]&lt;br /&gt;
&lt;br /&gt;
There's a rendered copy of this example on [http://www.youtube.com/watch?v=WyYLd7319Gw YouTube], and it's also available for download: [[Media:Time-loop-demo-0.2.avi‎|Time-loop-demo-0.2.avi‎]].&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8286</id>
		<title>Dev:Bone Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8286"/>
				<updated>2008-11-30T11:30:51Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* What happen if there are more than one bone affecting the point? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Initial seed for concepts ==&lt;br /&gt;
&lt;br /&gt;
[http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-12.log This portion] of IRC logs sets the basis for the implementation of a Bone Layer. The interesting part is from 16:49 to 18:56.&lt;br /&gt;
&lt;br /&gt;
Also [http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-13.log this one] has some interesting thoughts. From 8:20 to 14:43&lt;br /&gt;
&lt;br /&gt;
== Concepts ==&lt;br /&gt;
This is an unsorted list of concepts to let me clarify my thoughts and also allow others to understand the following sections.&lt;br /&gt;
&lt;br /&gt;
=== Bones intentions ===&lt;br /&gt;
Initial intention of Bones is to attempt to emulate the skeleton of a vertebrate animal. In this way you have the skin and a skeleton. Part of the skin are associated with the various bones of the skeleton. When the skeleton moves the skin follows.&lt;br /&gt;
&lt;br /&gt;
=== Application of bones in animation ===&lt;br /&gt;
In traditional animation producing a walk cycle implies drawing each keyframe for the walk and maybe, depending on the walking speed, drawing the in betweens too. To avoid having to draw the in between images there are tweening animation programs (like Synfig) to help the animator. Then the animator just needs to draw the keyframes and the application does the rest. That's quite good but in certain situations you see your self redrawing the same pose (with small variations) frequently at different times. Then bones come to help. They aid the animator in the following manner.&lt;br /&gt;
&lt;br /&gt;
* With the manipulation of a single object (or a set of them) you can manage a lot of points of the drawing definition.&lt;br /&gt;
* Rotations of drawings using keyframes needs lots of them (by nature of the fact that tweening is defined in the x,y coordinates system and the rotation is performed in the angle, radius coordinate system). Using bones you can perform rotations of large angles with just two waypoints. Also since characters have limbs and limbs in living beings do mainly rotations, the usage of bones becomes handy in that kind of animation.&lt;br /&gt;
* Once the character (or whatever thing that uses bones) is rigged (the skeleton structure is created and the relationship between it and the skin is defined) it is possible to produce different kinds of keyframes for different purposes: Walk, run, jump, sit, ...&lt;br /&gt;
&lt;br /&gt;
== How can we do implement this? ==&lt;br /&gt;
The relationship between the skeleton and the skin is like this:&lt;br /&gt;
&lt;br /&gt;
*The Skin is made using Points and BLines. BLines are defined by Points. Points are made of Vertexes and Tangents&lt;br /&gt;
*Skeleton is made of bones and the relationships between them.&lt;br /&gt;
*''If Bones would have influence on the Vertexes and Tangents then the bones movements would move the points and therefore the skin would be moved''.&lt;br /&gt;
&lt;br /&gt;
That's the key, if we understand how a bone has influence on a vertex and a tangent then we can find the way a skeleton can have influence over a skin.&lt;br /&gt;
&lt;br /&gt;
=== Bones Properties ===&lt;br /&gt;
From my experience with bones in other 2D animation applications, watching the strong and weak points, bones needs to have the following properties:&lt;br /&gt;
&lt;br /&gt;
* A bone has an origin point about which the rotation is performed.&lt;br /&gt;
* A bone has a length.&lt;br /&gt;
* A bone has an angle.&lt;br /&gt;
* A bone can have a region of influence.&lt;br /&gt;
* A bone can have a one or zero parent bones.&lt;br /&gt;
* A bone can have one or more child bones.&lt;br /&gt;
* A skeleton is defined as a connected set of bones (consisting of exactly one parent-less bone and its children bones and their descendants).&lt;br /&gt;
&lt;br /&gt;
All the bones in a Synfig Document can produce several distinct skeletons (depending on how many parent-less bones are in it).&lt;br /&gt;
&lt;br /&gt;
=== How does a Vertex move under the influence of a single Bone? ===&lt;br /&gt;
&lt;br /&gt;
Conceptually a bone has influence over a point by doing [http://en.wikipedia.org/wiki/Affine_transformation affine transformations] of its position according to the bone values. See also [http://en.wikipedia.org/wiki/Transformation_matrix transformation matrix]. A bone produces rotation, scale and translation to a point in this way:&lt;br /&gt;
&lt;br /&gt;
[[Image:Bonesimulation2.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see the values that produce the movement of the point P to the point P' are given by:&lt;br /&gt;
&lt;br /&gt;
*Translation of the bone: O'-O&lt;br /&gt;
*Rotation of the bone: &amp;lt;math&amp;gt;\alpha'-\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
*Scale of the bone: s=length'/length&lt;br /&gt;
&lt;br /&gt;
Then, given a Point P in the 2D space and knowing the translation, rotation and scale of the bone you can calculate the new position P' using this formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(-O)=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
-O_x &amp;amp; -O_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to origin (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(-\alpha)=\begin{bmatrix}&lt;br /&gt;
\cos(-\alpha) &amp;amp; \sin(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
-\sin(-\alpha) &amp;amp; \cos(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;-\alpha&amp;lt;/math&amp;gt;' about the origin. That aligns the bone with the X axis&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S_x(length'/length)=\begin{bmatrix}&lt;br /&gt;
length'/length &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Scale by a value of 's=length'/length' in the direction of X (the current direction of the bone).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(\alpha^')=\begin{bmatrix}&lt;br /&gt;
\cos(\alpha^') &amp;amp; \sin(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
-\sin(\alpha^') &amp;amp; \cos(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;\alpha'&amp;lt;/math&amp;gt;' about the origin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(O^')=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
O^'_x &amp;amp; O^'_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to new position O'&lt;br /&gt;
&lt;br /&gt;
Then the transformation from P to P' is given by the matrix multiplication:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T(-O)\cdot R(-\alpha)\cdot S_x(length'/length)\cdot R(\alpha^')\cdot T(O^')&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T\cdot R\cdot S_x\cdot R'\cdot T'=P\cdot B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Can Points (Bone influenced) be moved independently? ===&lt;br /&gt;
&lt;br /&gt;
Yes, they should be. If not the animator is restricted to only doing the animation with bones which would lead to some insoluble problems during the animation. Considering this, the point position result comes from the addition of two terms:&lt;br /&gt;
*(a) The movement of the point as described by the influence of the bone(s): P(B)&lt;br /&gt;
*(b) The free movement of the point in the 2D space. P(animated)&lt;br /&gt;
&lt;br /&gt;
In terms of the interface with the user, the value P(animated) is just obtained in this way:&lt;br /&gt;
&lt;br /&gt;
#In any position of the time line (bones are animated) the point has a position given by the influence of the bones: P(B).&lt;br /&gt;
#The user selects a point, drags it, placing it at P'.&lt;br /&gt;
#The final position of the point is P' but the user cannot modify the first term P(B) so the second term (b) becomes: P(animated)=P'-P(B).&lt;br /&gt;
&lt;br /&gt;
===What happen if there are more than one bone affecting the point?===&lt;br /&gt;
&lt;br /&gt;
The first thing you can think when you deal with more than one bone having influence over the same point is to calculate the average of the sum of the influences of all bones. So if there are N bones affecting the point then we can think of summing all the resulting points from each bone and then dividing the result by N to not scale the result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k}{N} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;B_k&amp;lt;/math&amp;gt; is the bone matrix for the bone ''k'' on the point P.&lt;br /&gt;
&lt;br /&gt;
That's fine but I would like to have more control to the way the bones affect the points. When you move a bone it looks reasonable that not all the points are influenced in the same way. This can be solved by using a &amp;quot;weighted&amp;quot; average instead of a plain one. That means giving a different amount of influence to one bone than to the other.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k \cdot w_k}{\sum_{k=1}^N w_k} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;w_k&amp;lt;/math&amp;gt; is the weight for the bone ''k'' over the point P.&lt;br /&gt;
&lt;br /&gt;
=== Skeleton ===&lt;br /&gt;
&lt;br /&gt;
A skeleton is a set of bones linked one to others in a tree hierarchy. A bone can have several children (or none) but only one parent (or none). This configuration allows to do a easy calculation of the forward kinematic (FK )of the chain and the inverse kinematic (IK) of the chain of bones. If the hierarchy were not tree type then the FK and IK can be not soluble. &lt;br /&gt;
&lt;br /&gt;
For those IK and FK calculations it is good to have the bone referenced to its parent. So the parameters of the bone are described as relative to the parent bone. The parent bone defines a local coordinate system where the origin of the coordinate system lies on the Origin of the bone and the tip of the bone is pointing to the positive direction of the X axis.&lt;br /&gt;
&lt;br /&gt;
[[Image: skeleton.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see in this image, each skeleton position and orientation is defined by the relative position of its immediate parent bone. In the diagram bone3 is a child of bone2 and bone 2 is a child of bone1. The bone 1 is the root parent bone but you can imagine it attached to a &amp;quot;master root bone&amp;quot; (defined by the origin of coordinates -red circumference- and the horizontal) so it can be said that the bone1 has its origin and angle defined relative to its &amp;quot;parent&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In this skeleton the three bones are parented in a linear way. But as you can imagine, following the rules stated for child-parent, a bone can have more than one child but not more than one parent. &lt;br /&gt;
That means that defined a bone in the skeleton, there is only one sequence of parents to reach the root parent of the skeleton. Also it means too that one root bone defines one skeleton so each skeleton has only one root bone and only one.&lt;br /&gt;
&lt;br /&gt;
Consider this: B3 is child of B2 and B2 is child of B1. Also B4 is child of B2 and B5 is child of B4. The way to travel from B5 to B1 is unique: B5-&amp;gt;B4-&amp;gt;B2-&amp;gt;B1.&lt;br /&gt;
&lt;br /&gt;
=== Setup and Animation ===&lt;br /&gt;
&lt;br /&gt;
During the animation of the skeleton it is supposed that the position of each bone, its angle and its scale changes. Position and angle are relative to the parent bone, but scale is a value that calculates the current length of the bone compared with the &amp;quot;original&amp;quot; bone length (scale=length'/length) as you can see from the original formulas in the previous section. That means that the &amp;quot;original&amp;quot; bone length shouldn't be never zero, otherwise there will be a division by zero and the scale of the bone becomes infinite.&lt;br /&gt;
&lt;br /&gt;
Also, the final position P' of a point that moves influenced by a single bone is given by the original point position relative to the bone in its &amp;quot;original&amp;quot; position (P). &lt;br /&gt;
&lt;br /&gt;
What I'm trying to explain is that it is needed that the setup of the bone (position, alpha and length) and the setup position of the point (P) to be moved would be given to calculate the final position of the point (P') given a moved position of the bone (position', alpha', length')&lt;br /&gt;
&lt;br /&gt;
Said this and considered the information of the previous sections, the bones and points that are influenced from the bones should have the following parameters:&lt;br /&gt;
&lt;br /&gt;
'''BONES PARAMETERS'''&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Origin ||&amp;lt;math&amp;gt; \textstyle O_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Angle || &amp;lt;math&amp;gt; \textstyle \alpha_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Length || &amp;lt;math&amp;gt; \textstyle l_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| Calculated, not animatable.&lt;br /&gt;
|- &lt;br /&gt;
| Scale || &amp;lt;math&amp;gt; \textstyle s_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| &amp;lt;math&amp;gt; \textstyle l_j(t) =l^0_j \cdot s_j(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Setup Origin || &amp;lt;math&amp;gt; \textstyle O^0_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Angle || &amp;lt;math&amp;gt; \textstyle \alpha^0_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Length || &amp;lt;math&amp;gt; \textstyle l^0_j &amp;lt;/math&amp;gt; || Real || No|| Constant, zero not allowed.&lt;br /&gt;
|- &lt;br /&gt;
| Setup Scale || &amp;lt;math&amp;gt; \textstyle s^0_j &amp;lt;/math&amp;gt; || Real || No|| &amp;lt;math&amp;gt; \textstyle s^0_j = 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Parent || &amp;lt;math&amp;gt; \textstyle PBone_j(t) &amp;lt;/math&amp;gt; || Bone ||Yes|| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''POINT PARAMETERS'''&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Position ||&amp;lt;math&amp;gt; \textstyle V(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Calculated: &amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt; Global coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Free Position ||&amp;lt;math&amp;gt; \textstyle VF(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Setup Position ||&amp;lt;math&amp;gt; \textstyle VS(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Matrix ||&amp;lt;math&amp;gt; \textstyle M(t) &amp;lt;/math&amp;gt; || Matrix (3x3) ||Yes|| Calculated. See formulas below&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Id ||&amp;lt;math&amp;gt; \textstyle BoneID_i &amp;lt;/math&amp;gt; || Bone || No || 'i' is the index for all the Bones that influences on the Point&lt;br /&gt;
|- &lt;br /&gt;
| Influence weight ||&amp;lt;math&amp;gt; \textstyle w_i &amp;lt;/math&amp;gt; || Real || Yes || the weight associated to the BoneID_i&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(t) denotes ''calculated at the time t''&lt;br /&gt;
&lt;br /&gt;
=== Position of a Point due to Bones Influence ===&lt;br /&gt;
&lt;br /&gt;
According to the table, the final position of a point influenced by the bones is calculated based on two terms: A free movement of the point plus a bone drive movement. In this section we are going to calculate the second term.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M(t) = \cfrac{\sum_{i=1}^N M_i(t) \cdot w_i(t)}{\sum_{i=1}^N w_i(t)} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M_i(t)=B^0_i(t) \cdot B_i(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where i is a index that runs all the Bones Influence ID from i=1 to N (N= total number of bones that influence to the point)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B^0_i(t)= \prod_{j=bone}^{j=root} C_j^0(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B_i(t)= \prod_{j=root}^{j=bone} C_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'j' runs the bone skeleton jumping from a child/parent bone to a parent/child bone each time. The travel of the index 'j' from ''bone'' to ''root'' and from ''root'' to ''bone'' is fixed -and unique- by the nature of skeletons constructions (a bone, a parent), as mentioned before.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j^0(t) = T(-O_j^0(t)) \cdot R(-\alpha_j^0(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the position of the point in local coordinates in relation to the bone 'j' at setup position. Notice that &amp;lt;math&amp;gt; s^0_j &amp;lt;/math&amp;gt; is equal to &amp;lt;math&amp;gt; \textstyle 1 &amp;lt;/math&amp;gt; for any bone and for any time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j(t) = S_x(s_j(t))\cdot R(\alpha_j(t)) \cdot T(O_j(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the global position of the point due to the bone 'j' at animated position of the skeleton.&lt;br /&gt;
&lt;br /&gt;
=== Calculate the position and angle of a bone in a skeleton ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Position and Angle at Setup ====&lt;br /&gt;
&lt;br /&gt;
If the bones are described using relative coordinates to its predecessor, the position &amp;lt;math&amp;gt;\textstyle Q^0_j&amp;lt;/math&amp;gt; and the angle &amp;lt;math&amp;gt;\textstyle \beta^0_j&amp;lt;/math&amp;gt; of the bone 'j' in relation to the &amp;quot;master root bone&amp;quot; (ie. the global coordinate system) is given by those equations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q^0_j(t) = O^0_j(t) \cdot B^0_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta^0_j(t) = \sum_{i=j}^{root} \alpha^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_j(t)=\prod_{i=parent}^{root} B^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the parent of the bone 'j' and climbs up by one parent each time until it reaches the 'root' bone of the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)= T(-O^0_i(t)) \cdot R(-\alpha^0_i(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)&amp;lt;/math&amp;gt; is the inverse matrix transformation of the position of the bone relative to its immediate parent.&lt;br /&gt;
&lt;br /&gt;
Notice that at setup, &amp;lt;math&amp;gt;s^0_j&amp;lt;/math&amp;gt; is always equal to 1.&lt;br /&gt;
&lt;br /&gt;
====Animated Position and Angle ====&lt;br /&gt;
&lt;br /&gt;
Once calculated the position and angle of a bone in global coordinates you can calculate its animated position and angle by the transformation of their parents in the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q_j(t) = O^0_j(t) \cdot B^0_j(t) \cdot B_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_j(t)= \beta^0_j(t) + \sum_{i=root}^{parent} \alpha_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;math&amp;gt;B_j(t)=\prod_{i=root}^{parent} B_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the root bone and jumps down by one child each time until it reaches the 'parent' bone of the bone 'j'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B_i(t)= S_x(s_j(t)) \cdot R(\alpha_i(t)) \cdot T(O_i(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\textstyle B_i(t)&amp;lt;/math&amp;gt; is the transformation matrix of the position of the bone 'j' at the time t. &lt;br /&gt;
&lt;br /&gt;
The results &amp;lt;math&amp;gt;\textstyle Q_j(t), \beta_j(t)&amp;lt;/math&amp;gt; are obtained in global coordinates.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8285</id>
		<title>Dev:Bone Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8285"/>
				<updated>2008-11-30T11:27:50Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Can Points (Bone influenced) be moved independently? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Initial seed for concepts ==&lt;br /&gt;
&lt;br /&gt;
[http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-12.log This portion] of IRC logs sets the basis for the implementation of a Bone Layer. The interesting part is from 16:49 to 18:56.&lt;br /&gt;
&lt;br /&gt;
Also [http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-13.log this one] has some interesting thoughts. From 8:20 to 14:43&lt;br /&gt;
&lt;br /&gt;
== Concepts ==&lt;br /&gt;
This is an unsorted list of concepts to let me clarify my thoughts and also allow others to understand the following sections.&lt;br /&gt;
&lt;br /&gt;
=== Bones intentions ===&lt;br /&gt;
Initial intention of Bones is to attempt to emulate the skeleton of a vertebrate animal. In this way you have the skin and a skeleton. Part of the skin are associated with the various bones of the skeleton. When the skeleton moves the skin follows.&lt;br /&gt;
&lt;br /&gt;
=== Application of bones in animation ===&lt;br /&gt;
In traditional animation producing a walk cycle implies drawing each keyframe for the walk and maybe, depending on the walking speed, drawing the in betweens too. To avoid having to draw the in between images there are tweening animation programs (like Synfig) to help the animator. Then the animator just needs to draw the keyframes and the application does the rest. That's quite good but in certain situations you see your self redrawing the same pose (with small variations) frequently at different times. Then bones come to help. They aid the animator in the following manner.&lt;br /&gt;
&lt;br /&gt;
* With the manipulation of a single object (or a set of them) you can manage a lot of points of the drawing definition.&lt;br /&gt;
* Rotations of drawings using keyframes needs lots of them (by nature of the fact that tweening is defined in the x,y coordinates system and the rotation is performed in the angle, radius coordinate system). Using bones you can perform rotations of large angles with just two waypoints. Also since characters have limbs and limbs in living beings do mainly rotations, the usage of bones becomes handy in that kind of animation.&lt;br /&gt;
* Once the character (or whatever thing that uses bones) is rigged (the skeleton structure is created and the relationship between it and the skin is defined) it is possible to produce different kinds of keyframes for different purposes: Walk, run, jump, sit, ...&lt;br /&gt;
&lt;br /&gt;
== How can we do implement this? ==&lt;br /&gt;
The relationship between the skeleton and the skin is like this:&lt;br /&gt;
&lt;br /&gt;
*The Skin is made using Points and BLines. BLines are defined by Points. Points are made of Vertexes and Tangents&lt;br /&gt;
*Skeleton is made of bones and the relationships between them.&lt;br /&gt;
*''If Bones would have influence on the Vertexes and Tangents then the bones movements would move the points and therefore the skin would be moved''.&lt;br /&gt;
&lt;br /&gt;
That's the key, if we understand how a bone has influence on a vertex and a tangent then we can find the way a skeleton can have influence over a skin.&lt;br /&gt;
&lt;br /&gt;
=== Bones Properties ===&lt;br /&gt;
From my experience with bones in other 2D animation applications, watching the strong and weak points, bones needs to have the following properties:&lt;br /&gt;
&lt;br /&gt;
* A bone has an origin point about which the rotation is performed.&lt;br /&gt;
* A bone has a length.&lt;br /&gt;
* A bone has an angle.&lt;br /&gt;
* A bone can have a region of influence.&lt;br /&gt;
* A bone can have a one or zero parent bones.&lt;br /&gt;
* A bone can have one or more child bones.&lt;br /&gt;
* A skeleton is defined as a connected set of bones (consisting of exactly one parent-less bone and its children bones and their descendants).&lt;br /&gt;
&lt;br /&gt;
All the bones in a Synfig Document can produce several distinct skeletons (depending on how many parent-less bones are in it).&lt;br /&gt;
&lt;br /&gt;
=== How does a Vertex move under the influence of a single Bone? ===&lt;br /&gt;
&lt;br /&gt;
Conceptually a bone has influence over a point by doing [http://en.wikipedia.org/wiki/Affine_transformation affine transformations] of its position according to the bone values. See also [http://en.wikipedia.org/wiki/Transformation_matrix transformation matrix]. A bone produces rotation, scale and translation to a point in this way:&lt;br /&gt;
&lt;br /&gt;
[[Image:Bonesimulation2.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see the values that produce the movement of the point P to the point P' are given by:&lt;br /&gt;
&lt;br /&gt;
*Translation of the bone: O'-O&lt;br /&gt;
*Rotation of the bone: &amp;lt;math&amp;gt;\alpha'-\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
*Scale of the bone: s=length'/length&lt;br /&gt;
&lt;br /&gt;
Then, given a Point P in the 2D space and knowing the translation, rotation and scale of the bone you can calculate the new position P' using this formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(-O)=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
-O_x &amp;amp; -O_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to origin (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(-\alpha)=\begin{bmatrix}&lt;br /&gt;
\cos(-\alpha) &amp;amp; \sin(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
-\sin(-\alpha) &amp;amp; \cos(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;-\alpha&amp;lt;/math&amp;gt;' about the origin. That aligns the bone with the X axis&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S_x(length'/length)=\begin{bmatrix}&lt;br /&gt;
length'/length &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Scale by a value of 's=length'/length' in the direction of X (the current direction of the bone).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(\alpha^')=\begin{bmatrix}&lt;br /&gt;
\cos(\alpha^') &amp;amp; \sin(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
-\sin(\alpha^') &amp;amp; \cos(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;\alpha'&amp;lt;/math&amp;gt;' about the origin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(O^')=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
O^'_x &amp;amp; O^'_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to new position O'&lt;br /&gt;
&lt;br /&gt;
Then the transformation from P to P' is given by the matrix multiplication:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T(-O)\cdot R(-\alpha)\cdot S_x(length'/length)\cdot R(\alpha^')\cdot T(O^')&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T\cdot R\cdot S_x\cdot R'\cdot T'=P\cdot B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Can Points (Bone influenced) be moved independently? ===&lt;br /&gt;
&lt;br /&gt;
Yes, they should be. If not the animator is restricted to only doing the animation with bones which would lead to some insoluble problems during the animation. Considering this, the point position result comes from the addition of two terms:&lt;br /&gt;
*(a) The movement of the point as described by the influence of the bone(s): P(B)&lt;br /&gt;
*(b) The free movement of the point in the 2D space. P(animated)&lt;br /&gt;
&lt;br /&gt;
In terms of the interface with the user, the value P(animated) is just obtained in this way:&lt;br /&gt;
&lt;br /&gt;
#In any position of the time line (bones are animated) the point has a position given by the influence of the bones: P(B).&lt;br /&gt;
#The user selects a point, drags it, placing it at P'.&lt;br /&gt;
#The final position of the point is P' but the user cannot modify the first term P(B) so the second term (b) becomes: P(animated)=P'-P(B).&lt;br /&gt;
&lt;br /&gt;
===What happen if there are more than one bone affecting the point?===&lt;br /&gt;
&lt;br /&gt;
The first thing you can think when you deal with more than one bone making influence over the same point is to calculate the average of the sum of the influences of all bones. So if there are N bones affecting to the point then we can think on sum all the resulting points from each bone and then divide the result by N to not scale the result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k}{N} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;B_k&amp;lt;/math&amp;gt; is the bone matrix for the bone ''k'' on the point P.&lt;br /&gt;
&lt;br /&gt;
That's fine but I would like to have more control to the way the bones affects to the points. When you move a bone it looks reasonable that not all the points are influence in the same way. This can be solved by using &amp;quot;weighted&amp;quot; average instead of a plain one. That means give different amount of influence to one bone than to other.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k \cdot w_k}{\sum_{k=1}^N w_k} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;w_k&amp;lt;/math&amp;gt; is the weight for the bone ''k'' over the point P.&lt;br /&gt;
&lt;br /&gt;
=== Skeleton ===&lt;br /&gt;
&lt;br /&gt;
A skeleton is a set of bones linked one to others in a tree hierarchy. A bone can have several children (or none) but only one parent (or none). This configuration allows to do a easy calculation of the forward kinematic (FK )of the chain and the inverse kinematic (IK) of the chain of bones. If the hierarchy were not tree type then the FK and IK can be not soluble. &lt;br /&gt;
&lt;br /&gt;
For those IK and FK calculations it is good to have the bone referenced to its parent. So the parameters of the bone are described as relative to the parent bone. The parent bone defines a local coordinate system where the origin of the coordinate system lies on the Origin of the bone and the tip of the bone is pointing to the positive direction of the X axis.&lt;br /&gt;
&lt;br /&gt;
[[Image: skeleton.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see in this image, each skeleton position and orientation is defined by the relative position of its immediate parent bone. In the diagram bone3 is a child of bone2 and bone 2 is a child of bone1. The bone 1 is the root parent bone but you can imagine it attached to a &amp;quot;master root bone&amp;quot; (defined by the origin of coordinates -red circumference- and the horizontal) so it can be said that the bone1 has its origin and angle defined relative to its &amp;quot;parent&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In this skeleton the three bones are parented in a linear way. But as you can imagine, following the rules stated for child-parent, a bone can have more than one child but not more than one parent. &lt;br /&gt;
That means that defined a bone in the skeleton, there is only one sequence of parents to reach the root parent of the skeleton. Also it means too that one root bone defines one skeleton so each skeleton has only one root bone and only one.&lt;br /&gt;
&lt;br /&gt;
Consider this: B3 is child of B2 and B2 is child of B1. Also B4 is child of B2 and B5 is child of B4. The way to travel from B5 to B1 is unique: B5-&amp;gt;B4-&amp;gt;B2-&amp;gt;B1.&lt;br /&gt;
&lt;br /&gt;
=== Setup and Animation ===&lt;br /&gt;
&lt;br /&gt;
During the animation of the skeleton it is supposed that the position of each bone, its angle and its scale changes. Position and angle are relative to the parent bone, but scale is a value that calculates the current length of the bone compared with the &amp;quot;original&amp;quot; bone length (scale=length'/length) as you can see from the original formulas in the previous section. That means that the &amp;quot;original&amp;quot; bone length shouldn't be never zero, otherwise there will be a division by zero and the scale of the bone becomes infinite.&lt;br /&gt;
&lt;br /&gt;
Also, the final position P' of a point that moves influenced by a single bone is given by the original point position relative to the bone in its &amp;quot;original&amp;quot; position (P). &lt;br /&gt;
&lt;br /&gt;
What I'm trying to explain is that it is needed that the setup of the bone (position, alpha and length) and the setup position of the point (P) to be moved would be given to calculate the final position of the point (P') given a moved position of the bone (position', alpha', length')&lt;br /&gt;
&lt;br /&gt;
Said this and considered the information of the previous sections, the bones and points that are influenced from the bones should have the following parameters:&lt;br /&gt;
&lt;br /&gt;
'''BONES PARAMETERS'''&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Origin ||&amp;lt;math&amp;gt; \textstyle O_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Angle || &amp;lt;math&amp;gt; \textstyle \alpha_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Length || &amp;lt;math&amp;gt; \textstyle l_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| Calculated, not animatable.&lt;br /&gt;
|- &lt;br /&gt;
| Scale || &amp;lt;math&amp;gt; \textstyle s_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| &amp;lt;math&amp;gt; \textstyle l_j(t) =l^0_j \cdot s_j(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Setup Origin || &amp;lt;math&amp;gt; \textstyle O^0_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Angle || &amp;lt;math&amp;gt; \textstyle \alpha^0_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Length || &amp;lt;math&amp;gt; \textstyle l^0_j &amp;lt;/math&amp;gt; || Real || No|| Constant, zero not allowed.&lt;br /&gt;
|- &lt;br /&gt;
| Setup Scale || &amp;lt;math&amp;gt; \textstyle s^0_j &amp;lt;/math&amp;gt; || Real || No|| &amp;lt;math&amp;gt; \textstyle s^0_j = 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Parent || &amp;lt;math&amp;gt; \textstyle PBone_j(t) &amp;lt;/math&amp;gt; || Bone ||Yes|| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''POINT PARAMETERS'''&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Position ||&amp;lt;math&amp;gt; \textstyle V(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Calculated: &amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt; Global coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Free Position ||&amp;lt;math&amp;gt; \textstyle VF(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Setup Position ||&amp;lt;math&amp;gt; \textstyle VS(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Matrix ||&amp;lt;math&amp;gt; \textstyle M(t) &amp;lt;/math&amp;gt; || Matrix (3x3) ||Yes|| Calculated. See formulas below&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Id ||&amp;lt;math&amp;gt; \textstyle BoneID_i &amp;lt;/math&amp;gt; || Bone || No || 'i' is the index for all the Bones that influences on the Point&lt;br /&gt;
|- &lt;br /&gt;
| Influence weight ||&amp;lt;math&amp;gt; \textstyle w_i &amp;lt;/math&amp;gt; || Real || Yes || the weight associated to the BoneID_i&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(t) denotes ''calculated at the time t''&lt;br /&gt;
&lt;br /&gt;
=== Position of a Point due to Bones Influence ===&lt;br /&gt;
&lt;br /&gt;
According to the table, the final position of a point influenced by the bones is calculated based on two terms: A free movement of the point plus a bone drive movement. In this section we are going to calculate the second term.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M(t) = \cfrac{\sum_{i=1}^N M_i(t) \cdot w_i(t)}{\sum_{i=1}^N w_i(t)} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M_i(t)=B^0_i(t) \cdot B_i(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where i is a index that runs all the Bones Influence ID from i=1 to N (N= total number of bones that influence to the point)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B^0_i(t)= \prod_{j=bone}^{j=root} C_j^0(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B_i(t)= \prod_{j=root}^{j=bone} C_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'j' runs the bone skeleton jumping from a child/parent bone to a parent/child bone each time. The travel of the index 'j' from ''bone'' to ''root'' and from ''root'' to ''bone'' is fixed -and unique- by the nature of skeletons constructions (a bone, a parent), as mentioned before.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j^0(t) = T(-O_j^0(t)) \cdot R(-\alpha_j^0(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the position of the point in local coordinates in relation to the bone 'j' at setup position. Notice that &amp;lt;math&amp;gt; s^0_j &amp;lt;/math&amp;gt; is equal to &amp;lt;math&amp;gt; \textstyle 1 &amp;lt;/math&amp;gt; for any bone and for any time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j(t) = S_x(s_j(t))\cdot R(\alpha_j(t)) \cdot T(O_j(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the global position of the point due to the bone 'j' at animated position of the skeleton.&lt;br /&gt;
&lt;br /&gt;
=== Calculate the position and angle of a bone in a skeleton ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Position and Angle at Setup ====&lt;br /&gt;
&lt;br /&gt;
If the bones are described using relative coordinates to its predecessor, the position &amp;lt;math&amp;gt;\textstyle Q^0_j&amp;lt;/math&amp;gt; and the angle &amp;lt;math&amp;gt;\textstyle \beta^0_j&amp;lt;/math&amp;gt; of the bone 'j' in relation to the &amp;quot;master root bone&amp;quot; (ie. the global coordinate system) is given by those equations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q^0_j(t) = O^0_j(t) \cdot B^0_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta^0_j(t) = \sum_{i=j}^{root} \alpha^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_j(t)=\prod_{i=parent}^{root} B^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the parent of the bone 'j' and climbs up by one parent each time until it reaches the 'root' bone of the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)= T(-O^0_i(t)) \cdot R(-\alpha^0_i(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)&amp;lt;/math&amp;gt; is the inverse matrix transformation of the position of the bone relative to its immediate parent.&lt;br /&gt;
&lt;br /&gt;
Notice that at setup, &amp;lt;math&amp;gt;s^0_j&amp;lt;/math&amp;gt; is always equal to 1.&lt;br /&gt;
&lt;br /&gt;
====Animated Position and Angle ====&lt;br /&gt;
&lt;br /&gt;
Once calculated the position and angle of a bone in global coordinates you can calculate its animated position and angle by the transformation of their parents in the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q_j(t) = O^0_j(t) \cdot B^0_j(t) \cdot B_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_j(t)= \beta^0_j(t) + \sum_{i=root}^{parent} \alpha_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;math&amp;gt;B_j(t)=\prod_{i=root}^{parent} B_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the root bone and jumps down by one child each time until it reaches the 'parent' bone of the bone 'j'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B_i(t)= S_x(s_j(t)) \cdot R(\alpha_i(t)) \cdot T(O_i(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\textstyle B_i(t)&amp;lt;/math&amp;gt; is the transformation matrix of the position of the bone 'j' at the time t. &lt;br /&gt;
&lt;br /&gt;
The results &amp;lt;math&amp;gt;\textstyle Q_j(t), \beta_j(t)&amp;lt;/math&amp;gt; are obtained in global coordinates.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8284</id>
		<title>Dev:Bone Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8284"/>
				<updated>2008-11-30T11:26:52Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Can Points (Bone influenced) be moved independently? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Initial seed for concepts ==&lt;br /&gt;
&lt;br /&gt;
[http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-12.log This portion] of IRC logs sets the basis for the implementation of a Bone Layer. The interesting part is from 16:49 to 18:56.&lt;br /&gt;
&lt;br /&gt;
Also [http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-13.log this one] has some interesting thoughts. From 8:20 to 14:43&lt;br /&gt;
&lt;br /&gt;
== Concepts ==&lt;br /&gt;
This is an unsorted list of concepts to let me clarify my thoughts and also allow others to understand the following sections.&lt;br /&gt;
&lt;br /&gt;
=== Bones intentions ===&lt;br /&gt;
Initial intention of Bones is to attempt to emulate the skeleton of a vertebrate animal. In this way you have the skin and a skeleton. Part of the skin are associated with the various bones of the skeleton. When the skeleton moves the skin follows.&lt;br /&gt;
&lt;br /&gt;
=== Application of bones in animation ===&lt;br /&gt;
In traditional animation producing a walk cycle implies drawing each keyframe for the walk and maybe, depending on the walking speed, drawing the in betweens too. To avoid having to draw the in between images there are tweening animation programs (like Synfig) to help the animator. Then the animator just needs to draw the keyframes and the application does the rest. That's quite good but in certain situations you see your self redrawing the same pose (with small variations) frequently at different times. Then bones come to help. They aid the animator in the following manner.&lt;br /&gt;
&lt;br /&gt;
* With the manipulation of a single object (or a set of them) you can manage a lot of points of the drawing definition.&lt;br /&gt;
* Rotations of drawings using keyframes needs lots of them (by nature of the fact that tweening is defined in the x,y coordinates system and the rotation is performed in the angle, radius coordinate system). Using bones you can perform rotations of large angles with just two waypoints. Also since characters have limbs and limbs in living beings do mainly rotations, the usage of bones becomes handy in that kind of animation.&lt;br /&gt;
* Once the character (or whatever thing that uses bones) is rigged (the skeleton structure is created and the relationship between it and the skin is defined) it is possible to produce different kinds of keyframes for different purposes: Walk, run, jump, sit, ...&lt;br /&gt;
&lt;br /&gt;
== How can we do implement this? ==&lt;br /&gt;
The relationship between the skeleton and the skin is like this:&lt;br /&gt;
&lt;br /&gt;
*The Skin is made using Points and BLines. BLines are defined by Points. Points are made of Vertexes and Tangents&lt;br /&gt;
*Skeleton is made of bones and the relationships between them.&lt;br /&gt;
*''If Bones would have influence on the Vertexes and Tangents then the bones movements would move the points and therefore the skin would be moved''.&lt;br /&gt;
&lt;br /&gt;
That's the key, if we understand how a bone has influence on a vertex and a tangent then we can find the way a skeleton can have influence over a skin.&lt;br /&gt;
&lt;br /&gt;
=== Bones Properties ===&lt;br /&gt;
From my experience with bones in other 2D animation applications, watching the strong and weak points, bones needs to have the following properties:&lt;br /&gt;
&lt;br /&gt;
* A bone has an origin point about which the rotation is performed.&lt;br /&gt;
* A bone has a length.&lt;br /&gt;
* A bone has an angle.&lt;br /&gt;
* A bone can have a region of influence.&lt;br /&gt;
* A bone can have a one or zero parent bones.&lt;br /&gt;
* A bone can have one or more child bones.&lt;br /&gt;
* A skeleton is defined as a connected set of bones (consisting of exactly one parent-less bone and its children bones and their descendants).&lt;br /&gt;
&lt;br /&gt;
All the bones in a Synfig Document can produce several distinct skeletons (depending on how many parent-less bones are in it).&lt;br /&gt;
&lt;br /&gt;
=== How does a Vertex move under the influence of a single Bone? ===&lt;br /&gt;
&lt;br /&gt;
Conceptually a bone has influence over a point by doing [http://en.wikipedia.org/wiki/Affine_transformation affine transformations] of its position according to the bone values. See also [http://en.wikipedia.org/wiki/Transformation_matrix transformation matrix]. A bone produces rotation, scale and translation to a point in this way:&lt;br /&gt;
&lt;br /&gt;
[[Image:Bonesimulation2.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see the values that produce the movement of the point P to the point P' are given by:&lt;br /&gt;
&lt;br /&gt;
*Translation of the bone: O'-O&lt;br /&gt;
*Rotation of the bone: &amp;lt;math&amp;gt;\alpha'-\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
*Scale of the bone: s=length'/length&lt;br /&gt;
&lt;br /&gt;
Then, given a Point P in the 2D space and knowing the translation, rotation and scale of the bone you can calculate the new position P' using this formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(-O)=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
-O_x &amp;amp; -O_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to origin (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(-\alpha)=\begin{bmatrix}&lt;br /&gt;
\cos(-\alpha) &amp;amp; \sin(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
-\sin(-\alpha) &amp;amp; \cos(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;-\alpha&amp;lt;/math&amp;gt;' about the origin. That aligns the bone with the X axis&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S_x(length'/length)=\begin{bmatrix}&lt;br /&gt;
length'/length &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Scale by a value of 's=length'/length' in the direction of X (the current direction of the bone).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(\alpha^')=\begin{bmatrix}&lt;br /&gt;
\cos(\alpha^') &amp;amp; \sin(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
-\sin(\alpha^') &amp;amp; \cos(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;\alpha'&amp;lt;/math&amp;gt;' about the origin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(O^')=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
O^'_x &amp;amp; O^'_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to new position O'&lt;br /&gt;
&lt;br /&gt;
Then the transformation from P to P' is given by the matrix multiplication:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T(-O)\cdot R(-\alpha)\cdot S_x(length'/length)\cdot R(\alpha^')\cdot T(O^')&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T\cdot R\cdot S_x\cdot R'\cdot T'=P\cdot B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Can Points (Bone influenced) be moved independently? ===&lt;br /&gt;
&lt;br /&gt;
Yes, they should be. If not the animator is restricted to only doing the animation with bones which would lead to some insoluble problems during the animation. Considering this, the point position result comes from the addition of two terms:&lt;br /&gt;
*(a) The movement of the point as described by the influence of the bone(s): P(B)&lt;br /&gt;
*(b) The free movement of the point in the 2D space. P(animated)&lt;br /&gt;
&lt;br /&gt;
In terms of the interface with the user, the value P(animated) is just obtained in this way:&lt;br /&gt;
&lt;br /&gt;
#In any position of the time line (bones are animated) the point has a position given by the influence of the bones: P(B).&lt;br /&gt;
#The user wrap a point, drags it, placing it at P'.&lt;br /&gt;
#The final position of the point is P' but the user cannot modify the first term P(B) so the second term (b) becomes: P(animated)=P'-P(B).&lt;br /&gt;
&lt;br /&gt;
===What happen if there are more than one bone affecting the point?===&lt;br /&gt;
&lt;br /&gt;
The first thing you can think when you deal with more than one bone making influence over the same point is to calculate the average of the sum of the influences of all bones. So if there are N bones affecting to the point then we can think on sum all the resulting points from each bone and then divide the result by N to not scale the result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k}{N} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;B_k&amp;lt;/math&amp;gt; is the bone matrix for the bone ''k'' on the point P.&lt;br /&gt;
&lt;br /&gt;
That's fine but I would like to have more control to the way the bones affects to the points. When you move a bone it looks reasonable that not all the points are influence in the same way. This can be solved by using &amp;quot;weighted&amp;quot; average instead of a plain one. That means give different amount of influence to one bone than to other.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k \cdot w_k}{\sum_{k=1}^N w_k} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;w_k&amp;lt;/math&amp;gt; is the weight for the bone ''k'' over the point P.&lt;br /&gt;
&lt;br /&gt;
=== Skeleton ===&lt;br /&gt;
&lt;br /&gt;
A skeleton is a set of bones linked one to others in a tree hierarchy. A bone can have several children (or none) but only one parent (or none). This configuration allows to do a easy calculation of the forward kinematic (FK )of the chain and the inverse kinematic (IK) of the chain of bones. If the hierarchy were not tree type then the FK and IK can be not soluble. &lt;br /&gt;
&lt;br /&gt;
For those IK and FK calculations it is good to have the bone referenced to its parent. So the parameters of the bone are described as relative to the parent bone. The parent bone defines a local coordinate system where the origin of the coordinate system lies on the Origin of the bone and the tip of the bone is pointing to the positive direction of the X axis.&lt;br /&gt;
&lt;br /&gt;
[[Image: skeleton.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see in this image, each skeleton position and orientation is defined by the relative position of its immediate parent bone. In the diagram bone3 is a child of bone2 and bone 2 is a child of bone1. The bone 1 is the root parent bone but you can imagine it attached to a &amp;quot;master root bone&amp;quot; (defined by the origin of coordinates -red circumference- and the horizontal) so it can be said that the bone1 has its origin and angle defined relative to its &amp;quot;parent&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In this skeleton the three bones are parented in a linear way. But as you can imagine, following the rules stated for child-parent, a bone can have more than one child but not more than one parent. &lt;br /&gt;
That means that defined a bone in the skeleton, there is only one sequence of parents to reach the root parent of the skeleton. Also it means too that one root bone defines one skeleton so each skeleton has only one root bone and only one.&lt;br /&gt;
&lt;br /&gt;
Consider this: B3 is child of B2 and B2 is child of B1. Also B4 is child of B2 and B5 is child of B4. The way to travel from B5 to B1 is unique: B5-&amp;gt;B4-&amp;gt;B2-&amp;gt;B1.&lt;br /&gt;
&lt;br /&gt;
=== Setup and Animation ===&lt;br /&gt;
&lt;br /&gt;
During the animation of the skeleton it is supposed that the position of each bone, its angle and its scale changes. Position and angle are relative to the parent bone, but scale is a value that calculates the current length of the bone compared with the &amp;quot;original&amp;quot; bone length (scale=length'/length) as you can see from the original formulas in the previous section. That means that the &amp;quot;original&amp;quot; bone length shouldn't be never zero, otherwise there will be a division by zero and the scale of the bone becomes infinite.&lt;br /&gt;
&lt;br /&gt;
Also, the final position P' of a point that moves influenced by a single bone is given by the original point position relative to the bone in its &amp;quot;original&amp;quot; position (P). &lt;br /&gt;
&lt;br /&gt;
What I'm trying to explain is that it is needed that the setup of the bone (position, alpha and length) and the setup position of the point (P) to be moved would be given to calculate the final position of the point (P') given a moved position of the bone (position', alpha', length')&lt;br /&gt;
&lt;br /&gt;
Said this and considered the information of the previous sections, the bones and points that are influenced from the bones should have the following parameters:&lt;br /&gt;
&lt;br /&gt;
'''BONES PARAMETERS'''&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Origin ||&amp;lt;math&amp;gt; \textstyle O_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Angle || &amp;lt;math&amp;gt; \textstyle \alpha_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Length || &amp;lt;math&amp;gt; \textstyle l_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| Calculated, not animatable.&lt;br /&gt;
|- &lt;br /&gt;
| Scale || &amp;lt;math&amp;gt; \textstyle s_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| &amp;lt;math&amp;gt; \textstyle l_j(t) =l^0_j \cdot s_j(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Setup Origin || &amp;lt;math&amp;gt; \textstyle O^0_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Angle || &amp;lt;math&amp;gt; \textstyle \alpha^0_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Length || &amp;lt;math&amp;gt; \textstyle l^0_j &amp;lt;/math&amp;gt; || Real || No|| Constant, zero not allowed.&lt;br /&gt;
|- &lt;br /&gt;
| Setup Scale || &amp;lt;math&amp;gt; \textstyle s^0_j &amp;lt;/math&amp;gt; || Real || No|| &amp;lt;math&amp;gt; \textstyle s^0_j = 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Parent || &amp;lt;math&amp;gt; \textstyle PBone_j(t) &amp;lt;/math&amp;gt; || Bone ||Yes|| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''POINT PARAMETERS'''&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Position ||&amp;lt;math&amp;gt; \textstyle V(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Calculated: &amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt; Global coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Free Position ||&amp;lt;math&amp;gt; \textstyle VF(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Setup Position ||&amp;lt;math&amp;gt; \textstyle VS(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Matrix ||&amp;lt;math&amp;gt; \textstyle M(t) &amp;lt;/math&amp;gt; || Matrix (3x3) ||Yes|| Calculated. See formulas below&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Id ||&amp;lt;math&amp;gt; \textstyle BoneID_i &amp;lt;/math&amp;gt; || Bone || No || 'i' is the index for all the Bones that influences on the Point&lt;br /&gt;
|- &lt;br /&gt;
| Influence weight ||&amp;lt;math&amp;gt; \textstyle w_i &amp;lt;/math&amp;gt; || Real || Yes || the weight associated to the BoneID_i&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(t) denotes ''calculated at the time t''&lt;br /&gt;
&lt;br /&gt;
=== Position of a Point due to Bones Influence ===&lt;br /&gt;
&lt;br /&gt;
According to the table, the final position of a point influenced by the bones is calculated based on two terms: A free movement of the point plus a bone drive movement. In this section we are going to calculate the second term.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M(t) = \cfrac{\sum_{i=1}^N M_i(t) \cdot w_i(t)}{\sum_{i=1}^N w_i(t)} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M_i(t)=B^0_i(t) \cdot B_i(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where i is a index that runs all the Bones Influence ID from i=1 to N (N= total number of bones that influence to the point)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B^0_i(t)= \prod_{j=bone}^{j=root} C_j^0(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B_i(t)= \prod_{j=root}^{j=bone} C_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'j' runs the bone skeleton jumping from a child/parent bone to a parent/child bone each time. The travel of the index 'j' from ''bone'' to ''root'' and from ''root'' to ''bone'' is fixed -and unique- by the nature of skeletons constructions (a bone, a parent), as mentioned before.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j^0(t) = T(-O_j^0(t)) \cdot R(-\alpha_j^0(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the position of the point in local coordinates in relation to the bone 'j' at setup position. Notice that &amp;lt;math&amp;gt; s^0_j &amp;lt;/math&amp;gt; is equal to &amp;lt;math&amp;gt; \textstyle 1 &amp;lt;/math&amp;gt; for any bone and for any time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j(t) = S_x(s_j(t))\cdot R(\alpha_j(t)) \cdot T(O_j(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the global position of the point due to the bone 'j' at animated position of the skeleton.&lt;br /&gt;
&lt;br /&gt;
=== Calculate the position and angle of a bone in a skeleton ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Position and Angle at Setup ====&lt;br /&gt;
&lt;br /&gt;
If the bones are described using relative coordinates to its predecessor, the position &amp;lt;math&amp;gt;\textstyle Q^0_j&amp;lt;/math&amp;gt; and the angle &amp;lt;math&amp;gt;\textstyle \beta^0_j&amp;lt;/math&amp;gt; of the bone 'j' in relation to the &amp;quot;master root bone&amp;quot; (ie. the global coordinate system) is given by those equations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q^0_j(t) = O^0_j(t) \cdot B^0_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta^0_j(t) = \sum_{i=j}^{root} \alpha^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_j(t)=\prod_{i=parent}^{root} B^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the parent of the bone 'j' and climbs up by one parent each time until it reaches the 'root' bone of the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)= T(-O^0_i(t)) \cdot R(-\alpha^0_i(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)&amp;lt;/math&amp;gt; is the inverse matrix transformation of the position of the bone relative to its immediate parent.&lt;br /&gt;
&lt;br /&gt;
Notice that at setup, &amp;lt;math&amp;gt;s^0_j&amp;lt;/math&amp;gt; is always equal to 1.&lt;br /&gt;
&lt;br /&gt;
====Animated Position and Angle ====&lt;br /&gt;
&lt;br /&gt;
Once calculated the position and angle of a bone in global coordinates you can calculate its animated position and angle by the transformation of their parents in the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q_j(t) = O^0_j(t) \cdot B^0_j(t) \cdot B_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_j(t)= \beta^0_j(t) + \sum_{i=root}^{parent} \alpha_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;math&amp;gt;B_j(t)=\prod_{i=root}^{parent} B_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the root bone and jumps down by one child each time until it reaches the 'parent' bone of the bone 'j'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B_i(t)= S_x(s_j(t)) \cdot R(\alpha_i(t)) \cdot T(O_i(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\textstyle B_i(t)&amp;lt;/math&amp;gt; is the transformation matrix of the position of the bone 'j' at the time t. &lt;br /&gt;
&lt;br /&gt;
The results &amp;lt;math&amp;gt;\textstyle Q_j(t), \beta_j(t)&amp;lt;/math&amp;gt; are obtained in global coordinates.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8283</id>
		<title>Dev:Bone Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8283"/>
				<updated>2008-11-30T11:19:33Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* How does a Vertex move under the influence of a single Bone? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Initial seed for concepts ==&lt;br /&gt;
&lt;br /&gt;
[http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-12.log This portion] of IRC logs sets the basis for the implementation of a Bone Layer. The interesting part is from 16:49 to 18:56.&lt;br /&gt;
&lt;br /&gt;
Also [http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-13.log this one] has some interesting thoughts. From 8:20 to 14:43&lt;br /&gt;
&lt;br /&gt;
== Concepts ==&lt;br /&gt;
This is an unsorted list of concepts to let me clarify my thoughts and also allow others to understand the following sections.&lt;br /&gt;
&lt;br /&gt;
=== Bones intentions ===&lt;br /&gt;
Initial intention of Bones is to attempt to emulate the skeleton of a vertebrate animal. In this way you have the skin and a skeleton. Part of the skin are associated with the various bones of the skeleton. When the skeleton moves the skin follows.&lt;br /&gt;
&lt;br /&gt;
=== Application of bones in animation ===&lt;br /&gt;
In traditional animation producing a walk cycle implies drawing each keyframe for the walk and maybe, depending on the walking speed, drawing the in betweens too. To avoid having to draw the in between images there are tweening animation programs (like Synfig) to help the animator. Then the animator just needs to draw the keyframes and the application does the rest. That's quite good but in certain situations you see your self redrawing the same pose (with small variations) frequently at different times. Then bones come to help. They aid the animator in the following manner.&lt;br /&gt;
&lt;br /&gt;
* With the manipulation of a single object (or a set of them) you can manage a lot of points of the drawing definition.&lt;br /&gt;
* Rotations of drawings using keyframes needs lots of them (by nature of the fact that tweening is defined in the x,y coordinates system and the rotation is performed in the angle, radius coordinate system). Using bones you can perform rotations of large angles with just two waypoints. Also since characters have limbs and limbs in living beings do mainly rotations, the usage of bones becomes handy in that kind of animation.&lt;br /&gt;
* Once the character (or whatever thing that uses bones) is rigged (the skeleton structure is created and the relationship between it and the skin is defined) it is possible to produce different kinds of keyframes for different purposes: Walk, run, jump, sit, ...&lt;br /&gt;
&lt;br /&gt;
== How can we do implement this? ==&lt;br /&gt;
The relationship between the skeleton and the skin is like this:&lt;br /&gt;
&lt;br /&gt;
*The Skin is made using Points and BLines. BLines are defined by Points. Points are made of Vertexes and Tangents&lt;br /&gt;
*Skeleton is made of bones and the relationships between them.&lt;br /&gt;
*''If Bones would have influence on the Vertexes and Tangents then the bones movements would move the points and therefore the skin would be moved''.&lt;br /&gt;
&lt;br /&gt;
That's the key, if we understand how a bone has influence on a vertex and a tangent then we can find the way a skeleton can have influence over a skin.&lt;br /&gt;
&lt;br /&gt;
=== Bones Properties ===&lt;br /&gt;
From my experience with bones in other 2D animation applications, watching the strong and weak points, bones needs to have the following properties:&lt;br /&gt;
&lt;br /&gt;
* A bone has an origin point about which the rotation is performed.&lt;br /&gt;
* A bone has a length.&lt;br /&gt;
* A bone has an angle.&lt;br /&gt;
* A bone can have a region of influence.&lt;br /&gt;
* A bone can have a one or zero parent bones.&lt;br /&gt;
* A bone can have one or more child bones.&lt;br /&gt;
* A skeleton is defined as a connected set of bones (consisting of exactly one parent-less bone and its children bones and their descendants).&lt;br /&gt;
&lt;br /&gt;
All the bones in a Synfig Document can produce several distinct skeletons (depending on how many parent-less bones are in it).&lt;br /&gt;
&lt;br /&gt;
=== How does a Vertex move under the influence of a single Bone? ===&lt;br /&gt;
&lt;br /&gt;
Conceptually a bone has influence over a point by doing [http://en.wikipedia.org/wiki/Affine_transformation affine transformations] of its position according to the bone values. See also [http://en.wikipedia.org/wiki/Transformation_matrix transformation matrix]. A bone produces rotation, scale and translation to a point in this way:&lt;br /&gt;
&lt;br /&gt;
[[Image:Bonesimulation2.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see the values that produce the movement of the point P to the point P' are given by:&lt;br /&gt;
&lt;br /&gt;
*Translation of the bone: O'-O&lt;br /&gt;
*Rotation of the bone: &amp;lt;math&amp;gt;\alpha'-\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
*Scale of the bone: s=length'/length&lt;br /&gt;
&lt;br /&gt;
Then, given a Point P in the 2D space and knowing the translation, rotation and scale of the bone you can calculate the new position P' using this formula:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(-O)=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
-O_x &amp;amp; -O_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to origin (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(-\alpha)=\begin{bmatrix}&lt;br /&gt;
\cos(-\alpha) &amp;amp; \sin(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
-\sin(-\alpha) &amp;amp; \cos(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;-\alpha&amp;lt;/math&amp;gt;' about the origin. That aligns the bone with the X axis&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S_x(length'/length)=\begin{bmatrix}&lt;br /&gt;
length'/length &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Scale by a value of 's=length'/length' in the direction of X (the current direction of the bone).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(\alpha^')=\begin{bmatrix}&lt;br /&gt;
\cos(\alpha^') &amp;amp; \sin(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
-\sin(\alpha^') &amp;amp; \cos(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate by an angle of amount '&amp;lt;math&amp;gt;\alpha'&amp;lt;/math&amp;gt;' about the origin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(O^')=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
O^'_x &amp;amp; O^'_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to new position O'&lt;br /&gt;
&lt;br /&gt;
Then the transformation from P to P' is given by the matrix multiplication:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T(-O)\cdot R(-\alpha)\cdot S_x(length'/length)\cdot R(\alpha^')\cdot T(O^')&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T\cdot R\cdot S_x\cdot R'\cdot T'=P\cdot B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Can Points (Bone influenced) be moved independently? ===&lt;br /&gt;
&lt;br /&gt;
Yes, they should be. If not the animator is tight to only do the animation with the bones animation what would end to some insoluble problems during the animation. Considered this, the point position result comes from the addition of two terms:&lt;br /&gt;
*(a) The movement of the point as described by the influence of the bone(s): P(B)&lt;br /&gt;
*(b) The free movement of the point in the 2D space. P(animated)&lt;br /&gt;
&lt;br /&gt;
In terms of the interface with the user, the value P(animated)is just obtained in this way:&lt;br /&gt;
&lt;br /&gt;
#In any position of the time line (bones are animated) the point have a position given by the influence of the bones: P(B).&lt;br /&gt;
#The user wrap a point, drags it, placing it at P'.&lt;br /&gt;
#The final position of the point is P' but the user cannot modify the first term P(B) so the second term (b) becomes: P(animated)=P'-P(B).&lt;br /&gt;
&lt;br /&gt;
===What happen if there are more than one bone affecting the point?===&lt;br /&gt;
&lt;br /&gt;
The first thing you can think when you deal with more than one bone making influence over the same point is to calculate the average of the sum of the influences of all bones. So if there are N bones affecting to the point then we can think on sum all the resulting points from each bone and then divide the result by N to not scale the result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k}{N} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;B_k&amp;lt;/math&amp;gt; is the bone matrix for the bone ''k'' on the point P.&lt;br /&gt;
&lt;br /&gt;
That's fine but I would like to have more control to the way the bones affects to the points. When you move a bone it looks reasonable that not all the points are influence in the same way. This can be solved by using &amp;quot;weighted&amp;quot; average instead of a plain one. That means give different amount of influence to one bone than to other.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k \cdot w_k}{\sum_{k=1}^N w_k} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;w_k&amp;lt;/math&amp;gt; is the weight for the bone ''k'' over the point P.&lt;br /&gt;
&lt;br /&gt;
=== Skeleton ===&lt;br /&gt;
&lt;br /&gt;
A skeleton is a set of bones linked one to others in a tree hierarchy. A bone can have several children (or none) but only one parent (or none). This configuration allows to do a easy calculation of the forward kinematic (FK )of the chain and the inverse kinematic (IK) of the chain of bones. If the hierarchy were not tree type then the FK and IK can be not soluble. &lt;br /&gt;
&lt;br /&gt;
For those IK and FK calculations it is good to have the bone referenced to its parent. So the parameters of the bone are described as relative to the parent bone. The parent bone defines a local coordinate system where the origin of the coordinate system lies on the Origin of the bone and the tip of the bone is pointing to the positive direction of the X axis.&lt;br /&gt;
&lt;br /&gt;
[[Image: skeleton.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see in this image, each skeleton position and orientation is defined by the relative position of its immediate parent bone. In the diagram bone3 is a child of bone2 and bone 2 is a child of bone1. The bone 1 is the root parent bone but you can imagine it attached to a &amp;quot;master root bone&amp;quot; (defined by the origin of coordinates -red circumference- and the horizontal) so it can be said that the bone1 has its origin and angle defined relative to its &amp;quot;parent&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In this skeleton the three bones are parented in a linear way. But as you can imagine, following the rules stated for child-parent, a bone can have more than one child but not more than one parent. &lt;br /&gt;
That means that defined a bone in the skeleton, there is only one sequence of parents to reach the root parent of the skeleton. Also it means too that one root bone defines one skeleton so each skeleton has only one root bone and only one.&lt;br /&gt;
&lt;br /&gt;
Consider this: B3 is child of B2 and B2 is child of B1. Also B4 is child of B2 and B5 is child of B4. The way to travel from B5 to B1 is unique: B5-&amp;gt;B4-&amp;gt;B2-&amp;gt;B1.&lt;br /&gt;
&lt;br /&gt;
=== Setup and Animation ===&lt;br /&gt;
&lt;br /&gt;
During the animation of the skeleton it is supposed that the position of each bone, its angle and its scale changes. Position and angle are relative to the parent bone, but scale is a value that calculates the current length of the bone compared with the &amp;quot;original&amp;quot; bone length (scale=length'/length) as you can see from the original formulas in the previous section. That means that the &amp;quot;original&amp;quot; bone length shouldn't be never zero, otherwise there will be a division by zero and the scale of the bone becomes infinite.&lt;br /&gt;
&lt;br /&gt;
Also, the final position P' of a point that moves influenced by a single bone is given by the original point position relative to the bone in its &amp;quot;original&amp;quot; position (P). &lt;br /&gt;
&lt;br /&gt;
What I'm trying to explain is that it is needed that the setup of the bone (position, alpha and length) and the setup position of the point (P) to be moved would be given to calculate the final position of the point (P') given a moved position of the bone (position', alpha', length')&lt;br /&gt;
&lt;br /&gt;
Said this and considered the information of the previous sections, the bones and points that are influenced from the bones should have the following parameters:&lt;br /&gt;
&lt;br /&gt;
'''BONES PARAMETERS'''&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Origin ||&amp;lt;math&amp;gt; \textstyle O_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Angle || &amp;lt;math&amp;gt; \textstyle \alpha_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Length || &amp;lt;math&amp;gt; \textstyle l_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| Calculated, not animatable.&lt;br /&gt;
|- &lt;br /&gt;
| Scale || &amp;lt;math&amp;gt; \textstyle s_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| &amp;lt;math&amp;gt; \textstyle l_j(t) =l^0_j \cdot s_j(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Setup Origin || &amp;lt;math&amp;gt; \textstyle O^0_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Angle || &amp;lt;math&amp;gt; \textstyle \alpha^0_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Length || &amp;lt;math&amp;gt; \textstyle l^0_j &amp;lt;/math&amp;gt; || Real || No|| Constant, zero not allowed.&lt;br /&gt;
|- &lt;br /&gt;
| Setup Scale || &amp;lt;math&amp;gt; \textstyle s^0_j &amp;lt;/math&amp;gt; || Real || No|| &amp;lt;math&amp;gt; \textstyle s^0_j = 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Parent || &amp;lt;math&amp;gt; \textstyle PBone_j(t) &amp;lt;/math&amp;gt; || Bone ||Yes|| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''POINT PARAMETERS'''&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Position ||&amp;lt;math&amp;gt; \textstyle V(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Calculated: &amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt; Global coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Free Position ||&amp;lt;math&amp;gt; \textstyle VF(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Setup Position ||&amp;lt;math&amp;gt; \textstyle VS(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Global Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Matrix ||&amp;lt;math&amp;gt; \textstyle M(t) &amp;lt;/math&amp;gt; || Matrix (3x3) ||Yes|| Calculated. See formulas below&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Id ||&amp;lt;math&amp;gt; \textstyle BoneID_i &amp;lt;/math&amp;gt; || Bone || No || 'i' is the index for all the Bones that influences on the Point&lt;br /&gt;
|- &lt;br /&gt;
| Influence weight ||&amp;lt;math&amp;gt; \textstyle w_i &amp;lt;/math&amp;gt; || Real || Yes || the weight associated to the BoneID_i&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(t) denotes ''calculated at the time t''&lt;br /&gt;
&lt;br /&gt;
=== Position of a Point due to Bones Influence ===&lt;br /&gt;
&lt;br /&gt;
According to the table, the final position of a point influenced by the bones is calculated based on two terms: A free movement of the point plus a bone drive movement. In this section we are going to calculate the second term.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M(t) = \cfrac{\sum_{i=1}^N M_i(t) \cdot w_i(t)}{\sum_{i=1}^N w_i(t)} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M_i(t)=B^0_i(t) \cdot B_i(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where i is a index that runs all the Bones Influence ID from i=1 to N (N= total number of bones that influence to the point)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B^0_i(t)= \prod_{j=bone}^{j=root} C_j^0(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B_i(t)= \prod_{j=root}^{j=bone} C_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'j' runs the bone skeleton jumping from a child/parent bone to a parent/child bone each time. The travel of the index 'j' from ''bone'' to ''root'' and from ''root'' to ''bone'' is fixed -and unique- by the nature of skeletons constructions (a bone, a parent), as mentioned before.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j^0(t) = T(-O_j^0(t)) \cdot R(-\alpha_j^0(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the position of the point in local coordinates in relation to the bone 'j' at setup position. Notice that &amp;lt;math&amp;gt; s^0_j &amp;lt;/math&amp;gt; is equal to &amp;lt;math&amp;gt; \textstyle 1 &amp;lt;/math&amp;gt; for any bone and for any time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j(t) = S_x(s_j(t))\cdot R(\alpha_j(t)) \cdot T(O_j(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the global position of the point due to the bone 'j' at animated position of the skeleton.&lt;br /&gt;
&lt;br /&gt;
=== Calculate the position and angle of a bone in a skeleton ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Position and Angle at Setup ====&lt;br /&gt;
&lt;br /&gt;
If the bones are described using relative coordinates to its predecessor, the position &amp;lt;math&amp;gt;\textstyle Q^0_j&amp;lt;/math&amp;gt; and the angle &amp;lt;math&amp;gt;\textstyle \beta^0_j&amp;lt;/math&amp;gt; of the bone 'j' in relation to the &amp;quot;master root bone&amp;quot; (ie. the global coordinate system) is given by those equations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q^0_j(t) = O^0_j(t) \cdot B^0_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta^0_j(t) = \sum_{i=j}^{root} \alpha^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_j(t)=\prod_{i=parent}^{root} B^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the parent of the bone 'j' and climbs up by one parent each time until it reaches the 'root' bone of the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)= T(-O^0_i(t)) \cdot R(-\alpha^0_i(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)&amp;lt;/math&amp;gt; is the inverse matrix transformation of the position of the bone relative to its immediate parent.&lt;br /&gt;
&lt;br /&gt;
Notice that at setup, &amp;lt;math&amp;gt;s^0_j&amp;lt;/math&amp;gt; is always equal to 1.&lt;br /&gt;
&lt;br /&gt;
====Animated Position and Angle ====&lt;br /&gt;
&lt;br /&gt;
Once calculated the position and angle of a bone in global coordinates you can calculate its animated position and angle by the transformation of their parents in the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q_j(t) = O^0_j(t) \cdot B^0_j(t) \cdot B_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_j(t)= \beta^0_j(t) + \sum_{i=root}^{parent} \alpha_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;math&amp;gt;B_j(t)=\prod_{i=root}^{parent} B_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the root bone and jumps down by one child each time until it reaches the 'parent' bone of the bone 'j'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B_i(t)= S_x(s_j(t)) \cdot R(\alpha_i(t)) \cdot T(O_i(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\textstyle B_i(t)&amp;lt;/math&amp;gt; is the transformation matrix of the position of the bone 'j' at the time t. &lt;br /&gt;
&lt;br /&gt;
The results &amp;lt;math&amp;gt;\textstyle Q_j(t), \beta_j(t)&amp;lt;/math&amp;gt; are obtained in global coordinates.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8279</id>
		<title>Dev:Bone Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Bone_Layer&amp;diff=8279"/>
				<updated>2008-11-29T20:54:52Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: part-way through editing for english&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Initial seed for concepts ==&lt;br /&gt;
&lt;br /&gt;
[http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-12.log This portion] of IRC logs sets the basis for the implementation of a Bone Layer. The interesting part is from 16:49 to 18:56.&lt;br /&gt;
&lt;br /&gt;
Also [http://dooglus.rincevent.net/synfig/logs/2008/%23synfig-2008-11-13.log this one] has some interesting thoughts. From 8:20 to 14:43&lt;br /&gt;
&lt;br /&gt;
== Concepts ==&lt;br /&gt;
This is an unsorted list of concepts to let me clarify my thoughts and also allow others to understand the following sections.&lt;br /&gt;
&lt;br /&gt;
=== Bones intentions ===&lt;br /&gt;
Initial intention of Bones is to attempt to emulate the skeleton of a vertebrate animal. In this way you have the skin and a skeleton. Part of the skin are associated with the various bones of the skeleton. When the skeleton moves the skin follows.&lt;br /&gt;
&lt;br /&gt;
=== Application of bones in animation ===&lt;br /&gt;
In traditional animation producing a walk cycle implies drawing each keyframe for the walk and maybe, depending on the walking speed, drawing the in betweens too. To avoid having to draw the in between images there are tweening animation programs (like Synfig) to help the animator. Then the animator just needs to draw the keyframes and the application does the rest. That's quite good but in certain situations you see your self redrawing the same pose (with small variations) frequently at different times. Then bones come to help. They aid the animator in the following manner.&lt;br /&gt;
&lt;br /&gt;
* With the manipulation of a single object (or a set of them) you can manage a lot of points of the drawing definition.&lt;br /&gt;
* Rotations of drawings using keyframes needs lots of them (by nature of the fact that tweening is defined in the x,y coordinates system and the rotation is performed in the angle, radius coordinate system). Using bones you can perform rotations of large angles with just two waypoints. Also since characters have limbs and limbs in living beings do mainly rotations, the usage of bones becomes handy in that kind of animation.&lt;br /&gt;
* Once the character (or whatever thing that uses bones) is rigged (the skeleton structure is created and the relationship between it and the skin is defined) it is possible to produce different kinds of keyframes for different purposes: Walk, run, jump, sit, ...&lt;br /&gt;
&lt;br /&gt;
== How can we do implement this? ==&lt;br /&gt;
The relationship between the skeleton and the skin is like this:&lt;br /&gt;
&lt;br /&gt;
*The Skin is made using Points and BLines. BLines are defined by Points. Points are made of Vertexes and Tangents&lt;br /&gt;
*Skeleton is made of bones and the relationships between them.&lt;br /&gt;
*''If Bones would have influence on the Vertexes and Tangents then the bones movements would move the points and therefore the skin would be moved''.&lt;br /&gt;
&lt;br /&gt;
That's the key, if we understand how a bone has influence on a vertex and a tangent then we can find the way a skeleton can have influence over a skin.&lt;br /&gt;
&lt;br /&gt;
=== Bones Properties ===&lt;br /&gt;
From my experience with bones in other 2D animation applications, watching the strong and weak points, bones needs to have the following properties:&lt;br /&gt;
&lt;br /&gt;
* A bone has an origin point about which the rotation is performed.&lt;br /&gt;
* A bone has a length.&lt;br /&gt;
* A bone has an angle with the horizontal.&lt;br /&gt;
* A bone can have a region of influence.&lt;br /&gt;
* A bone can have a one or zero parent bones.&lt;br /&gt;
* A bone can have one or more child bones.&lt;br /&gt;
* A skeleton is defined as a connected set of bones (consisting of exactly one parent-less bone and its children bones and their descendants).&lt;br /&gt;
&lt;br /&gt;
All the bones in a Synfig Document can produce several distinct skeletons (depending on how many parent-less bones are in it).&lt;br /&gt;
&lt;br /&gt;
=== How does a Vertex move under the influence of a single Bone? ===&lt;br /&gt;
&lt;br /&gt;
Conceptually a bone has influence over a point doing [http://en.wikipedia.org/wiki/Affine_transformation affine transformation] of it position according to the bone values. See also [http://en.wikipedia.org/wiki/Transformation_matrix transformation matrix]. A bone produces rotation, scale and translation to a point in this way:&lt;br /&gt;
&lt;br /&gt;
[[Image:Bonesimulation2.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see the values that produces the movement of the point P to the point P' are given by:&lt;br /&gt;
&lt;br /&gt;
*Translation of the bone: O'-O&lt;br /&gt;
*Rotation of the bone: &amp;lt;math&amp;gt;\alpha'-\alpha&amp;lt;/math&amp;gt;&lt;br /&gt;
*Scale of the bone: s=length'/length&lt;br /&gt;
&lt;br /&gt;
Then, given a Point P in the 2D space and known the translation, rotation and scale of the bone you can calculate the new point position P' using this formulation:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(-O)=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
-O_x &amp;amp; -O_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to origin (0,0)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(-\alpha)=\begin{bmatrix}&lt;br /&gt;
\cos(-\alpha) &amp;amp; \sin(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
-\sin(-\alpha) &amp;amp; \cos(-\alpha) &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate an angle of amount '&amp;lt;math&amp;gt;-\alpha&amp;lt;/math&amp;gt;' around the origin. That aligns the bone with the X axis&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
S_x(length'/length)=\begin{bmatrix}&lt;br /&gt;
length'/length &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Scale a value of 's=length'/length' in the direction of X (the current direction of the bone).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
R(\alpha^')=\begin{bmatrix}&lt;br /&gt;
\cos(\alpha^') &amp;amp; \sin(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
-\sin(\alpha^') &amp;amp; \cos(\alpha^') &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 0 &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Rotate an angle of amount '&amp;lt;math&amp;gt;\alpha'&amp;lt;/math&amp;gt;' around the origin.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;&lt;br /&gt;
T(O^')=\begin{bmatrix}&lt;br /&gt;
1 &amp;amp; 0 &amp;amp; 0 \\&lt;br /&gt;
0 &amp;amp; 1 &amp;amp; 0 \\&lt;br /&gt;
O^'_x &amp;amp; O^'_y &amp;amp; 1&lt;br /&gt;
\end{bmatrix}&lt;br /&gt;
 &amp;lt;/math&amp;gt; Translation to new position O'&lt;br /&gt;
&lt;br /&gt;
Then the transformation from P to P' is give by the matrix multiplication:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T(-O)\cdot R(-\alpha)\cdot S_x(length'/length)\cdot R(\alpha^')\cdot T(O^')&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; P'=P\cdot T\cdot R\cdot S_x\cdot R'\cdot T'=P\cdot B&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== Can Points (Bone influenced) be moved independently? ===&lt;br /&gt;
&lt;br /&gt;
Yes, they should be. If not the animator is tight to only do the animation with the bones animation what would end to some insoluble problems during the animation. Considered this, the point position result comes from the addition of two terms:&lt;br /&gt;
*(a) The movement of the point as described by the influence of the bone(s): P(B)&lt;br /&gt;
*(b) The free movement of the point in the 2D space. P(animated)&lt;br /&gt;
&lt;br /&gt;
In terms of the interface with the user, the value P(animated)is just obtained in this way:&lt;br /&gt;
&lt;br /&gt;
#In any position of the time line (bones are animated) the point have a position given by the influence of the bones: P(B).&lt;br /&gt;
#The user wrap a point, drags it, placing it at P'.&lt;br /&gt;
#The final position of the point is P' but the user cannot modify the first term P(B) so the second term (b) becomes: P(animated)=P'-P(B).&lt;br /&gt;
&lt;br /&gt;
===What happen if there are more than one bone affecting the point?===&lt;br /&gt;
&lt;br /&gt;
The first thing you can think when you deal with more than one bone making influence over the same point is to calculate the average of the sum of the influences of all bones. So if there are N bones affecting to the point then we can think on sum all the resulting points from each bone and then divide the result by N to not scale the result.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k}{N} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;B_k&amp;lt;/math&amp;gt; is the bone matrix for the bone ''k'' on the point P.&lt;br /&gt;
&lt;br /&gt;
That's fine but I would like to have more control to the way the bones affects to the points. When you move a bone it looks reasonable that not all the points are influence in the same way. This can be solved by using &amp;quot;weighted&amp;quot; average instead of a plain one. That means give different amount of influence to one bone than to other.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B=\frac{\sum_{k=1}^N B_k \cdot w_k}{\sum_{k=1}^N w_k} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Where &amp;lt;math&amp;gt;w_k&amp;lt;/math&amp;gt; is the weight for the bone ''k'' over the point P.&lt;br /&gt;
&lt;br /&gt;
=== Skeleton ===&lt;br /&gt;
&lt;br /&gt;
A skeleton is a set of bones linked one to others in a tree hierarchy. A bone can have several children (or none) but only one parent (or none). This configuration allows to do a easy calculation of the forward kinematic (FK )of the chain and the inverse kinematic (IK) of the chain of bones. If the hierarchy were not tree type then the FK and IK can be not soluble. &lt;br /&gt;
&lt;br /&gt;
For those IK and FK calculations it is good to have the bone referenced to its parent. So the parameters of the bone are described as relative to the parent bone. The parent bone defines a local coordinate system where the origin of the coordinate system lies on the Origin of the bone and the tip of the bone is pointing to the positive direction of the X axis.&lt;br /&gt;
&lt;br /&gt;
[[Image: skeleton.png]]&lt;br /&gt;
&lt;br /&gt;
As you can see in this image, each skeleton position and orientation is defined by the relative position of its immediate parent bone. In the diagram bone3 is a child of bone2 and bone 2 is a child of bone1. The bone 1 is the root parent bone but you can imagine it attached to a &amp;quot;master root bone&amp;quot; (defined by the origin of coordinates -red circumference- and the horizontal) so it can be said that the bone1 has its origin and angle defined relative to its &amp;quot;parent&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
In this skeleton the three bones are parented in a linear way. But as you can imagine, following the rules stated for child-parent, a bone can have more than one child but not more than one parent. &lt;br /&gt;
That means that defined a bone in the skeleton, there is only one sequence of parents to reach the root parent of the skeleton. Also it means too that one root bone defines one skeleton so each skeleton has only one root bone and only one.&lt;br /&gt;
&lt;br /&gt;
Consider this: B3 is child of B2 and B2 is child of B1. Also B4 is child of B2 and B5 is child of B4. The way to travel from B5 to B1 is unique: B5-&amp;gt;B4-&amp;gt;B2-&amp;gt;B1.&lt;br /&gt;
&lt;br /&gt;
=== Setup and Animation ===&lt;br /&gt;
&lt;br /&gt;
During the animation of the skeleton it is supposed that the position of each bone, its angle and its scale changes. Position and angle are relative to the parent bone, but scale is a value that calculates the current length of the bone compared with the &amp;quot;original&amp;quot; bone length (scale=length'/length) as you can see from the original formulas in the previous section. That means that the &amp;quot;original&amp;quot; bone length shouldn't be never zero, otherwise there will be a division by zero and the scale of the bone becomes infinite.&lt;br /&gt;
&lt;br /&gt;
Also, the final position P' of a point that moves influenced by a single bone is given by the original point position relative to the bone in its &amp;quot;original&amp;quot; position (P). &lt;br /&gt;
&lt;br /&gt;
What I'm trying to explain you is that it is needed that the setup of the bone (position, alpha and length) and the setup position of the point (P) to be moved would be given to calculate the final position of the point (P') given a moved position of the bone (position', alpha', length')&lt;br /&gt;
&lt;br /&gt;
Said this and considered the information of the previous sections, the bones and points that are influenced from the bones should have the following parameters:&lt;br /&gt;
&lt;br /&gt;
'''BONES PARAMETERS'''&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Origin ||&amp;lt;math&amp;gt; \textstyle O_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Angle || &amp;lt;math&amp;gt; \textstyle \alpha_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Length || &amp;lt;math&amp;gt; \textstyle l_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| Calculated, not animatable.&lt;br /&gt;
|- &lt;br /&gt;
| Scale || &amp;lt;math&amp;gt; \textstyle s_j(t) &amp;lt;/math&amp;gt; || Real ||Yes|| &amp;lt;math&amp;gt; \textstyle l_j(t) =l^0_j \cdot s_j(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Setup Origin || &amp;lt;math&amp;gt; \textstyle O^0_j(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Angle || &amp;lt;math&amp;gt; \textstyle \alpha^0_j(t) &amp;lt;/math&amp;gt; || Angle (DEG) ||Yes|| Relative to the parent&lt;br /&gt;
|- &lt;br /&gt;
| Setup Length || &amp;lt;math&amp;gt; \textstyle l^0_j &amp;lt;/math&amp;gt; || Real || No|| Constant, zero not allowed.&lt;br /&gt;
|- &lt;br /&gt;
| Setup Scale || &amp;lt;math&amp;gt; \textstyle s^0_j &amp;lt;/math&amp;gt; || Real || No|| &amp;lt;math&amp;gt; \textstyle s^0_j = 1 &amp;lt;/math&amp;gt;&lt;br /&gt;
|- &lt;br /&gt;
| Parent || &amp;lt;math&amp;gt; \textstyle PBone_j(t) &amp;lt;/math&amp;gt; || Bone ||Yes|| &lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
'''POINT PARAMETERS'''&lt;br /&gt;
&lt;br /&gt;
{| &lt;br /&gt;
! Parameter !! Notation !! Type !! Animated !! Comment&lt;br /&gt;
|- &lt;br /&gt;
| Position ||&amp;lt;math&amp;gt; \textstyle V(t) &amp;lt;/math&amp;gt; || Vector (Real,Real) ||Yes|| Calculated: &amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt; Global coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Setup Position ||&amp;lt;math&amp;gt; \textstyle VS(t) &amp;lt;/math&amp;gt; || Vector (Real, Real) ||Yes|| Absolute Coordinates&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Matrix ||&amp;lt;math&amp;gt; \textstyle M(t) &amp;lt;/math&amp;gt; || Matrix (3x3) ||Yes|| Calculated. See formulas below&lt;br /&gt;
|- &lt;br /&gt;
| Bone Influence Id ||&amp;lt;math&amp;gt; \textstyle BoneID_i &amp;lt;/math&amp;gt; || Bone || No || 'i' is the index for all the Bones that influences on the Point&lt;br /&gt;
|- &lt;br /&gt;
| Influence weight ||&amp;lt;math&amp;gt; \textstyle w_i &amp;lt;/math&amp;gt; || Real || Yes || the weight associated to the BoneID_i&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
(t) denotes ''calculated at the time t''&lt;br /&gt;
&lt;br /&gt;
=== Position of a Point due to Bones Influence ===&lt;br /&gt;
&lt;br /&gt;
According to the table, the final position of a point influenced by the bones is calculated based on two terms: A free movement of the point plus a bone drive movement. In this section we are going to calculate the second term.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; \textstyle V(t) =VF(t) +  VS(t) \cdot M(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M(t) = \cfrac{\sum_{i=1}^N M_i(t) \cdot w_i(t)}{\sum_{i=1}^N w_i(t)} &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; M_i(t)=B^0_i(t) \cdot B_i(t) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where i is a index that runs all the Bones Influence ID from i=1 to N (N= total number of bones that influence to the point)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B^0_i(t)= \prod_{j=bone}^{j=root} C_j^0(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; B_i(t)= \prod_{j=root}^{j=bone} C_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'j' runs the bone skeleton jumping from a child/parent bone to a parent/child bone each time. The travel of the index 'j' from ''bone'' to ''root'' and from ''root'' to ''bone'' is fixed -and unique- by the nature of skeletons constructions (a bone, a parent), as mentioned before.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j^0(t) = T(-O_j^0(t)) \cdot R(-\alpha_j^0(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the position of the point in local coordinates in relation to the bone 'j' at setup position. Notice that &amp;lt;math&amp;gt; s^0_j &amp;lt;/math&amp;gt; is equal to &amp;lt;math&amp;gt; \textstyle 1 &amp;lt;/math&amp;gt; for any bone and for any time.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt; C_j(t) = S_x(s_j(t))\cdot R(\alpha_j(t)) \cdot T(O_j(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
This matrix calculates the global position of the point due to the bone 'j' at animated position of the skeleton.&lt;br /&gt;
&lt;br /&gt;
=== Calculate the position and angle of a bone in a skeleton ===&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==== Position and Angle at Setup ====&lt;br /&gt;
&lt;br /&gt;
If the bones are described using relative coordinates to its predecessor, the position &amp;lt;math&amp;gt;\textstyle Q^0_j&amp;lt;/math&amp;gt; and the angle &amp;lt;math&amp;gt;\textstyle \beta^0_j&amp;lt;/math&amp;gt; of the bone 'j' in relation to the &amp;quot;master root bone&amp;quot; (ie. the global coordinate system) is given by those equations:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q^0_j(t) = O^0_j(t) \cdot B^0_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta^0_j(t) = \sum_{i=j}^{root} \alpha^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where  &lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_j(t)=\prod_{i=parent}^{root} B^0_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the parent of the bone 'j' and climbs up by one parent each time until it reaches the 'root' bone of the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)= T(-O^0_i(t)) \cdot R(-\alpha^0_i(t)) \cdot S_x(\frac{1}{s^0_j})&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B^0_i(t)&amp;lt;/math&amp;gt; is the inverse matrix transformation of the position of the bone relative to its immediate parent.&lt;br /&gt;
&lt;br /&gt;
Notice that at setup, &amp;lt;math&amp;gt;s^0_j&amp;lt;/math&amp;gt; is always equal to 1.&lt;br /&gt;
&lt;br /&gt;
====Animated Position and Angle ====&lt;br /&gt;
&lt;br /&gt;
Once calculated the position and angle of a bone in global coordinates you can calculate its animated position and angle by the transformation of their parents in the skeleton.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;Q_j(t) = O^0_j(t) \cdot B^0_j(t) \cdot B_j(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\beta_j(t)= \beta^0_j(t) + \sum_{i=root}^{parent} \alpha_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where &amp;lt;math&amp;gt;B_j(t)=\prod_{i=root}^{parent} B_i(t)&amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
where 'i' goes form the root bone and jumps down by one child each time until it reaches the 'parent' bone of the bone 'j'.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;B_i(t)= S_x(s_j(t)) \cdot R(\alpha_i(t)) \cdot T(O_i(t)) &amp;lt;/math&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;math&amp;gt;\textstyle B_i(t)&amp;lt;/math&amp;gt; is the transformation matrix of the position of the bone 'j' at the time t. &lt;br /&gt;
&lt;br /&gt;
The results &amp;lt;math&amp;gt;\textstyle Q_j(t), \beta_j(t)&amp;lt;/math&amp;gt; are obtained in global coordinates.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Keyboard_Shortcuts&amp;diff=8275</id>
		<title>Keyboard Shortcuts</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Keyboard_Shortcuts&amp;diff=8275"/>
				<updated>2008-11-28T19:33:27Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: delete -&amp;gt; control-delete&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Permalink]]&lt;br /&gt;
&lt;br /&gt;
Here is a list of some of the keyboard sortcuts you currently have at your disposal. These are the defaults. There is a way to customize these, but it is currently not intuitive. Basically you need to edit the accelrc file in your synfig settings directory.&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot; align=&amp;quot;center&amp;quot; width=&amp;quot;80%&amp;quot;&lt;br /&gt;
|'''Keystroke'''||'''Description'''&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-A || Select all ducks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Shift&amp;gt;&amp;lt;Control&amp;gt;-A || Select all layers&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-C || Copy currently selected layer(s) and put them in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-D || Deselect all ducks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Shift&amp;gt;&amp;lt;Control&amp;gt;-D || Deselect all layers&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-G || Toggle grid show&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-I || Import image&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-L || Toggle grid snap&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-N || New composition (since r1386)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-O || Open composition (since r1386)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-O || Toggle onion skin (since r1525 - it was Control-O until r1386)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-P || Play the current animation in the WorkArea&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-Q || Quit Synfig Studio&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-R || Redo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-S || Save&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-V || Paste the layer(s) from the clipboard above the currently selected layer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-W || Closes the current animation document. &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-X || Cut currently selected layer(s) and put them in the clipboard&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-Z || Undo&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-` || Toggle low/high-resolution (defaults to low resolution)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-0...9 || Change the current rendering quality (lower is better, but 0==10)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-1 || Toggle display of &amp;quot;Position&amp;quot; ducks &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-2 || Toggle display of &amp;quot;Vertex&amp;quot; ducks &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-3 || Toggle display of &amp;quot;Tangent&amp;quot; ducks &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-4 || Toggle display of &amp;quot;Radius&amp;quot; ducks &lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-5 || Toggle display of &amp;quot;Width&amp;quot; ducks (DEFAULTS TO OFF)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-6 || Toggle display of &amp;quot;Angle&amp;quot; ducks&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'-' || Zoom out of canvas (spacial zoom)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'=' || Zoom in on canvas (spacial zoom)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-&amp;lt;Shift&amp;gt;-Z || Zoom canvas to 100% (spacial zoom)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'_' || Zoom out of timeline (temporal zoom)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'+' || Zoom in on timeline (temporal zoom)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-',' || Move backward one frame&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'.' || Move forward one frame (be careful - can step past the end of an animation; fixed in svn r452)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'&amp;lt;' || Move backward one second&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'&amp;gt;' || Move forward one second&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'[' || Move backward to previous [[Keyframe|keyframe]]&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-']' || Move forward to next keyframe&lt;br /&gt;
|-&lt;br /&gt;
| Home || Jump to beginning of timeline (broken; fixed in svn r451)&lt;br /&gt;
|-&lt;br /&gt;
| End || Jump to end of timeline (broken; fixed in svn r451)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-'(' || Decrease workarea pixel size&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-')' || Increase workarea pixel size&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-&amp;lt;Alt&amp;gt;-'(' || Decrease 'amount' of selected layer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Control&amp;gt;-&amp;lt;Alt&amp;gt;-')' || Increase 'amount' of selected layer&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Shift&amp;gt;-PgUp || Raise currently selected layers&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Shift&amp;gt;-PgDn || Lower currently selected layers&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-A || Select 'normal' tool&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-V || Select 'smooth move' tool (shortcut added in svn r548)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-S || Select 'scale' tool (shortcut changed in svn r1985)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-T || Select 'rotate' tool (shortcut changed in svn r1985)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-M || Select 'mirror' tool (shortcut added in svn r548)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-C || Select 'circle' tool (shortcut added in svn r548)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-R || Select 'rectangle' tool (shortcut added in svn r548)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-Q || Select 'star' tool (tool and shortcut added in svn r1983)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-G || Select 'gradient' tool&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-P || Select 'polygon' tool (shortcut added in svn r548)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-B || Select 'bline' tool&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-X || Select 'text' tool (tool and shortcut added in svn r1959)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-F || Select 'fill' tool&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-E || Select 'eyedrop' tool&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-Z || Select 'zoom' tool&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-D || Select 'draw' tool (shortcut changed in svn r2009)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-K || Select 'sketch' tool (shortcut added in svn r548)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Alt&amp;gt;-W || Select 'width' tool (shortcut changed in svn r2009)&lt;br /&gt;
|-&lt;br /&gt;
| F8 || Canvas Properties&lt;br /&gt;
|-&lt;br /&gt;
| F9 || Render&lt;br /&gt;
|-&lt;br /&gt;
| F11 || Preview&lt;br /&gt;
|-&lt;br /&gt;
| F12 || Canvas Options (Grid size, etc.)&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Escape&amp;gt; || Stop current process. For example: when pressed it leaves the current state (Circle, Rectangle, Star, Gradient, Text, Fill, Eyedrop, Zoom, Draw and Sketch Tools) and returns to the Normal Tool State. Seems to be missing for the rest of Tools.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Delete&amp;gt; || Deletes the currently selected canvas. (CAREFUL! There is currently a bug which makes this work in just about any context! ie: if you are editing a parameter and press the delete key, it will delete the layer! this can be easily undone, but just keep it in mind)  Since SVN r2303 this has been changed to &amp;lt;Control&amp;gt;-&amp;lt;Delete&amp;gt; to avoid that bug.&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Cursor&amp;amp;nbsp;Key&amp;gt; || Nudge the currently selected duck(s) one pixel in the given direction&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Shift&amp;gt;-&amp;lt;Cursor&amp;amp;nbsp;Key&amp;gt; || Nudge the currently selected duck(s) ten pixels in the given direction&lt;br /&gt;
|-&lt;br /&gt;
| &amp;lt;Backspace&amp;gt; || Select the immediate paste canvas parent (if any) of the current selected layer.&lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
== Hotkeys Visual Guide ==&lt;br /&gt;
A good way to learn all this shorcuts is putting them in front of your eyes all the time. Because of that, we bring to you a beatiful &amp;quot;Hotkeys Visual Guide&amp;quot; that you can use as a poster.&lt;br /&gt;
&lt;br /&gt;
&amp;lt;gallery&amp;gt;&lt;br /&gt;
Image:hotkeys-visual-guide-SVN2011.png|PNG Version - SVN2011&lt;br /&gt;
&amp;lt;/gallery&amp;gt;&lt;br /&gt;
&lt;br /&gt;
We offer you two print sizes (both in PDF):&lt;br /&gt;
* [http://synfig.org/images/c/cd/Hotkeys-visual-guide-SVN2011-A4.pdf A4 Version]&lt;br /&gt;
* [A3 Version]&lt;br /&gt;
&lt;br /&gt;
And these are the source files in SVG format:&lt;br /&gt;
* [http://synfig.org/images/e/e1/Hotkeys-visual-guide-SVN2011-A4.svg A4 Version]&lt;br /&gt;
* [http://synfig.org/images/c/c2/Hotkeys-visual-guide-SVN2011-A3.svg A3 Version]&lt;br /&gt;
&lt;br /&gt;
Give us your [[Talk:Keyboard_Shortcuts|feedback and comments]].&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Focus_Point&amp;diff=8268</id>
		<title>Focus Point</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Focus_Point&amp;diff=8268"/>
				<updated>2008-11-26T23:46:54Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Parameters]]&lt;br /&gt;
The &amp;quot;Focus Point&amp;quot; parameter (added in SVN r2290, not yet released) is present only in the [[Paste Canvas]] layer.  It has a Vector value.  It defines which point in the encapsulated layers will stay still as the Paste Canvas layer's [[Zoom Parameter]] changes.&lt;br /&gt;
&lt;br /&gt;
The Focus Point is relative to the Paste Canvas layer's [[Origin Parameter]] and defaults to (0,0) so its duck will be hidden behind the green Origin duck initially.  Its duck can be seen by turning the Origin ducks off temporarily (by hitting ALT-1) or by editing its value to something small by non-zero in the Params Panel.&lt;br /&gt;
&lt;br /&gt;
It's best to edit the Focus Point parameter while the Paste Canvas' Zoom is set to 0.  Otherwise you'll be seeing a scaled version of the contents.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Focus_Point&amp;diff=8267</id>
		<title>Focus Point</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Focus_Point&amp;diff=8267"/>
				<updated>2008-11-26T23:46:31Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Parameters]]&lt;br /&gt;
The &amp;quot;Focus Point&amp;quot; parameter is present only in the [[Paste Canvas]] layer.  It has a Vector value.  It defines which point in the encapsulated layers will stay still as the Paste Canvas layer's [[Zoom Parameter]] changes.&lt;br /&gt;
&lt;br /&gt;
The Focus Point is relative to the Paste Canvas layer's [[Origin Parameter]] and defaults to (0,0) so its duck will be hidden behind the green Origin duck initially.  Its duck can be seen by turning the Origin ducks off temporarily (by hitting ALT-1) or by editing its value to something small by non-zero in the Params Panel.&lt;br /&gt;
&lt;br /&gt;
It's best to edit the Focus Point parameter while the Paste Canvas' Zoom is set to 0.  Otherwise you'll be seeing a scaled version of the contents.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Focus_Point&amp;diff=8266</id>
		<title>Focus Point</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Focus_Point&amp;diff=8266"/>
				<updated>2008-11-26T23:45:31Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: New page: &amp;lt;!--Categories--&amp;gt; Category:Parameters The &amp;quot;Focus Point&amp;quot; parameter is present only in the Paste Canvas layer.  It has a Vector value.  It defines which point in the encapsulated lay...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Parameters]]&lt;br /&gt;
The &amp;quot;Focus Point&amp;quot; parameter is present only in the [[Paste Canvas]] layer.  It has a Vector value.  It defines which point in the encapsulated layers will stay still as the Paste Canvas layer's Zoom parameter changes.&lt;br /&gt;
&lt;br /&gt;
The Focus Point is relative to the Paste Canvas layer's Origin parameter and defaults to (0,0) so its duck will be hidden behind the green Origin duck initially.  Its duck can be seen by turning the Origin ducks off temporarily (by hitting ALT-1) or by editing its value to something small by non-zero in the Params Panel.&lt;br /&gt;
&lt;br /&gt;
It's best to edit the Focus Point parameter while the Paste Canvas' Zoom is set to 0.  Otherwise you'll be seeing a scaled version of the contents.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Group_Layer&amp;diff=8265</id>
		<title>Group Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Group_Layer&amp;diff=8265"/>
				<updated>2008-11-26T23:39:39Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: add 'focus point' parameter; mention translate, scale, time offset&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Parameters]]&lt;br /&gt;
[[Image:Pastecanvas_icon.png|64px]]&lt;br /&gt;
&lt;br /&gt;
The Paste Canvas layer is a special layer that can hold other layers. It is generated via the [[Encapsulate]] command accessed via the context menu in the [[Layers Panel]] or through the [[Layer Menu]] in the [[Canvas Menu Caret]].  As well as grouping a set of layers it can also translate them, scale them, and even modify the time for the layers it contains.&lt;br /&gt;
&lt;br /&gt;
Paste Canvas layers can also be created through the [[New Layer Menu]], using New Layer &amp;gt; Other &amp;gt; Paste Canvas.&lt;br /&gt;
&lt;br /&gt;
A Paste Canvas layer has the following parameters:&lt;br /&gt;
* [[Z Depth]]&lt;br /&gt;
* [[Amount Parameter|Amount]]&lt;br /&gt;
* [[Blend Method]]&lt;br /&gt;
* [[Origin Parameter|Origin]]&lt;br /&gt;
* [[Canvas]]: This is &amp;quot;Inline Canvas&amp;quot; by default if the Paste Canvas layer was created by encapsulating other layers, or &amp;quot;Pasted Canvas&amp;quot; if it was created from the [[New Layer Menu]]. This parameter lets you select another canvas.&lt;br /&gt;
* [[Zoom Parameter|Zoom]]&lt;br /&gt;
* [[Time Offset Parameter|Time Offset]]&lt;br /&gt;
* [[Children Lock]]&lt;br /&gt;
* [[Focus Point]] (since SVN r2290)&lt;br /&gt;
&lt;br /&gt;
== Canvas Parameter ==&lt;br /&gt;
[[Image:canvas_pointer_icon.png|64px]]&lt;br /&gt;
&lt;br /&gt;
The canvas parameter presents a drop-down menu of the exported canvases, plus an extra entry called &amp;quot;Other...&amp;quot;.  Selecting &amp;quot;Other...&amp;quot; presents the user with a text entry box asking for the name of the canvas to use.  The name typed should have the following format (where &amp;lt;nowiki&amp;gt;[ ]&amp;lt;/nowiki&amp;gt; indicates an optional part, ( ) is for grouping, and * means &amp;quot;0 or more times&amp;quot;):&lt;br /&gt;
&lt;br /&gt;
  &amp;lt;nowiki&amp;gt;  [[&amp;lt;/nowiki&amp;gt;''filename''&amp;lt;nowiki&amp;gt;]#][:]&amp;lt;/nowiki&amp;gt;''id''(:''id'')*&lt;br /&gt;
&lt;br /&gt;
In its simplest form, this is just an ''id'', ie. the exported name of one of the child canvases of the current canvas.&lt;br /&gt;
&lt;br /&gt;
Other possibilities are:&lt;br /&gt;
* if a '#' is present, the part before the '#' is interpreted as the filename of an external .sif file to use.&lt;br /&gt;
* if the '#' is the first character of the string (ie. the filename is blank) then the '#' is ignored, and the current canvas is used instead&lt;br /&gt;
* if a ':' appears before the first ''id'', it means to start at the root canvas of the current canvas&lt;br /&gt;
* each subsequent :id steps down into the specified child&lt;br /&gt;
&lt;br /&gt;
Examples:&lt;br /&gt;
* '''/usr/share/doc/synfig/examples/business_card.sifz#:IndividualCard''' -- gives the absolute path to a .sifz file, and says to use the canvas that was exported from its root canvas as &amp;quot;IndividualCard&amp;quot;&lt;br /&gt;
* '''../../examples/business_card.sifz#:IndividualCard''' -- the same, but with a relative path to the .sifz file&lt;br /&gt;
* '''#:sy:head:eyes:left''' -- look in the current composition, and starting from the root, navigate down through the canvas tree.  Find a child canvas of the root canvas called 'sy', look in 'sy' for a child canvas called 'head', and so on.&lt;br /&gt;
* ''':sy:head:eyes:left''' -- exactly as above.  an empty filename is the same as not using the '#' at all&lt;br /&gt;
* '''eyes:left''' -- without a ':' before the first ''id'', this starts at the current canvas (presumably the PasteCanvas in question is in the &amp;quot;head&amp;quot; subcanvas of the &amp;quot;sy&amp;quot; subcanvas of the root)&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Zoom_Tool&amp;diff=8260</id>
		<title>Zoom Tool</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Zoom_Tool&amp;diff=8260"/>
				<updated>2008-11-25T20:45:07Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Usage */ add drag+CTRL to zoom out; link to mouse shourtcuts; mention CTRL+wheel&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Tools]]&lt;br /&gt;
[[Image:Zoom_icon.png|64px]] &amp;lt;span style=&amp;quot;font-size:150%&amp;quot;&amp;gt;'''ALT-Z'''&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Description==&lt;br /&gt;
&lt;br /&gt;
The Zoom tool is used to get a closer or far away view of the objects that are being edited in the working area. It doesn't affect to the output render so you don't mind how close or far away are watching your composition that it is rendered as described in the [[render options]]&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
Click on the Zoom tool button. Then the current status would change to zoom. You can:&lt;br /&gt;
&lt;br /&gt;
* Click anywhere in the working area: it will zoom in to 125% of the current zoom level. The zoom will be centered such that the point clicked on remains in the same place.&lt;br /&gt;
* CTRL + click anywhere in the working area: it will zoom out to 80% of the current zoom level.  (Notice that 80% of 125 is 100, so zooming in one step and out one step will leave you back at the original zoom level).&lt;br /&gt;
* Click at any place and drag to create a rectangle: it will zoom to fit the rectangle in the current working window.&lt;br /&gt;
* Click at any place and drag to create a rectangle, holding CTRL as you release the mouse button: it will zoom out to fit the current working window in the rectangle.&lt;br /&gt;
&lt;br /&gt;
Alternatively you can always use the existing [[Mouse_Shortcuts|mouse short cuts]] for that task (CTRL + mouse wheel) or the zoom buttons at the left bottom corners of the working area.&lt;br /&gt;
&lt;br /&gt;
[[Image:Zoom_buttons.png]]&lt;br /&gt;
&lt;br /&gt;
They do following:&lt;br /&gt;
&lt;br /&gt;
* Zoom in to 125% of the current zoom level&lt;br /&gt;
* Zoom to 100% (press again and restore last zoom)&lt;br /&gt;
* Zoom to fit the window (press again an restore last zoom)&lt;br /&gt;
* Zoom out to 80% of the current zoom level&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Unit_System&amp;diff=8237</id>
		<title>Unit System</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Unit_System&amp;diff=8237"/>
				<updated>2008-11-20T09:16:34Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: pixels per unit isn't fixed&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Selecting &amp;quot;[[Toolbox|Toolbox]] &amp;gt; File &amp;gt; [[Setup Dialog|Setup]] &amp;gt; Misc.&amp;quot; lets you set the unit system, with choices:&lt;br /&gt;
* units (u)&lt;br /&gt;
* pixels (px)&lt;br /&gt;
* points (pt)&lt;br /&gt;
* inches (in)&lt;br /&gt;
* metres (m)&lt;br /&gt;
* centimeters (cm)&lt;br /&gt;
* millimeters (mm)&lt;br /&gt;
&lt;br /&gt;
The conversions are:&lt;br /&gt;
* 1cm = 0.01m = 10mm&lt;br /&gt;
* 1in = 2.54cm&lt;br /&gt;
* 1in = 72pt&lt;br /&gt;
* 1u = (image width in pixels)/(image area width)px&lt;br /&gt;
* 1in = (res)px&lt;br /&gt;
&lt;br /&gt;
The default document is 480 x 270 pixels and has an image area from (-4,2.25) to (4,-2.25), giving an image area of 8 x 4.5 units, so by default 1 unit is 480 / 8 = 60 pixels.&lt;br /&gt;
&lt;br /&gt;
At an XRes = YRes = 36, 1in = 72pt = 36px = 0.6u.&lt;br /&gt;
&lt;br /&gt;
At an XRes = YRes = 72, 1in = 72pt = 72px = 1.2u.&lt;br /&gt;
&lt;br /&gt;
Another example, linking all 7 units:&lt;br /&gt;
&lt;br /&gt;
 72 DPI: (1m = 100cm = 1000mm = 39.37in = 2834.65pt) = (2834.65px = 47.24u)&lt;br /&gt;
 36 DPI: (1m = 100cm = 1000mm = 39.37in = 2834.65pt) = (1417.32px = 23.62u)&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Zoom_Tool&amp;diff=8216</id>
		<title>Zoom Tool</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Zoom_Tool&amp;diff=8216"/>
				<updated>2008-11-18T10:57:42Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Usage */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Tools]]&lt;br /&gt;
[[Image:Zoom_icon.png|64px]] &amp;lt;span style=&amp;quot;font-size:150%&amp;quot;&amp;gt;'''ALT-Z'''&amp;lt;/span&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
==Description==&lt;br /&gt;
&lt;br /&gt;
The Zoom tool is used to get a closer or far away view of the objects that are being edited in the working area. It doesn't affect to the output render so you don't mind how close or far away are watching your composition that it is rendered as described in the [[render options]]&lt;br /&gt;
&lt;br /&gt;
==Usage==&lt;br /&gt;
&lt;br /&gt;
Click on the Zoom tool button. Then the current status would change to zoom. You can:&lt;br /&gt;
&lt;br /&gt;
* Click anywhere in the working area: it will zoom in to 125% of the current zoom level. The zoom will be centered such that the point clicked on remains in the same place.&lt;br /&gt;
* CTRL + click anywhere in the working area: it will zoom out to 80% of the current zoom level.  (Notice that 80% of 125 is 100, so zooming in one step and out one step will leave you back at the original zoom level).&lt;br /&gt;
* Click at any place and drag to create a rectangle: it will zoom to fit the rectangle in the current working window.&lt;br /&gt;
&lt;br /&gt;
Alternatively you can always use the existing mouse short cuts for that task or the zoom buttons at the left bottom corners of the working area.&lt;br /&gt;
&lt;br /&gt;
[[Image:Zoom_buttons.png]]&lt;br /&gt;
&lt;br /&gt;
They do following:&lt;br /&gt;
&lt;br /&gt;
* Zoom in 25%&lt;br /&gt;
* Zoom to 100% (press again and restore last zoom)&lt;br /&gt;
* Zoom to fit the window (press again an restore last zoom)&lt;br /&gt;
* Zoom out 20%&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Download&amp;diff=8209</id>
		<title>Download</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Download&amp;diff=8209"/>
				<updated>2008-11-16T22:25:21Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Releases */ link to forum thread about ubuntu 8.10 problem&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;div style=&amp;quot;margin-bottom:20px; margin-top:-10px;-moz-border-radius:10px; padding:5px; width:100%; text-align:center; border: 1px solid #a6d577; background: #F8EA85;&amp;quot;&amp;gt;We are updating the download page to have the new release available on all platforms&amp;lt;/div&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== Disclaimer ==&lt;br /&gt;
&lt;br /&gt;
We are aware that there are lots of features missing in synfig. This software is under development and needs more polishing to become a mature program. Lots of bugs have been killed and now the stability of the program has increased considerably. There are some known issues than occasionally might make you frustrated. Despite this disclaimer there are proofs that the program is completely usable for professional work as demonstrated by some of the works in the [[Gallery]]. Please help us to make a better program in any of its aspects (artwork, translation, wiki improvement, tutorials, finding bugs, sending patches, etc.). We will embrace any of your proposals!.&lt;br /&gt;
&lt;br /&gt;
A special thanks to [http://www.bridgetone.com/ Bridgetone] for hosting our videos and early downloads!&lt;br /&gt;
&lt;br /&gt;
== Download ==&lt;br /&gt;
&lt;br /&gt;
Synfig 0.61.09 is the latest release from the Synfig community. Please read the [[Releases/0.61.09|release notes]] for information about what changed.&lt;br /&gt;
&lt;br /&gt;
[[#source|&amp;lt;img src=&amp;quot;http://www.reactos.org/media/pictures/2007/devpack1.png&amp;quot;/&amp;gt;]] [[#windows|&amp;lt;img src=&amp;quot;http://www.bibirmer.com/Extensions/windows_icon.png&amp;quot;&amp;gt;]] [[#macosx|&amp;lt;img src=&amp;quot;http://www.washington.edu/computing/web/images/icon-macos.gif&amp;quot;/&amp;gt;]] [[#ubuntu|&amp;lt;img src=&amp;quot;http://www.ubuntu.com/themes/ubuntu07/images/icon-ubuntu.png&amp;quot;/&amp;gt;]] [[#debian|&amp;lt;img src=&amp;quot;http://www.winehq.org/images/distro/debian.png&amp;quot;/&amp;gt;]] [[#fink|&amp;lt;img src=&amp;quot;http://upload.wikimedia.org/wikipedia/en/thumb/2/25/FinkLogo.jpg/80px-FinkLogo.jpg&amp;quot;/&amp;gt;]] [[#zenwalk|&amp;lt;img src=&amp;quot;http://wiki.zenwalk.org/images/thumb/d/dd/CommunityPortal.png/50px-CommunityPortal.png&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#gentoo|&amp;lt;img src=&amp;quot;http://fillets.sourceforge.net/img/logo/gentoo.png&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#arch|&amp;lt;img src=&amp;quot;http://upload.wikimedia.org/wikipedia/commons/thumb/2/21/Archlinux_logo.svg/48px-Archlinux_logo.svg.png&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#pardus|&amp;lt;img src=&amp;quot;http://www.acikbilgi.com/wp-content/pardus.jpg&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#freebsd|&amp;lt;img src=&amp;quot;http://albumshaper.sourceforge.net/images/supportedSystems/freebsd.png&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#opensuse|&amp;lt;img src=&amp;quot;http://files.opensuse.org/opensuse/en/2/22/Geeko_head_simple.png&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#slackware|&amp;lt;img src=&amp;quot;http://www.slackware.com/~msimons/slackware/grfx/shared/slackweb.jpg&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#fedora|&amp;lt;img src=&amp;quot;https://www.inteco.es/extfrontinteco/osi/actualizacionesSW/SO/fedora_peq.png&lt;br /&gt;
&amp;quot;/&amp;gt;]]&lt;br /&gt;
[[#mandriva|&amp;lt;img src=&amp;quot;http://www.mandriva.com/archives/var/mdk/storage/images/media/images/star_on_transparent_background/261440-3-eng-US/star_on_transparent_background.png&amp;quot;&amp;gt;]]&lt;br /&gt;
[[#momonga|&amp;lt;img src=&amp;quot;http://www.momonga-linux.org/img/momo_banner.png&amp;quot;&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
=== Licence ===&lt;br /&gt;
&lt;br /&gt;
ETL, synfig and synfigstudio are [[License|licensed]] under the GNU General Public Licence, version 2 or later.&lt;br /&gt;
&lt;br /&gt;
=== Issues ===&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;macosx_issues&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
'''MacOS X''': '''''Taken offline''''', please see bug [http://sf.net/support/tracker.php?aid=1686495 1686495]. Patches and volunteers to create new packages are welcome. Until someone volunteers, you can [[Building_On_Mac_OS_X|build it yourself]] or install via [[#fink|fink]].&lt;br /&gt;
&lt;br /&gt;
&amp;lt;div id=&amp;quot;windows_issues&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;&lt;br /&gt;
'''Windows''': There are [[Security|'''security issues''']] with the dv, imagemagick and ffmpeg targets, please avoid using them to import or render untrusted files.&lt;br /&gt;
&lt;br /&gt;
'''Windows''': Rendering issues may be encountered on Hyperthreaded or multi-core CPUs.  Please see the FAQ for [[FAQ#Can_I_do_anything_to_improve_the_stability_of_the_Windows_version_of_Synfig.3F|workaround details]].&lt;br /&gt;
&lt;br /&gt;
=== Releases ===&lt;br /&gt;
&lt;br /&gt;
If you know of any other packages, please add them below or [[Contact|contact]] us and ask for them to be added here.&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!align=&amp;quot;center&amp;quot;| Type&lt;br /&gt;
!align=&amp;quot;center&amp;quot;| Links&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;source&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[[Source code]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://sf.net/project/showfiles.php?group_id=144022&amp;amp;package_id=198849 ETL]  [http://sf.net/project/showfiles.php?group_id=144022&amp;amp;package_id=158279 synfig] [http://sf.net/project/showfiles.php?group_id=144022&amp;amp;package_id=198850 synfigstudio]&lt;br /&gt;
| Please read the [[Build_instructions|build instructions]].&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;windows&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.microsoft.com/windows/ Windows]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://downloads.sourceforge.net/gladewin32/gtk-2.10.11-win32-1.exe gtk] [http://ftp.gnome.org/pub/gnome/binaries/win32/gtkmm/2.10/gtkmm-win32-runtime-2.10.11-1.exe gtkmm] &lt;br /&gt;
[http://downloads.sourceforge.net/synfig/synfig-0.61.09.exe synfig] [http://downloads.sourceforge.net/synfig/synfigstudio-0.61.09.exe synfigstudio]&lt;br /&gt;
| Has '''''[[#windows_issues|important issues]]'''''. All four are '''''required''''', see the [http://uk.youtube.com/watch?v=mrDqiRI7fwk install walkthrough video].&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;macosx&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.apple.com/macosx/ MacOS X]&lt;br /&gt;
|&lt;br /&gt;
| '''''Taken offline''''', has [[#macosx_issues|major issues]]&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;ubuntu&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.ubuntu.com/ Ubuntu]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://packages.ubuntu.com/src:etl etl] [http://packages.ubuntu.com/src:synfig synfig] [http://packages.ubuntu.com/src:synfigstudio synfigstudio]&lt;br /&gt;
| Available in Ubuntu 7.04 (Feisty Fawn) and later in universe.  For information on Synfig on Ubuntu 8.10 Intrepid Ibex see [http://synfig.org/forums/viewtopic.php?f=13&amp;amp;t=277 this link].&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;debian&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.debian.org/ Debian]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://packages.debian.org/src:etl etl] [http://packages.debian.org/src:synfig synfig]  [http://packages.debian.org/src:synfigstudio synfigstudio]&lt;br /&gt;
| Available in Debian 5.0 (lenny) and later in main&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;fink&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.finkproject.org/ Fink]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://pdb.finkproject.org/pdb/package.php/etl etl] [http://pdb.finkproject.org/pdb/package.php/synfig synfig] [http://pdb.finkproject.org/pdb/package.php/synfigstudio synfigstudio]&lt;br /&gt;
| Available in Fink unstable&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;momonga&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.momonga-linux.org/ Momonga]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://sophie.zarb.org/rpmfind?distrib=Momonga&amp;amp;version=&amp;amp;arch=&amp;amp;search=etl&amp;amp;st=rpmname etl] [http://sophie.zarb.org/rpmfind?distrib=Momonga&amp;amp;version=&amp;amp;arch=&amp;amp;search=synfig&amp;amp;st=rpmname synfig] [http://sophie.zarb.org/rpmfind?distrib=Momonga&amp;amp;version=&amp;amp;arch=&amp;amp;search=synfigstudio&amp;amp;st=rpmname synfigstudio]&lt;br /&gt;
| Available in Momonga Linux 5 and later&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;zenwalk&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.zenwalk.org/ Zenwalk]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://packages.zenwalk.org/?q=ETL&amp;amp;zversion=all etl] [http://packages.zenwalk.org/?q=synfig-core&amp;amp;zversion=all synfig] [http://packages.zenwalk.org/?q=synfig-studio&amp;amp;zversion=all synfigstudio]&lt;br /&gt;
| Available in Zenwalk extras&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;gentoo&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.gentoo.org Gentoo]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://bugs.gentoo.org/show_bug.cgi?id=111277 etl] [http://bugs.gentoo.org/show_bug.cgi?id=111278 synfig] [http://bugs.gentoo.org/show_bug.cgi?id=111279 synfigstudio]&lt;br /&gt;
| Available in Gentoo [http://www.gentoo.org/proj/en/sunrise/ Project Sunrise]&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;arch&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.archlinux.org/ Arch Linux]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;|  [http://aur.archlinux.org/packages.php?K=VoriaETL etl] [http://aur.archlinux.org/packages.php?K=synfig synfig synfigstudio]&lt;br /&gt;
|Available in Arch Linux unsupported&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;pardus&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.pardus.org.tr/eng/ Pardus]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://packages.pardus.org.tr/contrib/source/etl.html etl] [http://packages.pardus.org.tr/contrib/source/synfig.html synfig] [http://packages.pardus.org.tr/contrib/source/synfigstudio.html synfigstudio]&lt;br /&gt;
| Available in Pardus contrib&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;freebsd&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.freebsd.org/ FreeBSD]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://www.freebsd.org/cgi/url.cgi?ports/devel/etl/pkg-descr etl] [http://www.freebsd.org/cgi/url.cgi?ports/devel/synfig/pkg-descr synfig] [http://www.freebsd.org/cgi/url.cgi?ports/graphics/synfigstudio/pkg-descr synfigstudio]&lt;br /&gt;
| Available in FreeBSD ports&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;mandriva&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.mandriva.com/ Mandriva]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://sophie.zarb.org/rpmfind?distrib=Mandriva&amp;amp;version=&amp;amp;arch=&amp;amp;search=etl&amp;amp;st=rpmname etl] [http://sophie.zarb.org/rpmfind?distrib=Mandriva&amp;amp;version=&amp;amp;arch=&amp;amp;search=synfig&amp;amp;st=rpmname synfig] [http://sophie.zarb.org/rpmfind?distrib=Mandriva&amp;amp;version=&amp;amp;arch=&amp;amp;search=synfigstudio&amp;amp;st=rpmname synfigstudio]&lt;br /&gt;
| Available in Mandriva [http://wiki.mandriva.com/en/Policies/SoftwareMedia#.2Fcontrib.2Fbackports /contrib/backports]&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;opensuse&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.opensuse.org openSUSE]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://packman.links2linux.de/package/etl etl] [http://packman.links2linux.de/package/synfig synfig] [http://packman.links2linux.de/package/synfigstudio synfigstudio]&lt;br /&gt;
| Available in [http://packman.links2linux.de/ PackMan]&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;slackware&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://www.slackware.com/ Slackware]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://slacky.eu/?searchword=synfig&amp;amp;option=com_search&amp;amp;Itemid=5 etl synfig synfigstudio]&lt;br /&gt;
| Available in [http://slacky.eu/ Slacky.eu]&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| &amp;lt;div id=&amp;quot;fedora&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;[http://fedoraproject.org/ Fedora]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [https://bugzilla.redhat.com/show_bug.cgi?id=428567 etl] [https://bugzilla.redhat.com/show_bug.cgi?id=428568 synfig]&lt;br /&gt;
| Available in [https://bugzilla.redhat.com/ Red Hat Bugzilla]&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
=== Snapshots ===&lt;br /&gt;
&lt;br /&gt;
{|&lt;br /&gt;
|-&lt;br /&gt;
!align=&amp;quot;center&amp;quot;| Type&lt;br /&gt;
!align=&amp;quot;center&amp;quot;| Links&lt;br /&gt;
! Notes&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [[Source code]]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://synfig.org/code/ETL-svn.tar.gz etl] [http://synfig.org/code/synfig-svn.tar.gz synfig] [http://synfig.org/code/synfigstudio-svn.tar.gz synfigstudio]&lt;br /&gt;
| Please read the [[Build_instructions|build instructions]]. Automatically updated daily from SVN.&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://www.microsoft.com/windows/ Windows]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://downloads.sourceforge.net/gladewin32/gtk-2.10.11-win32-1.exe gtk] [http://ftp.gnome.org/pub/gnome/binaries/win32/gtkmm/2.10/gtkmm-win32-runtime-2.10.11-1.exe gtkmm] [http://synfig.org/files/synfig-0.61.09-2167.exe synfig] [http://synfig.org/files/synfigstudio-0.61.09-2167.exe synfigstudio]&lt;br /&gt;
| Built occasionally by pxegeek, currently SVN 2167. Has '''''[[#windows_issues|important issues]]'''''. All four are '''''required''''', see the [http://uk.youtube.com/watch?v=mrDqiRI7fwk install walkthrough video].&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://www.gentoo.org Gentoo]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [[Gentoo_Ebuilds#SVN_Ebuilds|etl synfig synfigstudio]]&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://fedoraproject.org/ Fedora]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| Fedora 8: [http://atrus.mmaa.ru/synfig/#fc etl synfig synfigstudio]&amp;lt;br&amp;gt;&lt;br /&gt;
Fedora 7: [http://zelgadis.profusehost.net/blog/tags/download/ etl synfig synfigstudio]&lt;br /&gt;
| Built by Atrus and Zelgadis&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://www.ubuntu.com/ Ubuntu]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://dooglus.rincevent.net/synfig/repository/ repositories] for feisty (svn 1513), gutsy (svn 1456), hardy (svn 1514)&lt;br /&gt;
| These packages are outdated as of 2 October 2008&lt;br /&gt;
|-&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://www.debian.org/ Debian]&lt;br /&gt;
|align=&amp;quot;center&amp;quot;| [http://dooglus.rincevent.net/synfig/repository/ repository] for sid (svn 1514)&lt;br /&gt;
| These packages are outdated as of 2 October 2008&lt;br /&gt;
|}&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Source_code&amp;diff=8182</id>
		<title>Dev:Source code</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Source_code&amp;diff=8182"/>
				<updated>2008-11-14T23:07:22Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: link to the sf.net SVN browser&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Code]] [[Category:Permalink]]&lt;br /&gt;
&lt;br /&gt;
Hey you! Do you want access to bleeding-edge Synfig? Well, I have good news. Anonymous access to the Synfig Subversion repository for Synfig is now enabled! Here are the URLs to the respective repositories:&lt;br /&gt;
&lt;br /&gt;
* https://synfig.svn.sourceforge.net/svnroot/synfig/ETL/&lt;br /&gt;
* https://synfig.svn.sourceforge.net/svnroot/synfig/synfig-core/&lt;br /&gt;
* https://synfig.svn.sourceforge.net/svnroot/synfig/synfig-studio/&lt;br /&gt;
&lt;br /&gt;
Sourceforge provides a web interface to [http://synfig.svn.sourceforge.net/viewvc/synfig/ browse the Subversion repository].&lt;br /&gt;
&lt;br /&gt;
From the command line, to check out ETL, synfig-core and synfig-studio, you would type:&lt;br /&gt;
&lt;br /&gt;
  svn co https://synfig.svn.sourceforge.net/svnroot/synfig/ETL/trunk/ etl&lt;br /&gt;
  svn co https://synfig.svn.sourceforge.net/svnroot/synfig/synfig-core/trunk/ synfig-core&lt;br /&gt;
  svn co https://synfig.svn.sourceforge.net/svnroot/synfig/synfig-studio/trunk/ synfig-studio&lt;br /&gt;
&lt;br /&gt;
You can also download a [http://synfig.org/code/synfig-svn-checkout.tar.gz daily updated svn checkout] that you can update using svn up. This was created using a [[Subversion|procedure]] by [[User:Dooglus|dooglus]].&lt;br /&gt;
&lt;br /&gt;
You can also download daily updated svn exports for [http://synfig.org/code/ETL-svn.tar.gz ETL], [http://synfig.org/code/synfig-svn.tar.gz synfig], [http://synfig.org/code/synfigstudio-svn.tar.gz synfigstudio].&lt;br /&gt;
&lt;br /&gt;
Once you grab the code, you will need to bootstrap the build environment and then [[Build instructions|build the code]].&lt;br /&gt;
&lt;br /&gt;
Commit notifications are sent to [http://cia.vc/stats/project/synfig CIA] and show up in the [[Contact|IRC channel]].&lt;br /&gt;
&lt;br /&gt;
While you are browsing the code, you may wish to refer to these links:&lt;br /&gt;
&lt;br /&gt;
* [[Source Outline|source code outline]]&lt;br /&gt;
* [[Source Glossary|source code glossary]]&lt;br /&gt;
* [http://synfig.org/api/ API documentation]&lt;br /&gt;
* [[Source:ETL_make_check|ETL make check failures]]&lt;br /&gt;
* [[Source:Layers|Mapping between layer types, classes and .cpp files]]&lt;br /&gt;
* [[Source:class_ValueNode|ValueNode types]]&lt;br /&gt;
* [[Source:BlendMethods|Blend Method enumeration values]]&lt;br /&gt;
&lt;br /&gt;
== GIT ==&lt;br /&gt;
&lt;br /&gt;
We are trialling [http://git.or.cz/ git] and may switch to it:&lt;br /&gt;
&lt;br /&gt;
  git clone git://synfig.org/git/ETL.git&lt;br /&gt;
  git clone git://synfig.org/git/synfig.git&lt;br /&gt;
  git clone git://synfig.org/git/synfigstudio.git&lt;br /&gt;
&lt;br /&gt;
People behind restrictive firewalls may be able to use these instead:&lt;br /&gt;
&lt;br /&gt;
  git clone http://synfig.org/git/ETL.git&lt;br /&gt;
  git clone http://synfig.org/git/synfig.git&lt;br /&gt;
  git clone http://synfig.org/git/synfigstudio.git&lt;br /&gt;
&lt;br /&gt;
People with commit access should use these commands instead:&lt;br /&gt;
&lt;br /&gt;
  git clone git@synfig.org:ETL.git&lt;br /&gt;
  git clone git@synfig.org:synfig.git&lt;br /&gt;
  git clone git@synfig.org:synfigstudio.git&lt;br /&gt;
&lt;br /&gt;
You can also check out the [http://synfig.org/gitweb/ web interface] to these repositories.&lt;br /&gt;
&lt;br /&gt;
Also, dooglus maintains a git-svn repository of synfig and has a [http://kibi.dyndns.org:8083/~dooglus/gitweb.pl?p=synfig;a=summary gitweb interface] for it.&lt;br /&gt;
&lt;br /&gt;
Proposed git workflow:&lt;br /&gt;
&lt;br /&gt;
* Do all work on the '''master''' branch&lt;br /&gt;
* Latest stable releases should be tagged with '''stable-release'''.&lt;br /&gt;
* Latest development releases should be tagged with '''devel-release'''.&lt;br /&gt;
* All releases should be tagged with their version number (with no extra chars): '''0.61.08'''.&lt;br /&gt;
* For now, we don't need a stable release branch, when/if we do:&lt;br /&gt;
** Branch the '''stable-release''' tag (or whatever is appropriate) to something like '''0.62'''.&lt;br /&gt;
** Cherry-pick commits from the '''master''' branch to the stable branch where possible.&lt;br /&gt;
** Commit directly to the stable branch only when cherry-picks are not possible.&lt;br /&gt;
* Work on new non-trivial features/fixes on public topic branches where possible&lt;br /&gt;
* Obviously commit trivial fixes straight to the '''master''' or the stable branch.&lt;br /&gt;
* Rebase &amp;amp; rework branches to keep history more sane, linear and atomic&lt;br /&gt;
&lt;br /&gt;
Proposed set of git repositories:&lt;br /&gt;
&lt;br /&gt;
* admin.git - gitosis admin settings - holds groups, repos and users&lt;br /&gt;
* code/* - direct conversions from SVN&lt;br /&gt;
** code/ETL.git - ETL&lt;br /&gt;
** code/synfig.git - synfig&lt;br /&gt;
** code/synfigstudio.git - synfigstudio&lt;br /&gt;
* pkg/* - bits for various packaging systems&lt;br /&gt;
** pkg/windows.git - Windows packaging (needs separating from the code repos)&lt;br /&gt;
** pkg/macos.git - MacOS packaging (needs separating from the code repos)&lt;br /&gt;
** pkg/jhbuild.git - JHBuild moduleset (needs writing)&lt;br /&gt;
** pkg/autopackage.git - Autopackage bits (needs writing)&lt;br /&gt;
* web/* - various bits used to maintain the website&lt;br /&gt;
** web/skin.git - skin for the website&lt;br /&gt;
** web/content.git - content for the website (pending switch to ikiwiki)&lt;br /&gt;
* misc/* - various stuff needed&lt;br /&gt;
** misc/svn2git.git - the scripts used to convert the SVN repo to git&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Environment_Variables&amp;diff=8158</id>
		<title>Environment Variables</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Environment_Variables&amp;diff=8158"/>
				<updated>2008-11-10T16:50:09Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Environment Variables */ add SYNFIG_FORCE_TILE_RENDER&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== Environment Variables ==&lt;br /&gt;
&lt;br /&gt;
Several environment variables can be set to affect the behavior of Synfig Studio:&lt;br /&gt;
&lt;br /&gt;
{| border=&amp;quot;1&amp;quot; cellspacing=&amp;quot;0&amp;quot;&lt;br /&gt;
|'''variable'''||'''description'''&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DISABLE_AUTOMATIC_DOCUMENT_CREATION || If no documents are specified when synfig is run, it will create a new blank document unless this variable is set.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_ENABLE_NEW_CANVAS_EDIT_PROPERTIES || When a new document is created, the [[Canvas Properties Dialog]] will only be shown if this variable is set.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DISABLE_OPTIMIZE&amp;lt;br/&amp;gt;SYNFIG_DISABLE_OPTIMIZE_TRANS&amp;lt;br/&amp;gt;SYNFIG_DISABLE_REMOVE_DUPS || These three variables, when set, disable various steps of the animated gif optimization process in the magick++ module.  Namely: disable optimization completely, disable optimization of transparent pixels, and disable the removal of adjacent duplicate frames respectively.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DISABLE_DRAW&amp;lt;br/&amp;gt;SYNFIG_DISABLE_POLYGON&amp;lt;br/&amp;gt;SYNFIG_DISABLE_SKETCH || These can be used to disable the named tools from being shown in the toolbox.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_ENABLE_WIDTH || If set, this enables the (mostly broken) width tool in the toolbox.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_TIMETRACK_HEADER_HEIGHT&amp;lt;br/&amp;gt;SYNFIG_TIMETRACK_ROW_HEIGHT || These are used to change the header and row heights in the timetrack panel.  This is sometimes needed to make the timetrack panel rows line up with the parameter panel's rows.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DISABLE_POPUP_WINDOWS || When set, this makes the splash screen and &amp;quot;one moment please&amp;quot; popup windows behave like regular windows - ie. they can be minimized, and covered by other windows.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DISABLE_TILE_RENDER || When set, the workarea is always rendered using the scanline renderer, rather than being broken up into small square tiles which are rendered separately.  This is overridden by SYNFIG_FORCE_TILE_RENDER.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_FORCE_TILE_RENDER || When set, the workarea is always rendered using the tile renderer, rather than being rendered in a single block.  This overrides SYNFIG_DISABLE_TILE_RENDER.  (added in SVN r2180)&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_SHOW_TILE_OUTLINES || For debugging, this draws a red outline around each tile when using the tile renderer.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_ENABLE_POPUP_MENU_IN_ALL_TOOLS || Allow the right-click context menu to be used in all the various tool states.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_MODULE_LIST || Specifies where to load the list of dynamic modules from.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_ROOT || Specifies the path to the synfig resources.  It should be the directory which contains share/pixmaps/synfigstudio/ - usually /usr or /usr/local.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_TOOLS_CLEAR_SELECTION || When set, unselect all layers before creating a new layer in any of the tools (other than the draw tool, which always leaves selected layers selected so that their ducks can be linked to).&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_TRANSIENT_DIALOGS || Some window managers fail to associate synfig's panels with the toolbox.  Setting this can help.  It seems to work quite well on Windows too, preventing the panels from taking up space on the task bar, but be careful not to minimize any of the panels, it can cause problems.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DEBUG_DESTRUCTORS || Logs the sequence of destructions that go on when closing things down.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_SHOW_FULL_TIME_ON_FOCUS || When editing a Time field, start with the full formatted time, ie. &amp;quot;0h 0m 1s 0f&amp;quot; rather than &amp;quot;1s&amp;quot;.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_WINDOW_POSITION_X_OFFSET&amp;lt;br/&amp;gt;SYNFIG_WINDOW_POSITION_Y_OFFSET || Added on to the stored position of each panel when studio starts up.  Used to combat the pixel-by-pixel drifting that happens with some window managers.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_SHOW_CANVAS_PARAM_WAYPOINTS || In PasteCanvas layers, show waypoints for the Canvas parameter itself, rather than for the canvas that is the parameter's value.  Experimental.  From SVN r1628.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_KEEP_ABORTED_DRAW_LINES || In the draw tool, if you make a very fast stroke, it's not used.  Studio always used to leave the unused stroke on the display until a longer stroke was made.  SVN r1689 changed things so that these short strokes are immediately hidden.  Setting this variable restores the previous behavior.&lt;br /&gt;
|-&lt;br /&gt;
| SYNFIG_DISABLE_OPTIMIZE_LAYER_TREE || Before starting to render a tree of layers, Synfig makes an optimized copy of the layer tree, omitting any layers that currently have an amount of 0.  The aim is to make the render go faster, but it may introduce some instability into the application.  Set this variable to disable the optimization step.&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
In older versions of studio, the polygon, draw, and sketch tools were disabled by default.  The following can be used to re-enable &amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;export SYNFIG_ENABLE_POLYGON=1&amp;lt;br&amp;gt;&lt;br /&gt;
export SYNFIG_ENABLE_DRAW=1&amp;lt;br&amp;gt;&lt;br /&gt;
export SYNFIG_ENABLE_SKETCH=1&amp;lt;br&amp;gt;&lt;br /&gt;
export SYNFIG_ENABLE_WIDTH=1&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Suggested starting values to try when attempting to line up the timetrack and parameter panels:&amp;lt;br&amp;gt;&lt;br /&gt;
&amp;lt;code&amp;gt;export SYNFIG_TIMETRACK_ROW_HEIGHT=21&amp;lt;br&amp;gt;&lt;br /&gt;
export SYNFIG_TIMETRACK_HEADER_HEIGHT=25&amp;lt;/code&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Beginning with SVN version r1127&amp;lt;br&amp;gt;&lt;br /&gt;
Addressing bug 1829182: the popup caret menu has been disabled for several&lt;br /&gt;
tools. There's no comment in the code saying why. Dooglus has added an environment variable which re-enables the popup menu when set. Export&lt;br /&gt;
SYNFIG_ENABLE_POPUP_MENU_IN_ALL_TOOLS=1 to try it, and report your findings back&lt;br /&gt;
to the bug report as to whether this should be the default or not.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Build_Instructions&amp;diff=8141</id>
		<title>Dev:Build Instructions</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Build_Instructions&amp;diff=8141"/>
				<updated>2008-11-07T22:44:15Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* synfig */ mention the libtool incompatibility&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Building]]&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
If you are using the released versions instead of SVN, none of the libtoolize or autoreconf steps are necessary. For released versions, &amp;quot;./configure &amp;amp;&amp;amp; make &amp;amp;&amp;amp; sudo make install&amp;quot; should be enough.&lt;br /&gt;
&lt;br /&gt;
If you are using packages for synfig's dependencies, you want the '''development packages''' not the main packages. Check below for your distribution's packages.&lt;br /&gt;
&lt;br /&gt;
Please read the [[Source code|source code]] page to check out the latest code. Please also check the [[Download|download page]] and the [[FAQ]] to find out about any issues that you may run into along the way.&lt;br /&gt;
&lt;br /&gt;
Some Linux/BSD distros have a pkg-config that doesn't look in /usr/local/lib/pkgconfig by default. So if you are installing in anywhere other than the system pkg-config path, please run &amp;quot;export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig&amp;quot; or similar before building or installing anything.&lt;br /&gt;
&lt;br /&gt;
Don't use automake 1.4, there are problems with it.&lt;br /&gt;
&lt;br /&gt;
Using automake 1.9, 'make install' seems to re-link and re-install all the synfig core modules every time whether they have changed or not.  [http://dooglus.rincevent.net/synfig/automake.html here] is an ugly workaround - it's only worth using if you intend to rebuild synfig repeatedly&lt;br /&gt;
&lt;br /&gt;
The instructions below result in 3 separate subversion working directories being created.  This is inconvenient to work with - you'll need to 'svn commit' in 3 different places to send changes, 'svn update' in 3 different places to get the latest updates, etc.  [[Subversion|This page]] shows how to arrange for the code to be checked out into a single working directory. You can also download a daily updated tarball that uses this from the [[Source code|source code]] page.&lt;br /&gt;
&lt;br /&gt;
The CVS requirement is only because the autopoint program run by autoreconf needs CVS. You can avoid the need for CVS by disabling the translation/gettext stuff in configure.ac.&lt;br /&gt;
&lt;br /&gt;
If you don't want to install to a system-wide directory using sudo, run something like these commands before starting:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PREFIX=&amp;quot;$HOME/opt&amp;quot;&lt;br /&gt;
export PKG_CONFIG_PATH=&amp;quot;$PKG_CONFIG_PATH:$PREFIX/lib/pkgconfig&amp;quot;&lt;br /&gt;
export PATH=&amp;quot;$PATH:$PREFIX/bin&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And when you run ./configure, run it with --prefix=&amp;quot;$PREFIX&amp;quot; and don't use sudo when you do make install.&lt;br /&gt;
&lt;br /&gt;
=== Automatic build/update script ===&lt;br /&gt;
&lt;br /&gt;
You can use [http://zelgadis.profusehost.net/files/synfig/synfigstudio-svn-build this] script to quickly build/update synfigstudio from SVN (software installed in ~/synfig-svn by default).&lt;br /&gt;
&lt;br /&gt;
To use the script just execute following single command in terminal: &lt;br /&gt;
&amp;lt;pre&amp;gt;cd &amp;amp;&amp;amp; \&lt;br /&gt;
wget http://zelgadis.profusehost.net/files/synfig/synfigstudio-svn-build &amp;amp;&amp;amp; \&lt;br /&gt;
chmod +x synfigstudio-svn-build &amp;amp;&amp;amp; \&lt;br /&gt;
./synfigstudio-svn-build initialize&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Your system must satisfy synfig's build requiments, the sript won't do it for you.&lt;br /&gt;
&lt;br /&gt;
=== System-specific instructions ===&lt;br /&gt;
&lt;br /&gt;
* Gentoo: SVN [[Gentoo Ebuilds|ebuilds]] are available&lt;br /&gt;
* MacOS X: [[Building_On_Mac_OS_X|instructions for building]] with the GTK+ Aqua port are available.&lt;br /&gt;
* Windows: [[Windows build instructions|instructions for building]] in [[Mingw_installation|mingw]] are available.&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
&lt;br /&gt;
ETL is a template library, there is nothing to build really, it just needed to be installed.&lt;br /&gt;
&lt;br /&gt;
Requires: autoconf automake&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: build-essential autoconf automake&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''ETL:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== synfig ==&lt;br /&gt;
&lt;br /&gt;
Requires: ETL, libxml++, libsigc++, libltdl, libtool, gettext, cvs&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: etl-dev libxml++2.6-dev libsigc++-2.0-dev libltdl3-dev libtool gettext cvs&lt;br /&gt;
* Gentoo: virtual/ETL dev-cpp/libxmlpp dev-libs/libsigc++ dev-util/cvs&lt;br /&gt;
** If you are using ./configure --prefix=&amp;quot;$PREFIX&amp;quot; to configure synfig, do not install virtual/ETL.&lt;br /&gt;
&lt;br /&gt;
Note: libpng isn't required to build synfig, but if you build synfig without PNG support and go on to build synfigstudio, that step will fail (because the build process for synfigstudio uses synfig to create .png icon files).  The package is  libpng12-dev on Debian or media-libs/libpng on Gentoo.&lt;br /&gt;
&lt;br /&gt;
Note: the 'configure.ac' file in the synfig-core directory doesn't work with libtool version 2, as shipped with ubuntu 8.10.  To work around the problem until a proper fix is found, comment out line 622 (it says &amp;quot;AC_CONFIG_SUBDIRS(libltdl)&amp;quot;) by putting a &amp;quot;#&amp;quot; at the front of the line.  The line is required for older versions of libtool, as shipped with other distributions.&lt;br /&gt;
&lt;br /&gt;
Optional: libpng, libmng, libjpeg, libfreetype, libfontconfig, libopenexr, libavcodec, libmagick++, vimage (MacOS only, proprietary)&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: libpng12-dev libmng-dev libjpeg62-dev libfreetype6-dev libfontconfig1-dev libopenexr-dev libavcodec-dev libavformat-dev libmagick++9-dev&lt;br /&gt;
* Gentoo: sys-devel/libtool media-libs/libpng media-libs/libmng media-libs/jpeg media-libs/freetype media-libs/fontconfig media-libs/openexr media-libs/libavcodec&lt;br /&gt;
Runtime: encodedv (from libdv), ffmpeg, convert (from imagemagick)&lt;br /&gt;
* Debian: libdv-bin ffmpeg imagemagick&lt;br /&gt;
* Gentoo: media-libs/libdv media-video/ffmpeg media-gfx/imagemagick&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''synfig-core:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ libtoolize --ltdl --copy --force&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ make&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Don't use --enable-half, it is slow.&lt;br /&gt;
&lt;br /&gt;
== synfigstudio ==&lt;br /&gt;
&lt;br /&gt;
Requires: ETL, synfig, gtkmm &amp;gt;= 2.4, gtk &amp;gt;= 2.0, glibmm, libsigc++, libltdl, libtool, gettext, cvs&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: etl-dev libsynfig-dev libgtkmm-2.4-dev libgtk2.0-dev libglibmm-2.4-dev libsigc++-2.0-dev libltdl3-dev libtool gettext cvs&lt;br /&gt;
* Gentoo: virtual/ETL virtual/synfig dev-cpp/gtkmm-2.4 dev-libs/libsigc++ sys-devel/libtool&lt;br /&gt;
** If you are using ./configure --prefix=&amp;quot;$PREFIX&amp;quot; to configure synfigstudio, do not install virtual/ETL or virtual/synfig.&lt;br /&gt;
Optional: fonts (for the images), [http://www.fmod.org FMOD] (version 3.x, proprietary)&lt;br /&gt;
* Debian: ttf-freefont ttf-dejavu ttf-dustin&lt;br /&gt;
* Gentoo: freefonts dejavu&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''synfig-studio:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ make&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
== synfig-docs ==&lt;br /&gt;
&lt;br /&gt;
(This step isn't required to run synfig or synfigstudio, and the documents it gets you are really quite out of date)&lt;br /&gt;
&lt;br /&gt;
This is basically a copy of what is on this wiki.&lt;br /&gt;
&lt;br /&gt;
Requires: sgml processor, ldp docbook stylesheets, db2ps, db2pdf&lt;br /&gt;
* Debian: openjade ldp-docbook-dsssl docbook-utils&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make multiple-html&lt;br /&gt;
make ps&lt;br /&gt;
make pdf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== finalizing ==&lt;br /&gt;
&lt;br /&gt;
Depending on where you installed synfig to, you might have to tell your system where the libraries can be found.  That can be done via the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ sudo ldconfig&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Build_Instructions&amp;diff=8135</id>
		<title>Dev:Build Instructions</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Build_Instructions&amp;diff=8135"/>
				<updated>2008-11-05T21:53:05Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Notes */ &amp;quot;the first three steps&amp;quot; probably dates back to &amp;quot;bootstrap&amp;quot; times?  if not, which 3 steps does it mean?&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;!--Categories--&amp;gt;&lt;br /&gt;
[[Category:Building]]&lt;br /&gt;
&lt;br /&gt;
== Notes ==&lt;br /&gt;
&lt;br /&gt;
If you are using the released versions instead of SVN, none of the libtoolize or autoreconf steps are necessary. For released versions, &amp;quot;./configure &amp;amp;&amp;amp; make &amp;amp;&amp;amp; sudo make install&amp;quot; should be enough.&lt;br /&gt;
&lt;br /&gt;
If you are using packages for synfig's dependencies, you want the '''development packages''' not the main packages. Check below for your distribution's packages.&lt;br /&gt;
&lt;br /&gt;
Please read the [[Source code|source code]] page to check out the latest code. Please also check the [[Download|download page]] and the [[FAQ]] to find out about any issues that you may run into along the way.&lt;br /&gt;
&lt;br /&gt;
Some Linux/BSD distros have a pkg-config that doesn't look in /usr/local/lib/pkgconfig by default. So if you are installing in anywhere other than the system pkg-config path, please run &amp;quot;export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig&amp;quot; or similar before building or installing anything.&lt;br /&gt;
&lt;br /&gt;
Don't use automake 1.4, there are problems with it.&lt;br /&gt;
&lt;br /&gt;
Using automake 1.9, 'make install' seems to re-link and re-install all the synfig core modules every time whether they have changed or not.  [http://dooglus.rincevent.net/synfig/automake.html here] is an ugly workaround - it's only worth using if you intend to rebuild synfig repeatedly&lt;br /&gt;
&lt;br /&gt;
The instructions below result in 3 separate subversion working directories being created.  This is inconvenient to work with - you'll need to 'svn commit' in 3 different places to send changes, 'svn update' in 3 different places to get the latest updates, etc.  [[Subversion|This page]] shows how to arrange for the code to be checked out into a single working directory. You can also download a daily updated tarball that uses this from the [[Source code|source code]] page.&lt;br /&gt;
&lt;br /&gt;
The CVS requirement is only because the autopoint program run by autoreconf needs CVS. You can avoid the need for CVS by disabling the translation/gettext stuff in configure.ac.&lt;br /&gt;
&lt;br /&gt;
If you don't want to install to a system-wide directory using sudo, run something like these commands before starting:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
export PREFIX=&amp;quot;$HOME/opt&amp;quot;&lt;br /&gt;
export PKG_CONFIG_PATH=&amp;quot;$PKG_CONFIG_PATH:$PREFIX/lib/pkgconfig&amp;quot;&lt;br /&gt;
export PATH=&amp;quot;$PATH:$PREFIX/bin&amp;quot;&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
And when you run ./configure, run it with --prefix=&amp;quot;$PREFIX&amp;quot; and don't use sudo when you do make install.&lt;br /&gt;
&lt;br /&gt;
=== Automatic build/update script ===&lt;br /&gt;
&lt;br /&gt;
You can use [http://zelgadis.profusehost.net/files/synfig/synfigstudio-svn-build this] script to quickly build/update synfigstudio from SVN (software installed in ~/synfig-svn by default).&lt;br /&gt;
&lt;br /&gt;
To use the script just execute following single command in terminal: &lt;br /&gt;
&amp;lt;pre&amp;gt;cd &amp;amp;&amp;amp; \&lt;br /&gt;
wget http://zelgadis.profusehost.net/files/synfig/synfigstudio-svn-build &amp;amp;&amp;amp; \&lt;br /&gt;
chmod +x synfigstudio-svn-build &amp;amp;&amp;amp; \&lt;br /&gt;
./synfigstudio-svn-build initialize&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
'''WARNING:''' Your system must satisfy synfig's build requiments, the sript won't do it for you.&lt;br /&gt;
&lt;br /&gt;
=== System-specific instructions ===&lt;br /&gt;
&lt;br /&gt;
* Gentoo: SVN [[Gentoo Ebuilds|ebuilds]] are available&lt;br /&gt;
* MacOS X: [[Building_On_Mac_OS_X|instructions for building]] with the GTK+ Aqua port are available.&lt;br /&gt;
* Windows: [[Windows build instructions|instructions for building]] in [[Mingw_installation|mingw]] are available.&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
&lt;br /&gt;
ETL is a template library, there is nothing to build really, it just needed to be installed.&lt;br /&gt;
&lt;br /&gt;
Requires: autoconf automake&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: build-essential autoconf automake&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''ETL:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== synfig ==&lt;br /&gt;
&lt;br /&gt;
Requires: ETL, libxml++, libsigc++, libltdl, libtool, gettext, cvs&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: etl-dev libxml++2.6-dev libsigc++-2.0-dev libltdl3-dev libtool gettext cvs&lt;br /&gt;
* Gentoo: virtual/ETL dev-cpp/libxmlpp dev-libs/libsigc++ dev-util/cvs&lt;br /&gt;
** If you are using ./configure --prefix=&amp;quot;$PREFIX&amp;quot; to configure synfig, do not install virtual/ETL.&lt;br /&gt;
&lt;br /&gt;
Note: libpng isn't required to build synfig, but if you build synfig without PNG support and go on to build synfigstudio, that step will fail (because the build process for synfigstudio uses synfig to create .png icon files).  The package is  libpng12-dev on Debian or media-libs/libpng on Gentoo.&lt;br /&gt;
&lt;br /&gt;
Optional: libpng, libmng, libjpeg, libfreetype, libfontconfig, libopenexr, libavcodec, libmagick++, vimage (MacOS only, proprietary)&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: libpng12-dev libmng-dev libjpeg62-dev libfreetype6-dev libfontconfig1-dev libopenexr-dev libavcodec-dev libavformat-dev libmagick++9-dev&lt;br /&gt;
* Gentoo: sys-devel/libtool media-libs/libpng media-libs/libmng media-libs/jpeg media-libs/freetype media-libs/fontconfig media-libs/openexr media-libs/libavcodec&lt;br /&gt;
Runtime: encodedv (from libdv), ffmpeg, convert (from imagemagick)&lt;br /&gt;
* Debian: libdv-bin ffmpeg imagemagick&lt;br /&gt;
* Gentoo: media-libs/libdv media-video/ffmpeg media-gfx/imagemagick&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''synfig-core:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ libtoolize --ltdl --copy --force&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ make&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Notes:&lt;br /&gt;
&lt;br /&gt;
* Don't use --enable-half, it is slow.&lt;br /&gt;
&lt;br /&gt;
== synfigstudio ==&lt;br /&gt;
&lt;br /&gt;
Requires: ETL, synfig, gtkmm &amp;gt;= 2.4, gtk &amp;gt;= 2.0, glibmm, libsigc++, libltdl, libtool, gettext, cvs&amp;lt;br&amp;gt;&lt;br /&gt;
* Debian: etl-dev libsynfig-dev libgtkmm-2.4-dev libgtk2.0-dev libglibmm-2.4-dev libsigc++-2.0-dev libltdl3-dev libtool gettext cvs&lt;br /&gt;
* Gentoo: virtual/ETL virtual/synfig dev-cpp/gtkmm-2.4 dev-libs/libsigc++ sys-devel/libtool&lt;br /&gt;
** If you are using ./configure --prefix=&amp;quot;$PREFIX&amp;quot; to configure synfigstudio, do not install virtual/ETL or virtual/synfig.&lt;br /&gt;
Optional: fonts (for the images), [http://www.fmod.org FMOD] (version 3.x, proprietary)&lt;br /&gt;
* Debian: ttf-freefont ttf-dejavu ttf-dustin&lt;br /&gt;
* Gentoo: freefonts dejavu&lt;br /&gt;
&lt;br /&gt;
''Type the following commands at the directory that holds '''synfig-studio:'''''&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ autoreconf --install --force&lt;br /&gt;
$ ./configure&lt;br /&gt;
$ make&lt;br /&gt;
$ sudo make install&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;!--&lt;br /&gt;
&lt;br /&gt;
== synfig-docs ==&lt;br /&gt;
&lt;br /&gt;
(This step isn't required to run synfig or synfigstudio, and the documents it gets you are really quite out of date)&lt;br /&gt;
&lt;br /&gt;
This is basically a copy of what is on this wiki.&lt;br /&gt;
&lt;br /&gt;
Requires: sgml processor, ldp docbook stylesheets, db2ps, db2pdf&lt;br /&gt;
* Debian: openjade ldp-docbook-dsssl docbook-utils&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
make multiple-html&lt;br /&gt;
make ps&lt;br /&gt;
make pdf&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
&lt;br /&gt;
--&amp;gt;&lt;br /&gt;
&lt;br /&gt;
== finalizing ==&lt;br /&gt;
&lt;br /&gt;
Depending on where you installed synfig to, you might have to tell your system where the libraries can be found.  That can be done via the following command:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
$ sudo ldconfig&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7967</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7967"/>
				<updated>2008-10-08T19:29:27Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Curves Panel */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when creating a new one. Environment variable SYNFIG_TOOLS_CLEAR_SELECTION toggles this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string from an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string from an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string from a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string from a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now uses pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to the Communication page on the website being renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
The size of the foreground color and background color picker has been modified to allow the display of the reverse FG and BG colors and set FG and BG colors buttons properly in all GTK themes. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show an incorrect error message when selecting a filename or canvas parameter.  The error message was due these types not being representable in the Curves panel, but this isn't an error. [http://sf.net/support/tracker.php?aid=2060732 2060732]&lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7966</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7966"/>
				<updated>2008-10-08T19:25:31Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Toolbox Window */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when creating a new one. Environment variable SYNFIG_TOOLS_CLEAR_SELECTION toggles this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string from an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string from an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string from a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string from a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now uses pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to the Communication page on the website being renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
The size of the foreground color and background color picker has been modified to allow the display of the reverse FG and BG colors and set FG and BG colors buttons properly in all GTK themes. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show incorrect error message when selecting a filename or canvas parameter due the parameter is not representable in the Curves panel. [http://sf.net/support/tracker.php?aid=2060732 2060732] &lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7965</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7965"/>
				<updated>2008-10-08T19:22:54Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Files */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when creating a new one. Environment variable SYNFIG_TOOLS_CLEAR_SELECTION toggles this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string from an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string from an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string from a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string from a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now uses pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to the Communication page on the website being renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
Sizes of foreground color and background color picker has been modified to allow some GTK themes show the reverse FG and BG colors and set FG and BG colors buttons properly. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show incorrect error message when selecting a filename or canvas parameter due the parameter is not representable in the Curves panel. [http://sf.net/support/tracker.php?aid=2060732 2060732] &lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7964</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7964"/>
				<updated>2008-10-08T19:21:53Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Targets */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when creating a new one. Environment variable SYNFIG_TOOLS_CLEAR_SELECTION toggles this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string from an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string from an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string from a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string from a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now uses pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to Communication page on the website was renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
Sizes of foreground color and background color picker has been modified to allow some GTK themes show the reverse FG and BG colors and set FG and BG colors buttons properly. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show incorrect error message when selecting a filename or canvas parameter due the parameter is not representable in the Curves panel. [http://sf.net/support/tracker.php?aid=2060732 2060732] &lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7963</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7963"/>
				<updated>2008-10-08T19:18:12Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Value Nodes */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when creating a new one. Environment variable SYNFIG_TOOLS_CLEAR_SELECTION toggles this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string from an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string from an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string from a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string from a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now use pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to Communication page on the website was renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
Sizes of foreground color and background color picker has been modified to allow some GTK themes show the reverse FG and BG colors and set FG and BG colors buttons properly. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show incorrect error message when selecting a filename or canvas parameter due the parameter is not representable in the Curves panel. [http://sf.net/support/tracker.php?aid=2060732 2060732] &lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7962</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7962"/>
				<updated>2008-10-08T19:17:12Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Layers */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when creating a new one. Environment variable SYNFIG_TOOLS_CLEAR_SELECTION toggles this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string form an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string form an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string form a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string form a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now use pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to Communication page on the website was renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
Sizes of foreground color and background color picker has been modified to allow some GTK themes show the reverse FG and BG colors and set FG and BG colors buttons properly. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show incorrect error message when selecting a filename or canvas parameter due the parameter is not representable in the Curves panel. [http://sf.net/support/tracker.php?aid=2060732 2060732] &lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7961</id>
		<title>Releases/0.61.09</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Releases/0.61.09&amp;diff=7961"/>
				<updated>2008-10-08T19:15:24Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* General */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Released October XX 2008&lt;br /&gt;
&lt;br /&gt;
== General ==&lt;br /&gt;
* Forum use nows phpBB3.&lt;br /&gt;
* We have migrated from the Voria server to a new VPS server. &lt;br /&gt;
* We moved our subversion repository to sourceforge &lt;br /&gt;
* We are testing Review Board for patches in synfig. http://patches.synfig.org/&lt;br /&gt;
&lt;br /&gt;
== ETL ==&lt;br /&gt;
* Improved the derivative class for hermites.&lt;br /&gt;
&lt;br /&gt;
== Layers ==&lt;br /&gt;
* Don't let feather be negative for any Shape layers or Circle layers.&lt;br /&gt;
* Fix handling of segments so that the examples/walk/walk.sifz file will load correctly.&lt;br /&gt;
* Use 0 for the index if the closest point is on the segment which closes the loop.  This keeps the final 'amount' value in the range 0..1.&lt;br /&gt;
* Fix a bug in the plant layer: when the plant is so small that we can't calculate the perpendicular to its bline, skip trying to branch it.&lt;br /&gt;
* Improve a warning message when we find an unknown layer parameter.&lt;br /&gt;
* Rename all 'pos' and 'offset' parameters to 'origin'.&lt;br /&gt;
* Add parameter 'add_width' to the [[Plant Layer|plant layer]].  It's on by default, and means to scale the velocity of a plant's shoot by the width of the bline at that point.&lt;br /&gt;
* Now circles with large feather and zero radius are visible.  Only shortcut zero-radius circles if they're not inverted and have no feathering. [http://sf.net/support/tracker.php?aid=2120629 2120629]&lt;br /&gt;
* Leave previously selected layers selected when create a new one. SYNFIG_TOOLS_CLEAR_SELECTION toggle this option.&lt;br /&gt;
* Add &amp;quot;select all layers&amp;quot; (S-C-a) and &amp;quot;unselect all ducks&amp;quot; (C-d).  Move &amp;quot;unselect all layers&amp;quot; onto S-C-d.&lt;br /&gt;
* When multiple layers are selected, only show parameters which are present in all selected layers *with the same type*.&lt;br /&gt;
&lt;br /&gt;
== Value Nodes ==&lt;br /&gt;
*Add new types:&lt;br /&gt;
** [[Convert#Logarithm|Logarithm]]: To convert to a natural logarithm&lt;br /&gt;
** [[Convert#Int String|Int String]]: To convert to a string form an integer&lt;br /&gt;
** [[Convert#Angle String|Angle String]] : To convert to a string form an angle&lt;br /&gt;
** [[Convert#Joined List|Joined List]]: Join two strings&lt;br /&gt;
** [[Convert#Real String|Real String]]: To convert to a string form a real&lt;br /&gt;
** [[Convert#Time String|Time String]]: To convert to a string form a time&lt;br /&gt;
** [[Convert#Dot Product|Dot Product]]: Convert to a real from the dot product of two vectors&lt;br /&gt;
** [[Convert#Gradient Color|Gradient Color]]: Convert to a color from a gradient &lt;br /&gt;
** [[Convert#Vector X|Vector X]]: Convert to a real from a vector (get its X)&lt;br /&gt;
** [[Convert#Vector Y|Vector Y]]: Convert to a real from a vector (get its Y)&lt;br /&gt;
** [[Convert#Vector Length|Vector Length]]: Convert to a real from a vector (get its length)&lt;br /&gt;
** [[Convert#Vector Angle|Vector Angle]]: Convert to an angle from a vector (get its angle)&lt;br /&gt;
* Add &amp;quot;Loop&amp;quot; link to the &amp;quot;Gradient Color&amp;quot; ValueNode.&lt;br /&gt;
&lt;br /&gt;
== Targets ==&lt;br /&gt;
* Unless OpenEXR half mode is used, don't ask synfigstudio to depend on it.&lt;br /&gt;
* Fix build problem with newer versions of libavformat due to the pb member of AVFormatContext changing from a structure to a pointer. [http://sf.net/support/tracker.php?aid=11877061 11877061]&lt;br /&gt;
* Fix Debian 487639: for mod_libav, allow the use of libswscale instead of the depreciated img_convert function. Apply [http://sf.net/support/tracker.php?aid=2036627 2036627]&lt;br /&gt;
* Fix the libjpeg configure test to look for the right function.&lt;br /&gt;
* Windows builds now include OpenEXR version 1.6.&lt;br /&gt;
* Configure now use pkg-config to find libswscale. [http://sf.net/support/tracker.php?aid=2108984 2108984]&lt;br /&gt;
* Cope with some changes in the locations of the libavformat and libswscale headers.&lt;br /&gt;
* Add a configure flag to switch on/off jpeg support. Apply [http://patches.synfig.org/r/5/ 5]&lt;br /&gt;
&lt;br /&gt;
== Blend Methods ==&lt;br /&gt;
* Fix this bug: when a layer was composed 'straight onto' a context with which its bounding box had no overlap, the context was being displayed as if the 'straight onto' layer wasn't there. [http://sf.net/support/tracker.php?aid=1960543 1960543]&lt;br /&gt;
&lt;br /&gt;
== Canvases ==&lt;br /&gt;
* To allow backward compatibility, canvas version has been set to 0.6.&lt;br /&gt;
&lt;br /&gt;
== Files ==&lt;br /&gt;
* In the 'open &amp;gt; recent files' menu entry, only show files which still exist.  Previously, it was saving documents into /tmp. After rebooting /tmp had been emptied, but the files were still showing up in the menu.&lt;br /&gt;
* Modified the Help menu due to Communication page on the website was renamed to Contact.&lt;br /&gt;
* Fix error when trying to change value of Filename property. [http://sf.net/support/tracker.php?aid=1988939 1988939]&lt;br /&gt;
&lt;br /&gt;
== Settings ==&lt;br /&gt;
* Added a new tab in the [[Setup Dialog|Setup Dialog]] to allow user set the preferences for: X and Y sizes for new documents, the new Document filename prefix and a selector for predefined resolutions.&lt;br /&gt;
&lt;br /&gt;
== Linking == &lt;br /&gt;
Added new feature [[Linking to Blines| Link to Bline]]: allow the user link vertexes, tangents and widths to a parametrized position of a bline. Also inverse manipulation is allowed. This makes easier to build complex figures without need to have a vertex on the joining point.&lt;br /&gt;
&lt;br /&gt;
== Waypoints ==&lt;br /&gt;
* [[TCB|TENSION and TEMPORAL TENSION]] were the same; use the 'temporal' version everywhere.&lt;br /&gt;
* Don't render waypoints that lie outside the bounds of the timetrack's adjustment. [http://sf.net/support/tracker.php?aid=1888863 1888863]&lt;br /&gt;
* Don't offer 'Manual' as an interpolation type.  It's not clear what it is supposed to do, and looks like the code to implement it was never written.  Attempting to use it causes uninitialized memory to be read.&lt;br /&gt;
&lt;br /&gt;
== Time ==&lt;br /&gt;
*  Fix bad time entry when format is set to FFf. Apply [http://patches.synfig.org/r/4/ 4]&lt;br /&gt;
* Show time 3.0 as &amp;quot;3s&amp;quot; in the default (FORMAT_NORMAL) time display mode, rather than sometimes showing &amp;quot;3s 0f&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
== Windows ==&lt;br /&gt;
=== Console Window ===&lt;br /&gt;
* Make the file selector dialogs print less output to the console.&lt;br /&gt;
* Show the 'fifo_activity' message less.&lt;br /&gt;
* Show commands as they are received over the FIFO.&lt;br /&gt;
* Don't show debugging messages about saving preference directories.&lt;br /&gt;
&lt;br /&gt;
=== Toolbox Window ===&lt;br /&gt;
* Add new icon for the reset colors button and change the code to use it.&lt;br /&gt;
Sizes of foreground color and background color picker has been modified to allow some GTK themes show the reverse FG and BG colors and set FG and BG colors buttons properly. Apply [http://patches.synfig.org/r/2/ 2]&lt;br /&gt;
&lt;br /&gt;
=== Workarea Window ===&lt;br /&gt;
* Fix zoom fit so it really does zoom the canvas to fit the window. [http://sf.net/support/tracker.php?aid=1901244 1901244]&lt;br /&gt;
* Show a 'zoom to fit' icon in the zoomdial as well as a 'zoom 100%' icon.&lt;br /&gt;
* Fix &amp;quot;zoom to fit&amp;quot; so that it centers the fitted canvas on the screen, and always zooms back to the previous zoom level and position if clicked a second time.&lt;br /&gt;
&lt;br /&gt;
=== Canvas Properties Dialog ===&lt;br /&gt;
* When calculating the start and end frames, round to the nearest integer rather than always rounding down.&lt;br /&gt;
* Editing the name, description, or id of a canvas should mark the canvas as needing to be saved, and should also be undoable. [http://sf.net/support/tracker.php?aid=1924592 1924592]&lt;br /&gt;
&lt;br /&gt;
=== Color Editor Dialog ===&lt;br /&gt;
* Allow clicking or scrolling on colour sliders to change the colour.&lt;br /&gt;
&lt;br /&gt;
=== Gradient Editor Dialog ===&lt;br /&gt;
* Properly manage the situation when all CPoints of a gradient are removed. [http://sf.net/support/tracker.php?aid=2096641 2096641]&lt;br /&gt;
&lt;br /&gt;
=== Time Track Panel ===&lt;br /&gt;
* Update the timeline scrollbars' major step size when zooming time in and out. [http://sf.net/support/tracker.php?aid=1914874 1914874]&lt;br /&gt;
* Allow scrolling left and right in time widgets.&lt;br /&gt;
* Fix a bug that was causing the time slider to not be displayed in certain circumstances.&lt;br /&gt;
&lt;br /&gt;
=== Curves Panel ===&lt;br /&gt;
* Don't show incorrect error message when selecting a filename or canvas parameter due the parameter is not representable in the Curves panel. [http://sf.net/support/tracker.php?aid=2060732 2060732] &lt;br /&gt;
&lt;br /&gt;
=== Splash Screen ===&lt;br /&gt;
* Remove the build information and use a new image by Yaco &amp;amp; Genete &lt;br /&gt;
&lt;br /&gt;
== Tools ==&lt;br /&gt;
* Text, Plant, Polyline and Star have new icons.&lt;br /&gt;
* [[Circle Tool|Circle tool]] allows now make Blined circles too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* [[ Rectangle Tool|Rectangle tool]] now does the same. &lt;br /&gt;
* New [[Text Tool| Text tool]] has been added to the [[Toolbox|ToolBox]]. &lt;br /&gt;
* New [[Star Tool|Star Tool]] has been added to the tool palette. It allows now make blined stars too. Regions, Outlines, Gradients and Plants are included.&lt;br /&gt;
* Now [[Eyedrop Tool|eyedropper]] works correctly with straight blends for all types of layers. [http://sf.net/support/tracker.php?aid=2119764 2119764]&lt;br /&gt;
* The &amp;quot;Link Offsets&amp;quot; option in the [[BLine Tool|BLine tool]] now only links offsets if we're creating more than one layer at a time.&lt;br /&gt;
* Added options to the circle tool for creation of bline approximations to circles. Number of points and points angle offset.&lt;br /&gt;
* Use the 'feather' and 'invert' tool options when creating outline or region layers in the circle tool.&lt;br /&gt;
* Remove the &amp;quot;blend method&amp;quot; option from the tool options panel for the circle and gradient tools (unless the BLEND_METHOD_IN_TOOL_OPTIONS #define in toolbox.h is uncommented).&lt;br /&gt;
* Add 'inner tangent', 'outer tangent' and 'radius ratio' options to the star tool for creating rounded stars and different ratios stars.&lt;br /&gt;
* Show the name of the current tool in the tool options panel if it has any options.  For the zoom tool, show the message that it doesn't have any options, instead of just showing a blank panel.&lt;br /&gt;
* Replace &amp;quot;Gradient&amp;quot; check button with &amp;quot;Create Gradient BLine&amp;quot;, etc., like in the other tools.&lt;br /&gt;
* Using the Circle tool over an existing duck now doesn't crash. [http://sf.net/support/tracker.php?aid=1959064 1959064]&lt;br /&gt;
&lt;br /&gt;
== Ducks ==&lt;br /&gt;
* Fixed infinite error message loop on split tangents. [http://sf.net/support/tracker.php?aid=1947076 1947076]&lt;br /&gt;
&lt;br /&gt;
== Miscellaneous ==&lt;br /&gt;
* Improve Segment Tangent and Bline Tangent calculations. Now they give more accurate results.&lt;br /&gt;
* If only one of -w and -h is specified on the command line, calculate the other in order to keep the aspect ratio fixed.&lt;br /&gt;
* Check for Gtk::AboutDialog::set_wrap_license, which was added in Gtkmm 2.8. Allows synfigstudio to build on the fink distribution.&lt;br /&gt;
* Update configure.ac as suggested by autoupdate.&lt;br /&gt;
* Improved GUI for the sound file selection dialog. [http://sf.net/support/tracker.php?aid=1932525 1932525]&lt;br /&gt;
* Alt-D = draw, Alt-W = width.  Previously there were 2 different definitions for Alt-T.&lt;br /&gt;
* More strings has been extracted to be marked as translatable. Spanish, French and Catalan translations Updated.&lt;br /&gt;
* Add multiple sizes and a scalable version of synfig_icon installed in freedesktop.org icon directories. [http://sf.net/support/tracker.php?aid=2109095 2109095]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Doc_talk:Gimp2synfig&amp;diff=6978</id>
		<title>Doc talk:Gimp2synfig</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Doc_talk:Gimp2synfig&amp;diff=6978"/>
				<updated>2008-04-26T20:39:09Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;vonhalenbach on IRC was using GIMP 2.2 and Python 2.5.1 and found that his generated sif output was ending after 20 lines:&lt;br /&gt;
&lt;br /&gt;
 19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;&lt;br /&gt;
 20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; yres=&amp;quot;10.000000&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas for me (with Python 2.5.2 and Gimp 2.4.5) it continues:&lt;br /&gt;
&lt;br /&gt;
 19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;&lt;br /&gt;
 20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; yres=&amp;quot;10.000000&amp;quot;&amp;gt;&lt;br /&gt;
 21        &amp;lt;layer type=&amp;quot;import&amp;quot; active=&amp;quot;true&amp;quot; version=&amp;quot;0.1&amp;quot; desc=&amp;quot;Background.png&amp;quot;&amp;gt;&lt;br /&gt;
 22          &amp;lt;param name=&amp;quot;z_depth&amp;quot;&amp;gt;&lt;br /&gt;
 23            [...]&lt;br /&gt;
&lt;br /&gt;
Yes, this script was writen for 2.4.*. I have no 2.2.* to test it. So I'll try to fix this problem if you give me information from gimp-2.2.* console with backtrace. --[[User:AkhIL|AkhIL]] 12:42, 26 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
 $ gimp /tmp/111.xcf&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:428: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   hbox = gtk.HBox(gtk.FALSE, 5)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:430: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   dialog.vbox.pack_start(hbox, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:433: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   table = gtk.Table(len(params), 2, gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:437: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   hbox.pack_end(table, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:440: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   vbox = gtk.VBox(gtk.FALSE, 10)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:441: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   hbox.pack_start(vbox, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:446: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   vbox.pack_start(pix, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:450: GtkDeprecationWarning: gtk.TRUE is deprecated, use True instead&lt;br /&gt;
   label.set_line_wrap(gtk.TRUE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:453: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   vbox.pack_start(label, expand=gtk.FALSE)&lt;br /&gt;
 Traceback (most recent call last):&lt;br /&gt;
   File &amp;quot;/usr/local/lib/gimp/2.0/python/gimpfu.py&amp;quot;, line 469, in response&lt;br /&gt;
     dialog.res = run_script(params)&lt;br /&gt;
   File &amp;quot;/usr/local/lib/gimp/2.0/python/gimpfu.py&amp;quot;, line 257, in run_script&lt;br /&gt;
     return apply(function, params)&lt;br /&gt;
   File &amp;quot;/home/chris/.gimp-2.2/plug-ins/synfigexport.py&amp;quot;, line 248, in python_fu_exportsynfig&lt;br /&gt;
     newlayer = gimp.Layer(newimg, l.name, l.width, l.height, l.type)&lt;br /&gt;
 TypeError: gimp.Layer.__init__() takes exactly 7 arguments (5 given)&lt;br /&gt;
&lt;br /&gt;
http://dooglus.rincevent.net/random/synfigexport.py is a fixed version.  In GIMP 2.2, all the arguments to Layer.__init__ are required, so I specify the opacity and blend method. -- [[User:Dooglus|dooglus]] 16:39, 26 April 2008 (EDT)&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Doc:Gimp2synfig&amp;diff=6977</id>
		<title>Doc:Gimp2synfig</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Doc:Gimp2synfig&amp;diff=6977"/>
				<updated>2008-04-26T20:38:00Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;To simplify the work of animating my cartoon about a mouse, a plug-in for the [http://gimp.org/ GIMP] raster editor has been written to allow the direct exporting of multi-layered images to corresponding layers of the 2D animation package Synfig.&lt;br /&gt;
&lt;br /&gt;
The plug-in registers itself in the GIMP image menu &amp;lt;image&amp;gt;-&amp;gt; File-&amp;gt; Export-&amp;gt; Synfig.&lt;br /&gt;
&lt;br /&gt;
[http://img246.imageshack.us/my.php?image=gimp2synfigmenuxh9.jpg http://img246.imageshack.us/img246/4126/gimp2synfigmenuxh9.th.jpg]&lt;br /&gt;
&lt;br /&gt;
There are export options you can choose. If the field &amp;quot;output path&amp;quot; is empty, the synfig canvas will be kept in the same directory as the initial GIMP document.&lt;br /&gt;
&lt;br /&gt;
[http://img292.imageshack.us/my.php?image=gimp2synfigsettingsvs3.jpg http://img292.imageshack.us/img292/269/gimp2synfigsettingsvs3.th.jpg]&lt;br /&gt;
&lt;br /&gt;
Here is the result:&lt;br /&gt;
&lt;br /&gt;
[http://img201.imageshack.us/my.php?image=gimp2synfig003yn6.jpg http://img201.imageshack.us/img201/9369/gimp2synfig003yn6.th.jpg]&lt;br /&gt;
&lt;br /&gt;
On the left you can see the initial image in Gimp, and on the right the same image imported into Synfig.  &lt;br /&gt;
&lt;br /&gt;
After adding a scale layer, the images cannot be distinguished.&lt;br /&gt;
&lt;br /&gt;
[http://img151.imageshack.us/my.php?image=gimp2synfig003withgammafd6.jpg http://img151.imageshack.us/img151/5450/gimp2synfig003withgammafd6.th.jpg]&lt;br /&gt;
&lt;br /&gt;
You can download the [http://akhil.nm.ru/tools/pygimp/synfigexport.py GIMP2synfig plugin].  Or a [http://dooglus.rincevent.net/random/synfigexport.py fixed version] that also works with GIMP 2.2.&lt;br /&gt;
&lt;br /&gt;
For it to work, GIMP must support Python, and the most recent version of Python must be fully installed. &lt;br /&gt;
&lt;br /&gt;
To install it, simply place the file in ~/.gimp-*/plug-ins/ and make it executable (chmod +x synfigexport.py), then restart The GIMP.&lt;br /&gt;
&lt;br /&gt;
This program is licensed under Creative Commons Attribution 3.0 Unported License. Distribution and updating of the code is welcomed.&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Doc_talk:Gimp2synfig&amp;diff=6975</id>
		<title>Doc talk:Gimp2synfig</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Doc_talk:Gimp2synfig&amp;diff=6975"/>
				<updated>2008-04-26T19:23:25Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;vonhalenbach on IRC was using GIMP 2.2 and Python 2.5.1 and found that his generated sif output was ending after 20 lines:&lt;br /&gt;
&lt;br /&gt;
 19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;&lt;br /&gt;
 20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; yres=&amp;quot;10.000000&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas for me (with Python 2.5.2 and Gimp 2.4.5) it continues:&lt;br /&gt;
&lt;br /&gt;
 19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;&lt;br /&gt;
 20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; yres=&amp;quot;10.000000&amp;quot;&amp;gt;&lt;br /&gt;
 21        &amp;lt;layer type=&amp;quot;import&amp;quot; active=&amp;quot;true&amp;quot; version=&amp;quot;0.1&amp;quot; desc=&amp;quot;Background.png&amp;quot;&amp;gt;&lt;br /&gt;
 22          &amp;lt;param name=&amp;quot;z_depth&amp;quot;&amp;gt;&lt;br /&gt;
 23            [...]&lt;br /&gt;
&lt;br /&gt;
Yes, this script was writen for 2.4.*. I have no 2.2.* to test it. So I'll try to fix this problem if you give me information from gimp-2.2.* console with backtrace. --[[User:AkhIL|AkhIL]] 12:42, 26 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
 $ gimp /tmp/111.xcf&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:428: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   hbox = gtk.HBox(gtk.FALSE, 5)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:430: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   dialog.vbox.pack_start(hbox, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:433: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   table = gtk.Table(len(params), 2, gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:437: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   hbox.pack_end(table, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:440: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   vbox = gtk.VBox(gtk.FALSE, 10)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:441: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   hbox.pack_start(vbox, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:446: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   vbox.pack_start(pix, expand=gtk.FALSE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:450: GtkDeprecationWarning: gtk.TRUE is deprecated, use True instead&lt;br /&gt;
   label.set_line_wrap(gtk.TRUE)&lt;br /&gt;
 /usr/local/lib/gimp/2.0/python/gimpfu.py:453: GtkDeprecationWarning: gtk.FALSE is deprecated, use False instead&lt;br /&gt;
   vbox.pack_start(label, expand=gtk.FALSE)&lt;br /&gt;
 Traceback (most recent call last):&lt;br /&gt;
   File &amp;quot;/usr/local/lib/gimp/2.0/python/gimpfu.py&amp;quot;, line 469, in response&lt;br /&gt;
     dialog.res = run_script(params)&lt;br /&gt;
   File &amp;quot;/usr/local/lib/gimp/2.0/python/gimpfu.py&amp;quot;, line 257, in run_script&lt;br /&gt;
     return apply(function, params)&lt;br /&gt;
   File &amp;quot;/home/chris/.gimp-2.2/plug-ins/synfigexport.py&amp;quot;, line 248, in python_fu_exportsynfig&lt;br /&gt;
     newlayer = gimp.Layer(newimg, l.name, l.width, l.height, l.type)&lt;br /&gt;
 TypeError: gimp.Layer.__init__() takes exactly 7 arguments (5 given)&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Doc_talk:Gimp2synfig&amp;diff=6972</id>
		<title>Doc talk:Gimp2synfig</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Doc_talk:Gimp2synfig&amp;diff=6972"/>
				<updated>2008-04-26T15:03:33Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: New page: vonhalenbach on IRC was using GIMP 2.2 and Python 2.5.1 and found that his generated sif output was ending after 20 lines:   19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;  20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; y...&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;vonhalenbach on IRC was using GIMP 2.2 and Python 2.5.1 and found that his generated sif output was ending after 20 lines:&lt;br /&gt;
&lt;br /&gt;
 19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;&lt;br /&gt;
 20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; yres=&amp;quot;10.000000&amp;quot;&amp;gt;&lt;br /&gt;
&lt;br /&gt;
whereas for me it continues:&lt;br /&gt;
&lt;br /&gt;
 19    &amp;lt;param name=&amp;quot;canvas&amp;quot;&amp;gt;&lt;br /&gt;
 20      &amp;lt;canvas xres=&amp;quot;10.000000&amp;quot; yres=&amp;quot;10.000000&amp;quot;&amp;gt;&lt;br /&gt;
 21        &amp;lt;layer type=&amp;quot;import&amp;quot; active=&amp;quot;true&amp;quot; version=&amp;quot;0.1&amp;quot; desc=&amp;quot;Background.png&amp;quot;&amp;gt;&lt;br /&gt;
 22          &amp;lt;param name=&amp;quot;z_depth&amp;quot;&amp;gt;&lt;br /&gt;
 23            [...]&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Talk:Main_Page&amp;diff=6793</id>
		<title>Talk:Main Page</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Talk:Main_Page&amp;diff=6793"/>
				<updated>2008-04-17T07:01:39Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;== New Layout ==&lt;br /&gt;
&lt;br /&gt;
The new layout does look a lot better, but before deleting the old layout, can we make sure we're not losing any useful links?  For example, currently the &amp;quot;Special:Allpages&amp;quot; link is only in the old layout. -- [[User:Dooglus|dooglus]] 12:27, 26 December 2007 (EST)&lt;br /&gt;
:We can add al that links in the left bar if you think its ok.&lt;br /&gt;
::Yaco&lt;br /&gt;
&lt;br /&gt;
The 0.61.08 download image needs to say &amp;quot;Synfig Animation Studio&amp;quot; instead of &amp;quot;Synfig&amp;quot;&lt;br /&gt;
:[[User:PaulWise|pabs]] 04:27, 6 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
I saw there's a way to remove the toolbox for un-connected people, maybe we could do that, as the links in the toolbox are only usefull to connected persons.&amp;lt;br&amp;gt;&lt;br /&gt;
And then, add the &amp;quot;Sidebar&amp;quot; back to the left side, with much more links in it (like, the ones from the bottom of the main page, that I even removed on the [[Main_Page.fr]]), that would be great. &amp;lt;br&amp;gt;&lt;br /&gt;
And have a &amp;quot;Topbar&amp;quot;  page or just some fixed link for the topbar, with only &amp;quot;Home / About / Download / Gallery / Screenshots / Tutorials / Forums &amp;quot; in a smaller font, and a lighter color (not-visited pages are #2A4D66 on #030336 and they're hardly visible at 1st sight).&lt;br /&gt;
:[[User:Rore|Rore]] 02:49, 7 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Upper image overlaps search bar and user menu on 1024x768 screen resolution. Tested with opera. --[[User:AkhIL|AkhIL]] 22:45, 8 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
There's a thick black nothing between the left hand boxes and the main central page content. -- [[User:Dooglus|dooglus]] 15:31, 11 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
I'd like to see more links in the left hand boxes - at least &amp;quot;all pages&amp;quot; should be there, and things like &amp;quot;people&amp;quot;, &amp;quot;bugs&amp;quot;, &amp;quot;press&amp;quot;, etc from the top would be better at the side.  There are too many links across the top.  We should just have the most useful ones there. -- [[User:Dooglus|dooglus]] 15:31, 11 April 2008 (EDT)&lt;br /&gt;
&lt;br /&gt;
[http://dooglus.rincevent.net/random/mainpage.png] shows some remaining problems:&lt;br /&gt;
* the border of the top image is different widths on the two sides&lt;br /&gt;
* the text links and search box on the right are hidden by the image&lt;br /&gt;
* the image text isn't readable&lt;br /&gt;
* the image text mis-spells &amp;quot;beatiful&amp;quot;&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6789</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6789"/>
				<updated>2008-04-16T17:53:12Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
Section 1, &amp;quot;The Code&amp;quot; will present the entire source, uninterrupted, and section 2, &amp;quot;The Description&amp;quot; will break it up into small chunks and discuss it.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
We need to create two new files (one header (.h) file, and one implementation (.cpp) file), and edit two existing files (the module's main.cpp, and the Makefile.am), all in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define four methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the four methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
Note the &amp;quot;G L O B A L S&amp;quot; section of the code defines the layer's name (lower case, used in .sif files), its &amp;quot;local&amp;quot; name (this is the string which is translated, and is capitalized), which category the layer belongs in (this determines where it appears in the 'new layer' menu), the layer's version (0.1 for new layers), etc.&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Adding Parameters ==&lt;br /&gt;
&lt;br /&gt;
Suppose now we want to add a parameter to the layer.  Let's add a Real valued parameter called &amp;quot;scale&amp;quot;.  It will let the user set a value to scale the saturation by.  It will default to zero, meaning to scale the saturation down to zero.  When adding parameters, it's a good idea to set the default value to its effective previous value, so that old .sif files will continue to be rendered the same as before.&lt;br /&gt;
&lt;br /&gt;
To add this parameter, we need to do the following:&lt;br /&gt;
&lt;br /&gt;
=== desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
In the desaturate.h header file, include real.h (the parameter is Real valued, so we need the typedef for Real):&lt;br /&gt;
&lt;br /&gt;
 #include &amp;lt;synfig/real.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add a private member to the class, type Real:&lt;br /&gt;
&lt;br /&gt;
 private:&lt;br /&gt;
     synfig::Real scale;&lt;br /&gt;
&lt;br /&gt;
Declare a default constructor.  This is where we will set the default value of the new parameter:&lt;br /&gt;
&lt;br /&gt;
     Desaturate();&lt;br /&gt;
&lt;br /&gt;
Declare set_param().  This will allow our layer to accept new values for the parameter:&lt;br /&gt;
&lt;br /&gt;
     virtual bool set_param(const synfig::String&amp;amp;, const synfig::ValueBase&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
=== desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
In the implementation file, we need to:&lt;br /&gt;
&lt;br /&gt;
write a simple default constructor, which initializes the value of 'scale' to zero:&lt;br /&gt;
&lt;br /&gt;
 Desaturate::Desaturate():&lt;br /&gt;
     scale(0)&lt;br /&gt;
 {}&lt;br /&gt;
&lt;br /&gt;
Add a line to supply the value of 'scale' in get_param():&lt;br /&gt;
&lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     EXPORT(scale);&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Add new method set_param():&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::set_param(const String &amp;amp;param, const ValueBase &amp;amp;value)&lt;br /&gt;
 {&lt;br /&gt;
      IMPORT(scale);&lt;br /&gt;
 &lt;br /&gt;
      return false;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Replace the definition of get_param_vocab():&lt;br /&gt;
&lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     Layer::Vocab ret;&lt;br /&gt;
 &lt;br /&gt;
     ret.push_back(ParamDesc(&amp;quot;scale&amp;quot;)&lt;br /&gt;
        .set_local_name(_(&amp;quot;Scale&amp;quot;))&lt;br /&gt;
        .set_description(_(&amp;quot;Factor to scale the saturation by&amp;quot;))&lt;br /&gt;
     );&lt;br /&gt;
 &lt;br /&gt;
     return ret;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
And change the two places where the saturation is set.  In get_color():&lt;br /&gt;
&lt;br /&gt;
     return tmp.set_s(scale * tmp.get_s());&lt;br /&gt;
&lt;br /&gt;
And in accelerated_render():&lt;br /&gt;
&lt;br /&gt;
             pen.put_value(tmp.set_s(scale * tmp.get_s()));&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6786</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6786"/>
				<updated>2008-04-16T17:03:37Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: adding a parameter - wip.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
Section 1, &amp;quot;The Code&amp;quot; will present the entire source, uninterrupted, and section 2, &amp;quot;The Description&amp;quot; will break it up into small chunks and discuss it.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
We need to create two new files (one header (.h) file, and one implementation (.cpp) file), and edit two existing files (the module's main.cpp, and the Makefile.am), all in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define four methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the four methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
Note the &amp;quot;G L O B A L S&amp;quot; section of the code defines the layer's name (lower case, used in .sif files), its &amp;quot;local&amp;quot; name (this is the string which is translated, and is capitalized), which category the layer belongs in (this determines where it appears in the 'new layer' menu), the layer's version (0.1 for new layers), etc.&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== Adding Parameters ==&lt;br /&gt;
&lt;br /&gt;
Suppose now we want to add a parameter to the layer.  Let's add a Real valued parameter called &amp;quot;scale&amp;quot;.  It will let the user set a value to scale the saturation by.  It will default to zero, meaning to scale the saturation down to zero.  When adding parameters, it's a good idea to set the default value to its effective previous value, so that old .sif files will continue to be rendered the same as before.&lt;br /&gt;
&lt;br /&gt;
To add this parameter, we need to do the following:&lt;br /&gt;
&lt;br /&gt;
=== desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
In the desaturate.h header file, include real.h (the parameter is Real valued, so we need the typedef for Real):&lt;br /&gt;
&lt;br /&gt;
 #include &amp;lt;synfig/real.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Add a private member to the class, type Real:&lt;br /&gt;
&lt;br /&gt;
 private:&lt;br /&gt;
     synfig::Real scale;&lt;br /&gt;
&lt;br /&gt;
Declare a default constructor.  This is where we will set the default value of the new parameter:&lt;br /&gt;
&lt;br /&gt;
     Desaturate();&lt;br /&gt;
&lt;br /&gt;
Declare set_param().  This will allow our layer to accept new values for the parameter:&lt;br /&gt;
&lt;br /&gt;
     virtual bool set_param(const synfig::String&amp;amp;, const synfig::ValueBase&amp;amp;);&lt;br /&gt;
&lt;br /&gt;
=== desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
In the implementation file, we need to:&lt;br /&gt;
&lt;br /&gt;
write a simple default constructor, which initializes the value of 'scale' to zero:&lt;br /&gt;
&lt;br /&gt;
 Desaturate::Desaturate():&lt;br /&gt;
     scale(0)&lt;br /&gt;
 {}&lt;br /&gt;
&lt;br /&gt;
&amp;gt;      EXPORT(scale);&lt;br /&gt;
&amp;gt; &lt;br /&gt;
60a67,74&lt;br /&gt;
&amp;gt; bool&lt;br /&gt;
&amp;gt; Desaturate::set_param(const String &amp;amp;param, const ValueBase &amp;amp;value)&lt;br /&gt;
&amp;gt; {&lt;br /&gt;
&amp;gt;      IMPORT(scale);&lt;br /&gt;
&amp;gt; &lt;br /&gt;
&amp;gt;      return false;&lt;br /&gt;
&amp;gt; }&lt;br /&gt;
&amp;gt; &lt;br /&gt;
64c78,85&lt;br /&gt;
&amp;lt;      return Layer::Vocab();&lt;br /&gt;
---&lt;br /&gt;
&amp;gt;      Layer::Vocab ret;&lt;br /&gt;
&amp;gt; &lt;br /&gt;
&amp;gt;      ret.push_back(ParamDesc(&amp;quot;scale&amp;quot;)&lt;br /&gt;
&amp;gt;         .set_local_name(_(&amp;quot;Scale&amp;quot;))&lt;br /&gt;
&amp;gt;         .set_description(_(&amp;quot;Factor to scale the saturation by&amp;quot;))&lt;br /&gt;
&amp;gt;      );&lt;br /&gt;
&amp;gt; &lt;br /&gt;
&amp;gt;      return ret;&lt;br /&gt;
71c92&lt;br /&gt;
&amp;lt;      return tmp.set_s(0);&lt;br /&gt;
---&lt;br /&gt;
&amp;gt;      return tmp.set_s(scale * tmp.get_s());&lt;br /&gt;
95c116&lt;br /&gt;
&amp;lt;              pen.put_value(tmp.set_s(0));&lt;br /&gt;
---&lt;br /&gt;
&amp;gt;              pen.put_value(tmp.set_s(scale * tmp.get_s()));&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6785</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6785"/>
				<updated>2008-04-16T16:27:26Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
Section 1, &amp;quot;The Code&amp;quot; will present the entire source, uninterrupted, and section 2, &amp;quot;The Description&amp;quot; will break it up into small chunks and discuss it.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
We need to create two new files (one header (.h) file, and one implementation (.cpp) file), and edit two existing files (the module's main.cpp, and the Makefile.am), all in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define four methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the four methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
Note the &amp;quot;G L O B A L S&amp;quot; section of the code defines the layer's name (lower case, used in .sif files), its &amp;quot;local&amp;quot; name (this is the string which is translated, and is capitalized), which category the layer belongs in (this determines where it appears in the 'new layer' menu), the layer's version (0.1 for new layers), etc.&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6784</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6784"/>
				<updated>2008-04-16T16:24:08Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
Section 1, &amp;quot;The Code&amp;quot; will present the entire source, uninterrupted, and section 2, &amp;quot;The Description&amp;quot; will break it up into small chunks and discuss it.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
We need to create two new files (one header (.h) file, and one implementation (.cpp) file), and edit two existing files (the module's main.cpp, and the Makefile.am), all in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define four methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the four methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6783</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6783"/>
				<updated>2008-04-16T16:19:08Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
Section 1, &amp;quot;The Code&amp;quot; will present the entire source, uninterrupted, and section 2, &amp;quot;The Description&amp;quot; will break it up into small chunks and discuss it.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
We need to create two new files (one header (.h) file, and one implementation (.cpp) file), and edit two existing files (the module's main.cpp, and the Makefile.am), all in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6782</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6782"/>
				<updated>2008-04-16T16:17:38Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* The Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
We need to create two new files (one header (.h) file, and one implementation (.cpp) file), and edit two existing files (the module's main.cpp, and the Makefile.am), all in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6781</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6781"/>
				<updated>2008-04-16T16:15:54Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* desaturate.h */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6780</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6780"/>
				<updated>2008-04-16T16:15:39Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* desaturate.cpp */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/Makefile.am ===&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
=== &amp;lt;module&amp;gt;/main.cpp ===&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6779</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6779"/>
				<updated>2008-04-16T16:14:24Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* The Code */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
=== desaturate.h ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
=== desaturate.cpp ===&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6778</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6778"/>
				<updated>2008-04-16T16:13:26Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* get_color() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
desaturate.h:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
desaturate.cpp:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero using [http://synfig.org/api/synfig/classsynfig_1_1Color.html#b62c2069fc43baa97fba17b33ff4d32d color.set_s()] and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6777</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6777"/>
				<updated>2008-04-16T16:02:35Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* accelerated_render() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
desaturate.h:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
desaturate.cpp:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
=== accelerated_render() ===&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6776</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6776"/>
				<updated>2008-04-16T16:02:19Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* get_color() */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
desaturate.h:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
desaturate.cpp:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== Implementation ==&lt;br /&gt;
&lt;br /&gt;
=== get_color() ===&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== accelerated_render() ==&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6775</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6775"/>
				<updated>2008-04-16T16:01:45Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* The Methods */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
desaturate.h:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
desaturate.cpp:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
==== get_param ====&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== get_param_vocab ====&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
==== get_color ====&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
==== accelerated_render ====&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
==== reads_context ====&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== get_color() ==&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== accelerated_render() ==&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6774</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6774"/>
				<updated>2008-04-16T16:00:44Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* The Class */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
desaturate.h:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
desaturate.cpp:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
=== SYNFIG_LAYER_MODULE_EXT ===&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== get_color() ==&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== accelerated_render() ==&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	<entry>
		<id>https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6773</id>
		<title>Dev:Adding a Layer</title>
		<link rel="alternate" type="text/html" href="https://www.wiki.synfig.org/index.php?title=Dev:Adding_a_Layer&amp;diff=6773"/>
				<updated>2008-04-16T16:00:16Z</updated>
		
		<summary type="html">&lt;p&gt;Dooglus: /* Protection against Multiple Inclusion */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Here's an example of how to add a simple layer to an existing module.  For this example I picked something very easy: a layer which removes all colour from the layers beneath it.  I will call this creation &amp;quot;Desaturate&amp;quot;, and add it to the mod_filter module.&lt;br /&gt;
&lt;br /&gt;
== The Code ==&lt;br /&gt;
&lt;br /&gt;
So first I need to create desaturate.h and desaturate.cpp in the synfig/src/modules/mod_filter/ folder:&lt;br /&gt;
&lt;br /&gt;
desaturate.h:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
desaturate.cpp:&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.cpp&lt;br /&gt;
 **  \brief Implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #ifdef USING_PCH&lt;br /&gt;
 #   include &amp;quot;pch.h&amp;quot;&lt;br /&gt;
 #else&lt;br /&gt;
 #ifdef HAVE_CONFIG_H&lt;br /&gt;
 #   include &amp;lt;config.h&amp;gt;&lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/context.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/paramdesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/renddesc.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/surface.h&amp;gt;&lt;br /&gt;
 #include &amp;lt;synfig/value.h&amp;gt;&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
 &lt;br /&gt;
 using namespace synfig;&lt;br /&gt;
 &lt;br /&gt;
 /* === G L O B A L S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 SYNFIG_LAYER_INIT(Desaturate);&lt;br /&gt;
 SYNFIG_LAYER_SET_NAME(Desaturate,&amp;quot;desaturate&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_LOCAL_NAME(Desaturate,N_(&amp;quot;Desaturate&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_CATEGORY(Desaturate,N_(&amp;quot;Filters&amp;quot;));&lt;br /&gt;
 SYNFIG_LAYER_SET_VERSION(Desaturate,&amp;quot;0.1&amp;quot;);&lt;br /&gt;
 SYNFIG_LAYER_SET_CVS_ID(Desaturate,&amp;quot;$Id$&amp;quot;);&lt;br /&gt;
 &lt;br /&gt;
 /* === M E T H O D S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 ValueBase&lt;br /&gt;
 Desaturate::get_param(const String &amp;amp;param)const&lt;br /&gt;
 {&lt;br /&gt;
     EXPORT_NAME();&lt;br /&gt;
     EXPORT_VERSION();&lt;br /&gt;
 &lt;br /&gt;
     return ValueBase();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Layer::Vocab&lt;br /&gt;
 Desaturate::get_param_vocab()const&lt;br /&gt;
 {&lt;br /&gt;
     return Layer::Vocab();&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
 &lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
 &lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
Then I need to edit modules/mod_filter/Makefile.am and add these two files to the list of source files (maintain alphabetical order please):&lt;br /&gt;
&lt;br /&gt;
 libmod_filter_la_SOURCES = blur.cpp blur.h colorcorrect.cpp colorcorrect.h desaturate.cpp desaturate.h halftone2.cpp halftone2.h lumakey.cpp lumakey.h radialblur.cpp radialblur.h main.cpp halftone.cpp halftone.h halftone3.cpp halftone3.h&lt;br /&gt;
&lt;br /&gt;
And finally we edit modules/mod_filter/main.cpp.  Add this with the other #include lines:&lt;br /&gt;
&lt;br /&gt;
 #include &amp;quot;desaturate.h&amp;quot;&lt;br /&gt;
&lt;br /&gt;
and add this with the other LAYER(...) lines:&lt;br /&gt;
&lt;br /&gt;
 LAYER(Desaturate)&lt;br /&gt;
&lt;br /&gt;
then rebuild (including the autoreconf, ./configure, etc., to get the new files added to the Makefile) and we're done.&lt;br /&gt;
&lt;br /&gt;
== The Description ==&lt;br /&gt;
&lt;br /&gt;
I'll break the header up into sections, describing each part:&lt;br /&gt;
&lt;br /&gt;
=== The initial comment ===&lt;br /&gt;
&lt;br /&gt;
This contains basic documentation and legal stuff.  Just copy, paste, and edit from another file.&lt;br /&gt;
&lt;br /&gt;
 /* === S Y N F I G ========================================================= */&lt;br /&gt;
 /*! \file desaturate.h&lt;br /&gt;
 **  \brief Header file for implementation of the &amp;quot;Desaturate&amp;quot; layer&lt;br /&gt;
 **&lt;br /&gt;
 **  \legal&lt;br /&gt;
 **  Copyright (c) 2008 Chris Moore&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is free software; you can redistribute it and/or&lt;br /&gt;
 **  modify it under the terms of the GNU General Public License as&lt;br /&gt;
 **  published by the Free Software Foundation; either version 2 of&lt;br /&gt;
 **  the License, or (at your option) any later version.&lt;br /&gt;
 **&lt;br /&gt;
 **  This package is distributed in the hope that it will be useful,&lt;br /&gt;
 **  but WITHOUT ANY WARRANTY; without even the implied warranty of&lt;br /&gt;
 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU&lt;br /&gt;
 **  General Public License for more details.&lt;br /&gt;
 **  \endlegal&lt;br /&gt;
 ** ========================================================================= */&lt;br /&gt;
 &lt;br /&gt;
 /* === S T A R T =========================================================== */&lt;br /&gt;
 &lt;br /&gt;
=== Protection against Multiple Inclusion ===&lt;br /&gt;
&lt;br /&gt;
This #ifndef is a standard way to make sure the header is only compiled once, even if it happens to be included multiple times.  Use a unique symbol, based on the file name.&lt;br /&gt;
&lt;br /&gt;
 #ifndef __SYNFIG_DESATURATE_H&lt;br /&gt;
 #define __SYNFIG_DESATURATE_H&lt;br /&gt;
&lt;br /&gt;
=== Headers ===&lt;br /&gt;
&lt;br /&gt;
Include files which are needed.  We're not doing anything much, so all we need to include is layer.h, which defines the Layer class that all layers inherit from.&lt;br /&gt;
&lt;br /&gt;
 /* === H E A D E R S ======================================================= */&lt;br /&gt;
 &lt;br /&gt;
 #include &amp;lt;synfig/layer.h&amp;gt;&lt;br /&gt;
&lt;br /&gt;
=== The Class ===&lt;br /&gt;
&lt;br /&gt;
Define the class which implements our layer.  We inherit from the Layer class.  For this simple example we only define five methods.  The rest will be inherited from the Layer class.&lt;br /&gt;
 &lt;br /&gt;
 /* === C L A S S E S &amp;amp; S T R U C T S ======================================= */&lt;br /&gt;
 &lt;br /&gt;
 class Desaturate : public synfig::Layer&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
This is standard.  Just use it for every layer.  It declares members to hold the layer's name, version, category, etc., and also declares a method to create() the layer.  See synfig/src/synfig/layer.h for its definition.&lt;br /&gt;
&lt;br /&gt;
     SYNFIG_LAYER_MODULE_EXT&lt;br /&gt;
&lt;br /&gt;
=== The Methods ===&lt;br /&gt;
&lt;br /&gt;
Then we declare the five methods we're going to implement.  First &amp;quot;get_param()&amp;quot;.  Since our layer isn't going to have any parameters, all it needs to do is make the layer's name and &lt;br /&gt;
version available.&lt;br /&gt;
&lt;br /&gt;
 public:&lt;br /&gt;
     virtual synfig::ValueBase get_param(const synfig::String&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
This one returns a list of the layer's parameters.  We have no parameters, so we return an empty list.&lt;br /&gt;
&lt;br /&gt;
     virtual Vocab get_param_vocab()const;&lt;br /&gt;
&lt;br /&gt;
This one is used to find the color of a single given pixel.  It's used by the &amp;quot;Info&amp;quot; panel to display the R,G,B values as you mouse over the canvas.  It's also used if our layer has any transformation layers over the top of it.  The absence of a working implementation of this method in the &amp;quot;Text&amp;quot; layer is why distorting text currently causes render artifacts.&lt;br /&gt;
&lt;br /&gt;
     virtual synfig::Color get_color(synfig::Context, const synfig::Point&amp;amp;)const;&lt;br /&gt;
&lt;br /&gt;
This one is used to render a large rectangular piece of our layer in one go.  It typically calls the accelerated_render() method for the layers under our layer (the 'context') and then modifies the results of that call in some way:&lt;br /&gt;
&lt;br /&gt;
     virtual bool accelerated_render(synfig::Context,synfig::Surface*,int,&lt;br /&gt;
                                     const synfig::RendDesc &amp;amp;, synfig::ProgressCallback *)const;&lt;br /&gt;
&lt;br /&gt;
This one returns true always, meaning that this layer's output depends on the layers under it (the 'context'):&lt;br /&gt;
&lt;br /&gt;
     virtual bool reads_context()const { return true; }&lt;br /&gt;
 }; // END of class Desaturate&lt;br /&gt;
 &lt;br /&gt;
 #endif&lt;br /&gt;
&lt;br /&gt;
I won't reproduce the whole of the .cpp file here and go through it.  The only two methods which are really interesting here are get_color() and accelerated_render():&lt;br /&gt;
&lt;br /&gt;
== get_color() ==&lt;br /&gt;
&lt;br /&gt;
Given the context, and a point, get_color() should return the color of the pixel at the given point.  The context has a get_color() method, so we use that to look up the color of the pixel before our layer has had a chance to affect it, and store that in 'tmp'.  Then we set its saturation to zero and return it.  That's all:&lt;br /&gt;
&lt;br /&gt;
 Color&lt;br /&gt;
 Desaturate::get_color(Context context, const Point &amp;amp;getpos)const&lt;br /&gt;
 {&lt;br /&gt;
     Color tmp(context.get_color(getpos));&lt;br /&gt;
     return tmp.set_s(0);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
== accelerated_render() ==&lt;br /&gt;
&lt;br /&gt;
We accept five arguments:&lt;br /&gt;
&lt;br /&gt;
The context (ie. the layers under us):&lt;br /&gt;
&lt;br /&gt;
 bool&lt;br /&gt;
 Desaturate::accelerated_render(Context              context,&lt;br /&gt;
&lt;br /&gt;
The surface we are supposed to write our results onto:&lt;br /&gt;
&lt;br /&gt;
                                Surface*             surface,&lt;br /&gt;
&lt;br /&gt;
The quality at which we are to render:&lt;br /&gt;
&lt;br /&gt;
                                int                  quality,&lt;br /&gt;
&lt;br /&gt;
A description of the area to render - width, height, top left corner, resolution, etc, etc:&lt;br /&gt;
&lt;br /&gt;
                                const RendDesc&amp;amp;      renddesc,&lt;br /&gt;
&lt;br /&gt;
An object which is used to monitor our progress.  It's used for calculating the expected remaining time while rendering:&lt;br /&gt;
&lt;br /&gt;
                                ProgressCallback*    cb&lt;br /&gt;
                               )const&lt;br /&gt;
 {&lt;br /&gt;
&lt;br /&gt;
I didn't get around to looking at the way the 'cb' ProgressCallback is used.  But this code is in pretty much all layers:&lt;br /&gt;
&lt;br /&gt;
     SuperCallback supercb(cb,0,9500,10000);&lt;br /&gt;
&lt;br /&gt;
We call accelerated_render() on the context, to render the layers under us.  We just pass on the arguments we received for surface, quality and renddesc, along with the new callback we just made.  If that render fails, then we fail too:&lt;br /&gt;
 &lt;br /&gt;
     // render the context onto the given surface&lt;br /&gt;
     if(!context.accelerated_render(surface,quality,renddesc,&amp;amp;supercb))&lt;br /&gt;
         return false;&lt;br /&gt;
&lt;br /&gt;
Now we do the real work of this layer.  We define integers to do the looping, and a 'pen' which we can walk over the rectangle we're working on:&lt;br /&gt;
&lt;br /&gt;
     // set the saturation of each pixel to zero&lt;br /&gt;
     int x,y;&lt;br /&gt;
     Surface::pen pen(surface-&amp;gt;begin());&lt;br /&gt;
&lt;br /&gt;
We loop through every pixel on every row of the rectangle we're working on.  The 'renddesc' gives us the width and height of the rectangle.  The pen has methods inc_x(), dec_x(), inc_y(), dec_y() which move it a given amount:&lt;br /&gt;
&lt;br /&gt;
     for(y=0;y&amp;lt;renddesc.get_h();y++,pen.inc_y(),pen.dec_x(x))&lt;br /&gt;
         for(x=0;x&amp;lt;renddesc.get_w();x++,pen.inc_x())&lt;br /&gt;
&lt;br /&gt;
At each pixel, we get the color as rendered from the context, set its saturation to zero, and write it back to the same surface:&lt;br /&gt;
&lt;br /&gt;
         {&lt;br /&gt;
             Color tmp(pen.get_value());&lt;br /&gt;
             pen.put_value(tmp.set_s(0));&lt;br /&gt;
         }&lt;br /&gt;
&lt;br /&gt;
And that's about it.&lt;br /&gt;
 &lt;br /&gt;
     // mark our progress as finished&lt;br /&gt;
     if(cb &amp;amp;&amp;amp; !cb-&amp;gt;amount_complete(10000,10000)) return false;&lt;br /&gt;
     return true;&lt;br /&gt;
 }&lt;/div&gt;</summary>
		<author><name>Dooglus</name></author>	</entry>

	</feed>