Bonsoir à tous.
J'avais rien à faire ce soir, donc je vais vous faire profiter de ce que j'ai appris récemment.
Tout d'abord, cela fait un moment que j'avais découvert qu'on pouvait écrire sur des bitmaps RGSS depuis une dll en C. J'avais trouvé des bouts de codes C ici et là (venant de
poccil), et d'autres que l'on m'a passés mais dont je ne connais pas l'auteur), mais c'était pas commenté et je ne comprenais rien. J'ai laissé tombé ça pendant quelques mois.
Mais en bossant récemment toute une journée j'ai réussi à comprendre tout ça et à pondre un effet d'ondulation d'image et un effet d'ondulation d'eau (une seule couleur de remplissage + ondulation irrégulière : effet fluide).
Et je vais vous apprendre comment on fait. Et je tiens à prévenir que
ce tutoriel nécessite des bases en C.Déjà créez un nouveau projet sous votre IDE favori (pour moi CodeBlocks) et créez un projet dll (et choisissez votre compileur : j'utilise GNU GCC Compiler et ça marche).
Hop, vous avez un template, vous le détruisez, et vous allez mettre les include et quelques typedef d'objets ruby :
#include <stdio.h>
#include <windows.h>
#include <math.h>
#define API __declspec(dllexport)
typedef unsigned long VALUE; // Pour presque tout ce qui vient de ruby
typedef struct {
unsigned long flags;
VALUE klass;
} RBasic;
// Arrays ruby
typedef struct {
RBasic basic;
long len;
union {
long capa;
VALUE shared;
} aux;
VALUE *ptr;
} RArray;
// Couleur RGSS
typedef struct{
DWORD flags;
DWORD klass;
void (*dmark)(void*);
void (*dfree)(void*);
double *data;
} RGSSCOLOR;
typedef struct{
DWORD unk1;
DWORD unk2;
BITMAPINFOHEADER *infoheader;
RGBQUAD *firstRow;
RGBQUAD *lastRow;
} RGSSBMINFO;
typedef struct{
DWORD unk1;
DWORD unk2;
RGSSBMINFO *bminfo;
} BITMAPSTRUCT;
typedef struct{
DWORD flags;
DWORD klass;
void (*dmark)(void*);
void (*dfree)(void*);
BITMAPSTRUCT *bm;
} RGSSBITMAP;
// Strings
typedef struct {
RBasic basic;
long len;
char *ptr;
union {
long capa;
VALUE shared;
} aux;
} RString;
Voilà, ça c'est le point de départ.
Alors, nous allons créer une fonction, par exemple, une fonction qui remplit le Bitmap.
On commence par le début (logique) :
// Ca c'est pour exporter la fonction.
// Retourner un long n'est pas obligatoire, mais c'est pas mal de retourner tel nombre pour telle erreur par exemple
LONG API BitmapFillColorTest(long bitmap_id)
{
// On récupère un pointeur vers le bitmap.
// bitmap_id c'est l'id d'un objet Bitmap. (bmp.__id__)
// En shiftant d'un bit, on a l'adresse du pointeur vers cet objet. Et c'est comme ça qu'on a le pointeur.
RGSSBMINFO *bitmap = ((RGSSBITMAP*)(bitmap_id<<1))->bm->bminfo;
// On récupère la première ligne du bitmap
LPBYTE row = bitmap->firstRow;
// On récupère des infos
DWORD width = bitmap->infoheader->biWidth;
DWORD height = bitmap->infoheader->biHeight;
DWORD rowsize = width*4;
}
La on a récupéré les données nécessaires pour aller plus loin.
Maintenant j'explique le mécanisme pour se balader dans le bitmap.
LPBYTE row est en fait ce qui va nous permettre de ce déplacer dans notre bitmap, qui est en fait une matrice en une dimension d'une taille de 4*largeur*hauteur octets (4 octets par pixel).
row += 4;
Va déplacer d'un pixel vers la droite
row -= rowsize;
Va déplacer d'un pixel vers le bas.
Et pour changer la couleur du pixel :
row[0] = 0; // bleu
row[1] = 0; // vert
row[2] = 0; // rouge
row[3] = 0; // opacité
Il va donc falloir boucler pour remplir le bitmap. Ici on va faire simple, on va le remplir en blanc (255, 255, 255, 255).
// Ca c'est pour exporter la fonction.
// Retourner un long n'est pas obligatoire, mais c'est pas mal de retourner tel nombre pour telle erreur par exemple
LONG API BitmapFillColorTest(long bitmap_id)
{
// On récupère un pointeur vers le bitmap.
// bitmap_id c'est l'id d'un objet Bitmap. (bmp.__id__)
// En shiftant d'un bit, on a l'adresse du pointeur vers cet objet. Et c'est comme ça qu'on a le pointeur.
RGSSBMINFO *bitmap = ((RGSSBITMAP*)(bitmap_id<<1))->bm->bminfo;
// On récupère la première ligne du bitmap
LPBYTE row = bitmap->firstRow;
// On récupère des infos
DWORD width = bitmap->infoheader->biWidth;
DWORD height = bitmap->infoheader->biHeight;
DWORD rowsize = width*4;
LONG x, y;
x = 0;
y = 0;
while(y<height)
{
row = bitmap->firstRow; // On reprend le premier pixel en haut à gauche
row -= y*rowsize; // On se déplace de y vers le bs
x = 0 // On met x à 0
while(x<width)
{
row[0] = 255;
row[1] = 255;
row[2] = 255;
row[3] = 255;
row += 4; // on se déplace d'un pixel
x++;
}
y++;
}
}
Ca c'était simple.
Mais on peut faire plus compliqué, en fait c'est même l'intérêt.
Maintenant, pour l'appeler depuis ruby. Il faut créer un module dans lequel on regroupera toutes les fonctions venant de la Dll, on l'appellera CLib.
On va utiliser Win32API pour l'appeler.
module CLib
extend self
# api = Win32API.new("nom dll", "nom fonction", "types arguments", "type retour")
@@test = Win32API.new("nom", "BitmapFillColorTest", "l", "l")
def fill_white(bmp)
@@test.call(bmp.__id__)
end
end
Précision au niveau des types d'arguments pour l'appel de Win32API :
"l" => long (inclut les floats me semble-t-il)
"i" => integer
"s" => string
"p" => pointeur
Voilà, amusez-vous bien !
RPG-man
PS : le sujet porte apparemment à confusion.
Le père de la technique est poccil, je ne fais que mettre au propre des explications dessus, n'en ayant trouvé nulle part et ayant galéré pendant longtemps pour m'en sortir.