| ||||||||||||||||||||||
Transférer les données dans la carte graphique c'est bien, mais les mettre à jour quand un objet bouge c'est quand même mieux. Notre caisse n'en a pas vraiment besoin car elle ne bouge pas. Mais lorsque nous animerons des personnages, il faudra bien mettre à jour leurs vertices pour voir leurs déplacements. La modification de données dans la mémoire vidéo se fait un peu comme l'écriture de texte dans un fichier. Avec les fichiers, on commence par en ouvrir un avec un mode d'accès (lecture, écriture ou les deux), puis on écrit les données, et une fois qu'on a fini on ferme le fichier. Avec les VBO c'est un peu la même chose, on va commencer par récupérer l'espace mémoire qu'on a allouée, puis on écrira les données à l'intérieur et enfin on fermera l'accès à la zone mémoire. La seule véritable différence avec les fichiers c'est que les VBO il faut les verrouiller. Pour accéder à la mémoire vidéo, nous devons utiliser une fonction qui permet de retourner un pointeur un peu spéciale. Celui-ci forme en quelque sorte une passerelle entre le VBO et la RAM. Grâce à lui, nous pourrons accéder aux données de la mémoire vidéo comme s'il s'agissait de données présentes dans la RAM. La fonction en question s’appelle glMapBuffer().
Contrairement à ce qu'on pourrait penser, la fonction renvoie bien quelque chose. L'utilisation du type void* permet de spécifier un pointeur. Un pointeur qui, ici, forme la passerelle dont nous avons parlée à l'instant. Le paramètre mode peut prendre 3 valeurs :
Dans la plupart des cas, nous utiliserons la deuxième valeur car on ne fera que transférer des données, pas besoin de lecture dans ce cas Ainsi, pour mettre à jour les informations contenues dans un VBO on commence par le verrouiller puis on récupère l'adresse de sa zone mémoire :
Il peut arriver que la récupération de l'adresse échoue, ce n'est pas très courant mais ça peut arriver. Si c'est le cas alors la fonction glMapBuffer() renvoie un pointeur NULL, il faut donc vérifier sa valeur avant de continuer. Si elle est nulle, alors on déverrouille le VBO et on annule le transfert. S'il n'y a aucune erreur on peut continuer :
Bien sûr, vous pouvez broder le message d'erreur si vous en avez envie. Une fois notre adresse trouvée et validée nous pouvons commencer le transfert, et comme d'habitude avec les VBO les transferts se font en bytes. Le seul problème ici, c'est qu'on n'a pas de fonction OpenGL pour mettre à jour nos données, il va falloir le faire par nous-même avec comme seul outil l'adresse de destination dans la mémoire vidéo. Heureusement pour nous, nous n'aurons pas à faire ça à la main. Il existe une fonction C (oui oui C pas C++) qui permet de copier tout un tas de bytes d'un coup. Cette fonction s'appelle memcpy() :
Le seul problème avec cette fonction, c'est qu'elle ne prend pas en compte le décalage dans une zone mémoire, elle n'est capable d'écrire qu'à partir du début. Pour contourner ceci, nous allons reprendre la macro BUFFER_OFFSET() que nous utilisons pour l'affichage :
Le code qui nous intéresse ici c'est la définition de la macro :
Ce code permet de spécifier un décalage offset à partir de l'adresse NULL. Ce que nous voulons nous, c'est spécifier un décalage à partir de l'adresse adresseVBO. Pour ce faire, nous devons simplement remplacer le mot-clef NULL par le pointeur adresseVBO et l'offset par la variable decalage :
Simple n'est-ce pas ? Alors bon, nous n'allons pas recréer une macro pour ça, ce ne serait pas utile et ça alourdirait le header (mais comme je sens que ça va me gonfler dans pas longtemps, on fera sûrement une macro, car un header de 4 lignes au lieu d'un header de 3 lignes, ça ne change pas grand chose). A la place, nous allons juste donner ce code au paramètre destination de la fonction memcpy(). Quant aux autres, nous leur donnerons en valeur la taille des données à copier et le pointeur source. L'appel à la fonction ressemblera au final à ceci :
Avec ça, nous pouvons mettre à jour n'importe quel VBO. Il ne manque plus qu'une seule chose à faire. Pour sécuriser le VBO, il faut invalider le pointeur retourné par glMapBuffer(). Si on ne le fait pas il y a un risque d'écraser les données présentes à l'intérieur, on peut se retrouver avec un magnifique bug d'affichage avec ça. :lol: La fonction permettant d'invalider ce pointeur s'appelle glUnmapBuffer() :
La fonction renvoie un GLboolean pour savoir si tout s'est bien passé. On l'appelle juste après les transferts précédents. On en profite au passage pour affecter la valeur NULL (ou 0, mais je préfère NULL, ça permet de se rappeler que c'est bien un pointeur) au pointeur pour une double sécurisation :
| ||||||||||||||||||||||
|