[documentation/docs-krita-org/krita/4.3] /: GSoC 2020: Add Disney Animation's SeExpr as a new Fill Layer type
L. E. Segovia
null at kde.org
Fri Aug 7 15:38:06 BST 2020
Git commit a71ad098ba1c33708d60365edf66fb8219674644 by L. E. Segovia.
Committed on 07/08/2020 at 14:37.
Pushed by lsegovia into branch 'krita/4.3'.
GSoC 2020: Add Disney Animation's SeExpr as a new Fill Layer type
This commit documents the SeExpr Fill Layer generator, as implemented in graphics/krita!380 and graphics/krita!411.
See !145
CCMAIL: kimageshop at kde.org
(cherry picked from commit 9bb62c8ea128d9c5a059438108a5c8492d10e3c6)
A +- -- images/layers/SeExpr-David-Revoy.jpg
A +17 -0 images/seexpr/LICENSE.md
A +- -- images/seexpr/SeExpr_add_variable.png
A +- -- images/seexpr/SeExpr_add_variable_vector.png
A +- -- images/seexpr/SeExpr_editor.png
A +- -- images/seexpr/SeExpr_editor_preset_mgmt.png
A +- -- images/seexpr/SeExpr_editor_script_error.png
A +- -- images/seexpr/SeExpr_editor_widgets.png
A +- -- images/seexpr/SeExpr_first_render.png
A +- -- images/seexpr/SeExpr_overwrite_preset.png
A +- -- images/seexpr/SeExpr_prop_1.png
A +- -- images/seexpr/SeExpr_rename_preset.png
A +- -- images/seexpr/SeExpr_save.png
A +- -- images/seexpr/SeExpr_script.png
A +- -- images/seexpr/Se_voronoi_1.png
A +- -- images/seexpr/Se_voronoi_2.png
A +- -- images/seexpr/Se_voronoi_3.png
A +- -- images/seexpr/Se_voronoi_4.png
A +- -- images/seexpr/Se_voronoi_5.png
A +67 -0 reference_manual/layers_and_masks/fill_layer_generators/seexpr.rst
M +1 -0 reference_manual/layers_and_masks/fill_layers.rst
A +51 -0 reference_manual/resource_management/seexpr_scripts.rst
A +706 -0 reference_manual/seexpr.rst
A +255 -0 tutorials/seexpr.rst
https://invent.kde.org/documentation/docs-krita-org/commit/a71ad098ba1c33708d60365edf66fb8219674644
diff --git a/images/layers/SeExpr-David-Revoy.jpg b/images/layers/SeExpr-David-Revoy.jpg
new file mode 100644
index 000000000..17dd7c4b4
Binary files /dev/null and b/images/layers/SeExpr-David-Revoy.jpg differ
diff --git a/images/seexpr/LICENSE.md b/images/seexpr/LICENSE.md
new file mode 100644
index 000000000..94ba4cf59
--- /dev/null
+++ b/images/seexpr/LICENSE.md
@@ -0,0 +1,17 @@
+The images Se_voronoi_*.png are under the following license:
+
+Copyright Disney Enterprises, Inc. All rights reserved.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License
+and the following modification to it: Section 6 Trademarks.
+deleted and replaced with:
+
+6. Trademarks. This License does not grant permission to use the
+trade names, trademarks, service marks, or product names of the
+Licensor and its affiliates, except as required for reproducing
+the content of the NOTICE file.
+
+You may obtain a copy of the License at
+http://www.apache.org/licenses/LICENSE-2.0
+
diff --git a/images/seexpr/SeExpr_add_variable.png b/images/seexpr/SeExpr_add_variable.png
new file mode 100644
index 000000000..d611abebf
Binary files /dev/null and b/images/seexpr/SeExpr_add_variable.png differ
diff --git a/images/seexpr/SeExpr_add_variable_vector.png b/images/seexpr/SeExpr_add_variable_vector.png
new file mode 100644
index 000000000..74a66571f
Binary files /dev/null and b/images/seexpr/SeExpr_add_variable_vector.png differ
diff --git a/images/seexpr/SeExpr_editor.png b/images/seexpr/SeExpr_editor.png
new file mode 100644
index 000000000..843c7b344
Binary files /dev/null and b/images/seexpr/SeExpr_editor.png differ
diff --git a/images/seexpr/SeExpr_editor_preset_mgmt.png b/images/seexpr/SeExpr_editor_preset_mgmt.png
new file mode 100644
index 000000000..9d4146c98
Binary files /dev/null and b/images/seexpr/SeExpr_editor_preset_mgmt.png differ
diff --git a/images/seexpr/SeExpr_editor_script_error.png b/images/seexpr/SeExpr_editor_script_error.png
new file mode 100644
index 000000000..35316d3bc
Binary files /dev/null and b/images/seexpr/SeExpr_editor_script_error.png differ
diff --git a/images/seexpr/SeExpr_editor_widgets.png b/images/seexpr/SeExpr_editor_widgets.png
new file mode 100644
index 000000000..5b7d7e0e9
Binary files /dev/null and b/images/seexpr/SeExpr_editor_widgets.png differ
diff --git a/images/seexpr/SeExpr_first_render.png b/images/seexpr/SeExpr_first_render.png
new file mode 100644
index 000000000..24bd59fdf
Binary files /dev/null and b/images/seexpr/SeExpr_first_render.png differ
diff --git a/images/seexpr/SeExpr_overwrite_preset.png b/images/seexpr/SeExpr_overwrite_preset.png
new file mode 100644
index 000000000..0a6d18bdc
Binary files /dev/null and b/images/seexpr/SeExpr_overwrite_preset.png differ
diff --git a/images/seexpr/SeExpr_prop_1.png b/images/seexpr/SeExpr_prop_1.png
new file mode 100644
index 000000000..3a2017699
Binary files /dev/null and b/images/seexpr/SeExpr_prop_1.png differ
diff --git a/images/seexpr/SeExpr_rename_preset.png b/images/seexpr/SeExpr_rename_preset.png
new file mode 100644
index 000000000..66c209597
Binary files /dev/null and b/images/seexpr/SeExpr_rename_preset.png differ
diff --git a/images/seexpr/SeExpr_save.png b/images/seexpr/SeExpr_save.png
new file mode 100644
index 000000000..359c3db1d
Binary files /dev/null and b/images/seexpr/SeExpr_save.png differ
diff --git a/images/seexpr/SeExpr_script.png b/images/seexpr/SeExpr_script.png
new file mode 100644
index 000000000..a94db9bee
Binary files /dev/null and b/images/seexpr/SeExpr_script.png differ
diff --git a/images/seexpr/Se_voronoi_1.png b/images/seexpr/Se_voronoi_1.png
new file mode 100644
index 000000000..270bf786b
Binary files /dev/null and b/images/seexpr/Se_voronoi_1.png differ
diff --git a/images/seexpr/Se_voronoi_2.png b/images/seexpr/Se_voronoi_2.png
new file mode 100644
index 000000000..d937ddc01
Binary files /dev/null and b/images/seexpr/Se_voronoi_2.png differ
diff --git a/images/seexpr/Se_voronoi_3.png b/images/seexpr/Se_voronoi_3.png
new file mode 100644
index 000000000..fc2623628
Binary files /dev/null and b/images/seexpr/Se_voronoi_3.png differ
diff --git a/images/seexpr/Se_voronoi_4.png b/images/seexpr/Se_voronoi_4.png
new file mode 100644
index 000000000..72dc31aa6
Binary files /dev/null and b/images/seexpr/Se_voronoi_4.png differ
diff --git a/images/seexpr/Se_voronoi_5.png b/images/seexpr/Se_voronoi_5.png
new file mode 100644
index 000000000..8025849a2
Binary files /dev/null and b/images/seexpr/Se_voronoi_5.png differ
diff --git a/reference_manual/layers_and_masks/fill_layer_generators/seexpr.rst b/reference_manual/layers_and_masks/fill_layer_generators/seexpr.rst
new file mode 100644
index 000000000..64cd6bb89
--- /dev/null
+++ b/reference_manual/layers_and_masks/fill_layer_generators/seexpr.rst
@@ -0,0 +1,67 @@
+.. meta::
+ :description:
+ How to use SeExpr as a Fill Layer in Krita.
+
+.. metadata-placeholder
+
+ :authors: - L. E. Segovia <amy at amyspark.me>
+ :license: GNU free documentation license 1.3 or later.
+
+.. index:: SeExpr
+.. _seexpr_fill_layer:
+
+SeExpr
+------
+
+.. versionadded:: 4.3.1
+
+.. image:: /images/layers/SeExpr-David-Revoy.jpg
+
+Fills the layer with a pattern specified through Disney Animation's
+`SeExpr expression language <https://wdas.github.io/SeExpr>`_.
+
+.. seealso::
+ - :ref:`seexpr_tut_intro`
+ - :ref:`seexpr`
+ - :ref:`resource_seexpr_scripts`
+ - `"Procedural texture generator (example and wishes)" on Krita Artists <https://krita-artists.org/t/procedural-texture-generator-example-and-wishes/7638>`_
+ - `Inigo Quilez's articles <https://iquilezles.org/www/index.htm>`_
+ - `The Book of Shaders <https://thebookofshaders.com/>`_
+
+SeExpr is an embeddable, arithmetic expression language that enables you to
+write shader-like scripts. Through this language, Krita can add dynamically
+generated textures like lava (example above), force fields, wood, marble,
+etc. to your layers.
+
+As with Patterns, you can create your own and use those as well.
+For some examples, please check out the thread `"Procedural texture generator (example and wishes)" on Krita Artists <https://krita-artists.org/t/procedural-texture-generator-example-and-wishes/7638>`_.
+You can download them as a bundle through `Amyspark's blog <https://www.amyspark.me/blog/posts/2020/07/03/third-alpha-release.html>`_.
+
+Script
+ Select the desired preset out of any existing bundled presets.
+ This tab is identical to the Pattern preset selector.
+
+ .. image:: /images/seexpr/SeExpr_script.png
+
+Options
+ This tab allows you to edit the selected preset, and apply its script
+ to the layer.
+
+ .. image:: /images/seexpr/SeExpr_editor.png
+
+ There are three sections. The first bar allows you to edit and save the selected preset:
+
+ .. image:: /images/seexpr/SeExpr_editor_preset_mgmt.png
+
+ If your script is syntactically correct, the middle box lets you
+ adjust its variables through widgets.
+
+ .. image:: /images/seexpr/SeExpr_editor_widgets.png
+
+ The lower box contains the script text, and shows the detected syntax
+ errors, if any.
+
+ .. image:: /images/seexpr/SeExpr_editor_script_error.png
+
+ You can adjust how much space the latter two boxes have through their
+ splitter.
diff --git a/reference_manual/layers_and_masks/fill_layers.rst b/reference_manual/layers_and_masks/fill_layers.rst
index 2c474f91b..cbb08f8ca 100644
--- a/reference_manual/layers_and_masks/fill_layers.rst
+++ b/reference_manual/layers_and_masks/fill_layers.rst
@@ -7,6 +7,7 @@
:authors: - Wolthera van Hövell tot Westerflier <griffinvalley at gmail.com>
- Scott Petrovic
- Alan
+ - L. E. Segovia <amy at amyspark.me>
:license: GNU free documentation license 1.3 or later.
.. index:: Layers, Fill, Generator
diff --git a/reference_manual/resource_management/seexpr_scripts.rst b/reference_manual/resource_management/seexpr_scripts.rst
new file mode 100644
index 000000000..815be24a8
--- /dev/null
+++ b/reference_manual/resource_management/seexpr_scripts.rst
@@ -0,0 +1,51 @@
+.. meta::
+ :description:
+ Creating and managing SeExpr script presets in Krita.
+
+.. metadata-placeholder
+
+ :authors: - L. E. Segovia <amy at amyspark.me>
+ :license: GNU free documentation license 1.3 or later.
+
+.. index:: Resources, SeExor
+.. _resource_seexpr_scripts:
+
+SeExpr Scripts
+==============
+
+.. image:: /images/seexpr/SeExpr_editor.png
+ :align: center
+
+SeExpr scripts allow you to render dynamically generated textures.
+They are saved as .se files.
+They can be used as fill for generated layers.
+
+.. seealso::
+ - :ref:`seexpr_tut_intro`
+ - :ref:`seexpr`
+ - :ref:`seexpr_fill_layer`
+ - `"Procedural texture generator (example and wishes)" on Krita Artists <https://krita-artists.org/t/procedural-texture-generator-example-and-wishes/7638>`_
+ - `Inigo Quilez's articles <https://iquilezles.org/www/index.htm>`_
+ - `The Book of Shaders <https://thebookofshaders.com/>`_
+
+Adding new scripts
+------------------
+
+Like with :ref:`resource_patterns`, there is a similar UI with which you
+can manage SeExpr presets.
+This panel is available by opening the Fill Layer dialog, and selecting
+:guilabel:`SeExpr`:
+
+.. image:: /images/seexpr/SeExpr_script.png
+ :align: center
+
+At the bottom of the tab, beneath the resource-filter input field, there are the :guilabel:`Import resource` and :guilabel:`Delete resource` buttons. Select the former to add presets to the list.
+
+Similarly, removing presets can be done by pressing the :guilabel:`Delete resource` button. Krita will not delete the actual file then, but rather black list it, and thus not load it.
+
+Temporary scripts
+-----------------
+
+Layers keep a copy of the textual script that was used to generate them.
+You can access it by going to the Options tab and copying the text.
+You can then paste it into a new SeExpr Fill Layer.
diff --git a/reference_manual/seexpr.rst b/reference_manual/seexpr.rst
new file mode 100644
index 000000000..f3bcd6477
--- /dev/null
+++ b/reference_manual/seexpr.rst
@@ -0,0 +1,706 @@
+.. meta::
+ :description:
+ SeExpr Quick Reference for Krita
+
+.. metadata-placeholder
+
+ :authors: - L. E. Segovia <amy at amyspark.me> (reStructuredText)
+ - Disney Enterprises, Inc. (for the original)
+ :license: GNU free documentation license 1.3 or later, Apache 2.0
+
+.. index:: Fill Layer, SeExpr
+
+.. _seexpr:
+
+======================
+SeExpr Quick Reference
+======================
+
+This page details all the available variables, functions, and operators in SeExpr.
+It is a heavily edited version of the official `user documentation <https://wdas.github.io/SeExpr/doxygen/userdoc.html>`_, adapted for usage with Krita.
+
+.. seealso::
+ - Source code at `KDE Invent <https://invent.kde.org/lsegovia/seexpr>`_
+ - Disney's SeExpr `API Documentation <http://wdas.github.io/SeExpr/doxygen/>`_
+
+.. seealso::
+ - :ref:`seexpr_tut_intro`
+ - :ref:`seexpr_fill_layer`
+ - :ref:`resource_seexpr_scripts`
+ - `"Procedural texture generator (example and wishes)" on Krita Artists <https://krita-artists.org/t/procedural-texture-generator-example-and-wishes/7638>`_
+ - `Inigo Quilez's articles <https://iquilezles.org/www/index.htm>`_
+ - `The Book of Shaders <https://thebookofshaders.com/>`_
+
+.. contents::
+
+*********
+Variables
+*********
+
+External variables
+==================
+
+These variables are provided by host applications, in this case Krita.
+They are registered with SeExpr's autocomplete help, which can be
+accessed by :kbd:`Ctrl+Space`.
+
+.. glossary::
+
+ $u, $v
+ Pixel position in normalized coordinates.
+
+ $w, $h
+ Image's width and height in pixels.
+
+Local Variables
+===============
+
+Local variables can be defined at the start of the expression::
+
+ $a = noise($P);
+ $b = noise($a * 1);
+ pow($a, 0.5) + $b
+
+External variables can also be overridden by local assignment. This can be useful to scale the noise frequency for instance::
+
+ $P = $P * 10; # increase noise frequency
+ fbm(vnoise($P) + $P/4)
+
+
+******************
+Control Structures
+******************
+
+SeExpr, unlike many languages, provides **no control structures** except
+a form of `if` statements, known as the *ternary operator*::
+
+ $u = $i < .5 ? 0.0 : 10.0
+
+*******************************************
+Operators (listed in decreasing precedence)
+*******************************************
+
+.. glossary::
+
+ [ a, b, c ]
+ vector constructor
+
+ $P[ n ]
+ vector component access
+
+ .. hint:: ``n`` must be 0, 1, or 2, e.g.::
+
+ $P[0]
+
+ ^
+ exponentiation
+
+ .. note:: Same as the ``pow`` function.
+
+ !
+ logical NOT
+
+ ~
+ inversion
+
+ .. hint::
+ ::
+
+ ~$A
+
+ gives the same result as::
+
+ 1 - $A
+
+ * / %
+ multiply, divide, modulus
+
+ .. note:: ``%`` is the same as the ``fmod`` function.
+
+ + -
+ add, subtract
+
+ < > <= >=
+ comparison: less than, greater than, less or equal than, greater or equal than
+
+ .. note:: Only uses the first component of a vector.
+
+ == !=
+ equality, inequality
+
+ &&
+ logical AND
+
+ ||
+ logical OR
+
+ ? :
+ ternary ``if`` operator
+
+ .. hint:: Example::
+
+ $u < .5 ? 0 : 1
+
+ ->
+ apply - The function on the right of the arrow is applied to the expression on the left.
+
+ .. hint:: Examples::
+
+ $Cs -> contrast(.7) -> clamp(0.2, 0.8)
+ $u -> hsi(20, 1.2, 1, $Cs -> gamma(1.2))
+
+********************
+Assignment Operators
+********************
+
+Besides the basic assignment statement::
+
+ $foo = $bar
+
+you can also do operator assignments such as::
+
+ $foo += $bar;
+
+which is equivalent to::
+
+ $foo = $foo + $bar;
+
+Additionally, there are:
+
+- ``+=``
+- ``-=``
+- ``/=``
+- ``%=``
+- ``*=``
+- ``^=``
+
+********
+Comments
+********
+
+You can add comments to your script by using the ``#`` character.
+SeExpr will then skip the rest of the line for rendering purposes.
+However, they are not ignored; comments can still be used to declare
+the valid value range of integer, float, and vector variables.
+This enables you to manage them using widgets that will accept the
+specified range.
+
+.. hint::
+ ``$var0`` is an integer variable that ranges between 0 and 10 inclusive::
+
+ $var0 = 0; # 0, 10
+
+ ``$var1`` is a floating point variable with the same range::
+
+ $var1 = 0; # 0.000, 10.000
+
+ ``$var2`` is a vector variable::
+
+ $var2 = [0, 0, 0] # 0.000, 10.000
+
+ The latter is very helpful; SeExpr considers vectors with range ``[0, 1]`` as colors::
+
+ # this is a dark red
+ $color = [0.5, 0, 0] # 0.000, 1.000
+
+ In all cases, if not specified, the associated widgets' range will go from 0 to 1.
+
+For a multi-line expression, each line may have its own comment.
+
+*****************
+Logging Functions
+*****************
+
+.. glossary::
+
+ void **printf** ( string format, [param0, param1, ...] )
+ Prints a string to stdout that is formatted as given. Formatting
+ parameters possible are ``%f`` for float (takes first component of vector
+ argument) or ``%v`` for vector.
+
+ .. hint::
+ For example, if you wrote::
+
+ printf("test %f %v",[1,2,3],[4,5,6]);
+
+ you would get::
+
+ test 1 [4,5,6]
+
+***************************************
+Color, Masking, and Remapping Functions
+***************************************
+
+.. glossary::
+
+ float **bias** ( float x, float b)
+ Variation of gamma where control parameter goes from ``0`` to ``1`` with
+ values ``> 0.5`` pulling the curve up and values ``< 0.5`` pulling the curve
+ down. Defined as ``pow(x, log(b)/log(0.5))``.
+
+ float **boxstep** ( float x, float a )
+ float **gaussstep** ( float x, float a, float b )
+ float **linearstep** ( float x, float a, float b )
+ float **smoothstep** ( float x, float a, float b )
+ The step functions are zero for ``x < a`` and one for ``x > b`` (or ``x > a`` in
+ the case of boxstep). Between ``a`` and ``b``, the value changes
+ continuously between zero and one. The ``gausstep`` function uses the
+ standard Gaussian "bell" curve which is based on an exponential
+ curve. The ``smoothstep`` function uses a cubic curve. Intuitively,
+ ``gausstep`` is has a sharper transition near one and a softer transition
+ near zero whereas ``smoothstep`` is has a medium softness near both one
+ and zero.
+
+ float **clamp** ( float x, float lo, float hi )
+ Constrain ``x`` to range ``[lo, hi]``.
+
+ float **compress** ( float x, float lo, float hi )
+ Compress the dynamic range from ``[0, 1]`` to ``[lo, hi]``.
+
+ float **contrast** ( float x, float c )
+ Adjust the contrast. For ``c`` from ``0`` to ``0.5``, the contrast
+ is decreased. For ``c > 0.5``, the contrast is increased.
+
+ float **expand** ( float x, float lo, float hi )
+ Expand the dynamic range from ``[lo, hi]`` to ``[0, 1]``.
+
+ float **fit** ( float x, float a1, float b1, float a2, float b2 )
+ Linear remapping of ``[a1..x..b1]`` to ``[a2..x..b2]``
+
+ float **gamma** ( float x, float g)
+ ``pow(x, 1/g)``
+
+ float **invert** ( float x )
+ Invert the value. Defined as ``1 - x``.
+
+ color **hsi** ( color x, float h, float s, float i, float map=1 )
+ The ``hsi`` function shifts the hue by ``h`` (in degrees) and
+ scales thesaturation and intensity by ``s`` and ``i``
+ respectively. A map may be
+ supplied which will control the shift - the full shift will happen
+ when the map is one and no shift will happen when the map is zero.
+ The shift will be scaled back for values between zero and one.
+
+ color **hsltorgb** ( color hsl )
+ color **rgbtohsl** ( color rgb )
+ RGB to HSL color space conversion.
+ HSL is Hue, Saturation, Lightness (all in range ``[0, 1]``).
+ These functions have also been extended to support RGB and HSL values
+ outside of the range ``[0, 1]`` in a reasonable way. For any RGB or HSL
+ value (except for negative values), the conversion is well-defined
+ and reversible.
+
+ color **midhsi** ( color x, float h, float s, float i, float map, float falloff=1, int interp=0 )
+ The ``midhsi`` function is just like the ``hsi`` function except that the
+ control map is centered around the mid point (value of ``0.5``) and can
+ scale the shift in both directions. At the mid point, no shift
+ happens. At *1.0*, the full shift happens, and at ``0.0``, the full
+ inverse shift happens. Additional ``falloff`` and ``interp`` controls are
+ provided to adjust the map using the ``remap`` function. The default
+ ``falloff`` and ``interp`` values result in no remapping.
+
+ float **mix** ( float a, float b, float alpha )
+ Blend of a and b according to alpha. Defined as
+ ``a*(1-alpha) +b*alpha``.
+
+ float **remap** ( float x, float source, float range, float falloff, int interp )
+ General remapping function. When ``x`` is within ``± range`` of source,
+ the result is one. The result falls to zero beyond that range over
+ ``falloff`` distance. The falloff shape is controlled by ``interp``.
+
+ .. note::
+ Numeric values or named constants may be used:
+
+ - int **linear** = 0
+ - int **smooth** = 1
+ - int **gaussian** = 2
+
+***************
+Noise Functions
+***************
+
+.. glossary::
+
+ float **cellnoise** ( vector v )
+ float **cellnoise1** ( float x )
+ float **cellnoise2** ( float x, float y )
+ float **cellnoise3** ( float x, float y, float z )
+ color **ccellnoise** ( vector v )
+ ``cellnoise`` generates a field of constant colored cubes based on the
+ integer location. This is the same as the `PRMan cellnoise function <https://renderman.pixar.com/resources/RenderMan_20/cellnoise.html>`_.
+
+ .. note::
+ ``ccellnoise`` outputs color cellnoise.
+
+
+ float **fbm** ( vector v, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ color **cfbm** ( vector v, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ vector **vfbm** ( vector v, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ float **fbm4** ( vector v, float time, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ color **cfbm4** ( vector v, float time, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ vector **vfbm4** ( vector v, float time, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ ``fbm`` (Fractal Brownian Motion) is a multi-frequency noise function.
+ The base frequency is the same as the ``noise`` function. The total
+ number of frequencies is controlled by ``octaves``. The ``lacunarity``
+ is the spacing between the frequencies - a value of 2 means each
+ octave is twice the previous frequency. The ``gain`` controls how much
+ each frequency is scaled relative to the previous frequency.
+
+ .. note::
+
+ ``cfbm`` and ``cfbm4`` outputs color noise.
+
+ ``vfbm`` and ``vfbm4`` outputs vector noise.
+
+ float **hash** ( float seed1, [float seed2, ...] )
+ Like ``rand``, but with no internal seeds. Any number of seeds may be
+ given and the result will be a random function based on all the
+ seeds.
+
+ float **noise** ( vector v )
+ float **noise** ( float x, float y )
+ float **noise** ( float x, float y, float z )
+ float **noise** ( float x, float y, float z, float w )
+ color **cnoise** ( vector v)
+ color **cnoise4** ( vector v, float t)
+ float **pnoise** ( vector v, vector period )
+ float **snoise** ( vector v)
+ float **snoise4** ( vector v, float t)
+ vector **vnoise** (vector v )
+ vector **vnoise4** (vector v, float t )
+ ``noise`` is a random function that smoothly blends between samples at
+ integer locations. This is Ken Perlin's original noise function.
+
+ .. note::
+
+ ``cnoise`` and ``cnoise4`` output color noise.
+
+ ``noise4`` outputs signed vector noise.
+
+ ``pnoise`` outputs periodic noise.
+
+ ``snoise`` and ``snoise4`` output signed noise with range ``[-1, 1]``.
+
+ ``vnoise`` outputs signed vector noise.
+
+ float **rand** ( [float min, float max], [float seed] )
+ Random number between ``[min, max]`` (or ``[0, 1]`` if unspecified).
+ If a seed is supplied, it will be used in addition to the internal
+ seeds and may be used to create multiple distinct generators.
+
+ float **turbulence** ( vector v, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ color **cturbulence** ( vector v, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ vector **vturbulence** ( vector v, int octaves = 6, float lacunarity = 2, float gain = 0.5 )
+ ``turbulence`` is a variant of ``fbm`` where the absolute value of each
+ noise term is taken. This gives a more billowy appearance.
+
+ float **voronoi** ( vector v, int type = 1, float jitter = 0.5, float fbmScale = 0, int fbmOctaves = 4, float fbmLacunarity = 2, float fbmGain = 0.5)
+ color **cvoronoi** ( vector v, int type = 1, float jitter = 0.5, float fbmScale = 0, int fbmOctaves = 4, float fbmLacunarity = 2, float fbmGain = 0.5)
+ vector **pvoronoi** ( vector v, float jitter = 0.5, float fbmScale = 0, int fbmOctaves = 4, float fbmLacunarity = 2, float fbmGain = 0.5)
+ ``voronoi`` is a cellular noise pattern. It is a jittered variant of
+ ``cellnoise``.
+ The type parameter describes different variants of the noise
+ function. The ``jitter`` param controls how irregular the pattern is
+ (0 is like ordinary cellnoise). The ``fbm...`` params can be
+ used to distort the noise field. When ``fbmScale`` is zero (the
+ default), there is no distortion. The remaining params are the same
+ as for the ``fbm`` function.
+
+ .. hint::
+
+ Voronoi types 1 through 5:
+
+ |image0| |image1| |image2| |image3| |image4|
+
+ .. note::
+ ``cvoronoi`` returns a random color for each cell and
+ ``pvoronoi`` returns the point location of the center of the cell.
+
+
+*******************
+Selection Functions
+*******************
+
+.. glossary ::
+
+ float **choose** ( float index, float choice1, float choice2, [...] )
+ Chooses one of the supplied choices based on the index (assumed to be
+ in range ``[0, 1]``).
+
+ int **cycle** ( int index, int loRange, int hiRange )
+ Cycles through values between loRange and hiRange based on supplied
+ index. This is an offset ``mod`` function. The result is computed as
+ ``loRange + value % (hiRange-loRange+1)``.
+
+ int **pick** ( float index, int loRange, int hiRange, [ float weights, ... ] )
+ Picks values randomly between loRange and hiRange based on supplied
+ index (which is automatically hashed). The values will be
+ distributed according to the supplied weights. Any weights not
+ supplied are assumed to be 1.0.
+
+ float **wchoose** ( float index, float choice1, float weight1, float choice2, float weight2, [...] )
+ Chooses one of the supplied choices based on the index (assumed to be
+ in range ``[0, 1]``). The values will be distributed according to
+ the supplied weights.
+
+.. hint::
+
+ This example returns integer values between 1 and 10::
+
+ pick(value, 1, 10)
+
+ This example returns the values 1 and 2 twice and 2.5 times as often
+ respectively as compared to the other values (3-10)::
+
+ pick(value, 1, 10, 2, 2.5)
+
+ This example returns 10, 11, and 13 through 20 (12 is skipped due to zero weight)::
+
+ pick(value, 10, 20, 1, 1, 0)
+
+
+********************************************
+General Mathematical Constants and Functions
+********************************************
+
+.. glossary::
+
+ float **PI**
+ ::
+
+ float PI = 3.14159...
+
+ float **E**
+ ::
+
+ float E = 2.71828...
+
+.. glossary ::
+
+ float **abs** ( float x)
+ Absolute value of ``x``.
+
+ float **cbrt** ( float x )
+ Cube root.
+
+ float **ceil** ( float x )
+ Next higher integer.
+
+ float **exp** ( float x )
+ ``E`` raised to the ``x`` power.
+
+ float **floor** ( float x )
+ Next lower integer.
+
+ float **fmod** ( float x, float y )
+ Remainder of ``x / y``.
+
+ .. note:: Also available as the ``%`` operator.
+
+ float **log** ( float x )
+ Natural logarithm.
+
+ float **log10** ( float x )
+ Base 10 logarithm.
+
+ float **max** ( float a, float b )
+ Greater of ``a`` and ``b``.
+
+ float **min** ( float a, float b )
+ Lesser of ``a`` and ``b``.
+
+ float **pow** ( float x, float y )
+ ``x`` to the ``y`` power.
+
+ .. note:: Also available as the ``^`` operator.
+
+ float **round** ( float x )
+ Nearest integer.
+
+ float **sqrt** ( float x )
+ Square root.
+
+ float **trunc** ( float x )
+ Nearest integer towards zero.
+
+**********************
+Trigonometry Functions
+**********************
+
+.. glossary::
+
+ float **acos** ( float x )
+ Arc cosine.
+
+ float **acosd** ( float x )
+ Arc cosine in degrees.
+
+ float **acosh** ( float x )
+ Hyperbolic arc cosine.
+
+ float **asin** ( float x )
+ Arc sine.
+
+ float **asind** ( float x )
+ Arc sine in degrees.
+
+ float **asinh** ( float x )
+ Hyperbolic arc sine.
+
+ float **atan** ( float x )
+ Arc tangent.
+
+ float **atand** ( float x )
+ Arc tangent in degrees.
+
+ float **atan2** ( float y, float x)
+ Arc tangent of ``y/x`` between ``-PI`` and ``PI``.
+
+ float **atan2d** ( float y, float x )
+ Arc tangent in degrees of ``y/x`` between ``-180º`` and ``180º``.
+
+ float **atanh** ( float x )
+ Hyperbolic arc tangent.
+
+ float **cos** ( float x )
+ Cosine.
+
+ float **cosd** ( float x )
+ Cosine in degrees.
+
+ float **cosh** ( float x )
+ Hyperbolic cosine.
+
+ float **deg** ( float x )
+ Radians to degrees.
+
+ float **hypot** ( float x, float y )
+ Length of 2D vector ``[x, y]``.
+
+ float **rad** ( float x )
+ Degrees to radians.
+
+ float **sin** ( float x )
+ Sine.
+
+ float **sind** ( float x )
+ Sine in degrees.
+
+ float **sinh** ( float x )
+ Hyperbolic sine.
+
+ float **tan** ( float x )
+ Tangent.
+
+ float **tand** ( float x )
+ Tangent in degrees.
+
+ float **tanh** ( float x )
+ Hyperbolic tangent.
+
+****************
+Vector Functions
+****************
+
+.. glossary::
+
+ float angle ( vector a, vector b )
+ Angle between two vectors (in radians).
+
+ vector **cross** ( vector a, vector b )
+ Vector cross product.
+
+ float **dist** ( vector a, vector b )
+ Distance between two points.
+
+ float **dot** ( vector a, vector b)
+ Vector dot product.
+
+ float **length** ( vector v )
+ Length of vector.
+
+ vector **norm** ( vector v )
+ Vector scaled to unit length.
+
+ vector **ortho** ( vector a, vector b )
+ Vector orthographic to two vectors.
+
+ vector **rotate** ( vector v, vector axis, float angle )
+ Rotates ``v`` around axis by given ``angle`` (in radians).
+
+ vector **up** ( vector v, vector up )
+ Rotates ``v`` such that the Y axis points in the given ``up`` direction.
+
+
+**************
+Vector Support
+**************
+
+*Vectors* (points, colors, or 3D vectors) may be intermixed with *scalars*
+(simple floating point values). If a scalar is used in a vector context, it is
+replicated into the three components, e.g. ``0.5`` becomes ``[0.5, 0.5, 0.5]``.
+
+If a vector is used in a scalar context, only the first component is used.
+One of the benefits of this is that all the functions that are defined
+to work with scalars automatically extend to vectors. For instance,
+``pick``, ``choose``, ``cycle``, ``spline``, etc., will work just fine
+with vectors.
+
+Arithmetic operators such as ``+``, ``*``, etc., and scalar functions are
+applied component-wise to vectors. For example, applying the ``gamma``
+function to a map adjusts the gamma of all three color channels.
+
+***************
+Curve Functions
+***************
+
+Interpolation of parameter values to a set of control points is governed
+by the following functions.
+
+.. glossary::
+
+ color **ccurve** ( float param, float pos0, color val0, int interp0, float pos1, color val1, int interp1, [...] )
+ Interpolates color ramp given by control points at ``param``. Control
+ points are specified by triples of parameters ``pos_i``, ``val_i``, and
+ ``interp_i``.
+
+ .. hint::
+ Interpolation codes are:
+
+ - 0 - none
+ - 1 - linear
+ - 2 - smooth
+ - 3 - spline
+ - 4 - monotone (non-oscillating) spline
+
+ float **curve** ( float param, float pos0, float val0, int interp0, float pos1, float val1, int interp1, [...] )
+ Interpolates a 1D ramp defined by control points at ``param``. Control
+ points are specified by triples of parameters ``pos_i``, ``val_i``, and
+ ``interp_i``.
+
+ .. hint::
+ Interpolation codes are:
+
+ - 0 - none
+ - 1 - linear
+ - 2 - smooth
+ - 3 - spline
+ - 4 - monotone (non-oscillating) spline
+
+ float **spline** ( float param, float y1, float y2, float y3, float y4, [...] )
+ Interpolates a set of values to the parameter specified where
+ ``y1``, ..., ``yn`` are distributed evenly from ``[0, 1]``.
+
+**************
+Custom Plugins
+**************
+
+Custom functions may be written in C++ and loaded as one or more dynamic plugins. See `Writing Custom Expression Plugins <https://wdas.github.io/SeExpr/doxygen/plugins.html>`_ for more details.
+
+.. warning:: This functionality is not supported in Krita.
+
+.. |image0| image:: /images/seexpr/Se_voronoi_1.png
+.. |image1| image:: /images/seexpr/Se_voronoi_2.png
+.. |image2| image:: /images/seexpr/Se_voronoi_3.png
+.. |image3| image:: /images/seexpr/Se_voronoi_4.png
+.. |image4| image:: /images/seexpr/Se_voronoi_5.png
diff --git a/tutorials/seexpr.rst b/tutorials/seexpr.rst
new file mode 100644
index 000000000..acd7e951e
--- /dev/null
+++ b/tutorials/seexpr.rst
@@ -0,0 +1,255 @@
+.. meta::
+ :description lang=en:
+ Introduction to SeExpr
+
+.. metadata-placeholder
+ :authors: - L. E. Segovia <amy at amyspark.me>
+ :license: GNU free documentation license 1.3 or later.
+
+.. _seexpr_tut_intro:
+
+Introduction to SeExpr
+======================
+
+.. versionadded:: 4.3.1
+
+ This document will introduce you to the SeExpr expression language.
+
+****************
+What is SeExpr?
+****************
+
+SeExpr is an embeddable expression language, designed by Disney Animation,
+that allows host applications to render dynamically generated content.
+Pixar calls it `in its documentation <https://renderman.pixar.com/resources/RenderMan_20/PxrSeExpr.html>`_ a "scriptable pattern generator and
+combiner".
+
+SeExpr is available within Krita as a Fill Layer.
+
+.. seealso::
+ - :ref:`seexpr`
+ - :ref:`seexpr_fill_layer`
+ - :ref:`resource_seexpr_scripts`
+ - `"Procedural texture generator (example and wishes)" on Krita Artists <https://krita-artists.org/t/procedural-texture-generator-example-and-wishes/7638>`_
+ - `Inigo Quilez's articles <https://iquilezles.org/www/index.htm>`_
+ - `The Book of Shaders <https://thebookofshaders.com/>`_
+
+**********
+Background
+**********
+
+To understand what SeExpr is about, we need to differentiate between two types
+of graphics, *raster* and *procedural*.
+
+The vast majority of the computer-generated stuff you see every day belong to
+the first type-- images like photos, your favourite anime screenshots, memes,
+are all a multitude of tiny little dots of color, or *pixels*, arranged into a
+grid.
+
+Raster graphics have two drawbacks. First, once you create them, their
+resolution is **fixed**. You cannot zoom in and magically get any more detail.
+And if you need to change them, either you go back to the source and sample it
+again (which is sometimes impossible), or edit it with a raster graphics
+program, like Krita.
+
+One of the biggest problems, however, is that we are always limited by the
+**space** our programs can use; either secondary storage, like SD cards, or
+RAM. Unless compressed, image memory needs are `quadratic in the size of the
+image <https://blender.stackexchange.com/questions/112505/why-is-my-half-resolution-render-taking-a-quarter-of-the-time-of-the-full-one>`_.
+For a quick example, the :ref:`create_new_document` dialog of Krita tells
+you three bits of information: its size in pixels, the size of the pixel
+itself, and *the total memory needed*.
+
+.. image:: /images/Krita_newfile.png
+
+Here's a summary for square textures. Note that the memory needed
+is for *one layer only*:
+
+===== ==============
+Size Memory needed
+===== ==============
+256 256 KB
+512 1 MB
+1024 4 MB
+2048 16 MB
+4096 64 MB
+===== ==============
+
+An alternative is to use :ref:`vector_graphics`. Vector graphics, for instance
+SVGs, employ mathematic formulae like splines and Bézier curves to describe a
+shape. As they are mathematically defined, they can be resized to suit your
+needs without losing resolution.
+
+SeExpr belongs to a different class, *procedural graphics*. Similarly to vector
+graphics, procedural graphics only need a few KBs of secondary storage for
+their definition. But they are not defined by mathematical formulae; you
+actually *code* how the color is calculated at each point of the texture.
+And, because it is not limited in its precision, you can render complex
+patterns in your layers at completely arbitrary resolution.
+
+****************
+Writing a script
+****************
+
+In this tutorial, we'll show you how to write a script in SeExpr, render it to
+a layer, and then save it as a preset.
+
+We'll start by going to the :ref:`layer_docker`, and adding a new Fill Layer.
+Then select the SeExpr generator from the list. You'll be greeted by this
+window:
+
+ .. image:: /images/seexpr/SeExpr_editor.png
+
+The SeExpr generator dialog is divided in two tabs. For now, we'll stay on
+:guilabel:`Options`.
+
+.. note::
+ :ref:`fill_layers` describes these tabs in more detail.
+
+Let's start by painting a layer in light blue.
+
+First, SeExpr scripts must define an output variable, let's call it ``$color``.
+As SeExpr thinks of colors in the :ref:`RGB color space<model_rgb>`,
+color variables are defined by a triplet of numbers known as a *vector*.
+We'll start by defining the ``$color`` variable and giving it a value.
+
+Go to the text box, and clear it if it has any text.
+Then, define and set ``$color`` to something like ``[0.5, 0.5, 1]``
+(half lit red, half lit green, fully lit blue)::
+
+ $color = [0.5, 0.5, 1];
+
+SeExpr needs to know which variable holds the final color value. This
+is done by writing at the end, on its own line, the name of the variable::
+
+ $color
+
+The script should now look like this::
+
+ $color = [0.5, 0.5, 1];
+ $color
+
+Click :guilabel:`OK`, and you'll render your first script!
+
+ .. image:: /images/seexpr/SeExpr_first_render.png
+
+.. warning::
+ To be absolutely precise, SeExpr **has no color management**.
+ It always renders textures as :ref:`32-bit float <bit_depth>`,
+ :ref:`gamma corrected <linear_and_gamma>`,
+ sRGB images. Krita transforms them to your document's color space
+ using the sRGB-elle-V2-srgbtrc.icc profile.
+
+ See :ref:`color_managed_workflow` for what this means.
+
+**********************************
+Managing your script using widgets
+**********************************
+
+There is also another way to define and edit your variables.
+Open the fill layer's properties by right clicking on :guilabel:`Fill Layer 1`,
+and selecting :guilabel:`Layer Properties...`.
+
+.. image:: /images/seexpr/SeExpr_prop_1.png
+
+Notice the middle box? Once it detects a syntactically correct script,
+SeExpr enables a whole chunk of knobs to manage individual variables.
+In our example above, you can change ``$color``'s in three ways:
+
+- enter the red, green, or blue channel's value in the input fields
+- move the little colored sliders to change the respective channel
+- click on the preview square to the left of the boxes, to select a completely new color.
+
+The last button on the middle box is always :guilabel:`Add new variable`.
+Click it and this dialog will open:
+
+.. image:: /images/seexpr/SeExpr_add_variable.png
+
+This dialog shows you all the types of variables that SeExpr accepts:
+
+.. glossary ::
+
+ Curve and Color curve
+ They are the SeExpr version of :ref:`Stop Gradients <resource_gradients>`: they interpolate a ramp given by a set of values.
+
+ Curves represent 1D gradients, returning a single float at each evaluation point.
+
+ Color curves represent RGB gradients, returning a Color at each point.
+
+ Integers and Floats
+ Numbers.
+
+ Vector
+ A triplet of floats.
+
+ Color
+ A vector representing a RGB color.
+
+ Swatch
+ A list of Colors.
+
+ String
+ Usually single words.
+
+For instance, you could replicate ``$color`` in the :guilabel:`Vector` tab:
+
+.. image:: /images/seexpr/SeExpr_add_variable_vector.png
+
+**************************
+Creating your first preset
+**************************
+
+Once your script is ready, you can reuse it by making a preset.
+
+You can create one through the top bar of the Options tab:
+
+ .. image:: /images/seexpr/SeExpr_editor.png
+
+Select :guilabel:`Save New SeExpr Preset...` and the following dialog will
+open:
+
+ .. image:: /images/seexpr/SeExpr_save.png
+
+You can edit the name of the preset in the top line edit box, and set a thumbnail for easy identification.
+
+.. hint :: The dialog will append "Copy" to the preset's name if it is a copy of an existing one. You can change it at will.
+
+The dialog provides the following choices for setting a thumbnail:
+
+.. glossary::
+
+ Load Existing Thumbnail
+ If the preset already has a thumbnail (for instance, if you created it from an existing preset), this button will load and apply it.
+
+ Load Image
+ Applies an image from the filesystem as a thumbnail.
+
+ Render Script to Thumbnail
+ Renders your script to a 256x256 texture, and applies the latter as a thumbnail.
+
+ Clear Thumbnail
+ Deletes the thumbnail. Note that, if the preset is a copy of an existing one, this can be reverted by clicking :guilabel:`Load Existing Thumbnail`.
+
+*************************
+Changing existing presets
+*************************
+
+If you change a preset's script, you will notice two new buttons in the top bar of the :guilabel:`Options` tab:
+
+ .. image:: /images/seexpr/SeExpr_overwrite_preset.png
+
+The reload button will restore the preset to its original properties, while clicking on :guilabel:`Overwrite Preset` will save your changes.
+
+Additionally, you can edit the preset's name by clicking on the rename button,
+entering the new name, and clicking on :guilabel:`Save`:
+
+ .. image:: /images/seexpr/SeExpr_rename_preset.png
+
+
+*********************
+Bundling your presets
+*********************
+
+Sharing your scripts is easy! SeExpr script presets are just like any other
+resource in Krita. Follow the instructions in :ref:`resource_management` to
+create your own bundles.
More information about the kimageshop
mailing list