Rendre accessible OpenGL sous Dalvik
Le gros problème de développer des applications OpenGL en JAVA est le suivant:
Votre programme tourne dans un environnement particulier: Dalvik qui est une JVM (Java Virtual Machine), ce qui signifie que votre programme n'a pas un accès direct au hardware, il doit passer par des API.
Alors qu'OpenGL doit fonctionner directement avec le hardware (en autre avec le rendu graphique via les shaders qui passe par la carte graphique), il n'est donc pas exécuté sous Dalvik mais directement dans l'environnement natif.
Deux mondes complétement différents:Ce n'est pas le même langage binaire, la gestion de la mémoire est différente (Garbage collection pour Dalvik, gestion de la mémoire beaucoup plus classique pour le second), ...
Déclencher les fonctions OpenGL
Donc comment déclencher les fonctions OpenGL lorsque le programme fonctionne sous Dalvik: Il faut passer par les Java Native Interface (JNI). Heureusement, dans le SDK, cette partie est transparente lors de l'utilisation des méthodes de android.opengl.GLES20 qui exploitent justement les JNI pour appeller les librairies correspondantes du système natif.
Ouf ...
Transmettre les données de JAVA vers OpenGL sous Android
Mais de la même manière, OpenGL doit accéder à des données qui doivent se situées dans la mémoire de l'environnement natif. Mémoire native où JAVA n'a absolument pas le droit d'accéder pour des questions évidente de sécurité des données et donc de sécurité du système natif (c'est en même temps la raison d'être de JAVA en plus de la portabilité du binaire).
Une méthode d'une classe a cependant été spécialement conçue pour permettre d'allouer de la mémoire en mémoire native et permettre ainsi l'échange de données entre Dalvik et le système natif sans risque que le garbage collection fasse du ménage:
Il s'agit de la classe ByteBuffer et de la méthode allocateDirect:
public static ByteBuffer allocateDirect (int capacity)
En entrée:
capacity taille en octet de la zone mémoire souhaitée (> 0).
Mais comment déterminer la capacité qui est basée sur l'octet ?
Les données accédées par OpenGL vont correspondre à des positions, des couleurs, ... Or ces informations sont de type float. Il faut donc indiquer que le buffer sera de type float:
public abstract FloatBuffer asFloatBuffer ();
Et il est maintenant possible de déterminer cette capacité, sachant que sous Android un float occupe 4 octets, la capacité du buffer sera = 4 x le nombre de float qui seront stockés dans le buffer.
Reste un point important: eviter les problèmes d'endianness. En effet, les appareils Android peuvent supporter n'importe quel type de microprocesseurs, (d'où l'intérêt de développer en JAVA, votre code sera forcement portable quelque soit le CPU présent). Or l'opération consiste à réserver de la mémoire dans le système natif. Il faut donc prendre en compte l'ordre de rangement des octets composants un mot, un mot long, ...
D'où la précision sur l'allocation en récupérant l'ordre de rangement:
qui sera passé à la méthode final ByteBuffer order(ByteOrder byteOrder)
D'où un code ressemblant à:
FloatBuffer vertexData = ByteBuffer.allocateDirect(tableVertices.length * BYTES_PER_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
avec tableVertices un tableau de float en JAVA contenant les coodonnées des vertices
avec la constante BYTES_PER_FLOAT positionnée à 4.
ou
ByteBuffer bb = ByteBuffer.allocateDirect (tableVertices.length * BYTES_PER_FLOAT);
bb .order(ByteOrder.nativeOrder());
vertexData = bb.asFloatBuffer();
Pour transmettre les données, il suffit d'utiliser la méthode put
vertexBuffer.put(tableVertices);
Cependant, il existe d'autres informations qui permettent au système de naviguer dans le buffer. Si vous voulez afficher votre image, il faut réinitialiser sa position:
En effet, le put déplace la position courante du pointeur dans le buffer d'autant d'éléments qui ont été copiés et ceci automatiquement...
put (src) est équivalent
à écrire put(src, 0, src.length).
Par exemple pour revenir au début du buffer:
vertexBuffer.position(0);
Cette méthode
sera utile si, par exemple, vous decidez de passer dans un même buffer
des vertice et les couleurs associées.
Exemple de code
Il manque encore des explications sur la solution OpenGL pour dessiner des vertice à partir du contenu du tableau. Donc pas d'exemple pour le moment, voyez le chapitre Dessiner des objets géométriques dans lequel un exemple plus complet est fourni.