
/*! \addtogroup glsl shaders et GLSL 

le pipeline a besoin d'un vertex shader et d'un fragment shader pour fonctionner, repassez dans \ref intro3d si nécessaire, et 
dans \ref tuto2GL pour savoir comment les compiler, et \ref tuto3GL pour afficher simplement quelques triangles (un cube, par exemple).

## présentation GLSL

GLSL est le langage permettant d'écrire des shaders, il est très proche du C/C++, avec quelques limitations :
    - pas de pointeurs,
    - pas de fonctions récursives,
    - des tableaux, mais une dimension,
    - des structs, mais pas d'heritage,
    - pas de passage de valeur par référence, mais par copie.

il existe plusieurs versions du langage, il faut préciser laquelle avec la directive `#version xxx`. la version classique est
la version 330 / openGL 3.3. la plupart des shaders commencent donc par la ligne `#version 330`.

les types de base sont classiques : int, uint, bool, float, mais les vecteurs et les matrices sont définies ainsi que leurs opérations :
    - vec2, vec3, vec4 : pour des vecteurs à 2, 3, 4 composantes float,
    - ivec2, ivec3, ivec4 : pour des vecteurs d'entiers,
    - uvec2, uvec3, uvec4 : pour des vecteurs d'entiers non signés,
    - bvec2, bvec3, bvec4 : pour des vecteurs de bool,
    - mat2, mat3, mat4 : pour les matrices 2x2, 3x3 et 4x4.

la librairie standard contient à peu près tout ce qui est nécessaire pour des calculs graphiques, consultez la doc officielle :
[openGL SDK](https://www.opengl.org/sdk/docs/man/),
par exemple les produits de matrices, les produits matrices / vecteurs... 

l'initialisation des vecteurs, matrices et vecteurs n'utilise pas toujours la même syntaxe que le C++, par exemple :
\code
vec3 point;
point= vec3(1, 1, 1);
vec3 extremite= vec3(1, 0, 0);  // vec3 extremite(1, 0, 0); n'existe pas
vec3 direction= extremite - point;

mat4 m= mat4( vec4(....), vec4(...), vec4(...), vec4(...) );

vec3 positions[3]= vec3[3]( vec3(-0.5, -0.5, 0), vec3(0.5, -0.5, 0), vec3(0, 0.5, 0) );
\endcode

la déclaration des structures est sans surprise :
\code
struct Sphere
{
    vec3 centre;
    float rayon;
};

Sphere scene[4];
\endcode

les opérateurs sur les vecteurs et les matrices fonctionnent, là encore, sans surprises :
\code
vec4 point= vec4( ... );
mat4 m= mat4( ... );
vec4 r= m * point;

vec4 q= r + vec4( ... );
vec4 s= r + point;
\endcode

l'opérateur de sélection de composantes sur les vecteurs est plutôt pratique :
\code
vec4 a= vec4( ... );
vec3 b= a.xyz;
vec4 c= a.zwxx;

vec3 p= vec3( ... );
vec3 q.xzy= p.xzy;      // quelle valeur est affectee a q ?
\endcode

les constructeurs acceptent aussi d'extraire les premières composantes, pour les vecteurs mais aussi pour les matrices :
\code
vec4 p= vec4( ... );
vec3 q= vec3(p);        // ou q= p.xyz;

mat4 m= mat4( ... );
mat3 t= mat3(m);        // t[0]= vec3(m[0]); t[1]= vec3(m[1]); t[2]= vec3(m[2]);
\endcode

et ça fonctionne aussi dans l'autre sens, on peut construire un vecteur à partir d'un autre vecteur plus court, 
plus d'autres valeurs :
\code
#version 330

vec3 position= vec3( ... );
mat4 mvpMatrix= mat4( ... );

gl_Position= mvpMatrix * vec4(position, 1);     // position 3 floats + un float == 4 floats 
\endcode


### fonctions et passage par copie 

les fonctions (non récursives) s'écrivent comme d'habitude, la seule différence notable est le passage des paramètres 
qui utilise des mot clés `in`, `out`, `inout` pour indiquer les paramètres d'entrée, de sortie et d'entrée / sortie :
\code
void f1( in float a, out float b )
{
    b= a + 10;
}

void f2( in a, inout b )
{
    b= a + 2*b;
}
\endcode

il est également possible d'utiliser `const` sur les parametres des fonctions :
\code
void f1( const in float a, out float b )
{
    b= a + 10;
}

void f2( const in a, inout b )
{
    b= a + 2*b;
}
\endcode



## vertex shader et GLSL

un vertex shader est composée d'une fonction principale, `void main( void )`, et doit écrire les coordonnées des sommets 
dans une variable globale `vec4 gl_Position` (_rappel :_ coordonnées x, y, z et w dans le repère projectif).

les attributs se déclarent en global avec le mot clé `in`, les varyings/sorties avec `out`, les constantes initialisées avec `const`.

les variables fournies par l'application sont déclarées avec le mot-clé `uniform` en plus de leur type et de leur nom.

le vertex shader à également accès à des variables définies par le pipeline, elles sont toutes prefixées par `gl_` 
(cf  [openGL SDK](https://www.opengl.org/sdk/docs/man/), section glsl, lettre g), 
par exemple : gl_VertexID, l'indice du sommet à traiter.

exemple :
\code
// vertex shader de tuto3GL
#version 330

uniform vec3 positions[36];     // declare un uniform, un tableau de vec3
uniform float time;             // declare un uniform, time de type float

const vec3 deplace= vec3(...);  // declare une constante

void main( )
{
    gl_Position= vec4( positions[gl_VertexID] + deplace * time / 1000.0, 1.0 );
    // positions[gl_VertexID] est un vec3 + vec3 * float / float, ce qui donne bien un vec3
    // et le vec3 est complete par une valeur pour etre affecte a un vec4
}
\endcode

le vertex shader déclare, en général, des attributs de sommets initialisés par le pipeline (l'application devra configurer 
un vertex array et créer des buffers, cf \ref tuto4GL) :
\code
// vertex shader et attributs
#version 330

in vec3 position;               // declare un attribut, position de type vec3

uniform mat4 mvpMatrix;         // declare un uniform, mvpMatrix de type mat4

void main( void )
{
    gl_Position= mvpMatrix * vec4(position, 1);
}
\endcode


## fragment shader et GLSL

le fragment shader est similaire au vertex shader, mais il ne peut pas utiliser les valeurs des attributs, ils ne sont plus
accessibles, uniquement leurs valeurs interpolées, les _varyings_ (repassez dans \ref intro3d et \ref pipeline, si ce n'est 
pas clair)

la couleur du fragment doit être écrite dans un `out vec4 gl_FragColor` ou une variable en sortie déclarée par le shader 
`out vec4 fragment_color;` selon la version d'openGL.

un fragment shader peut déclarer des uniforms et des varyings, et accéder à plusieurs variables définies par le pipeline, 
par exemple :
    - `vec4 gl_FragCoord`, les coordonnées dans le repère image du fragment,
    - `int gl_PrimitiveID`, l'indice de la primitive, du triangle, traité par le shader,
    - `bool gl_FrontFacing`, l'orientation de la primitive traitée par le shader, toujours vrai si les faces arrières sont éliminées 
    avant la fragmentation (cf \ref intro3d).

exemple:
\code
// fragment shader et variables
#version 330

uniform vec3 back_color;        // uniform, couleur pour les faces mal orientees

out vec4 fragment_color;        // varying, couleur du fragment, ecrite dans l'image par le pipeline

void main( void )
{
    vec3 color;
    
    // utiliser l'indice du triangle, gl_PrimitiveID, pour fabriquer une couleur "aleatoire"
    color= vec3(1.0 - float(gl_PrimitiveID % 100) / 99.0, float(gl_PrimitiveID % 10) / 9.0, float(gl_PrimitiveID % 1000) / 999.0);
    // glsl n'autorise pas les casts avec la syntaxe du C, 
    // donc utiliser la notation constructeur comme en C++
    
    // si le triangle est une face arriere, l'afficher d'une couleur differente, cf parametre uniform, initialise par l'application 
    if(gl_FrontFacing == false)
        color= back_color;
        
    fragment_color= vec3(color, 1);       // couleur opaque, alpha= 1
}
\endcode


## uniforms, varyings et variables

à quoi servent les différents types de variables ?
    - les `uniform` correspondent à des valeurs fournies par l'application, elles ne changent pas de valeur pendant l'exécution des shaders, cf \ref tuto2GL,
    
    - les `in` sont les entrées du shader : 
        - pour un vertex shader, ils représentent les attributs du sommet, c'est le pipeline qui affecte 
        les valeurs en fonction du vertex array object sélectionné par l'application au moment du draw( ). cf \ref tuto4GL
        
        - pour les autres shaders, les fragment shaders, par exemple, ce sont des varyings, des entrées qui doivent correspondre à des sorties déclarées par 
        les shaders précédents dans le pipeline. ces variables n'existent que pendant l'exécution du pipeline et ne sont pas accessibles par l'application.
    
    - les `out` sont les sorties du shader.

_exemple :_
si chaque sommet est décrit par une position et une couleur, les entrées du vertex shader sont 2 attributs, déclarés avec `in` et configurés par l'application.

\code
#version 330
// vertex shader

in vec3 position;               // attribut
in vec4 color;                  // attribut

void main( )
{
    gl_Position= ... ;          // obligatoire, affecter une position
}
\endcode

si on veut que le fragment shader utilise la couleur des sommets pour calculer sa couleur, il faut les lui transmettre explicitement, il ne peut pas y accéder 
tout seul. dans ce cas, la couleur est un varying, déclarée comme sortie optionnelle du vertex shader (avec `out`) et comme entrée (avec `in`) 
du fragment shader.

\code
#version 330
// vertex shader

in vec3 position;
in vec4 color;

out vec4 vertex_color;          // sortie, varying
void main( )
{
    vertex_color= color;
    gl_Position= ... ;
}
\endcode

\code
#version 330
// fragment shader

in vec4 vertex_color;           // entree, varying, meme type et meme nom que dans le vertex shader

out vec4 fragment_color;        // varying, couleur du fragment, ecrite dans l'image par le pipeline

void main( )
{
    fragment_color= vertex_color;
    // le fragment shader doit ecrire une couleur dans la variable declaree en sortie, cf out vec4 fragment_color.
}
\endcode
 */
