Dolphin et les homebrews

Dans un article précédent j’avais mentionné que l’émulateur Dolphin avait un problème avec l’infrarouge de la Wii Remote. Eh bien ce problème a été réglé. En effet, il est désormais possible de contrôler le pointeur d’une Wii Remote à l’aide de la souris de votre ordinateur. C’est un avancement formidable pour ceux qui testent leur homebrew avec ce logiciel.

C’est un programmeur du nom de godisgovernment qui a finalement fixé le problème à la révision 6177. Cette modification ne fait donc pas partie de la version 2.0, qui est la dernière version officielle à être distribuée. Les dernières versions de Dolphin sous Subversion sont quand même disponibles en téléchargement à partir de ce site Web.

Étant donné que ce n’est pas mon habitude de terminer un article sans code, je vous laisse avec un programme qui vous permettra de faire vous-même le test sous Dolphin. La bibliothèque GRRLIB sera utilisée pour la partie graphique. Comme pour tous les homebrews sur la Wii, c’est wiiuse qui servira pour la communication avec la Wii Remote.

#include <grrlib.h>
#include <stdlib.h>
#include <wiiuse/wpad.h>

#include "player1_point_png.h"

#define HOTSPOTX 48 // Cursor hot spot for x coordinate
#define HOTSPOTY 48 // Cursor hot spot for y coordinate

int main(int argc, char **argv) {
    // Initialise the Graphics & Video subsystem
    GRRLIB_Init();

    GRRLIB_texImg *Cursor0 = GRRLIB_LoadTexture(player1_point_png);
    GRRLIB_SetHandle(Cursor0, HOTSPOTX, HOTSPOTY);// Not needed, by default center is selected

    // Initialise the Wiimotes
    WPAD_Init();
    WPAD_SetDataFormat(WPAD_CHAN_ALL, WPAD_FMT_BTNS_ACC_IR);
    WPAD_SetVRes(WPAD_CHAN_ALL, rmode->fbWidth, rmode->efbHeight);

    // Loop forever
    while(1) {
        WPAD_ScanPads();  // Scan the Wiimotes
        WPADData *WPadData0 = WPAD_Data(WPAD_CHAN_0);

        // If [HOME] was pressed on the first Wiimote, break out of the loop
        if (WPadData0->btns_d & WPAD_BUTTON_HOME)  break;

        // ---------------------------------------------------------------------
        if(WPadData0->ir.valid) {
            GRRLIB_DrawImg(WPadData0->ir.x - HOTSPOTX,
                WPadData0->ir.y - HOTSPOTY, Cursor0,
                WPadData0->ir.angle, 1, 1, 0xFFFFFFFF);
        }
        // ---------------------------------------------------------------------

        GRRLIB_Render();  // Render the frame buffer to the TV
    }

    GRRLIB_Exit(); // Be a good boy, clear the memory allocated by GRRLIB

    GRRLIB_FreeTexture(Cursor0);

    exit(0);
}

À la ligne 14 on charge l’image dans une texture. L’image utilisée pour le pointeur est celle-ci:

Player 1 Wii pointer

Il s’agit d’une image qui fait partie d’un ensemble de curseurs pour la Wii conçus par drmr. Toutes les images sont de 96×96 pixels et le point sensible, habituellement le bout du doigt, est situé au centre. L’auteur a renoncé à ses droits sur les images pour les mettre dans le domaine public. Vous pouvez donc les utiliser dans vos applications sans problème de copyright.

À la ligne 19 on spécifie le format des données qui seront prises sur la Wii Remote. BTNS_ACC_IR veut dire boutons + accéléromètre + infrarouge. Par la suite, la fonction WPAD_SetVRes sert à définir la résolution d’écran virtuel pour la localisation de l’infrarouge. Pour ces opérations on utilise le paramètre WPAD_CHAN_ALL pour que tous les contrôleurs soient affectés. Pour que la fonction affecte une télécommande en particulier on doit utiliser WPAD_CHAN_0, WPAD_CHAN_1, WPAD_CHAN_2 ou WPAD_CHAN_3.

À la ligne 25 on va chercher les données de la première Wii Remote avec la fonction WPAD_Data. Les lignes 31 à 35 servent à faire afficher le curseur avec le bon angle à la position vers laquelle la télécommande pointe. Et ce, seulement si les coordonnés sont valides. Donc, si vous mettez votre main devant la Wii Remote, le pointeur disparaîtra de l’écran de votre téléviseur.

J’aurais pu ajouter bien des choses dans le code, mais j’ai décidé de le garder simple.

Bonne programmation…

Écrire du texte avec GRRLIB

Il existe trois manières différentes d’écrire du texte à l’aide de la bibliothèque GRRLIB. On peut utiliser une texture, un fichier BMF ou un fichier TTF. Chacune de ces méthodes possède des avantages et des inconvénients.

La première méthode qui sera expliquée sera l’utilisation d’une texture. Bien sûr, lorsqu’on parle de texture, on parle d’une image. Même si GRRLIB supporte les formats JPEG et Bitmap, il serait préférable que celle-ci soit en format PNG, car ce format permet l’utilisation de transparence. Il existe plusieurs logiciels qui permettent de générer de telles images. Celui que j’utilise est WiiBuilder. Voici l’image qui sera utilisée pour cet article:
Police de caractères pour GRRLIB Vous pouvez vous rendre compte de certaines limites simplement en regardant l’image. Tous les caractères qui seront nécessaires dans l’application devront être générés dans l’image. Dans celle-ci, il n’y a que les caractères 32 à 128, qui sont les caractères visibles du code ASCII. Donc, pas question d’utiliser un E accent aigu ou un A accent grave. Ces caractères auraient pu être générés, mais l’image aurait été plus grande.

Le plus grand inconvénient à utiliser une image est que chaque caractère doit avoir la même largeur. Dans l’exemple ci-dessus, c’est 13 pixels. Cela veut dire que même si on décide d’afficher un i ou un !, ils vont prendre la même place qu’un m ou w, qui sont généralement plus grand. Donc, à l’écran le mot Wii, pourrait avoir l’air de "W i i ". Bien sûr cela dépend toujours de la police utilisée. Dans celle que j’ai choisie, tous les caractères ont sensiblement la même largeur. On dit que c’est une police d’écriture à chasse fixe.

Il faut convertir l’image en fichier d’entête et la transformer en texture à l’aide de la fonction GRRLIB_LoadTexture. Ces manipulations ont déjà été abordées dans un article précédent, donc veuillez vous y référer si vous avez besoin d’aide. Il existe deux différences entre l’affichage de texte et l’affichage d’images. La première est qu’après avoir chargé l’image dans une structure de type GRRLIB_texImg, il faut spécifier les détails de notre image avec la fonction GRRLIB_InitTileSet. Les paramètres de la fonction dans l’ordre sont un pointeur vers la texture, la largeur et la hauteur d’un caractère et le caractère de départ. La seconde différence est l’utilisation de GRRLIB_Printf au lieu de GRRLIB_DrawImg.

Voici donc le code. Les lignes surlignées sont celles ajoutées au code du template du dossier examples de GRRLIB.

#include <grrlib.h>

#include <stdlib.h>
#include <wiiuse/wpad.h>

#include "demofont.h"

int main(int argc, char **argv) {
    // Initialise the Graphics & Video subsystem
    GRRLIB_Init();

    GRRLIB_texImg *demo_font = GRRLIB_LoadTexture(demofont);
    GRRLIB_InitTileSet(demo_font, 13, 23, 32);

    // Initialise the Wiimotes
    WPAD_Init();

    // Loop forever
    while(1) {

        WPAD_ScanPads();  // Scan the Wiimotes

        // If [HOME] was pressed on the first Wiimote, break out of the loop
        if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)  break;

        // ---------------------------------------------------------------------
        // Place your drawing code here
        GRRLIB_Printf(5, 100, demo_font, 0xFFFFFFFF, 1,
            "Ceci est un test de texture");
        // ---------------------------------------------------------------------

        GRRLIB_Render();  // Render the frame buffer to the TV
    }

    GRRLIB_FreeTexture(demo_font);
    GRRLIB_Exit(); // Be a good boy, clear the memory allocated by GRRLIB

    exit(0);
}

Cela fait le tour de la première méthode. La prochaine dont il va être question est l’utilisation de fichier BMF pour afficher du texte. BMF est l’extension qui désigne un bitmap font. Ce type de fichier peut être téléchargé sur le site Web suivant: http://bmf.wz.cz. La police que j’ai choisie se nomme NOSTK. Elle possède seulement 35 caractères et les lettres minuscules ne sont pas présentes.

Les étapes pour afficher du texte sont assez simples. Encore une fois, on transforme le fichier en entête qui sera inclus dans le main.c. On charge l’image dans une structure. Cette fois-ci, il s’agit d’un GRRLIB_bytemapFont. On dessine le texte avec GRRLIB_PrintBMF et la mémoire est libérée grâce à GRRLIB_FreeBMF.

Voici le code avec les nouvelles lignes surlignées:

#include <grrlib.h>

#include <stdlib.h>
#include <wiiuse/wpad.h>

#include "demofont.h"
#include "nostk.h"

int main(int argc, char **argv) {
    // Initialise the Graphics & Video subsystem
    GRRLIB_Init();

    GRRLIB_texImg *demo_font = GRRLIB_LoadTexture(demofont);
    GRRLIB_InitTileSet(demo_font, 13, 23, 32);
    GRRLIB_bytemapFont *bmf_font = GRRLIB_LoadBMF(nostk);

    // Initialise the Wiimotes
    WPAD_Init();

    // Loop forever
    while(1) {

        WPAD_ScanPads();  // Scan the Wiimotes

        // If [HOME] was pressed on the first Wiimote, break out of the loop
        if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)  break;

        // ---------------------------------------------------------------------
        // Place your drawing code here
        GRRLIB_Printf(10, 100, demo_font, 0xFFFFFFFF, 1,
            "Ceci est un test de texture");
        GRRLIB_PrintBMF(10, 150, bmf_font,
            "CECI EST UN TEST DE FICHIER BMF");
        // ---------------------------------------------------------------------

        GRRLIB_Render();  // Render the frame buffer to the TV
    }

    GRRLIB_FreeTexture(demo_font);
    GRRLIB_FreeBMF(bmf_font);
    GRRLIB_Exit(); // Be a good boy, clear the memory allocated by GRRLIB

    exit(0);
}

La dernière méthode est l’utilisation de fichier TTF. TTF est l’extension pour désigner une police de caractères de format TrueType. Les polices TrueType sont constituées de vecteurs donc la qualité du texte ne diminue pas contrairement au bitmap lorsque la taille augmente. La police que j’ai choisie se nomme Miama et elle possède 1110 caractères. Par contre, sa taille est de 106 Ko, ce qui reste quand même raisonnable. Elle a été téléchargée sur le site Open Font Library.org.

Les étapes pour afficher du texte sont les mêmes que pour les BMF, sauf que l’on remplace le mot BMF par TTF. On charge l’image dans une structure de type GRRLIB_ttfFont avec la fonction GRRLIB_LoadTTF. On dessine le texte avec GRRLIB_PrintfTTF et la mémoire est libérée grâce à GRRLIB_FreeTTF. Il est possible d’utiliser des chaînes de caractères de type wchar_t avec la fonction GRRLIB_PrintfTTFW.

Voici le code avec les nouvelles lignes surlignées:

#include <grrlib.h>

#include <stdlib.h>
#include <wiiuse/wpad.h>

#include "demofont.h"
#include "nostk.h"
#include "Miama.h"

int main(int argc, char **argv) {
    // Initialise the Graphics & Video subsystem
    GRRLIB_Init();

    GRRLIB_texImg *demo_font = GRRLIB_LoadTexture(demofont);
    GRRLIB_InitTileSet(demo_font, 13, 23, 32);
    GRRLIB_bytemapFont *bmf_font = GRRLIB_LoadBMF(nostk);
    GRRLIB_ttfFont *ttf_font = GRRLIB_LoadTTF(Miama, Miama_size);

    // Initialise the Wiimotes
    WPAD_Init();

    // Loop forever
    while(1) {

        WPAD_ScanPads();  // Scan the Wiimotes

        // If [HOME] was pressed on the first Wiimote, break out of the loop
        if (WPAD_ButtonsDown(0) & WPAD_BUTTON_HOME)  break;

        // ---------------------------------------------------------------------
        // Place your drawing code here
        GRRLIB_Printf(10, 100, demo_font, 0xFFFFFFFF, 1,
            "Ceci est un test de texture");
        GRRLIB_PrintBMF(10, 150, bmf_font,
            "CECI EST UN TEST DE FICHIER BMF");
        GRRLIB_PrintfTTF(10, 200, ttf_font,
            "Ceci est un test de police TrueType", 60, 0xFFFFFFFF);
        // ---------------------------------------------------------------------

        GRRLIB_Render();  // Render the frame buffer to the TV
    }

    GRRLIB_FreeTexture(demo_font);
    GRRLIB_FreeBMF(bmf_font);
    GRRLIB_FreeTTF(ttf_font);
    GRRLIB_Exit(); // Be a good boy, clear the memory allocated by GRRLIB

    exit(0);
}

L’encodage par défaut des fichiers dans Programmer’s Notepad pourrait vous causer des problèmes avec certains caractères de la langue française. Si c’est la cas, il faut donc aller dans File / Properties… ou sinon utiliser le raccourci Alt + Entrée avec le bon fichier ouvert. Au lieu de Default dans la liste Encoding, vous pouvez sélectionner UTF-8. Si vous désirez ne pas altérer votre fichier qui contient le code, vous pouvez alors créer un fichier d’entête avec l’encodage de votre choix qui contiendra tout le texte dans des directives #define.

Je vous laisse avec une image du résultat final.
Texte avec GRRLIB

Configurer Programmer’s Notepad pour lancer Indent

Lors d’un article précédent, j’avais expliqué comment démarrer Dolphin à partir de Programmer’s Notepad. Voici maintenant un article similaire qui vous expliquera comment lancer Indent à partir de ce même éditeur.

Tout d’abord, un petit mot à propos d’Indent. Indent est un logiciel de mise en forme de codes source. Il change l’apparence d’un programme codé en C en y insérant ou en effaçant des espaces et des retours à la ligne. Il peut être utilisé afin de rendre votre code plus facile à lire et aussi pour changer le style d’écriture vers un autre.

La première étape consiste à télécharger Indent. Pour télécharger la version pour Windows, il suffit d’aller sur ce site Web. Lors de l’écriture de cet article, la dernière version disponible était la 2.2.10. Les fichiers zip que je vous conseille de télécharger sont Binaries et Dependencies. Sur votre disque dur, créez un nouveau dossier, par exemple: C:\indent. Dans le fichier indent-2.2.10-bin.zip, il faut extraire le fichier indent.exe qui se trouve dans le dossier bin. Dans le fichier qui contient les dépendances (indent-2.2.10-dep.zip), il faut extraire les fichiers libiconv2.dll et libintl3.dll qui se trouvent dans le dossier bin. Maintenant, votre dossier C:\indent devrait contenir le minimum requis pour faire fonctionner Indent.

Programmer’s Notepad, ajout de Indent

Indent est prêt à être utilisé, alors voici comment faire pour le démarrer à partir de Programmer’s Notepad:

  • Ouvrir Programmer’s Notepad
  • Ouvrir la fenêtre d’options en allant dans Tools / Options
  • Sélectionner Tools dans la structure arborescente
  • Sélectionner C / C++ dans la liste déroulante Scheme
  • Cliquer sur le bouton Add
  • Entrer les informations suivantes
    • Name: Format Source
    • Command: C:\indent\indent.exe
    • Folder: %d
    • Parameters: -linux %f
    • Shortcut: CTRL + Shift + F
    • Save: Current File
    • Cocher This tool will modify the current file.
  • Cliquer sur OK pour fermer la fenêtre de propriété d’outils
  • Cliquer sur OK pour fermer la fenêtre d’options

La propriété Command doit être modifiée pour représenter le chemin d’accès de Indent sur votre disque dur. Pour Shortcut, j’ai décidé d’utiliser CTRL + Shift + F, F comme dans Format. Ne vous gênez pas pour mettre la touche de raccourci qui fait votre bonheur.

La propriété Parameters est sans doute la plus importante, car c’est là que le style de programmation y est décidé. Dans la configuration précédente, j’utilise -linux pour le style Linux. Il existe quelques autres styles communs:

  • GNU (style par défaut depuis la version 1.2): -gnu
  • Kernighan & Ritchie: -kr
  • Berkeley original: -orig

Chacun de ces styles est l’équivalent de plusieurs paramètres. Par exemple, le style Linux:

-nbad -bap -nbc -bbo -hnl -br -brs -c33 -cd33 -ncdb -ce -ci4 -cli0 -d0 -di1 -nfc1 -i8 -ip0 -l80 -lp -npcs -nprs -npsl -sai -saf -saw -ncs -nsc -sob -nfca -cp33 -ss -ts8 -il1

Pour plus de détails, veuillez vous référer à la documentation de Indent.

À partir de maintenant vous n’aurez plus d’excuses pour soumettre du code désorganisé.

Changer l’alpha d’un PNG à l’exécution

Cet article montrera comment changer le canal alpha d’une image de type PNG lors de l’exécution d’un programme codé avec C++Builder.

En premier lieu, il faut créer un nouveau projet auquel on ajoute un composant TTrackBar. C’est avec ce contrôle que l’on changera la transparence de l’image. Il sera gradué de 0 à 100, car il représente un pourcentage d’opacité.

Transparence d'un PNG

Dans le constructeur de la Form, on ajoute le code suivant:

    OriginalImage = new TPngImage();
    OriginalImage->LoadFromFile("../tux.png");

    TrackBar1->Align = alBottom;// Le composant est aligné au bas de la fenêtre
    TrackBar1->Min = 0;         // Le minimum est 0%
    TrackBar1->Max = 100;       // Le maximum est 100%
    TrackBar1->Position = 0;    // Position de départ à 0%
    TrackBar1->Frequency = 5;   // Marque de graduation à tout les 5 incréments
    TrackBar1->PageSize = 5;    // Déplacement par bonds de 5
    TrackBar1->ShowSelRange = false;// La zone sélectionnée n'est pas affichée

    DoubleBuffered = true; // Évite le scintillement lors d'un redimensionnement

Les lignes 1 et 2 servent à créer un objet TPngImage qui servira à garder en mémoire l’image originale. Le but de OriginalImage est de ne pas avoir à recharger l’image à chaque fois que le TTrackBar se déplacera. Dans ce code, on charge l’image directement du disque dur avec LoadFromFile, mais on aurait pu la charger à partir des ressources du programme.

Dans l’évènement OnDestroy de la fenêtre, on ajoute cette ligne pour libérer la mémoire allouée par OriginalImage:

    delete OriginalImage;

Dans votre fichier d’en-tête, ajoutez le code suivant dans la section private:

    TPngImage *OriginalImage;
    void __fastcall SetTransparency(TPngImage *PngImage, float TransPct);

Maintenant, voici la pièce de résistance, la méthode qui change l’alpha d’un PNG:

void __fastcall TForm1::SetTransparency(TPngImage *PngImage, float TransPct)
{
    int x, y;
    Byte *DestAlpha, Alpha;
    float Pct = TransPct / 100.0f;
    for(y = 0; y < PngImage->Height; y++)
    {
        DestAlpha = (Byte *)PngImage->AlphaScanline[y];
        for(x = 0; x < PngImage->Width; x++)
        {
            Alpha = RoundTo(Pct * DestAlpha[x], 0);
            if((DestAlpha[x] - Alpha) < 0)
                DestAlpha[x] = 0;
            else
                DestAlpha[x] -= Alpha;
        }
    }
}

Le premier paramètre d’entrée est un objet de type TPngImage qui sera modifié. Le deuxième paramètre est une valeur en pourcentage, donc on attend une valeur entre 0 et 100. 0 rendra l’image complètement opaque et celle-ci ne sera donc pas modifiée tandis qu’à 100, elle est complètement transparente.

La méthode AlphaScanline lit une ligne de numérisation contenant le canal alpha et renvoie un pointeur sur la mémoire contenant cette ligne.

Puisque la fonction RoundTo est utilisée pour arrondir, il faut ajouter cet entête:

#include <Math.hpp>

À cause de problème de scintillement avec un TImage, l’image sera dessinée directement sur le Canvas de la fenêtre. Voici le code à ajouter à l’évènement OnChange du TTrackBar:

    TPngImage *ImageToProcess = new TPngImage();
    Graphics::TBitmap *TempImage = new Graphics::TBitmap();

    ImageToProcess->Assign(OriginalImage);
    SetTransparency(ImageToProcess, TrackBar1->Position);

    TempImage->Canvas->Brush->Color = Form1->Color;
    TempImage->SetSize(OriginalImage->Width, OriginalImage->Height);
    TempImage->Canvas->Draw(0, 0, ImageToProcess);

    Canvas->Draw(Width/2 - TempImage->Width/2,
        Height/2 - TempImage->Height/2 - TrackBar1->Height, TempImage);

    delete ImageToProcess;
    delete TempImage;

Deux images temporaires seront créées. ImageToProcess est de type TPngImage et on lui assigne l’image originale et on la modifie ensuite en appelant SetTransparency. TempImage est un TBitmap qui sert à la double mise en mémoire tampon. On y dessine l’arrière plan de la couleur de la fenêtre et ensuite on y dessine ImageToProcess. C’est cette image que l’on dessine sur le Canvas au centre de la fenêtre avec la méthode Draw.

Dans l’évènement OnPaint de la fenêtre, on ajoute ce code pour que l’image soit toujours présente:

    TrackBar1Change(NULL);

Dans l’évènement OnResize de la fenêtre, on doit redessiner l’image pour qu’elle reste centrée:

    Invalidate();

Voilà ce qui met fin à l’article. Vous pouvez maintenant vous amuser avec la barre graduée afin de changer l’opacité de l’image.

Je vous laisse avec une ligne de code qui pourrait vous être pratique si vous désirez seulement changer à une reprise le canal alpha d’un PNG dans un TImage:

SetTransparency((TPngImage *)Image1->Picture->Graphic, 75);

Initiation à la bibliothèque GRRLIB

GRRLIB est une bibliothèque graphique codée en langage C pour la conception d’homebrews sur la Wii. Grâce à cette bibliothèque, l’utilisation des fonctions GX n’est plus nécessaire. GX est la bibliothèque graphique de Nintendo qui interface le processeur graphique de la console.

GRRLIB est un projet à code source ouvert qui est hébergé sur le site Web de GitHub. La dernière version stable est disponible en téléchargement sous forme de fichier compressé et la version en développement peut être récupérée sous Subversion.

Pour compiler GRRLIB, il faut d’abord que devkitPro avec les composants devkitPPC, libogc et libfat soit installé sur votre PC. devkitPPC permet la compilation de code pour l’architecture powerpc-eabi. La bibliothèque libogc assure un support pour les fonctions GX et libfat permet l’utilisation du système de fichiers FAT.

Lors de son installation, GRRLIB va installer d’autres bibliothèques telles que libjpeg pour l’utilisation de fichiers JPEG, libpngu qui nécessite libpng et zlib pour l’utilisation d’images PNG et enfin FreeType pour l’utilisation de polices de caractères TrueType.

Pour lancer l’installateur, ouvrez une invite de commandes dans le dossier GRRLIB et tapez la ligne suivante:
make clean all install
Ceci pourrait prendre un peu de temps dépendant de la puissance de votre ordinateur. Quand le défilement de commande cessera, cela voudra dire que tout est installé. Les bibliothèques devraient avoir été copiées dans le dossier C:\devkitPro\libogc\lib\wii et les fichiers d’entête dans le dossier C:\devkitPro\libogc\include.

Pour ceux qui n’ont rien compris au dernier paragraphe, vous pouvez créer un fichier nommé install.bat dans le dossier GRRLIB et y insérer le code suivant:

@echo off
echo Nettoyage de l'installation pr‚c‚dente
make clean -s
echo Compilation du code source
make -s
echo Installation des bibliothŠques dans le dossier de libogc
make install -s

Ensuite, il suffit de double-cliquer sur le fichier pour démarrer l’installation de GRRLIB.

Vous êtes maintenant prêts à commencer à programmer un homebrew pour la Wii à l’aide de GRRLIB. Dans le dossier examples, il y a un projet Programmer’s Notepad qui contient le code minimum pour utiliser GRRLIB. Le projet se nomme template.pnproj et il est situé à l’intérieur du dossier template. Le projet inclut les fichiers main.c et Makefile. Ces fichiers devraient toujours être utilisés pour démarrer la programmation d’un nouveau jeu.

Maintenant, si vous faites Tools / make ou Alt+1, le projet se compilera et les fichiers template.elf et template.dol seront gérés. S’il y a une erreur, c’est que vous n’avez pas suivi les étapes correctement. Je vous conseille donc de lire attentivement le document README.html incorporé dans le téléchargement de GRRLIB. Si le problème persiste, vous pourrez toujours aller poser une question sur le forum officiel de la bibliothèque.

Les images ne sont pas utilisées directement dans GRRLIB. Il faut d’abord les transformer en texture avec la fonction GRRLIB_LoadTexture. Le résultat sera enregistré dans une structure de type GRRLIB_texImg. Il existe aussi des fonctions spécifiques pour les trois types d’image supportés par GRRLIB, soit GRRLIB_LoadTexturePNG, GRRLIB_LoadTextureJPG et GRRLIB_LoadTextureBMP. Si vous avez besoin de plus d’information sur les fonctions incluses dans la bibliothèque, il existe une documentation générée par Doxygen.

Avant d’incorporer une image à un projet, il faut savoir que ses dimensions doivent être inférieures ou égales à 1024 pixels. De plus, elles doivent être des multiples de quatre. Si l’image est un PNG, il faut aussi qu’elle soit en 24 ou 32 bits. Les palettes ne sont pas gérées par PNGU.

Les images peuvent être chargées à partir d’une carte SD avec la fonction GRRLIB_LoadTextureFromFile. Par contre, ce n’est pas cette façon qui sera démontrée ici. Les images seront ajoutées à l’intérieur des fichiers .elf et .dol dans le but d’avoir un seul fichier exécutable. Ceci permettra de tester plus facilement le homebrew dans Dolphin ou de l’exécuter sur la Wii à l’aide de wiiload.

Pour accomplir cette transformation, il existe quelques outils. raw2c est un utilitaire qui fonctionne par ligne de commandes et il est inclus dans le dossier bin de devkitPPC. WiiBuilder est un logiciel fonctionnant sous Windows qui permet de faire la même chose que raw2c en plus de plusieurs autres choses. Il est disponible en téléchargement sur le site Web de WiiBrew. Les avantages sont qu’il ne nécessite pas de lignes de commandes, qu’il donne des avertissements lorsque les images n’ont pas un format approprié et qu’il permet de générer seulement les fichiers d’entête. Le dernier point peut paraître inutile, mais cela fait en sorte que le fichier généré pourra être déplacé dans n’importe quel dossier sans avoir à modifier le Makefile pour ajouter un endroit supplémentaire à la compilation. La modification du fichier Makefile cause souvent des maux de tête au programmeur débutant, c’est pourquoi je ne parlerai pas de l’utilisation de bin2o pour générer un fichier objet qui inclut l’image.

Pour la démonstration, je vais me servir de l’image pirate.png qui se trouve dans le dossier \examples\bitmap_fx\source\gfx. Vous pouvez créer un dossier images à l’intérieur du dossier template dans lequel vous pourrez copier l’image. Si vous utilisez WiiBuilder, il suffit de faire un glisser-déposer de l’image à l’intérieur de la liste de la section File. Un fichier portant le nom de pirate.h devrait avoir été créé. C’est ce fichier qu’il faut ajouter dans main.c.

Passons maintenant à la programmation. Pour afficher l’image, il suffit d’ajouter quatre lignes au code du template. On ajoute à la liste d’entête celui-ci:

#include "../images/pirate.h"

Après la commande GRRLIB_Init, il faut ajouter ceci pour charger la texture:

GRRLIB_texImg *MaTexture = GRRLIB_LoadTexture(pirate);

À l’endroit où il est écrit « Place your drawing code here », on met le code suivant pour dessiner la texture à l’écran:

GRRLIB_DrawImg(100, 100, MaTexture, 0, 1, 1, 0xFFFFFFFF);

Finalement, on ajoute le code suivant à la suite de GRRLIB_Exit pour libérer la mémoire attribuée par GRRLIB_LoadTexture:

GRRLIB_FreeTexture(MaTexture);

Si vous utilisez l’émulateur Dolphin vous devriez avoir le résultat suivant:

L'émulateur Dolphin qui roule un homebrew assez simple

Ce n’est pas ce qu’on pourrait qualifier de meilleur homebrew au monde, mais au moins c’est un point de départ. Si vous êtes intéressés a continuer, allez regarder les autres exemples inclus avec GRRLIB.

Bonne chance dans la programmation de votre jeu révolutionnaire!

Le bouton « Notify on Language Exceptions »

Dans cet article, je vous présente un petit truc pour mieux gérer les exceptions du langage dans C++Builder.

Depuis la version 2007, il est possible d’ajouter un bouton à la barre d’outils qui se nomme Notify on Language Exceptions. Ce bouton permet d’activer ou de désactiver l’option du même nom que l’on trouve dans Tools / Options… / Debugger Options / Embarcadero Debuggers / Language Exceptions.

Comme vous le voyez, on dirait que cette option est quasiment cachée, donc le fait d’avoir un bouton accessible d’un seul clique de souris peut faire sauver beaucoup de temps lors du débogage d’un programme.

Pour ajouter le bouton dans la barre d’outils, il suffit d’aller dans View / Toolbars / Customize…. Ensuite, il faut aller dans l’onglet Commands et choisir la catégorie Run. Maintenant, il faut faire un glisser-déposer de l’item Notify on Language Exceptions dans la barre d’outils de C++Builder. Voici une capture d’écran pour mieux illustrer mes propos:

Notify on Language Exceptions

Une fois terminé, vous pouvez fermer la fenêtre Customize.

Dans le but de tester le bon fonctionnement du bouton, nous allons créer un nouveau projet dans lequel le code suivant sera inséré dans le constructeur de la Form:

    try
    {
        int a, b = 0;
        a = 2 / b;
    }
    catch(...)
    {
    }

Si le bouton est enfoncé lorsqu’on appuie sur Run en mode Debug, alors le message suivant apparaîtra:

Project Project1.exe raised exception class EDivByZero with message 'Division by zero'

C’est normal car il y a effectivement une division par zéro. Si l’on désactive l’option et que l’on relance l’application, le message disparaît comme par magie.

Voilà, c’est tout!

Utiliser la bibliothèque MikMod sous C++Builder

Cet article vous expliquera comment compiler la bibliothèque MikMod sous forme de bibliothèque statique (.lib) que vous pourrez intégrer directement dans un programme fait avec C++Builder. Tout d’abord, MikMod est une bibliothèque de programmes codée en langage C qui sert à faire jouer des fichiers module. Cela inclut les fichiers MOD (15 et 31 instruments), S3M (ScreamTracker 3), IT (Impulse Tracker) et XM (FastTracker 2).

La première étape consiste à aller télécharger le code source de la bibliothèque logicielle sur le site Web officiel. Il se trouve dans la section Files de la page. C’est le fichier libmikmod-3.2.0-beta2.zip qui sera utilisé. Il est a noter qu’une version plus récente du code est disponible par CVS sur le site Web de SourceForge.

Une fois le téléchargement terminé, il faut extraire les données dans un dossier que l’on nommera MikMod. Dans C++Builder nous allons créer le nouveau projet en allant dans File / New / Other…. La touche de raccourcis Ctrl+N aurait pu être utilisée. Puis, on sélectionne Static Library et on clique sur OK. Maintenant, nous pouvons sauvegarder notre projet. Pour cela, on va dans File et on sélectionne Save Project As… On choisit comme nom de projet MikMod pour que le fichier lib porte ce nom. L’emplacement du fichier cbproj doit être dans le dossier où les données on été extraites.

Il faut ajouter les fichiers .c au projet.

  • Pour le dossier drivers: "drv_stdout.c" "drv_wav.c" "drv_win.c" "drv_ds.c" "drv_nos.c" "drv_raw.c"
  • Pour le dossier loaders, on sélectionne tous les fichiers.
  • Pour le dossier mmio, on sélectionne tous les fichiers.
  • Pour le dossier playercode, on sélectionne tous les fichiers.

Étant donné que seulement les fichiers .c ont été ajoutés au projet, il manque les chemins d’accès pour certains fichiers .h. Il faut donc aller dans Project / Options… ou Alt+F7. Dans Include path on ajoute: win32\;include\;
Ensuite, dans Conditional defines, on ajoute ceci: WIN32;DRV_WIN;HAVE_FCNTL_H;HAVE_MALLOC_H;HAVE_LIMITS_H;__STDC__=1
Par la suite, on quitte la fenêtre d’option, on choisit la configuration Release et on compile le code. Il se peut qu’il y ait plusieurs avertissements lors de la compilation, mais cela n’empêchera pas le code de fonctionner correctement. Le fichier MikMod.lib devrait être créé dans le dossier Release.

Afin de valider les étapes précédentes, il va falloir créer un nouveau projet indépendant pour être certain que la bibliothèque fonctionnera peu importe l’emplacement du projet. Dans cette nouvelle application VCL, on ajoute un contrôle TTimer et on met la propriété Interval à 100ms. Par la suite, on ajoute au projet les fichiers mikmod_build.h et MikMod.lib.

Dans le constructeur de la Form, on ajoute le code suivant:

// Enregistrement de la bibliothèque
MikMod_RegisterDriver(&drv_win);
MikMod_RegisterAllLoaders();

// Initialise la bibliothèque
if(MikMod_Init(""))
{
    throw(Exception("L'initialisation de MikMod a échouée."));
}
else
{
    // Charge le module
    AnsiString FileName = "..\\music.s3m";
    module = Player_Load(FileName.c_str(), 32, 0);
    if(module)
    {
        module->wrap = true;    // Recommence lorsqu'il finit
        Player_Start(module);   // Démarre la musique
    }
    else
    {
        throw(Exception("Le fichier n'a pu être chargé."));
    }
}

C’est le pilote pour l’API multimédia de Windows qui est chargé à la ligne 2. On aurait aussi pu utiliser drv_ds pour que le son soit pris en charge par DirectSound. Par contre, si l’on décide de faire ce choix, il va falloir ajouter DRV_DS à la liste des Conditional defines. En plus, il est nécessaire d’ajouter le fichier dsound.lib au projet pour accéder aux fonctions l’API de DirectSound. Si vous êtes intéressé à générer un fichier wav plutôt que de lire un fichier audio, alors c’est le pilote drv_wav qu’il faut utiliser.

À la ligne 13, on trouve la variable FileName, on doit lui affecter le chemin du fichier module que l’on veut faire jouer.

Dans le destructeur, on arrête la musique et on libère la mémoire avec le code suivant:

Timer1->Enabled = false;
if(module)
{
    Player_Stop();
    Player_Free(module);
    MikMod_Exit();
}

Dans l’évènement OnTimer du TTimer, on ajoute ceci:

if(module && Player_Active())
{
    MikMod_Update();
}

La fonction MikMod_Update doit être appelée sur une base régulière, car elle sert à remplir la mémoire tampon de la sortie audio.

Si vous êtes intéressé à aller un peu plus loin, vous pouvez ajouter un contrôle TTrackBar au projet auquel les propriétés Max et Position devront être initialisées à 128. Dans l’évènement OnChange, ajoutez le code suivant:

   	Player_SetVolume(TrackBar1->Position);

Un contrôle de volume est maintenant disponible dans votre logiciel.

Si vous êtes à la recherche de pièces musicales, je vous conseille d’aller faire un tour sur le site Web The Mod Archive.

À présent, vous avez tout ce qu’il faut pour inclure de la musique à vos applications.

Listview avec un watermark

Il existe quelques dossiers spéciaux dans Windows XP qui possèdent un watermark, aussi appelé filigrane en français, en bas à droite. Voici l’exemple du dossier Ma musique:

Listview with a watermark

Le but de cet article est de vous aider à faire la même chose dans un TListview sous C++Builder. Pour que l’effet soit réussi, je vous suggère d’utiliser un fichier de type PNG ou icône car ces deux formats permettent l’utilisation du canal alpha. Si vous décidez d’utiliser le format PNG, je vous conseille de jeter un coup d’œil à mon article qui explique comment charger une image dans les ressources. Parce qu’il est plus simple de faire un code qui charge l’icône de l’application, c’est ce format que nous utiliserons.

La première étape est bien sûr de créer un nouveau projet auquel on ajoute un contrôle TListView. Vous pouvez y ajouter quelques TListColumns et TListItems pour faire un peu plus réel.

Étant donné que j’ai décidé d’utiliser un auto_ptr, il faut inclure l’entête suivant dans votre fichier cpp.

#include <memory>

Dans le constructeur de la Form, ajoutez le code suivant:

static std::auto_ptr<Graphics::TBitmap> Bitmap(new Graphics::TBitmap);
Bitmap->Canvas->Brush->Color = ListView1->Color;
Bitmap->SetSize(32, 32); // Le casque romain est seulement en 32x32 pixels
Bitmap->Canvas->Draw(0, 0, Application->Icon);
 
LVBKIMAGE lv;
lv.ulFlags = LVBKIF_TYPE_WATERMARK;
lv.hbm = Bitmap->Handle;
ListView_SetBkImage(ListView1->Handle, &lv);
ListView_SetTextBkColor(ListView1->Handle, CLR_NONE);

La première ligne sert à créer une image de type Bitmap. Ce format est nécessaire car la fonction qui va être utilisée plus tard nécessite comme paramètre un HBITMAP. Le seconde ligne va servir à définir la couleur de fond de l’image. Si on effectue cette tâche avant d’établir la grandeur de l’image, l’image sera alors automatiquement de cette couleur. Cela évite d’avoir à dessiner un rectangle de la grandeur du Bitmap par la suite. À la troisième ligne, on utilise une grandeur de 32 par 32 pixels, car c’est la grandeur de l’icône de l’application. L’image par défaut dans C++Builder 2010 est un casque romain. La ligne d’après est utilisée pour dessiner l’icône sur le Bitmap. Maintenant, l’image est prête à être utilisée.

Les lignes 6 à 8 servent à remplir une structure de type LVBKIMAGE qui sera utilisée par la fonction ListView_SetBkImage à la ligne 9.

On pourrait penser que l’on a terminé, eh bien non. Il reste un petit tour de passe nécessaire pour voir notre image dans la listview.

Dans votre fichier d’en-tête, ajoutez les déclarations suivantes dans la section private:

void __fastcall ListViewWndProc(Messages::TMessage &Message);
Classes::TWndMethod OldListViewProc;

Ensuite, on retourne dans le constructeur de la Form pour ajouter ce code qui sert à rediriger les appels de Windows à la listview vers la méthode ListViewWndProc:

OldListViewProc = ListView1->WindowProc;
ListView1->WindowProc = ListViewWndProc;

Il faut par la suite ajouter cette méthode:

void __fastcall TForm1::ListViewWndProc(Messages::TMessage &Message)
{
    if(Message.Msg == WM_ERASEBKGND)
    {
        ListView1->DefaultHandler(&Message);
        return;
    }
    OldListViewProc(Message);
}

Si ce code n’est pas utilisé, l’événement WMEraseBkgnd de la classe TWinControl, l’ancêtre de TListView, sera appelé. Cette méthode empêche le message WM_ERASEBKGND de se rendre à la procédure par défaut. C’est pourquoi la méthode DefaultHandler de la listview est appelée et que l’on interdit un appel à OldListViewProc si on reçoit ce message.

À présent, vous avez tout le code nécessaire pour faire votre propre watermark dans un contrôle de type listview.

La propriété TextHint d’un TEdit

Depuis C++Builder 2009, le contrôle TEdit possède une nouvelle propriété qui se nomme TextHint. Étant curieux de nature, je décide de l’essayer. Première constatation: il s’agit d’une zone de texte. Donc, je me dis que si je tape quelque chose à l’intérieur et que je compile le code, mon message devrait apparaître quelque part. C’est ce que je m’empresse de faire. Malheureusement, j’ai beau essayer de faire plusieurs actions sur mon contrôle, je ne vois pas mon texte. Alors, je me dis que j’ai sans doute mal compris à quoi peut bien servir cette propriété. Ainsi, je décide d’aller faire un tour dans l’aide. Sur la page de la propriété du TEdit, il n’y a aucune information. Alors, je vais donc sur la page de son parent: le classe TCustomEdit. Voici la description que j’y trouve:

Un conseil ou un message à afficher quand la propriété Text est vide.

Utilisez TextHint pour informer l’utilisateur du type d’entrée attendu dans le champ texte. Les thèmes d’exécution doivent être activés.

Donc, si je me fie à cette information, il devrait y avoir un texte dans mon contrôle car il est vide et les thèmes sont activés sur mon PC. Je décide d’employer les grands moyens: j’ouvre le fichier StdCtrls.pas et je regarde le code de la méthode SetTextHint. La fonction DoSetTextHint est appelée alors je me dirige vers ce code pour me rendre compte que le message EM_SETCUEBANNER est envoyé à Windows. Sur la page MSDN du message, je trouve un texte qui explique que ça ne fonctionne pas si sous Windows XP les langues d’Extrême-Orient sont installées. Bien sûr, sur mon ordinateur, j’ai coché la petite case car j’ai besoin de ces caractères pour tester mes applications multi-langues. Pour ceux qui se demandent où est cette configuration, elle est dans les Options régionales et linguistiques du Panneau de configuration sous l’onglet Langues.

Voici le résultat lorsque je teste sur un système qui remplit toutes les exigences, même celles non documentées dans l’aide officielle:

La propriété TextHint d'un TEdit

Le problème semble être résolu depuis Windows Vista.

J’espère que vous lirez cet article avant de perdre du temps à essayer de comprendre pourquoi cela ne fonctionne pas sur votre ordinateur, ou encore pire sur celui d’un client :).

Programmer’s Notepad 2.1.3

Depuis le 11 mars, la version 2.1.3 de Programmer’s Notepad est disponible en téléchargement. Je désire vous en informer pour faire suite à mon article sur ce logiciel.

Programmer’s Notepad version 2.1.3

Si vous ne voulez pas perdre les configurations effectuées pour démarrer vos outils préférés, vous allez devoir copier le fichier UserTools.xml qui se trouve dans le dossier settings avant de supprimer l’ancienne version du logiciel. Ensuite, faites l’installation de la nouvelle version et écrasez le fichier existant avec votre copie de sauvegarde.

Si vous avez un peu de temps devant vous et que vous possédez une bonne connaissance de la langue de Molière, il vous est alors possible de participer à la traduction du logiciel en français. Présentement, les seules langues disponibles sont l’anglais, le chinois et le hongrois. Le format PO est utilisé pour la traduction. Plusieurs éditeurs le reconnaissent dont Poedit qui est multiplate-forme. Pour plus de détails, il existe une page Web qui vous explique comment faire.