
/*! \addtogroup tuto_mesh_shader tuto9

cf \ref tuto9.cpp

Mesh::draw( ) et les utilitaires DrawParam de draw.h dessinent l'objet avec un shader crée en fonction de la description de l'objet et des paramètres. Il est aussi 
très simple de continuer à utiliser Mesh pour décrire l'objet et de le dessiner avec un shader différent, cf Mesh::draw( const GLuint program ). Il faut par contre
créer et configurer le shader avant de pouvoir dessiner l'objet.

repassez dans \ref intro3d et \ref glsl, si nécessaire.

## créer un shader program

repassez dans \ref tuto2GL, si nécessaire.

\code
GLuint program= 0;

program= read_program("...");
program_print_errors(program);
\endcode

## configurer un shader program

les attributs des sommets sont configurés par Mesh, il faut respecter la convention utilisée par Mesh :
    - attribut 0, `vec3 position`,
    - attribut 1, `vec2 texcoord`,
    - attribut 2, `vec3 normal`,
    - attribut 3, `vec4 color`.
    
voila la déclaration à utiliser dans le vertex shader :
\code
layout(location= 0) in vec3 position;
layout(location= 1) in vec2 texcoord;
layout(location= 2) in vec3 normal;
layout(location= 3) in vec4 color;
\endcode

Le vertex shader aura probablement besoin d'appliquer une transformation aux sommets, il faut donc la lui transmettre. repassez dans \ref tuto3GL, si nécessaire.
\code
// selectionner le shader program, si necessaire
// glUseProgram(program);

Transform mvp= { ... };
program_uniform(program, "mvpMatrix", mvp);
\endcode

En général c'est un Orbiter qui fournit les transformations `view` et `projection`:
\code
Orbiter camera= { ... };

Transform model= { ... };
Transform view= camera.view();
Transform projection= camera.projection(window_width(), window_height(), 45);
Transform mvp= projection * view * model;
\endcode

## dessiner

Une fois le shader program complètement paramétré, il ne reste plus qu'à dessiner l'objet :
\code
Mesh objet= { ... };
GLuint program= { ... };

objet.draw(program);
\endcode

cf \ref tuto9.cpp pour un exemple complet qui utilise un uniform supplémentaire, qui permet de donner la même couleur aux pixels de l'objet.

## et avec une texture ?

Il y a plusieurs étapes :
    - d'abord charger la texture, cf GLuint texture= read_texture(0, fichier ); documenté dans texture.h,
    - vérifier que les sommets de l'objet à dessiner sont bien associés à des coordonnées de texture, cf Mesh::texcoord() pour décrire les attributs 
    de sommet, ou Mesh::texcoord_buffer_size(), pour vérifier que les coordonnées de texture sont bien présentes,
    - déclarer l'attribut dans le vertex shader, cf layout(location= 1) in vec2 texcoord;
    - transmettre les texcoord au fragment shader,
    - lire la texture dans la fragment shader, aux bonnes coordonnées.
    
Lisez la section "écrire le fragment shader (et le vertex shader)" dans \ref tuto5GL pour comprendre comment les différents morceaux se connectent ensemble.

Dernière étape, configurer le pipeline pour utiliser la texture, vous pouvez lire les détails dans \ref tuto5GL ou utiliser l'utilitaire program_use_texture( );
\code
// init( ) :
    // verifie que l'objet a bien des coordonnées de texture
    if(m_objet.texcoord_buffer_size() == 0)
        return "erreur, pas de texcoords...";
    
    // charge une texture sur l'unite 0
    m_texture= read_texture(0, "...");

// render( ) :
    // selectionner le shader program, si necessaire
    // glUseProgram(program);

    // . parametres "supplementaires" :
    //   . utilisation d'une texture configuree sur l'unite 0, cf texture= read_texture(0, "...");
    program_use_texture(program, "texture0", 0, m_texture);

    // go !
    m_objet.draw(m_program);
\endcode
cf \ref tuto9_texture1.cpp pour un exemple complet qui charge une texture.

## et avec plusieurs textures ?

C'est la même chose, par contre, il faut charger et configurer une unité de texture par image / texture à utiliser et déclarer un sampler2D par texture dans le shader.
\code
// init( ) :
    // verifie que l'objet a bien des coordonnées de texture
    if(m_objet.texcoord_buffer_size() == 0)
        return "erreur, pas de texcoords...";

    // charge une texture sur l'unite 0
    m_texture0= read_texture(0, "...");

    // charge une texture sur l'unite 1
    m_texture1= read_texture(1, "...");

// render( ) :
    // selectionner le shader program, si necessaire
    // glUseProgram(program);

    // . parametres "supplementaires" :
    //   . utilisation d'une texture configuree sur l'unite 0, cf texture= read_texture(0, "...");
    program_use_texture(program, "texture0", 0, m_texture0);    // le shader déclare un uniform sampler2D texture0;
    
    //   . utilisation d'une texture configuree sur l'unite 1, cf texture= read_texture(1, "...");
    program_use_texture(program, "texture1", 1, m_texture1);    // le shader déclare un uniform sampler2D texture1;

    // go !
    m_objet.draw(m_program);
\endcode

cf \ref tuto9_textures.cpp pour un exemple complet qui charge et utilise 2 textures.

*/
