use SnippetHook;
use fmt;
// @short_description: Functions for creating and manipulating shader snippets
//
// #Snippets are used to modify or replace parts of a
// #Pipeline using GLSL. GLSL is a programming language supported
// by OpenGL on programmable hardware to provide a more flexible
// description of what should be rendered. A description of GLSL
// itself is outside the scope of this documentation but any good
// OpenGL book should help to describe it.
//
// Unlike in OpenGL, when using GLSL with it is possible to write
// short snippets to replace small sections of the pipeline instead of
// having to replace the whole of either the vertex or fragment
// pipelines. Of course it is also possible to replace the whole of
// the pipeline if needed.
//
// Each snippet is a standalone chunk of code which would attach to
// the pipeline at a particular point. The code is split into four
// separate strings (all of which are optional):
//
// declarations
//
// The code in this string will be inserted outside of any fn in
// the global scope of the shader. This can be used to declare
// uniforms, attributes, varyings and functions to be used by the
// snippet.
//
// pre
//
// The code in this string will be inserted before the hook point.
//
// post
//
// The code in this string will be inserted after the hook point. This
// can be used to modify the results of the builtin generated code for
// that hook point.
//
// replace
//
// If present the code in this string will replace the generated code
// for the hook point.
//
//
// All of the strings apart from the declarations string of a pipeline
// are generated in a single fn so they can share variables
// declared from one string in another. The scope of the code is
// limited to each snippet so local variables declared in the snippet
// will not collide with variables declared in another
// snippet. However, code in the 'declarations' string is global to
// the shader so it is the application's responsibility to ensure that
// variables declared here will not collide with those from other
// snippets.
//
// The snippets can be added to a pipeline with
// pipeline_add_snippet() or
// pipeline_add_layer_snippet(). Which fn to use depends on
// which hook the snippet is targetting. The snippets are all
// generated in the order they are added to the pipeline. That is, the
// post strings are executed in the order they are added to the
// pipeline and the pre strings are executed in reverse order. If any
// replace strings are given for a snippet then any other snippets
// with the same hook added before that snippet will be ignored. The
// different hooks are documented under #SnippetHook.
//
// For portability with GLES2, it is recommended not to use the GLSL
// builtin names such as gl_FragColor. Instead there are replacement
// names under the * namespace which can be used instead. These
// are:
//
// uniform mat4
// modelview_matrix
//
// The current modelview matrix. This is equivalent to
// #gl_ModelViewMatrix.
//
// uniform mat4
// projection_matrix
//
// The current projection matrix. This is equivalent to
// #gl_ProjectionMatrix.
//
// uniform mat4
// modelview_projection_matrix
//
// The combined modelview and projection matrix. A vertex shader
// would typically use this to transform the incoming vertex
// position. The separate modelview and projection matrices are
// usually only needed for lighting calculations. This is
// equivalent to #gl_ModelViewProjectionMatrix.
//
// uniform mat4
// texture_matrix[]
//
// An array of matrices for transforming the texture
// coordinates. This is equivalent to #gl_TextureMatrix.
//
//
// In a vertex shader, the following are also available:
//
// attribute vec4
// position_in
//
// The incoming vertex position. This is equivalent to #gl_Vertex.
//
// attribute vec4
// color_in
//
// The incoming vertex color. This is equivalent to #gl_Color.
//
// attribute vec4
// tex_coord_in
//
// The texture coordinate for layer 0. This is an alternative name
// for #tex_coord0_in.
//
// attribute vec4
// tex_coord0_in
//
// The texture coordinate for the layer 0. This is equivalent to
// #gl_MultiTexCoord0. There will also be #tex_coord1_in and
// so on if more layers are added to the pipeline.
//
// attribute vec3
// normal_in
//
// The normal of the vertex. This is equivalent to #gl_Normal.
//
// vec4
// position_out
//
// The calculated position of the vertex. This must be written to
// in all vertex shaders. This is equivalent to #gl_Position.
//
// float
// point_size_in
//
// The incoming point size from the point_size_in attribute.
// This is only available if
// pipeline_set_per_vertex_point_size() is set on the
// pipeline.
//
// float
// point_size_out
//
// The calculated size of a point. This is equivalent to #gl_PointSize.
//
// varying vec4
// color_out
//
// The calculated color of a vertex. This is equivalent to #gl_FrontColor.
//
// varying vec4
// tex_coord0_out
//
// The calculated texture coordinate for layer 0 of the pipeline.
// This is equivalent to #gl_TexCoord[0]. There will also be
// #tex_coord1_out and so on if more layers are added to the
// pipeline. In the fragment shader, this varying is called
// #tex_coord0_in.
//
//
// In a fragment shader, the following are also available:
//
// varying vec4 color_in
//
// The calculated color of a vertex. This is equivalent to #gl_FrontColor.
//
// varying vec4
// tex_coord0_in
//
// The texture coordinate for layer 0. This is equivalent to
// #gl_TexCoord[0]. There will also be #tex_coord1_in and so
// on if more layers are added to the pipeline.
//
// vec4 color_out
//
// The final calculated color of the fragment. All fragment shaders
// must write to this variable. This is equivalent to
// #gl_FrontColor.
//
// float depth_out
//
// An optional output variable specifying the depth value to use
// for this fragment. This is equivalent to #gl_FragDepth.
//
// bool front_facing
//
// A readonly variable that will be true if the current primitive
// is front facing. This can be used to implement two-sided
// coloring algorithms. This is equivalent to #gl_FrontFacing.
//
// vec2 point_coord
//
// When rendering points, this will contain a vec2 which represents
// the position within the point of the current fragment.
// vec2(0.0,0.0) will be the topleft of the point and vec2(1.0,1.0)
// will be the bottom right. Note that there is currently a bug in
// where when rendering to an offscreen buffer these
// coordinates will be upside-down. The value is undefined when not
// rendering points. This builtin can only be used if the
// %FEATURE_ID_POINT_SPRITE feature is available.
//
//
// Here is an example of using a snippet to add a desaturate effect to the
// generated color on a pipeline.
//
// <programlisting>
// Pipeline *pipeline = pipeline_new ();
//
// /* Set up the pipeline here, ie by adding a texture or other
// layers */
//
// /* Create the snippet. The first string is the declarations which
// we will use to add a uniform. The second is the 'post' string which
// will contain the code to perform the desaturation. */
// Snippet *snippet =
// snippet_new (SNIPPET_HOOK_FRAGMENT,
// "uniform float factor;",
// "float gray = dot (vec3 (0.299, 0.587, 0.114), "
// " color_out.rgb);"
// "color_out.rgb = mix (vec3 (gray),"
// " color_out.rgb,"
// " factor);");
//
// /* Add it to the pipeline */
// pipeline_add_snippet (pipeline, snippet);
// /* The pipeline keeps a reference to the snippet
// so we don't need to */
// object_unref (snippet);
//
// /* Update the custom uniform on the pipeline */
// int location = pipeline_get_uniform_location (pipeline, "factor");
// pipeline_set_uniform_1f (pipeline, location, 0.5f);
//
// /* Now we can render with the snippet as usual */
// push_source (pipeline);
// rectangle (0, 0, 10, 10);
// pop_source ();
// </programlisting>