Updated for Snowmix 0.4.4
Snowmix supports shapes from version 0.4.1 and onwards. Shapes makes it possible to construct complicated graphics as overlay for the video mixer using simple graphic primitives known from the Cairo Graphics library including the following primitives:
Shapes support control of the alpha channel as well as painting with colours, shape based clipping, images, live video feeds and a lot more.
A shape is the basic drawing mechanism in Snowmix. A shape is defined by a place holder id, a name and a list of graphic primitives executed in the order they are defined. The list of graphic primitives can include reference to one or more other shapes recursively.
In the following example 3 basic shapes are defined:
# Basic shape : Circle shape add 1 Unit Circle shape arc_cw 1 0 0 0.5 0 2PI # Basic shape : Rectangle shape add 2 Unit Rectangle shape rectangle 2 -0.5 -0.5 1 1 # Basic shape : Diamond shape add 3 Unit Diamond shape moveto 3 0.5 0 shape linerel 3 -0.5 0.5 shape linerel 3 -0.5 -0.5 shape linerel 3 0.5 -0.5 shape linerel 3 0.5 0.5
First we create a place holder for the shape using the shape id 1 and give it the name Unit Circle. Then we add the arc_cw graphic primitive to shape id 1 and specify the center of the arc to be 0,0 and the radius to be 0.5. Furthermore we define the starting angle to be 0 and the ending angle to be 2PI. Technically speaking, this is not a unit circle as the radius of the circle is 0.5 and not 1, but we name it a unit circle because it covers one pixel.
Likewise for shape id 2 and shape id 3 we define a rectangle shape and a diamond shape each covering exactly one pixel. The syntax for the commands discussed in this section are:
shape add [shape id> [<shape name>]] // shape id alone deletes shape shape arc_cw <shape id> <x> <y> <radius> <angle from> <angle to> shape moveto <shape id> <x> <y> shape linerel <shape id> <x> <y> shape rectangle <shape id> <x> <y> <width> <height> shape recursion <shape id> <level>
For created shapes to appear on screen, 3 things must be done. We must:
First we define two shapes including stroke or fill. This is shown below here.
shape add 10 Circle shape inshape 10 1 shape fill 10 shape add 11 Square shape inshape 11 2 shape source rgb 11 1.0 0.0 0.0 shape line width 11 -2.5 shape stroke 11
First we create a place holder for shape id 10 giving it the name Circle, Then we define shape 10 to include shape id 1 defined earlier and adds the command fill. It should be noted that no colour source definition has been given. Because of this, the shape, when it is drawn, it will inherit its colour from the colours set in the shape place comnmand. The second shape is defined as shape id 11 and given the name Square. This shape includes shape id 2 defined earlier, adds the colour red (1,0,0), defines the line width as -2.5 and ends with a stroke meaning a line of the absolute width of 2.5 will be drawn along the path defined (a square rectangle placed at 0,0 with the size 1). Negative line width is considered absolute no matter what scale is applied when the shape is used by a shape place command. Otherwise the line width will scale accordingly to the scale of the shape place command. Note that absolute line width gets fuzzy, when asymmetrical scaling is used, ie. scale_x and scale_y is not identical. The new commands introduced here have the the following syntax:
shape source rgb <shape id> <red> <green> <blue> [<alpha>] shape stroke <shape id> shape fill <shape id> shape line width <shape id> <width> shape inshape <shape id> <inshape id>
The two shapes defined, shape id 10 and 11, can now be placed using the command shape place. This command has the following syntax:
shape place [<place id> [ <shape id> <x> <y> <scale x> <scale y> [<rotation> [<red> <green> <blue> [<alpha> [(nw | ne | se | sw | n | s | e | w )]]]]]]
The last parameter is the anchor as for texts, images and virtual feeds can be one of nw, n, ne, e etc for north west, north, north east, east etc. An anchor is added to the coordinates x,y. Anchors are shown in the text tutorial video 1:04 into the video.
Assuming we want two circles, one in red and one in blue, one with the radius of 5 and the other 25 and one placed at 100,100 and the other at 45,55 and finally one with alpha 1.0 and the other with alpha 0.5, we apply the following two commands:
shape place 0 10 100.0 100.0 5.0 5.0 0.0 1.0 0.0 0.0 1.0 shape place 1 11 45.0 55.0 25.0 25.0 0.0 0.0 0.0 1.0 0.5
These 2 commands create two placed shapes with the placed shape id 0 and 1. Note that the placed shape id is not the shape id. If we want to display the two shapes, all we now need to do is to instruct the Snowmix main video loop to include it. Assuming the macro Show is the macro that will be called in the main video loop, we need to include the following command in it:
shape place overlay 0 1
The command shape place overlay follows the syntax for id numbers for overlay text, overlay virtual feeds and overlay image and these commands will in future versions be renamed to text overlay, image overlay etc.
Every time a placed shape is drawn the following cairo functions are called using the parameters from the placed shape place holder:
cairo_save(context) cairo_set_source_rgba(red,green,blue,alpha) cairo_translate(x,y) cairo_rotation(rotation) cairo_scale(scale_x, scale_y) cairo_new_path() OverlayShape(shape_id) cairo_scale(1/scale_x, 1/scale_y) cairo_rotation(-rotation) cairo_translate(-x,-y) while (contexts to restore) cairo_restore(context)
The last line restore the context back to its original state repeatedly in case context saved in shapes where not equally restored.
The OverlayShape function invokes the list of graphic primitives that has been defined for the shape identified by the shape id for the placed shape identified by its place id.
The parameters of a placed shape can be changed using the following commands:
shape place coor <place id> <x> <y> [(nw | ne | se | sw | n | s | e | w )] shape place shape <place id> <shape id> shape place scale <place id> <scale x> <scale y> shape place rotation <place id> <rotation> shape place rgb <place id> <red> <green> <blue> [<alpha>] shape place alpha <place id> <shape id> <alpha> shape place offset <place id> <offset x> <offset y>
Placed shapes can be animated with the following commands:
shape place move coor <place id> <delta x> <delta y> <steps x> <steps y> shape place move offset <place id> <delta x> <delta y> <steps x> <steps y> shape place move alpha <place id> <delta alpha> <steps> shape place move rotation <place id> <delta rotation> <steps> shape place move scale <place id> <delta scale_x> <delta scale y> <steps x> <steps y>
The delta value is the value that will be added to its parameter after each frame. The steps define how many times or frames the delta value will be added.
The definition of shapes can include drawing video feeds and already loaded images. In the context of shapes, video feeds are images that happens to change at system frame rate. Images are loaded using the image load command described elsewhere and video feeds are defined using the feed commands also described elsewhere. When using video feeds and loaded images, quite often knowing the geometry of the feeds and the images will be important to be able to place the resulting images correctly.
The syntax for including images and feeds when defining shapes is:
shape image <shape id> <image id> <x> <y> <scale_x> <scale_y> shape feed <shape id> <feed id> <x> <y> <scale_x> <scale_y>
The shape_id is the shape id of the shape being defined. The image_id and the feed_id is the id of the image and feed defined by the image load and feed commands. The x and y is the position to place the image or feed relative to the coordinates of the shape being placed. In the current version the position reference the position of the top left corner of the image or feed. In the following we will define two shapes, one shape with an image and one shape with a video feed. It is assumed that an image with id 5 has been loaded and that video feed 3 exist.
shape add 1 Image Shape shape image 1 5 0 0 1.0 1.0 shape paint 1 shape add 2 Video Feed Shape shape feed 2 3 10 200 1.0 1.3333333 shape paint 2 0.6
The lines 1 and 4 defines shape 1 and shape 2 named Image Shape and Video Feed Shape. Line 2 defines shape 1 to add image loaded id 5 and place it at 0,0 relative to where the shape will be used and scaled 1:1 in both x and y direction. Line 3 ensures that when shape 1 is used, it will be painted. Without this the shape will not have any effect when used alone. Line 5 adds video feed 3 to shape 2. The video feed will be placed at 10,200 relative to where the shape is placed. The feed in the shape will be scaled absolute to 1:1 for the x direction and 1:1.333333 for the y direction. Finally in line 6, shape 2 is instructed to paint the shape 2 with alpha being 0.6. Not specifying an alpha value for shape paint is equivalent to specifying an alpha value of 1.0. The alpha value in the paint command will be multiplied with the alpha value for a shape placed using or referencing the shape.
Now we have defined two shapes, we can now start placing them. The following illustrates this.
shape place 4 1 100 100 0.5 0.5 0.0 0 0 0 1.0 shape place 5 2 200 200 2.0 2.0 0.0 0 0 0 0.8
Here shape place 4 is placing shape 1, which is the image shape defined further up, at 100,100 and scale it half size in both x and y direction. The rotation of the placed shape is set to 0.0, which is no rotation. The background of the shape is set to 0,0,0 which is black, but in this case it has no effect as the shape will be defined by the image only and the alpha is set to 1.0. Shape place 5 places the shape 2, which is the video feed shape defined further up, at 200,200 and scales the shape to double size in both x and y direction. However scaling shape placed 5 will in this case have no effect because the shape used has defined its feed to be scaled absolut to 1:1 in x and 1:1.333333 in the y direction. You can read more about scaling images and feeds below. As for the shape placed placing the image shape, the rotation is set to 0.0 and the background is set to black, with no effect in this case. The alpha of the placed shape is set to 0.8. Because the feed in shape 2 is painted with alpha 0.6 relative, the video feed will eventually be painted with alpha being 0.6*0.8 = 0.48.
Finally to actually have the shapes being overlayed the mixer frame, we need to add one of the following 4 commands to the Snowmix main video mixer loop.
shape place overlay all shape place overlay 1..2 shape place overlay 1..end shape place overlay 1 2
When a feed or an image in a shape is overlayed, the method for doing so is by default a fast method. The fast method is in most cases a sufficient solution, but in some cases, especially when scaling of the feed or image is applied, a better solution is required. If the command shape filter follows immediately after the command shape feed or shape image in a shape definition, then the shape filter can control the overlay method and as such the quality. If the shape filter command is omitted, the default method is fast. In the following example a shape with a feed is defined and the overlay method or filter is set to bilinear instead of fast.
shape add 1 My shape shape moveto 1 0.0000 0.0000 shape inshape 1 2 shape clip 1 shape newpath 1 shape feed 1 -640.0000 -360.0000 0.6500 0.6500 shape filter 1 bilinear shape paint 1 1.0000
WARNING: Any filter setting not being fastor nearest will make the overlaying of that image 30-50 times slower. This can have serious implication for Snowmix if the system it is running on is not fast enough. The *shape filter command has the following syntax:
shape filter <shape id> (fast | good | best | nearest | bilinear | gaussian)
When you add an image command or a feed command to a shape definition, you are required to specify a scaling value for the x direction and the y direction. If you define the x and y scale being larger than 0.0, the final scaling of the image or video feed will be absolute and not also depend of the scale of shape place it will used in. If you define the x and y scale being less than 0.0, the final scale of the image or feed will be the positive scale multiplied the scale of the placed shape. If you set the scale of the image or feed command to be 0.0, this is equivalent to setting the scale to -1,-1. This will scale the image or feed exactly as the placed shape is scaled. If the image or feed scale is defined with a positive scale for x and negative scale for y or vice versa, the scale values of the image or feed will be ignored and the final scale will only depend on scale values given for the shape placed.
If you want to clip the image or feed used to define a shape, a clipping path or clipping shape has to be defined. The following examples will clip a circle and a square out of a video feed and overlay it. We assume the unit shapes defined earlier are available.
shape add 10 Circle Clipped Feed shape inshape 10 1 shape clip 10 shape newpath 10 shape feed 10 1 -384 -288 1.0 1.0 shape paint 10 1.0 shape add 11 Square Clipped Feed shape inshape 11 1 shape clip 11 shape newpath 11 shape feed 11 1 -384 -288 1.0 1.0 shape paint 11 0.5 shape place 1 10 100 100 75 75 0.0 0 0 0 1.0 shape place 2 11 300 300 200 200 0.0 0 0 0 1.0
Here we define shape place 1 to place shape 10 at 100,100 and scale it to 75,75. Alpha is set to 1.0. Shape 10 is defined as a circle clipped out of video feed 1. Video feed 1 is scaled absolute to 1 for both x and y and placed relative to the shape and the clipping with an offset of -384,-288. If video feed 1 has a width of 768 and a height of 576, then this will place video feed in the center of the clipping.
Shape place 2 does the same as shape place 1 except shape 11 is used and placed in 300,300 and scaled 200,200. The effect is that a square of 200x200 is clipped out of feed 1 and placed at 300,300. The reason why scaling and clipping matches so nicely is that the clipping shapes are defined to be placed in 0,0 and set to cover one pixel. If you define larger clipping scales, you will need to lower the scale of the shape placed.
The example above assumes that the Snowmix main video mixer loop includes a command to overlay shape placed 1 and 2 as described several times on this page.
Snowmix supports use of linear and radial patterns for sourcing colour patterns and masking (alpha blending) feeds and images. To create a pattern, a place holder for it needs to be created first using the shape pattern add command. The command has the following syntax:
shape pattern add [<pattern id> [<pattern name>]]
Using the command alone without any parameters lists the pattern place holders created. Using the command with just a pattrn id as parameter deletes the place holder identified by the pattern id number.
After creating the place holder, a pattern type and pattern geometry can be assigned to it using either the command shape pattern linear or shape pattern radial. The commands have the following syntax:
shape pattern radial <pattern id> <cx0> <cy0> <radius0> <cx1> <cy1> <radius1> shape pattern linear <pattern id> <x1> <y1> <x2> <y2>
After a pattern type and geometry has been assigned to the pattern place holder, a list of stoprgb parameters can be assigned to the pattern identified by its place holder id similar to what is known from using the Cairo graphics library. The stobrgb command has the following syntax:
has been assigned to the
shape pattern stoprgb <pattern id> <offset> <red> <green> <blue> [<alpha>]
Now that the pattern has been fully defined, the pattern can be used to either source a colour pattern or mask an image or feed. The commands for sourcing and masking have the following syntax:
shape source pattern <shape_id> <pattern id> shape mask pattern <shape_id> <pattern id>
The sourcing command is similar in use to the shape source rgb command. In the follwing example, we will define a linear and a radial pattern and use it for sourcing and masking. First we define two place holders and assign patterns
shape pattern add 1 Unit Linear Top-Bottom shape pattern add 2 Unit Radial In-Out shape pattern linear 1 0 -0.5 0 0.5 shape pattern radial 2 0 0 0.0 0 0 0.5
These commands define two place holders with place holder id 1 and 2. The first pattern is a linear pattern going from 0,-0.5 to 0,0.5 which in this case happens to be a vertical line centered at 0,0 and having a length of 1 pixel. The second pattern is one circle placed at 0,0 with a radius of 0 and a second circle likewise placed at 0,0, but with a radius of 0.5. Both patterns here are intentionally sized to be one pixel as for the unit shapes previously defined. The reason for this will be explained later. Now it is time to add stoprgb list as shown below here:
shape pattern stoprgb 1 0.00 0 0 0 1.0 shape pattern stoprgb 1 1.00 0 0 0 0.0 shape pattern stoprgb 2 0.00 0 0 0 1.0 shape pattern stoprgb 2 0.50 0 0 0 0.8 shape pattern stoprgb 2 0.60 0 0 0 0.6 shape pattern stoprgb 2 0.70 0 0 0 0.4 shape pattern stoprgb 2 1.00 0 0 0 0.0
Patterns can be used both as colour source when a shape is painted as well as alpha mask when an image is painted. Using a pattern is similar to use a rgb as source. In the following examples for using patterns will be shown. First we define a pattern with the pattern id 2:
shape pattern add 2 Unit Radial In-Out shape pattern radial 2 0 0 0.0 0 0 0.5 shape pattern stoprgb 2 0.00 1 0 0 0.0 shape pattern stoprgb 2 0.20 1 0 0 0.0 shape pattern stoprgb 2 0.50 1 0 0 1.0 shape pattern stoprgb 2 0.60 1 0 0 0.9 shape pattern stoprgb 2 0.70 1 1 0 0.8 shape pattern stoprgb 2 0.80 1 1 0 0.6 shape pattern stoprgb 2 0.90 1 1 1 0.4 shape pattern stoprgb 2 1.00 1 1 1 0.0
The pattern is a radial pattern and has 8 stoprgb entries 0.00, 0.20 and up to 1.00. Entries in stoprgb are defined to be between 0.0 (start) to 1.0 (end). The colour range from pitch black over red, yellow and ending in white. The alpha is set to 0.0 at the center up to 1.0 at 0.5 and down to 0.0 at 1.0. If we reuse the definition of the unit cirlce defined as shape 1, we can now define a shape that will use the pattern as a source as shown below for shape id 21.
shape add 21 Combined Clip using a pattern. shape inshape 21 1 shape clip 21 shape newpath 21 shape source pattern 21 2 shape paint 21 1.0
Here we see the fifth line is using the pattern defiend above. Instead of using the command shape source rgba described earlier and used for solid colours, we here apply a pattern before issuing the paint command. Now of course if we want to see the shape defined above, we need to place a shape using the shape place command and we need to add the shape place overlay command to the main video loop as described earlier.
Now if we want to use the alpha channel of the pattern to paint an image or a video feed, we can reuse the pattern described above. In addition to this, we reuse the circle unit shape with the shape id 1 as well as defining a shape mapping a video feed as shown below.
shape add 11 Source Feed 1 shape feed 11 1 -384 -288 1.09090909 1.0
Here we defined shape 11 to use (video) feed 1 and in this case the feed has a video geometry of 704x576 with PAR being 12:11 (704x576 -> 768x576). 12/11 = 1.090909....
If we reuse the shape id 21 for the combined clip, we can define it as shown below.
shape add 21 Combined Clip #1 shape inshape 21 1 shape clip 21 shape newpath 21 shape inshape 21 11 shape mask pattern 21 2
Here the shape mask pattern command is the command that transfers the video feed frame onto the overlay using the alpha values defined for the pattern.
As stated in the beginning, a shape can reference one or more other shapes. Such a reference can be circular/recursive, either directly or through one or more other shapes. In this case this would create an infinite loop and break the functionality of Snowmix thus subsequently to be avoided. However Snowmix currently accepts up to 10 levels of a shape recursively referencing another shape. This is controlled by the declaration of OVERLAY_SHAPE_LEVELS in the file video_shape.h. In addition to this, the command shape recursion adds control over the number of recursions accepted. This can be used for iterate a controlled number of identical shape commands. This is useful if the repeated command change relative position, scale, rotation etc. in each iteration. A recursion level of 0 prevents any call to another shape from within a shape. The following example sets the shape recursion level to 10 drawing one 10 steps stairway.
shape add 1 Step Shape shape linerel 1 0 1 shape linerel 1 1 0 shape inshape 1 shape add 2 Steps shape moveto 2 0 0 shape inshape 2 1 shape line width 2 -1 shape stroke 2 shape recursion 10 shape place 1 2 100 100 10 10
Using only relative placed commands after a newpath such as linerel, moverel and then followed by fill or stroke or paint etc. will confuse the graphic engines context and spill over between placed shapes quite likely preventing further rendering of the frame. The reason for this is not known, but it is a good idea to avoid this. The workaround is to ensure that after a newpath and absolute command such as moveto or lineto etc. follows. This also applies recursively. So the following example is *to be avoided:
shape newpath 3 shape linerel 3 10 0 shape linerel 3 10 10 shape linerel 3 0 10 shape linerel 3 0 0 shape fill 3
The following example works
shape newpath 3 shape moveto 3 0 0 shape linerel 3 10 0 shape linerel 3 10 10 shape linerel 3 0 10 shape linerel 3 0 0 shape fill 3
Discussion: Reference manual for shapes, a wiki on how to use shapes and a reference for Cairo Graphics
Discussion: Reference mnual for feeds available.
Wiki: Reference Cairo Graphics
Wiki: Reference Command
Wiki: Reference Feeds
Wiki: Reference General
Wiki: Reference Placed Shapes
Wiki: Reference Shapes
Wiki: Reserved Commands