Username:

Password:


collapse
Who's Online
  • Dot Invités: 11
  • Dot Caché: 0
  • Dot Membres: 0

There aren't any users online.

* Shoutbox
Refresh History
  • kriss: oui.. je dois faire des demandes pour que google refasse des analyse du site afin de "voir" s'il est tjr malveillant
    Dcembre 08, 2011, 22:47:27
  • Leopold: Cool! Mais Firefox me le déclare toujours malveillant...
    Dcembre 08, 2011, 22:30:32
  • kriss: réouverture du forum !
    Dcembre 06, 2011, 00:48:58
  • Fabien: Coucou facto!! Trop bon de repasser ici :)
    Septembre 25, 2011, 18:06:22
  • Krän: aye ! ^^
    Aot 21, 2011, 23:43:29
  • RPG-Man: lol manu
    Aot 20, 2011, 00:24:00
  • RPG-Man: JE SUIS REVENU MOUHAHA
    Aot 20, 2011, 00:22:26
  • Manucyan: Ca dit quoi un ivrogne dans le noir ? "hé... t'es qui là ?" xd
    Mai 07, 2011, 18:11:20
  • Krän: Il est 2h46 et tout est calme ! :)
    Mai 05, 2011, 01:47:01
  • Manucyan: La tronche du bestiaire ? Un pokédex ! xd
    Avril 30, 2011, 21:18:09
  • Manucyan: désolé je pensais que tout le monde connaissait le phénomène du rickroll (cf wikipédia)
    Avril 30, 2011, 14:08:48
  • kriss: ca merite un ban pour ce lien oO
    Avril 30, 2011, 12:29:51
  • RPG-Man: Sale vilain
    Avril 30, 2011, 11:26:31
  • Krän: Never gonna give u up, never gonna let u dooowwwn ...
    Avril 28, 2011, 20:29:20
  • kriss: en effet mais ce n'est pas normal.. il y a un bug que je dois trouver ^^
    Avril 25, 2011, 10:30:16
  • Leopold: Pour la mise à jour, on peut cliquer sur "Refresh" (deux flèches vertes) ou sur "History" (pendule).
    Avril 22, 2011, 21:31:57
  • RPG-Man: Manque plus qu'elle se mette à jour toute seule quand on ajoute un message et c'est le must !
    Avril 21, 2011, 20:29:39
  • RPG-Man: le shootbox CAY LE BIEN
    Avril 21, 2011, 20:29:14
  • kriss: on appel ca une shootbox :p
    Avril 18, 2011, 16:47:13
  • Manucyan: hé mais c'est marrant !
    Avril 17, 2011, 18:03:46

The Factory » ATELIER » PROGRAMMATION » Cours Ruby et outils » Ecrire sur des Bitmaps RGSS depuis une dll en C
Pages: [1] 2
« sujet précédent | | sujet suivant »
Imprimer
Auteur Fil de discussion: Ecrire sur des Bitmaps RGSS depuis une dll en C  (Lu 979 fois)
RPG-Man
Rubyste Fou Furieux
Factorien
Machiniste
*
Hors ligne Hors ligne

Messages: 320


Voir le profil
Ecrire sur des Bitmaps RGSS depuis une dll en C
« le: Aot 22, 2010, 23:36:02 »

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 :

Code:
#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) :
Code:
// 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).

Code:
row += 4;
Va déplacer d'un pixel vers la droite

Code:
row -= rowsize;
Va déplacer d'un pixel vers le bas.

Et pour changer la couleur du pixel :
Code:
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).

Code:
// 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.
Code:
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.
« Dernière édition: Aot 23, 2010, 21:06:14 par RPG-Man » Journalisée

L'Usine en Folie arrive bientôt sur vos moniteurs...
Zeus81
Forgeron
*
Hors ligne Hors ligne

Messages: 38


Ero-Maker

Zeus81@live.fr
Voir le profil Courriel
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #1 le: Aot 23, 2010, 00:16:59 »

C'est sympa. ;)
Journalisée
nuki
Sieur =D
Gardien
Forgeron
*
Hors ligne Hors ligne

Messages: 40


xavier-vdw@hotmail.fr
Voir le profil Courriel
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #2 le: Aot 23, 2010, 06:57:02 »

Superbe l'ami !
Journalisée
kriss
Architecte
Savant
*
Hors ligne Hors ligne

Messages: 4447


Don Quichotte de l'orthographe

krisss666@msn.com
Voir le profil Courriel
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #3 le: Aot 23, 2010, 07:23:41 »

maintenant je veux voir des videos de ceux qui ont compris comment ca fonctionne  :ahah
Journalisée

La plus vieille et la plus forte des émotions humaines est la peur, et la plus vieille et la plus forte peur est celle de l'inconnue
- H.P LOVECRAFT -
Projet en cours: MONOLITHE
http://rpgmakerxp-factory.net/forum/index.php?topic=10561.0
RPG-Man
Rubyste Fou Furieux
Factorien
Machiniste
*
Hors ligne Hors ligne

Messages: 320


Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #4 le: Aot 23, 2010, 10:58:29 »

Merci :)

Par contre vous constaterez que c'est beaucoup plus chiant de coder un algo de transormation de bitmap en C qu'en ruby avec RGSS.
Il faut à chaque fois connaître la position du pointeur, et ça plante sans message d'erreur (sauf le fameux "Game.exe à rencontré un problème et doit fermer") si on sort ne serais-ce que d'un pixel du bitmap.
Par contre, c'est vraiment beaucoup plus rapide !

Bonne chance xd
Journalisée

L'Usine en Folie arrive bientôt sur vos moniteurs...
Krän
Barbare Orgueilleux
Gardien
Chercheur
*
Hors ligne Hors ligne

Messages: 773


gilles_roudiere@hotmail.com
Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #5 le: Aot 23, 2010, 15:13:23 »

Génial ! 

J'avais eu quelques bouts de codes que King utilisait pour son moteur 3D. Je m'étais un peu penché sur le sujet et je crois que j'avais compris à peu près ça.

C'est vraiment bien d'avoir mit ça au propre.
Journalisée
RPG-Man
Rubyste Fou Furieux
Factorien
Machiniste
*
Hors ligne Hors ligne

Messages: 320


Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #6 le: Aot 23, 2010, 21:12:58 »

Code:
/*-------------------------------------------------------------------------------------
// RPG-man
-------------------------------------------------------------------------------------*/
LONG API BitmapOndulation(LONG src_object, LONG object, LONG vertical,
LONG amplitude, LONG puls, LONG frame){
    // On obtient nos bitmaps
    // SRC = original
    // DEST = self
    RGSSBMINFO *src = ((RGSSBITMAP*)(src_object<<1))->bm->bminfo;
    RGSSBMINFO *dest = ((RGSSBITMAP*)(object<<1))->bm->bminfo;
    long x, y;
    DWORD src_rowsize;
    DWORD dest_rowsize;
    DWORD src_width, src_height, dest_width, dest_height;
    LONG top, right, bottom, left;
    LPBYTE src_row, dest_row;
    if(!src || !dest) return 0;
    //if(dest_width != src_width+(long)amplitude*2) return 0;
    src_width = src->infoheader->biWidth;
    src_height = src->infoheader->biHeight;

    dest_width = dest->infoheader->biWidth;
    dest_height = dest->infoheader->biHeight;

    /*if(vertical == 1)
    {
        if(dest_width < src_width+(long)amplitude*2) return 0;
    }else{
        if(dest_height < src_height+(long)amplitude*2) return 0;
    }*/
    src_rowsize = src_width*4;
    dest_rowsize = dest_width*4;

    src_row = src->firstRow;
    dest_row = dest->firstRow;

    y = 0;
    x = 0;

    // Horizontal ; demande une marge de hauteur
    if(vertical == 0){
        for(x=0;x<src_width;x++)
        {
            src_row = src->firstRow;
            src_row += x*4; //y*src_rowsize;

            dest_row = dest->firstRow;
            dest_row += x*4; //y*dest_rowsize;

            //dest_row += (long)(amplitude*4); // on l'avance de l'amplitude, pour mieux le reculer après :p
            dest_row -= (long)((long)(amplitude+((double)amplitude)*cos((frame-x)/(double)puls)))*dest_rowsize;//(long)(((amplitude*sin((frame-x)/(float)(puls*step)))));
            for(y=0;y<=src_height;y++)
            {
                if(y < src_height)
                {
                    dest_row[0] = src_row[0];
                    dest_row[1] = src_row[1];
                    dest_row[2] = src_row[2];
                    dest_row[3] = src_row[3];
                }else{
                    dest_row[0] = 0;
                    dest_row[1] = 0;
                    dest_row[2] = 0;
                    dest_row[3] = 0;
                }
                src_row -= src_rowsize;
                dest_row -= dest_rowsize;
            }
        }
    }else{
        // BUG
        for(y=0;y<src_height;y++)
        {

            src_row = src->firstRow;
            src_row -= y*src_rowsize;

            dest_row = dest->firstRow;
            dest_row -= y*dest_rowsize;

            dest_row += (long)(amplitude+((double)amplitude)*cos((frame-y)/(double)puls))*4;
            for(x=0;x<=dest_width;x++) // <
            {
                if(x < src_width) // <=
                {
                    dest_row[0] = src_row[0];
                    dest_row[1] = src_row[1];
                    dest_row[2] = src_row[2];
                    dest_row[3] = src_row[3];
                }else{
                    dest_row[0] = 0;
                    dest_row[1] = 0;
                    dest_row[2] = 0;
                    dest_row[3] = 0;
                }
                src_row += 4;
                dest_row += 4;
            }
        }
    }
    return 1;
}
Voilà, je poste mon code pour l'ondulation, sur lequel j'ai travaillé toute une journée :p
Il est pas tout à fait parfait, il faut que le bitmap de destination soit à une taille adaptée, c'est à dire, que pour une ondulation verticale, la largeur du bitmap soit plus grande ou égale à la largeur du bitmap source + l'amplitude*2. De même pour l'ondulation horizontale, mais cette fois c'est sur la hauteur qu'on joue. Sinon, ça crashe.

Voilà comment on l'utilise :
Code:
  @@ondulate = Win32API.new("nom.dll", "BitmapOndulation", "llllll", "l")
  def ondulate_bitmap(src, dest, vertical=0, amplitude=20, puls=10, frame=0)
    @@ondulate.call(src.__id__, dest.__id__, vertical, amplitude, puls, frame)
  end

Bien utilisé il marche parfaitement.
Dans l'UeF il est utilisé pour les ondulations de l'arme Tesla par exemple.
« Dernière édition: Aot 23, 2010, 21:18:47 par RPG-Man » Journalisée

L'Usine en Folie arrive bientôt sur vos moniteurs...
Zeus81
Forgeron
*
Hors ligne Hors ligne

Messages: 38


Ero-Maker

Zeus81@live.fr
Voir le profil Courriel
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #7 le: Aot 24, 2010, 05:22:25 »

Ça serait pas plus pratique (et performant) de faire du précalculé ?
Journalisée
nuki
Sieur =D
Gardien
Forgeron
*
Hors ligne Hors ligne

Messages: 40


xavier-vdw@hotmail.fr
Voir le profil Courriel
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #8 le: Aot 24, 2010, 10:31:34 »

Plus pratique, je ne pense pas. Plus performant, surement maintenant, ce n'est plus comme l'ancienne ondulation, donc le gain serait palpable mais ... La question est de savoir si ça vaut la peine ou pas pour un gain si minim.
De plus, le précalculé pour l'arme Tesla, ce serait difficiel je pense.
Journalisée
RPG-Man
Rubyste Fou Furieux
Factorien
Machiniste
*
Hors ligne Hors ligne

Messages: 320


Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #9 le: Aot 24, 2010, 13:14:22 »

L'avantage de faire ça en C justement c'est que c'est ultra rapide.
J'ai beau faire onduler une image plus de 640x480, et faire tourner mon jeu, je monte pas au dessus de 20% de CPU utilisé (j'ai un 2.8Ghz).

Le pré-calculé, avec tout ce que j'ai à pré-calculer, ça boufferait beaucoup de mémoire, et y'aurait des temps de chargement plus longs. Là j'ai de bonnes performances avec ça, donc y'a aucune raison de pré-calculer.

D'autant plus que mon système de tiles sur l'UeF prend pas mal de mémoire (mais par contre ça bouffe beaucoup moins de CPU, j'ai pas de boucle à faire), donc le précalculé (même progressif) n'est pas une bonne option.

Journalisée

L'Usine en Folie arrive bientôt sur vos moniteurs...
berka
Prolétaire
*
Hors ligne Hors ligne

Messages: 6



Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #10 le: Aot 25, 2010, 22:47:17 »

Je me demande si on pourrait pas directement faire un binding ruby.

Parce que l'ennui avec l'utilisation de Win32API, c'est que cela reste toujours relativement long. Le temps que tu gagnes avec le c, tu en perds une bonne partie dans la classe Win32API. Parfois, en bas niveau, il faut meme "retoucher" les valeurs retournées ce qui ramène des boucles atroces.

Le but serait de compiler une dll en incluant ruby (ruby.h). On compile le tout et on utilise les fonctions à la manière de rgss:

Code:
#include "ruby.h"
VALUE cClasseRgss;

void Init_CRgss() {
  cClasseRgss = rb_define_class("Classe_Rgss", rb_cObject);
  rb_define_method(cClasseRgss, "test_rgss", fonction_c_pas_codee, 1);
}

int main(int argc, char *argv[]){
  Init_CRgss();
  return 1;
}
> Classe_Rgss#test_rgss(arg)

Ca, c'est utilisable en ruby pur, si on appelle un fichier de script ruby par le programme c. On pourra appeler la classe Classe_Rgss en ruby directement et utiliser sa méthode test_rgss en "natif".
Ce qu'il faudrait trouver c'est le moyen de faire le lien avec le Rgss de RM. En gros, charger la dll perso au démarrage ou avant. On pourrait le faire en Winapis, avec peut-etre Loadlibrary ?
Qu'en pensez vous ?

Bonne soirée,

Berka
Journalisée

.: Je code donc je suis :.
RPG-Man
Rubyste Fou Furieux
Factorien
Machiniste
*
Hors ligne Hors ligne

Messages: 320


Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #11 le: Aot 26, 2010, 09:18:59 »

Si j'ai bien compris, tu voudrais qu'on puisse utiliser la fonction C directement depuis Ruby, sans passer par Win32API ?

Donc il faudrait appeler cette dll au démarrage (avec Win32API) de façon à avoir les méthodes C "bindées" dans ruby dès le début, et à ne plus avoir de Win32API à utiliser (si j'ai bien compris).

Ca me semble une astuce intéressante :)
Journalisée

L'Usine en Folie arrive bientôt sur vos moniteurs...
berka
Prolétaire
*
Hors ligne Hors ligne

Messages: 6



Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #12 le: Aot 26, 2010, 14:39:27 »

Voilà, c'est ça.
Je peux pas tester actuellement (je le ferai dans 8 jours), mais ca me semble tout à fait réalisable:
Code:
Win32API.new("Xrgss.dll", "Xrgss_init", "", "v").call
et en c:
Code:
void Xrgss_init(){
 // Init de ruby
 // Construction de chacun des classes (cf. post précédent)
 // lancement de ruby
}

Ca me parait pas mal.

hs: tiens, je suis passé prolo ;)
Journalisée

.: Je code donc je suis :.
RPG-Man
Rubyste Fou Furieux
Factorien
Machiniste
*
Hors ligne Hors ligne

Messages: 320


Voir le profil
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #13 le: Aot 26, 2010, 17:58:10 »

Ok je vais voir pour faire ça.

Merci berka ;)
Journalisée

L'Usine en Folie arrive bientôt sur vos moniteurs...
kriss
Architecte
Savant
*
Hors ligne Hors ligne

Messages: 4447


Don Quichotte de l'orthographe

krisss666@msn.com
Voir le profil Courriel
Re : Ecrire sur des Bitmaps RGSS depuis une dll en C
« Répondre #14 le: Aot 28, 2010, 11:09:38 »

Tu progresse dans la hierarchie Berka xd
Journalisée

La plus vieille et la plus forte des émotions humaines est la peur, et la plus vieille et la plus forte peur est celle de l'inconnue
- H.P LOVECRAFT -
Projet en cours: MONOLITHE
http://rpgmakerxp-factory.net/forum/index.php?topic=10561.0
Pages: [1] 2
Imprimer
« sujet précédent | | sujet suivant »
Aller à:  


Powered by SMF 1.1.15 | SMF © 2006-2009, Simple Machines

EN Theme by Nati

Page générée en 0.097 secondes avec 26 requêtes.
Chargement...
SimplePortal 2.3.2 © 2008-2010, SimplePortal