Bonjour cher lecteur,

Aujourd'hui je vous présente comment programmer en D pour faire des applications 2D et 3D grâce à SDL et openGL.

Prérequis

Ajouter le dépôt D comme expliqué ici: Depôt pour le langage D
Installer ensuite les paquets Derelict-SDL et Derelict-GL, les bibliothèques statiques et de développement soit

# yum install  derelict-SDL* derelict-GL*

Exemple de code

Créons un fichier main.d qui contient

private import Display;
private import derelict.sdl.sdl:    SDL_Event, SDL_PollEvent, SDL_QUIT;
 
void main(){
    bool    isRunning   = true;
    Display display     = new Display();
    scope(exit) display.cleanup();
    while(isRunning){
        isRunning = display.event();
        // clear the screen. by default it clears to black
        display.clear();
        //display graphic
        display.drawGLFrame();
    }
}
  1. On crée un booléen pour la boucle principale du programme
  2. On crée une instance de classe Display que l'on verra son contenu plus loin
  3. Lorsque le programme se terminera, il executera obligatoirement la méthode display.cleanup()
  4. Tant qu'un évènement donne pas l'ordre de quitter (bouton fermer par exemple) le booléen sera vrai
    • On on rafraichit l'image

Maintenant créons notre fichier Display.d

private import derelict.sdl.sdl;
private import derelict.opengl.gl;
private import derelict.opengl.glu;
private import tango.stdc.stringz;
//private import tango.io.Stdout;
 
class Display{
    // horizontal and vertical screen resolution
    private uint height;
    private uint width;
    // number of bits per pixel used for display. 24 => true color
    private uint bitsPerPixel;
    // field of view => the angle our camera will see vertically
    private float fov;
    // distance of the near clipping plane
    private float nearPlane;
    // distance of the far clipping plane
    private float farPlane;
    /**
     * Setup some basic OpenGL parameters
     */
    private void setupGL(){
        // switch to the projection mode matrix
        glMatrixMode(GL_PROJECTION);
        // load the identity matrix for projection
        glLoadIdentity();
        // setup a perspective projection matrix
        gluPerspective(fov, cast(float)height / width, nearPlane, farPlane);
        // switch back to the modelview transformation matrix
        glMatrixMode(GL_MODELVIEW);
        // load the identity matrix for modelview
        glLoadIdentity();
    }
    /**
     * Library initializer
     */
    private void init(){
        // initialize SDL, GL and GLU Derelict modules
        DerelictSDL.load();
        DerelictGL.load();
        DerelictGLU.load();
        // initialize SDL's VIDEO module
        SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
        // enable double-buffering
        SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
        // create our OpenGL window
        SDL_SetVideoMode(height, width, bitsPerPixel, SDL_OPENGL);
        SDL_WM_SetCaption(toStringz("D is the best"), null);
        setupGL();
    }
    /**
     * Constructor
     */
    public this(){
        height      = 800;
        width       = 600;
        bitsPerPixel= 24;
        fov         = 90;
        nearPlane   = 0.1f;
        farPlane    = 100.f;
        init();
    }
    public ~this(){
        //cleanup();
    }
    /**
     * be nice and release all resources
     */
    public static void cleanup(){
        // tell SDL to quit
        if(SDL_Quit !is null)
            SDL_Quit();
        // release GL, GLU and SDL's shared libs
        DerelictGLU.unload();
        DerelictGL.unload();
        DerelictSDL.unload();
    }
    public void clear(){
        glClear(GL_COLOR_BUFFER_BIT);
    }
    public void drawGLFrame(){
        glBegin(GL_TRIANGLES);
            glColor3f (1,  0,  0);
            glVertex3f(-1, -1, -2);
            glColor3f (0,  1,  0);
            glVertex3f(1, -1, -2);
            glColor3f (0,  0,  1);
            glVertex3f(0,  1, -2);
        glEnd();
        // swap the buffers, making our backbuffer the visible one
        SDL_GL_SwapBuffers();
    }
 
    public bool event(){
        bool isRunning = true;
        SDL_Event event;
        // handle all SDL events that we might've received in this loop iteration
        while(SDL_PollEvent(&event)){
            switch(event.type){
                // user has clicked on the window's close button
                case SDL_QUIT:
                    isRunning = false;
                    break;
                // by default, we do nothing => break from the switch
                default:
                    break;
            }
            //Stdout.formatln("event.type: {}",event.type);
        }
        return isRunning;
    }
}

Ici on crée une classe pour gérer l'affichage que l'on appelle Display.

Elle contient des attributs pour:

  • La résolution de la fenêtre (height, width)
  • La qualité de l'image (bitsPerPixel)
  • Angle de caméra (fov)
  • Spécifie la distance minimum entre le spectateur par rapport au plan (nearPlane)
  • Spécifie la distance maximum entre le spectateur par rapport au plan (farPlane)

Le constructeur par défaut initialise les attributs ainsi que les bibliothèques openGL/SDL par l'appel de la fonction init()
La fonction event renvoie un booléen, faux si on souhaite quitter sinon vrai
La fonction drawGLFrame dessine un triangle
La fonction statique cleanup est optionnelle elle permet de s'assurer de quitter proprement

Je vous laisse potasser sur le code :)

Compilation

Pour compiler l'application on doit spécifier les bibliothèques avec lesquelles le programme est lié soit ici:

$ ldc -g -w -L -ldl -L -lDerelictGL -L -lDerelictGLU  -L -lDerelictSDL -L -lDerelictUtil *.d -of example

Produira un éxécutable nommé example

Éxécution

Simplement, après compilation

$ ./example

Résultat

Capture-D_is_the_best.png

C'est beau hein!

Liens

A bientôt

Signé: bioinfornatics, Jonathan MERCIER