pict  pict pict
____________________________________________________________________________________________________ 
Université Paris 8 - Vincennes à Saint-Denis 
 
Informatique
 
 
pict 
Synthèse d’Images et OpenGL avec GL4Dummies
Document en cours de rédaction
 
Farès Belhadj
 
Date de MAJ : 11 février 2018
 
 
email   mailto:amsi@ai.univ-paris8.fr
github   https://github.com/noalien/GL4Dummies
web   http://api8.fr/GL4D/

Table des matières

1 Introduction
 1.1 Présentation
 1.2 Objectifs du présent ouvrage
 1.3 Conventions de nommage
 1.4 Plan de lecture du document
2 Installer GL4Dummies
 2.1 À partir du code source
  2.1.1 Prérequis : la bibliothèque SDL2
  2.1.2 Compilation et installation de GL4Dummies
  2.1.3 Paramétrage de vos futurs projets
 2.2 À partir des binaires
3 Hello World
 3.1 Mon HelloWorld GL4Dummies
  3.1.1 Le Makefile de sample2d_00-1.0
  3.1.2 Le source window.c de sample2d_00-1.0
 3.2 Principe de fonctionnement d’une application graphique
 3.3 Le HelloWorld multi-coloré
 3.4 Le HelloPixels avec GL4Dummies
4 Bases de l’architecture d’un programme OpenGL®
 4.1 Environnement de représentation des données
 4.2 Les primitives
 4.3 Les transformations standards
  4.3.1 Projection perspective
 4.4 Projection orthogonale

Liste des codes source

Prototype de Makefile de projet GL4Dummies
Code source du projet sample2d_00-1.0 : écran noir
Code source du projet sample2d_00-1.1 : écran coloré changeant à chaque Frame
Code source du projet sample2d_00-1.2 : dégradé de niveaux de gris sur un screen de résolution inférieure à celle de la fenêtre

Chapitre 1
Introduction

1.1 Présentation

Ce document présente des éléments d’introduction à l’apprentissage de la synthèse d’images (ou les modèles et techniques pour la création d’images numériques et d’animations) à l’aide d’OpenGL®3.3 et plus et de GL4Dummies, une bibliothèque de développement (langage C) rendant plus accessible cet apprentissage aux débutants.

OpenGL® est une Application Programming Interface (API) ou bibliothèque de développement standardisée permettant de développer des applications graphiques portables. Initiée par Silicon Graphics en 1992, elle apportait un ensemble de fonctionnalités permettant la création, la manipulation et le rendu d’objets géométriques et d’images dans l’espace 2D ou 3D. Son développement, au travers de spécifications validées par un consortium d’industriels – the OpenGL® Architecture Review Board (ARB) – en a fait un standard supporté par une majorité de systèmes : systèmes d’exploitation et architectures matérielles (constructeurs de cartes graphiques, de dispositifs nomades ou de plateformes embarquées – voir OpenGL®ES pour Embedded Systems).

Avant sa version 3.3 et la dépréciation d’un certain nombre de fonctionnalités pratiques, OpenGL®, qui est une API en langage C, permettait, en toute relativité, de facilement créer dans l’espace des modèles géométriques basés maillage (les objets sont composés de facettes polygonales), de leur appliquer une ou plusieurs textures, de proposer des propriétés de matière (interaction lumière-matière), de placer une ou plusieurs lumières (différents modèles et paramétrages étaient disponibles) et de manipuler l’ensemble des entités virtuelles par le biais de transformations spaciales afin de les mettre en scène et de les rendre à l’écran. Hormis le rendu plat, permettant de calculer l’ombrage (ou shading) d’une facette en fonction de son orientation à (aux) la lumière(s), l’autre rendu proposé à l’époque était basé sur l’ombrage Gouraud – ou Gouraud shading [Gou71aGou71b] – il permet de lisser l’ombrage par interpolation du calcul du niveau d’intensité lumineuse en chaque sommet de la géométrie. Ainsi, sous sa forme initiale, OpenGL® était une bibliothèque offrant l’accès à un processus de traitement structuré et figé qui à partir de données vectorielles et pixelaires permettait d’obtenir certains types de rendus. Par ailleurs, de nombreuses composantes de ce processus étaient gérées par les pilotes des cartes graphiques permettant un considérable gain de performances. Ainsi, il était difficile, voire impossible, de proposer et d’implémenter d’autres types de traitements ou obtenir d’autres types de rendus à moins d’abandonner 1 l’usage de l’accélération matérielle. C’est donc en 2003, et sa version 1.5, que la spécification OpenGL® donne la possibilité de reprogrammer, directement dans le GPU (Graphics Processing Unit), certaines parties du processus de traitement, au début en assembleur, puis en GLSL (OpenGL® Shading Language, langage de programmation proche du langage C et permettant la surcharge de fonctions et la gestion d’opérations sur vecteurs et matrices).

Ainsi, depuis la version 3.3 d’OpenGL®, d’anciennes fonctionnalités dépréciées depuis la version 2.0 ont été officiellement supprimées 2  ; citons-en quelques unes :

Fonctions de description de géométrie : 
ensemble de fonctions permettant de créer/initier/clôturer/utiliser une géométrie (glNewList, glEndList, glBegin, glEnd, ...), d’injecter des sommets (glVertex), leur couleur (glColor), leur vecteur normal (glNormal) et leurs coordonnées de textures (glTexCoord), ...
Transformations spaciales : 
deux types de matrices, la première permettant de stocker les opérations liées à la modélisation des objets (placement des objets dans la scène) et à la vue (emplacement virtuel de l’utilisateur observant la scène), la seconde permet de paramétrer la projection de la scène à l’écran. De plus, des fonctions permettaient de gérer ces matrices sous la forme de piles de données donnant la possibilité de les sauvegarder et les restaurer ; d’autres permettaient d’y insérer des transformations telles que la rotation (glRotate), la translation (glTranslate) ou la mise à l’échelle (glScale), ...
Lumières : 
ensemble de fonctions d’activation, paramétrage et gestion des lumières de la scène ;
Rendus : 
le rendu coloré, le rendu ombrage-plat et l’ombrage Gouraud disparraissent et plus aucun rendu “par défaut” n’est proposé ; la spécification du flux de données étant entièrement décidée par l’utilisateur, l’idée d’un rendu par défaut devient caduque ;
...

Enfin, nous complétons la liste des fonctionnalités supprimées en citant deux API très utiles et devenues quasiment obsolètes depuis la version 3.3 d’OpenGL® : GLU (OpenGL® Utility Library) et GLUT (OpenGL® Utility Toolkit). La première permettait par exemple de créer et paramétrer des objets géométriques complexes tels que les courbes ou les surfaces paramétriques. La seconde gérait le fenêtrage, les interaction, les menus et permettait simplement de créer des objets géométriques basiques tels que le cube, la sphère ou la TeaPot (voir GLUT teapot dans votre moteur de recherche favori).

C’est dans ce contexte et afin de faciliter l’initiation, l’uniformisation de l’installation et la gestion des nouvelles possibilités offertes par la nouvelle architecture OpenGL® qu’a été pensée et initiée la bibliothèque GL4Dummies. GL4Dummies donne accès, dans la nouvelle architecture OpenGL®, à un ensemble de fonctionnalités reprenant dans la mesure du possible le modèle de celles supprimées depuis la version 3.3 ; ses fonctionnalités s’insèrent naturellement dans le modèle aujourd’hui programmable et accessible via le langage GLSL. GL4Dummiesest une API en cours de développement, elle sert de support de développement pour l’ensemble des cours liés à la synthèse d’images et enseignés à l’Université Paris 8 depuis 2014 ; nous incitons les personnes souhaitant participer à son développement de le faire.

1.2 Objectifs du présent ouvrage

Le but du présent document est d’exposer les principales fonctionnalités 3 des API OpenGL® et GL4Dummies et de les mettre en œuvre à l’aide d’exemples simples. Vous serez alors amener de manière progressive à utiliser ces acquis dans le cadre d’un projet personnel plus complexe

Par ailleurs, ce document est en constante évolution, si vous y découvrez des erreurs ou coquilles, n’hésitez pas à contacter les auteurs. Préférez l’utilisation d’un lecteur pdf supportant les liens hypertextes car de nombreux liens vous conduisent vers des sources de documentation.

Enfin, les exercices sont donnés pour entrainer le lecteur aux différentes techniques exposées.

1.3 Conventions de nommage

Ici nous décrivons les conventions de nammages adoptées dans les API OpenGL® et GL4Dummies. Ceci permettra au lecteur d’identifier plus aisément l’origine du type ou de la fonction et dans la mesure du possible son usage.

L’API OpenGL® adopte une convention de nommage proche de celle utilisée en langage Java (voir Naming conventions dans [jav97]). L’ensemble des éléments provenant de l’API OpenGL® sont préfixés des deux lettres gl. De la même manière, GL4Dummies suivra cette convention de nommage en préfixant par gl4d. Ces lettres se présentent en minuscule pour les fonctions et en majuscule pour les macros et types de données 4 . Ainsi une fonction OpenGL® peut prendre la forme suivante :

glNomCourt{u}{bsifd}{v}(type1     v1,  type2  v2, ...);
où le nom court étant le nom de la fonctionnalité. Il peut être suffixé d’éléments informant sur la nature et le type de données d’un sous-ensemble ou de l’intégralité des arguments de la fonction :

 
TODO : ajout d’un descriptif sur le choix des préfixes GL4Dummies permettant de déduire la famille de fonctionnalités ciblées et les fichiers concernés dans la documentation de référence écrites en, et générée par Doxygen.

1.4 Plan de lecture du document

TODO.

Le chapitre 2 donne des indications sur l’installation des outils et des API nécessaires à la réalisation des exemples donnés dans le présent support.

Dans le chapitre 3, nous aborderons sans détour l’écriture d’un code minimal permetant de fabriquer un programme utilisant GL4Dummies et OpenGL® et introduisant la notion de pixel à l’aide d’une représentation simple. La notion de boucle d’affichage sera introduite dans ce chapitre.

Une introduction à une architecture simplifiée du pipeline OpenGL® est donnée dans le chapitre 4 ; nous y aborderons la mise en place, côté CPU, de données vectorielles, le transfert et la description de ces données vers le GPU, la création d’un programme de rendu les prenant en compte et le rendu à proprement parler.

Chapitre 2
Installer GL4Dummies

2.1 À partir du code source

Cette section décrit l’installation de la bibliothèque GL4Dummies à partir de son code source. Dans chaque sous-partie vous trouverez les indications à suivre en fonction de votre système d’exploitation : Linux / Unix-like / Mac OS X et Windows.

2.1.1 Prérequis : la bibliothèque SDL2

SDL2 (http://www.libsdl.org/) est une bibliothèque de développement multi-plateformes permettant un accès hardware aux ressources graphiques présentes sur le système. Elle permet aussi l’accès bas niveau aux ressources d’interface (clavier, souris et joystick). Aussi, des extensions de la bibliothèque donnent un accès simple aux ressources audio, à la gestion des pthread, à l’utilisation de fonts Truetype, à l’ouverture et l’enregistrement de multiples formats d’images, etc.

GL4Dummies dépend de la bibliothèque SDL2 principalement pour ce qui concerne la gestion de fenêtres et du contexte OpenGL® (pour faire court : zone de l’écran dans laquelle OpenGL® effectue ses rendus). Il est nécessaire d’avoir la bibliothèque de développement (soit les paquets contenant les headers et les bibliothèques statiques) de SDL2 afin de pouvoir recompiler GL4Dummies. Aussi, pour de nombreux exemples proposés dans la suite, il sera nécessaire d’avoir certaines extensions de la bibliothèque, telles que : SDL_images, SDL_mixer et SDL_ttf. Faire attention à récupérer les versions pour SDL2 et non SDL1.2 (l’ancienne version de la bibliothèque ne permet pas de gérer un contexte OpenGL® 3 et plus).

Afin de vérifier que SDL2 est bien installée, et pour faire simple, nous pouvons considérer que la bibliothèque de développement est présente sur le système si la commande sdl2-config est présente et répond en donnant les bons chemins vers les différents fichiers (voir sdl2-config --help). Sinon, en fonction de l’OS (système d’exploitation) faire :

Pour les utilisateurs Linux, 
utiliser le gestionnaire de paquets afin d’installer la la bibliothèque de développement (lib dev) de SDL2. Par exemple un utilisateur Ubuntu fera :
sudo apt-get install libsdl2-dev
Pour les utilisateurs Mac OS X, 
commencer par installer les MacPorts (http://www.macports.org). Une fois les MacPorts pleinement fonctionnels, installer SDL2 en tapant (dans un terminal) :
sudo port install libsdl2
Pour les utilisateurs Windows, 
pas besoin d’installer SDL2 tout est dans l’archive GL4Dummies sauf si vous souhaitez utiliser une version plus récente de SDL2.

Enfin, il est aussi possible d’installer SDL2 à partir de son source, néanmoins, cette procédure n’est pas recommandée car certaines dépendances liées aux exemples ne seront pas automatiquement incluses dans la bibliothèque ; par exemple : le support de différents formats d’images ou de fichiers audio.

2.1.2 Compilation et installation de GL4Dummies

Dans un premier temps, il s’agit de récupérer le code source de la bibliothèque :

git clone https://github.com/noalien/GL4Dummies.git GL4Dummies  
cd GL4Dummies  
make -f Makefile.autotools

Ensuite, aller dans le dossier contenant le code source de GL4Dummies :

Sous Posix (Linux, OSX, ...) avec droits administrateur, 
faire :
./configure  
make  
sudo make install

Puis, sur certains Linux, il est nécessaire de spécifier que la variable d’environnement $LD_LIBRARY_PATH pointe sur /usr/local/lib. Ainsi, selon votre OS, à la racine de votre compte, vous devriez avoir (par ordre de préférence) un ou plusieurs des fichiers suivants : .bashrc, .bash_profile, ou .profile. Editez l’un d’eux en ajoutant la ligne suivante à la fin du fichier :

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib

Ces fichiers permettent de paramétrer votre environnement utilisateur au moment du login (.bash_profile ou .profile) ou lors de l’ouverture d’un nouveau bash (.bashrc). Pour forcer la relecture d’un de ces fichiers de paramétrage, utilisez la commande source. Par exemple, si vous aviez ajouté les deux lignes au .bashrc, faire :

source ~/.bashrc

Sous Posix (Linux, OSX, ...) sans droits administrateur, 
il peut être nécessaire de créer un dossier local à la racine de votre compte et y installer la bibliothèque (bibliothèque statique et dynamique, headers et autres fichiers nécessaires). En premier lieu, vérifiez que votre variable d’environnement $HOME pointe bien à la racine de votre compte (echo $HOME) et tapez :
[ -d $HOME/local ] || mkdir $HOME/local  
./configure --prefix=$HOME/local  
make  
make install

et là il vous reste à paramétrer vos chemins en fonction de $HOME/local où l’installation a été faite.
Pour que le système ait connaissance de ce chemin d’installation particulier (les dossiers bin include lib et share ont été ajoués dans $HOME/local) il faut renseigner ses variables d’environnement $PATH et $LD_LIBRARY_PATH. Selon votre OS, à la racine de votre compte, vous devriez avoir (par ordre de préférence) un ou deux des fichiers suivants .bashrc, .bash_profile, ou .profile. Éditez l’un d’eux en ajoutant les deux lignes suivantes à la fin du fichier :

export PATH=$PATH:$HOME/local/bin  
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$HOME/local/lib

Ces fichiers permettent de paramétrer votre environnement utilisateur au moment du login (.bash_profile ou .profile) ou lors de l’ouverture d’un nouveau bash (.bashrc). Pour forcer la relecture d’un de ces fichiers de paramétrage, utilisez la commande source. Par exemple, si vous aviez ajouté les deux lignes au .bashrc, faire :

source ~/.bashrc

Sous Windows, 
ouvrir le répertoire Windows à l’emplacement contenant le code source de GL4Dummies, et, selon votre IDE : Code::blocks, Dev C++ ou Visual Studio Express, vous trouverez respectivement un projet GL4Dummies.cbp, GL4Dummies.dev ou GL4Dummies.sln. Ouvrez celui qui correspond à votre IDE et compiler le projet. Dans le cas de Visual Studio, il compilera la bibliothèque puis les exemples utilisant la bibliothèque, il ne reste plus qu’à exécuter. Dans le cas de Code::blocks et Dev C++, la bibliothèque est compilée et les binaires créés dans le dossier bin/Win32 à partir de la racine du dossier contenant les sources. Les projets exemples (.cbp ou .dev) se trouvant dans Windows peuvent maintenant être compilés et exécutés.

2.1.3 Paramétrage de vos futurs projets

En fonction de l’emplacement où est installée la GL4Dummies, il faudra paramétrer vos futurs projets (par exemple paramétrer le Makefile) pour qu’ils puissent compiler et linker avec GL4Dummies. Vous devez ainsi vérifier que la ligne de compilation contient bien le chemin vers le dossier include de GL4Dummies et que la ligne de link (ld) contient le chemin vers le dossier lib et demande à utiliser glAd (par exemple -lGL4Dummies).
 

Par exemple, quand la bibliothèque est installée dans un $HOME/local, en utilisant un Makefile, vérifier dans ce dernier que les variables CPPFLAGS et LDFLAGS contiennent au minimum :

CPPFLAGS = -I. -I$(HOME)/local/include $(shell sdl2-config --cflags)  
LDFLAGS = -lm -L$(HOME)/local/lib -lGL4Dummies $(shell sdl2-config --libs)

2.2 À partir des binaires

Actuellement aucune version binaire n’est officiellement distribuée.

Chapitre 3
Démarrage rapide

Ce chapitre traite de la mise en place d’un premier projet utilisant l’API GL4Dummies et par conséquent OpenGL®. Nous ferons évoluer ce projet afin d’y introduire la notion du pixel et de sa représentation sans pour autant aborder le côté OpenGL® qui est bien présent mais reste caché par des notions haut-niveau apportées par GL4Dummies. Nous terminons par une introduction à la boucle d’affichage et l’ajout d’interactions simples avec l’utilisateur.

Des exercices sont proposés en fin de chapitre.

3.1 Mon HelloWorld GL4Dummies

Commençons par le premier Sample Project (projet échantillon) présent dans les sources de la bibliothèque GL4Dummies. Il s’agit du projet samples/sample2d_00-1.0 que l’utilisateur peut compiler (sous un système Posix 1 ) en se rendant dans le dossier et en saisissant la commande make  ←'  puis, si tout se déroule correctement (pour cela, il est nécessaire de réussir à installer GL4Dummies tel que décrit dans le chapitre 2) lancer l’exécutable produit en saisissant ./sample2d_00  ←'  . Ce qui donne :

MacBook-Pro-de-Fares:GL4Dummies amsi$ cd samples/sample2d_00-1.0/ 
MacBook-Pro-de-Fares:sample2d_00-1.0 amsi$ ls 
COPYING   Makefile   documentation  window.c 
MacBook-Pro-de-Fares:sample2d_00-1.0 amsi$ make 
gcc -I. -I/usr/local/include -I/opt/local/include/SDL2 -D_THREAD_SAFE -Wall -O3 -mmacosx-version-min=10.8 -c window.c -o window.o 
gcc window.o -lm -L/usr/local/lib -framework OpenGL -mmacosx-version-min=10.8 -lGL4Dummies -L/opt/local/lib -lSDL2 -o sample2d_00 
MacBook-Pro-de-Fares:sample2d_00-1.0 amsi$ ./sample2d_00 
OpenGL version: 4.1 NVIDIA-10.17.5 355.10.05.45f01 
Supported shaders version: 4.10 
GL4D/gl4du.c (344): Creation du programme 1 a l'aide des Shaders : 
gl4dp_basic_with_transforms.vs : vertex shader 
gl4dp_basic.fs : fragment shader

Ainsi, une exécution réussie du Sample Project sample2d_00-1.0 ouvre une fenêtre de 320 × 240 pixels, portant le titre “GL4Dummies’ Hello World” et affichant un fond noir telle qu’illustrée par la figure 3.1. Il est à noter que cette fenêtre possède un bouton permettant sa fermeture, un autre pour la réduire et que le bouton permettant le redimensionnement (s’il est présent) n’est pas actif. L’application quitte (donc la fenêtre se ferme) si l’utilisateur clique sur le bouton fermer. Ses comportements sont programmés et le lecteur les découvrira au fur et à mesure. Enfin, notons que si l’application est lancée depuis un terminal des nombres apparaissent toutes les 5 secondes. Ces nombres correspondent au Framerate de l’application ; soit le nombre d’images par seconde qu’elle produit. Il est fréquent que ce nombre corresponde à 60 car classiquement les drivers (pilotes) de cartes graphiques bloquent la fréquence de rafraîchissement afin de la synchroniser avec celle de l’écran (télévision ou vidéo-projecteur) qui est souvent à 60Hz. Enfin, en fonction du système et des pilotes fournis, il existe des outils permettant de désactiver cette synchronisation verticale.


pict

Figure 3.1: Résultat du Sample Project sample2d_00-1.0

3.1.1 Le Makefile de sample2d_00-1.0

Le fichier Makefile de ce projet donné par le Code source 3.1 est le fichier indiquant comment “fabriquer” des choses dans le projet. Ici, sans entrer dans le détail d’écriture d’un Makefile, nous nous intéressons à deux aspects : les actions possibles ; le paramétrage pour les futurs projet du lecteur.

  1. La cible principale est make ou make all ; et elle a pour objectif de fabriquer ou de mettre à jour le programme dont le nom est stocké dans la variable $(PROGNAME). De manière classique le make clean supprime l’ensemble des fichiers générés (ou générables) pour ne garder que le strict minimum de sources nécessaires au projet. En présence de l’outil doxygen2 , la commade make doc utilise le fichier de configuration Doxyfile présent dans le sous-dossier documentation pour générer la documentation dans le dossier documentation/html/. Enfin, make dist fabrique automatiquement une archive .tgz contenant l’ensemble des fichiers sources réunis dans la variable $(DISTFILES) ; le nom de cette archive dépend du nom du programme et de sa version.
  2. Sans être expert d’écriture de Makefile, il est possible de moduler celui fourni ici afin de le faire correspondre à un autre projet. Ci-après une liste de variables pouvant être modifiées sans trop de risques :
    CFLAGS 
    contient les option de compilation pour gcc, remplacer par exemple le -O3 par un -g pour activer la génération de symboles pour faciliter le débogage avec gdb (ne pas omettre de faire un make clean avant de recompiler) ;
    CPPFLAGS 
    afin d’ajouter des chemin vers d’autres répertoires contenant des fichiers à inclure (#include <...>) ;
    LDFLAGS 
    afin d’ajouter des chemin vers d’autres répertoires contenant des bibliothèques (static or dynamic libs) à utiliser ansi que les options de lien (link) ;
    PROGNAME 
    permet de changer le nom du programme et du projet ;
    VERSION 
    permet de changer la version du projet ;
    HEADERS 
    liste de noms de fichiers en-tête (headers ou .h) faisant partie des fichiers sources du projet. Ces noms doivent être séparés par des espaces ;
    SOURCES 
    liste de noms de fichiers sources-compilables (.c) faisant partie du projet. Ces noms doivent être séparés par des espaces ;
    EXTRAFILES 
    si nécessaire, d’autres fichiers à inclure dans l’archive du projet.

 
#  Makefile 
#  Auteur : Farès BELHADJ 
#  Email  : amsi@ai.univ-paris8.fr 
#  Date   : 04/02/2018 
# définition des commandes utilisées 
CC = gcc 
ECHO = echo 
RM = rm -f 
TAR = tar 
MKDIR = mkdir 
CHMOD = chmod 
CP = rsync -R 
# déclaration des options du compilateur 
CFLAGS = -Wall -O3 
CPPFLAGS = -I. 
LDFLAGS = -lm 
# définition des fichiers et dossiers 
PROGNAME = sample2d_00 
VERSION = 1.0 
distdir = $(PROGNAME)-$(VERSION) 
HEADERS = 
SOURCES = window.c 
OBJ = $(SOURCES:.c=.o) 
DOXYFILE = documentation/Doxyfile 
EXTRAFILES = COPYING $(wildcard shaders/*.?s images/*.png) 
DISTFILES = $(SOURCES) Makefile $(HEADERS) $(DOXYFILE) $(EXTRAFILES) 
# Traitements automatiques pour ajout de chemins et options (ne pas modifier) 
ifneq (,$(shell ls -d /usr/local/include 2>/dev/null | tail -n 1)) 
  CPPFLAGS += -I/usr/local/include 
endif 
ifneq (,$(shell ls -d $(HOME)/local/include 2>/dev/null | tail -n 1)) 
  CPPFLAGS += -I$(HOME)/local/include 
endif 
ifneq (,$(shell ls -d /usr/local/lib 2>/dev/null | tail -n 1)) 
  LDFLAGS += -L/usr/local/lib 
endif 
ifneq (,$(shell ls -d $(HOME)/local/lib 2>/dev/null | tail -n 1)) 
  LDFLAGS += -L$(HOME)/local/lib 
endif 
ifeq ($(shell uname),Darwin) 
  MACOSX_DEPLOYMENT_TARGET = 10.8 
        CFLAGS += -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) 
        LDFLAGS += -framework OpenGL -mmacosx-version-min=$(MACOSX_DEPLOYMENT_TARGET) 
else 
        LDFLAGS += -lGL 
endif 
CPPFLAGS += $(shell sdl2-config --cflags) 
LDFLAGS  += -lGL4Dummies $(shell sdl2-config --libs) 
all: $(PROGNAME) 
$(PROGNAME): $(OBJ) 
  $(CC) $(OBJ) $(LDFLAGS) -o $(PROGNAME) 
%.o: %.c 
  $(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@ 
dist: distdir 
  $(CHMOD) -R a+r $(distdir) 
  $(TAR) zcvf $(distdir).tgz $(distdir) 
  $(RM) -r $(distdir) 
distdir: $(DISTFILES) 
  $(RM) -r $(distdir) 
  $(MKDIR) $(distdir) 
  $(CHMOD) 777 $(distdir) 
  $(CP) $(DISTFILES) $(distdir) 
doc: $(DOXYFILE) 
  cat $< | sed -e "s/PROJECT_NAME *=.*/PROJECT_NAME = $(PROGNAME)/" |\ 
    sed -e "s/PROJECT_NUMBER *=.*/PROJECT_NUMBER = $(VERSION)/" >> $<.new 
  mv -f $<.new $< 
  cd documentation &doxygen &cd .. 
clean: 
  @$(RM) -r $(PROGNAME) $(OBJ) *~ $(distdir).tgz gmon.out core.*\ 
    documentation/*~ shaders/*~ documentation/html

Code source 3.1
 Prototype de Makefile de projet GL4Dummies

3.1.2 Le source window.c de sample2d_00-1.0

Dans ce Sample Project le seul fichier strictement nécessaire à la fabrication du programme est window.c, il est listé dans le Code source 3.1. Pour des raisons de lisibilité, nous avons supprimé les commentaires contenus dans le code téléchargeable et commenterons les principaux éléments de ce programme.

 
#include <GL4D/gl4dp.h> 
#include <GL4D/gl4duw_SDL2.h> 
int main(int argc, char ** argv) { 
  if(!gl4duwCreateWindow( argc, argv, "GL4Dummies' Hello World", 
        10, 10, 320, 240, GL4DW_SHOWN) ) { 
    return 1; 
  } 
  gl4dpInitScreen(); 
  gl4dpClearScreen(); 
  gl4dpUpdateScreen(NULL); 
  gl4duwMainLoop(); 
  return 0; 
}

Code source 3.1
 Code source du projet sample2d_00-1.0 : écran noir

Dans les grandes lignes, ce programme créé une fenêtre à l’aide de la fonction gl4duwCreateWindow ; créé, efface en noir puis met à jour un screen respectivement avec les fonctions gl4dpInitScreen, gl4dpClearScreen et gl4dpUpdateScreen ; et enfin se lance dans une boucle d’affichage infinie.

Le fichier header gl4dp.h contient les macros, structures et prototypes de fonctions liées aux primitives de dessin 2D ; la lettre p de gl4dp.h correspondant à primitives mais aussi à pédagogique car cette partie de la bibliothèque n’a pas pour vocation de proposer des outils de primitives optimisés mais possède une priorité pédagogique.

Le fichier header gl4duw_SDL2.h contient pour sa part les macros, structures et prototypes de fonctions liées à la gestion des fenêtres et à la gestion des fonctionnalités qui y sont liées.

La fonction gl4duwCreateWindow :

Cette fonction permet de créer une fenêtre pour GL4Dummies et initialise la bibliothèque. Sont prototype est le suivant :

GLboolean gl4duwCreateWindow(int argc, char ** argv, 
                              const char * title, int x, int y, 
                              int width, int height, Uint32 wflags);

les deux premiers arguments proviennent des arguments du main et permettent à la bibliothèque d’initialiser son contexte (principalement utile pour connaître les chemin vers le binaire et pouvoir trouver les dépendances – comme les fichiers shaders – de manière relative). Le troisième argument est le titre de la fenêtre, il peut aussi servir à retrouver la fenêtre parmi plusieurs autres afin de lui affecter le statut “courante”. x, y, width et height donnent position et dimensions de la fenêtre lors de la création. wflags est un entier non signé permettant de stocker des options relatives à la fenêtre comme par exemple : est-elle redimensionnable, visible, ... Nous laisserons le lecteur découvrir plus de détails en le renvoyant sur la documentation de référence. Enfin, cette fonction revoie un booléen afin d’indiquer si la création de la fenêtre a réussi ou échoué. L’échec peut être causé par l’absence de contexte graphique ou l’impossibilité d’ouvrir un contexte OpenGL® 3.2 (valeur par défaut dans GL4Dummies, voir la fonction gl4duwSetGLAttributes).

Le screen et la fonction gl4dpInitScreen :

Le screen est un écran virtuel géré par GL4Dummies et représentant un tableau de données proportionnel aux dimensions de la fenêtre quand le screen est créé à l’aide de la fonction gl4dpInitScreen (voir aussi la fonction gl4dpInitScreenWithDimensions pour des screens aux dimensions différentes de la fenêtre). Ci-après le prototype des fonctions InitScreen :

GLuint gl4dpInitScreen(void); 
GLuint gl4dpInitScreenWithDimensions(GLuint w, GLuint h);

Ces fonctions renvoient donc un identifiant de screen permettant, en cas de multiples screens, de passer de l’un à l’autre, afin d’effacer, dessiner, supprimer, ... Par ailleurs, la structure intrinsèque à un screen est simple, elle contient autant d’entiers non signés que de pixels. Pour faire simple, soit pour un screen de dimensions w × h la partie données du screen est comparable à un :
unsigned int data[w * h] ;

Nous inviton le lecteur à se rendre à la section 3.4 pour en savoir un peu plus sur ce qu’est un pixel, une de ses représentations simples adoptées dans la partie “pédagogique” (gl4dp.h) de GL4Dummies, et comment faire son premier programme créant un dégradé de pixels.

La fonction gl4dpClearScreen :

Cette fonction efface le screen en cours en y mettant des zéros (0). En pratique, cette fonction utilise un memset avec comme second argument 0 afin de remplir tous les octets de zéros ce qui produit un écran noir (les pixels contenant l’intensité de chaque couleur, l’omni-présence de zéros produit une image à intensité nulle donc noire). Pour un effacement avec une autre couleur voir la fonction gl4dpClearScreenWith(Uint32 color).

La fonction gl4dpUpdateScreen :

Sans rentrer dans les détails, cette fonction permet de communiquer entre la mémoire centrale, la RAM-CPU, et la mémoire graphique, la RAM-GPU. La données est partiellement ou dans sa globalité transférée vers OpenGL® pour que son état actuel en RAM-CPU soit reproduit à l’écran. Ci-après le prototype de la fonction :

void gl4dpUpdateScreen(GLint * rect);

rect représente le rectangle, sous partie du screen, à mettre à jour côté GPU. C’est le pointeur vers les quatre entiers positifs x,y – coin haut gauche du rectangle – et w,h – ses dimensions.

La fonction gl4duwMainLoop :

Enfin, nous revenons vers une fonction liée à la gestion du fenêtrage. Une application fenêtrée est un processus qui demeure alive (en quelques sortes “vivant”) au sein du système tant qu’il ne reçoit pas d’événement ou de signal lui indiquant ou le forçant à quitter. Donc, par définition, dans ce type d’applications il est nécessaire de produire une boucle infinie 3 dont le corps est en attente d’un signal de sortie. Afin de ne pas accaparer les ressources du système cette boucle doit ordonnancer les tâches à faire pour permettre à la fois d’écouter les événements, réagir en fonction et procéder à l’affichage. C’est le rôle de la fonction gl4duwMainLoop dont nous abordons le principe générale dans la section 3.2 ci-après.

3.2 Principe de fonctionnement d’une application graphique


pict

Figure 3.2: Principe général du fonctionnement d’une application graphique avec la boucle événements–simulation–dessin

3.3 Le HelloWorld multi-coloré

 
#include <GL4D/gl4dp.h> 
#include <GL4D/gl4duw_SDL2.h> 
 
static void quitte(void) { 
  gl4duClean(GL4DU_ALL); 
} 
 
static void dessine(void) { 
  GLubyte r = rand() % 256, g = rand() % 256, b = rand() % 256; 
  gl4dpClearScreenWith(RGB(r, g, b)); 
  gl4dpUpdateScreen(NULL); 
} 
 
int main(int argc, char ** argv) { 
  if(!gl4duwCreateWindow(argc, argv, "GL4Dummies' Hello World", 
       10, 10, 320, 240, GL4DW_SHOWN) ) { 
    return 1; 
  } 
  gl4dpInitScreen(); 
  atexit(quitte); 
  gl4duwDisplayFunc(dessine); 
  gl4duwMainLoop(); 
  return 0; 
}

Code source 3.1
 Code source du projet sample2d_00-1.1 : écran coloré changeant à chaque Frame

3.4 Le HelloPixels avec GL4Dummies

 
#include <GL4D/gl4dp.h> 
#include <GL4D/gl4duw_SDL2.h> 
 
static void quitte(void) { 
  gl4duClean(GL4DU_ALL); 
} 
 
static void dessin(void) { 
  int x, y; 
  Uint32 c; 
  for(y = 0; y < 16; y++) 
    for(x = 0; x < 16; x++) { 
      c = y * 16 + x; 
      c = c | (c << 8) | (c << 16) | (c << 24); 
      gl4dpSetColor(c); 
      gl4dpPutPixel(x, y); 
    } 
  gl4dpUpdateScreen(NULL); 
} 
 
int main(int argc, char ** argv) { 
  if(!gl4duwCreateWindow(argc, argv, "GL4Dummies' Hello Pixels", 
       10, 10, 320, 320, GL4DW_SHOWN) ) { 
    return 1; 
  } 
  gl4dpInitScreenWithDimensions(16, 16); 
  atexit(quitte); 
  gl4duwDisplayFunc(dessin); 
  gl4duwMainLoop(); 
  return 0; 
}

Code source 3.1
 Code source du projet sample2d_00-1.2 : dégradé de niveaux de gris sur un screen de résolution inférieure à celle de la fenêtre

Chapitre 4
Bases de l’architecture d’un programme OpenGL®

TODO sections 1 à 4 à revoir


pict

Figure 4.1: Pipeline OpenGL (3.3) simplifié

4.1 Environnement de représentation des données

4.2 Les primitives

Pour modéliser des objets, l’élément de base utilisé par l’API OpenGL®est le sommet — Vertex en anglais. Cette approche donne trois possibilités de rendu de l’objet à modéliser :

Ainsi, en pratique, pour modéliser un objet ou une partie d’objet, l’API OpenGL®fournie un ensemble de commandes permettant de décrire en détail la composition du modèle. Ces commandes donnent la possibilité d’introduire des données géométriques dans le Pipeline OpenGL®. Pour cela, ces données doivent 2 être déclarée entre la paire de commandes glBegin et glEnd dont voici les prototypes :

void glBegin(GLenum mode);  
void glEnd(void);

Chaque sommet est alors déclaré à l’aide des commandes glVertex* et le modèle est construit en fonction du mode (argument de glBegin) choisi. Nous donnons, ci-après, les valeurs possibles pour le paramètre mode ansi que les l’interprétation qui en découle. La figure 4.2 donne un aperçu des résultats pouvant être obtenus dans chaque situation.
Ainsi pour un ensemble de n sommets {V 0,V 1,...,V n-1} déclarés (à l’aide de glVertex*) entre la paire glBegin et glEnd, nous obtenons, quand le mode choisi est :


pict

Figure 4.2: (Seules) Primitives gérées par OpenGL 3.1 et plus

4.3 Les transformations standards

4.3.1 Projection perspective

GL4Dummiesoffre la possibilité de calculer une projection dont le point de perspective est l’œil de l’observateur (ou l’objectif de la caméra). Pour cela, il est nécessaire de décrire le plan virtuel (correspondant en définitif à l’écran de l’utilisateur) sur lequel le volume sera projeté ainsi que la profondeur du volume à projeter. C’est la fonction gl4duFrustum{f|d} qui permet de calculer les coefficients de la matrice de projection 3 en fonction des paramètres qui lui sont passés :

void glFrustumf(GLfloat left, GLfloat right, GLfloat bottom,  
                GLfloat top, GLfloat near, GLfloat far);  
void glFrustumd(GLdouble left, GLdouble right, GLdouble bottom,  
                GLdouble top, GLdouble near, GLdouble far);

La figure 4.3 illustre le résultat attendu lors de l’utilisation du gl4duFrustum{f|d}. Comme nous pouvons le voir sur ce schéma, le volume projeté s’élargie en fonction de la distance, ainsi, plus nous partons dans les z négatifs plus le volume nous permet d’y placer des objets. D’où, pour des objets de dimensions comparables, notons que, une fois projetés, ils parraissent plus petits pour une distance du point de vue qui est plus grande ; le volume subit une compression plus forte en fonction de la distance, c’est l’effet perspective (pensez à l’image de la route qui fuit vers l’horizon) qui est la conséquence de la transformation du volume projeté initial 4 en un Parallélépipède.


pict

Figure 4.3: Projection Perspective

4.4 Projection orthogonale

Ce second type de projection, fourni par l’API GL4Dummies, peut être vu comme un cas particulier de la projection perpective où le point de perpective fuit à l’infini vers les z positifs. Ici, l’impression d’éloignement liée à la distance par rapport au plan de projection (le plan perpendiculaire à l’axe des z et placé en z = Near) n’est plus préservée car tout est projeté orthogonalement à ce plan. Ainsi, la fonction gl4duOrtho{f|d} permet de calculer les coefficients de la matrice de projection 5 en fonction des paramètres qui lui sont passés :

void glOrthof(GLfloat left, GLfloat right, GLfloat bottom,  
              GLfloat top, GLfloat near, GLfloat far);  
void glOrthod(GLdouble left, GLdouble right, GLdouble bottom,  
              GLdouble top, GLdouble near, GLdouble far);

et la figure 4.4 illustre le résultat produit par l’utilisation de cette fonction.


pict

Figure 4.4: Projection Orthogonale

Bibliographie

[Gou71a]    H. Gouraud. Continuous shading of curved surfaces. IEEE Trans. Comput., 20(6) :623–629, June 1971.

[Gou71b]    Henri Gouraud. Computer Display of Curved Surfaces. Doctoral thesis, University of Utah, 1971.

[jav97]    Java code conventions. from oracle.com, 1997.

[SWND05]   Dave Shreiner, Mason Woo, Jackie Neider, and Tom Davis. OpenGL Programming Guide : The Official Guide to Learning OpenGL, Version 2. Addison-Wesley, 2005.