PDA

Voir la version complète : [PSP][Tutorial] OSlib - Jour 4 : Oohh la belle image


Yodajr
10/04/2006, 02h28
Jour 4 : Affichage et manipulation des images

Vous connaissez par coeur comment utiliser les boutons de la PSP ?
Excellent, nous allons maintenant apprendre à afficher des images, qui pourront servir de background et (ceux qui ont l'habitude de la prog sur GBA ou DS seront surpris) de sprites !
Effectivement, sur PSP, pas de systeme de bg/sprites gérés en hard, donc aucune limitation en vue ;)
Par exemple, dans ce tuto nous allons afficher un background qui est une image de 480x272 et un sprite qui et lui aussi une image, mais de 17x31 (les mêmes que tout à l'heure sont de nouveau étonnés ^^ )


1) Les images
Pour cet exemple, nous avons besoin de 2 images.
Elles devront etre au format PNG car c'est pour l'instant le seul format exploitable par oslib.

Pour celle qui servira de fond, je vous conseille une image de 480x272, ce qui permettra de bien remplir l'écran car il s'agit de la résolution de la PSP ;)

Pour celle qui servira de sprite, c'est un peu plus complexe :
Utilisez une plus petite image, mais bon, ca c'est accessoire, le plus important est de choisir la couleur qui sera definie comme transparente.
Par exemple, voici l'image qui constitue le sprite de ce tuto : http://hothmoon.free.fr/psp/dev/jour04_img1.png
Comme vous pouvez le constater, les parties qui ne devront pas s'afficher dans le jeu sont colorés de rose (codé 255.0.255) car c'est une couleur relativement rare et que je n'utiliserai surement jamais dans mes sprites :P
Mais vous pouvez évidement choisir la couleur que vous voulez, depuis que vous ne l'utilisez pas dans le sprite lui même (retenez juste son codage, il servira plus tard).

Ces images, tout comme toute future ressource des prochains tutos, sont à copier dans le répertoire du jeu sur la PSP (le dossier sans les %)

Vous pouvez aussi également utiliser celles du tuto (dans l'archive en bas de page)


2) Le code

//La librairie principale OSLib
#include <oslib/oslib.h>

//les callbacks
PSP_MODULE_INFO("OSLib Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);

//definition des pointeurs vers nos images
OSL_IMAGE *fond, *chrono;

int main()
{
//Initialisation de la librairie
oslInit(0);

//Initialisation du mode graphique
oslInitGfx(OSL_PF_8888, 1);

//definition de la transparence
oslSetTransparentColor(RGB(255,0,255));

//chargement de nos images (oui, le "loading" :p)
fond = oslLoadImageFile("fond_zora.png", OSL_IN_RAM, OSL_PF_5551);
chrono = oslLoadImageFile("chrono.png", OSL_IN_RAM, OSL_PF_5551);

//plus de transparence
oslDisableTransparentColor();

//vérification
if (!fond || !chrono)
oslDebug("Impossible de charger un ou plusieurs fichiers. Verifiez que tous les fichiers sont bien copiés dans le répertoire du jeu.");

//boucle principale
while (!osl_quit)
{
//Permet de dessiner
oslStartDrawing();

//Lit les touches
oslReadKeys();

//deplace le sprite de chrono
if (osl_keys->held.down) chrono->y += 2;
if (osl_keys->held.up) chrono->y -= 2;
if (osl_keys->held.left) chrono->x -= 2;
if (osl_keys->held.right) chrono->x += 2;

//dessine nos images
oslDrawImage(fond);
oslDrawImage(chrono);

//Fin du dessin
oslEndDrawing();

//Synchronise l'écran
oslSyncFrame();
}

//on quitte l'application
oslEndGfx();
oslQuit();
return 0;
}


3) Explications

OSL_IMAGE *fond, *chrono;
On definit les pointeurs vers nos images. Creez en un pour chaque image et bien sûr au tout début :)

oslSetTransparentColor(RGB(255,0,255));
C'est ici que je dit au programme quelle couleur il ne doit pas afficher (mon beau rose en l'occurence :p ).
Doit être appelée juste avant le chargement des images.

fond = oslLoadImageFile("fond_zora.png", OSL_IN_RAM, OSL_PF_5551);
Je charge l'image avec son nom exact (attention à la casse, elle joue).
Le paramètre suivant indique qu'elle est chargée en RAM et non en VRAM (voir la doc pour plus d'explication).
Et le dernier renseigne sur le pixel format choisi pour afficher l'image (ici 16bits par pixels, conseillé pour les sprites simples)
Attention : on ne peut pas charger des images de résolution supérieure à 512x512. Pour afficher de plus grands trucs (niveaux,...) il faudra se tourner vers les maps, mais nous verrons ca plus tard ;)

oslDisableTransparentColor();
On stoppe l'effet de transparence au cas ou notre couleur serais affichée par un dégradé par exemple.

if (!fond || !chrono) oslDebug("Impossible...
Ici on teste si les fichiers ont bien été chargés, et dans le cas contraire affiche une fenetre à l'écran proposant au joueur de quitter ou de continuer.
Ne négligez pas cette étape dans vos programmes, il arrive souvent qu'on oublie de copier certains fichiers sur la MS et le plantage est alors assuré :rolleyes:

chrono- >y += 2;
Chaque image est une structure qui contient toutes les informations sur l'image. Il y a tout plein pour parametrer l'image dans tous les sens (rotation, taille,...) mais nous les laissons pour les tutos consacrés aux effets spéciaux (ou alors consultez la doc comme toujours ;))
Donc ici nous n'abordons que la plus utile pour moi : les coordonnées : x et y.
Vous pouvez donc placer votre image ou vous voulez sur l'écran, (en sachant que le point haut gauche est 0,0 et le point bas droite est à 479,271), en renseignant les 2 coordonnées image- >x et image- >y

oslDrawImage(fond);
Affiche l'image. Remarquez l'ordre qui n'est pas un hasard : du fond de l'écran vers le premier plan : je dessine d'abord le fond puis mon perso.
Vous pouvez utiliser aussi oslDrawImageXY(image,x,y) pour dessiner votre image à un endroit précis sans passer par le renseignement des valeurs image->x et image->y, pratique pour les icones fixes à l'écran (vies,...)


4) Screen et eboot

Voila, vous devez obtenir un truc comme ça (il fout quoi là lui ? :p) :

http://hothmoon.free.fr/psp/dev/jour04_screen.png

Téléchargez l'eboot compilé pour 1.5 ici (http://hothmoon.free.fr/psp/dev/jour04_eboot.zip)

DJP
10/04/2006, 02h31
"Merde, je me suis trompé de jeu !"

KCV
22/05/2006, 23h10
Sympas les touches d'humour :D
Et didactique en plus, rien a redire pour le moment, du moins, pas sur les jours 2-3-4.
Le jour 1, c'est autre chose mais on en reparleras plus tard ;)

Cordialement,
Kcv

Cpasjuste
22/08/2006, 18h04
Salut Yodajr :)
Tout d'abord merci pour ces petits exemples, cette Librairie m'est bien utile !
Je "travail" actuellement sur un petit Shell pour la psp, et je rencontre un petit soucis concernant la gestion des images.

Voila mon prob :

Lorsque dans mon Shell je parcours ms0:, j'aimerais charger une image en entrant dans un repertoire que si elle exsite.

Je m'explique, je souhaite permettre aux utilisateur de placer une image "icon.png" dans n'importe quel répertoire et qui ce chargera lorsqu'il entrent dedans.
Ma 1ere terchnique a été d'essayer de load l'image a chaque repertoire mais comme elle n'est pas toujours la (l'image "icon.png) , la psp plante. Je pensais que si l'image n'existait pas la psp n'essaierait pas de la charger ...

J'ai donc essayer un truc du genre :


fd_data = sceIoOpen(icon_path, PSP_O_RDONLY, 0777);
if (fd_data) {
sceIoClose(fd_data);
icon = oslLoadImageFile(icon_path, OSL_IN_RAM, OSL_PF_5551);
if (!icon) printf("No icon to load");
icon->x = 240; //Place the icon
icon->y = 136;
oslDrawImage(icon);
} else {
sceIoClose(fd_data);
}


Malheureusement la psp ne retourne pas d'erreur si l'image n'existe pas ...

Aurais tu une idée ? (Surement que oui :) )

Désolé pour les fautes et pour le long roman ....
A +

Yodajr
22/08/2006, 18h31
Oui je crois...
En fait ton if ne sert à rien, tu teste si l'image a été chargée, mais après tu fait comme si elle a été chargée :
icon->x = 240;
icon->y = 136;
oslDrawImage(icon);
Ce qui n'est pas bon ;)
Si le fichier n'a pas été chargé, il ne faut rien faire avec l'image... du tout... ^^

Cpasjuste
22/08/2006, 18h46
Ok merci, ca fonctionne maintenant, j'ai vraiement été un boulet sur ce coup la :)

voici la bon code :

icon = oslLoadImageFile(icon_path, OSL_IN_RAM, OSL_PF_5551);
if (!icon) {
printf("No icon to load");
} else {
icon->x = 240;
icon->y = 136;
oslDrawImage(icon);
}


...

Sinon autre question, est-il possible d'écrir sur une image avec la fonction oslPrintf_xy ?

Yodajr
22/08/2006, 18h47
Bien sur, tu dessine l'image, puis tu écris :)

Cpasjuste
22/08/2006, 19h13
Hehe oui c'est bien ce que j'etais en train de me dire, mais cela me semblait trop facile ... Avec cette Lib je vais devoir aretter de me trutirer les méninges pour rien :)

Vraiement exellent ... j'ai hate de montrer mon shell, un petit shell tout plein d'effet et completement skinable.
A bientot et merci encore.

Cpasjuste
23/08/2006, 09h37
Re-bonjours !

Je penses que je me suis mal exprimé hier, et je ne peux pas tester de codes avant ce soir, donc je vais poser la question au cas ou car ca me turlupine :)

Si j'écris sur une image avec osprint, puis que je transforme celle ci genre une petite rotation, mon texte subira t-il les transformations également ?
Si ce n'est pas le cas, y a t-il une fonction de ce genre dans OSLib ou devrais-je trouver une autre méthode?

Autre petite question, est-il possible de libérer toute la mémoire utilisé par OSLib avec une simple fonction (libpng ne laisse que 1Mb de mémoire libre) dans le but d'executer un nouvel eboot sans utiliser la fonction sceKernelLoadExec() mais plutot load/start module?

J'espere que ces questions aideront d'autres débutant en C comme moi :)
A plush.

Yodajr
23/08/2006, 09h57
Si j'écris sur une image avec osprint, puis que je transforme celle ci genre une petite rotation, mon texte subira t-il les transformations également ?
Non, en tout cas pas aussi simplement :p
Si tu fait ca, ton image va se déformer, mais ton texte va rester tel quel...

Y'a une solution, j'en parlais avec Brunni l'autre soir, mais je n'ai pas encore essayé : si j'ai bien compris, l'idée c'est de copier le contenu d'un des buffer vers une autre image, et cette image tu pourra en faire ce que tu veux B)

Je cite Brunni :

OSL_IMAGE *img = OSL_DEFAULT_BUFFER, *copy;

oslLockImage(img);
copy = oslCreateImageCopy(img, OSL_IN_RAM);
oslUnlockImage(img);

ou encore

oslSetDrawBuffer(tonImage); //tonImage doit etre en VRAM

[ton dessin]

oslSyncDrawing(); //Lent, mais obligatoire avant de pouvoir manipuler l'image

oslSetDrawBuffer(OSL_DEFAULT_BUFFER);

N'ayant pas essayé, je ne peux t'en dire plus pour l'instant...

Pour ta deuxième question, je ne sais pas, pose la directement au chef sur le topic OSLib ;) (projets PC)

Cpasjuste
23/08/2006, 10h08
Merci beaucoup Yodajr je vais tester tout ça ce soir, il me tarde :D
Les idées fusent de tout bord depuis que j'ai testé OSLib ^^

Poison
06/04/2007, 17h49
Bravo encore pour ton tuto, cependant si je peut me permettre, tu à fait une toute petite erreur, lorsque tu dit :

Vous pouvez utiliser aussi oslDrawImageXY(x,y,image) pour dessiner votre image à un endroit précis sans passer par le renseignement

En fait c'est plutot oslDrawImageXY(image,x,y) et non oslDrawImageXY(x,y,image) :p , je précise cela, parce que lorsque l'on est débutant on se demande pourquoi sa marche pas v_v :p .

@++ :D

Yodajr
06/04/2007, 19h08
Tout a fait, bien vu, j'ai du mélanger avec oslPrintf ;)

Poison
14/04/2007, 16h27
Juste une petite question, comment faire pour qu'une variable x prenne la valeur d'une variable image ?

Exemple :

//La librairie principale OSLib
#include <oslib/oslib.h>

//les callbacks
PSP_MODULE_INFO("OSLib Sample", 0, 1, 1);
PSP_MAIN_THREAD_ATTR(THREAD_ATTR_USER | THREAD_ATTR_VFPU);

//definition des pointeurs vers nos images
OSL_IMAGE *mario_img;
OSL_IMAGE *clad_img;
OSL_IMAGE *personnage_choisi;



int main()
{
//Initialisation de la librairie
oslInit(0);

//Initialisation du mode graphique
oslInitGfx(OSL_PF_8888, 1);

//definition de la transparence
oslSetTransparentColor(RGB(255,0,255));

//On charge les images
mario_img = oslLoadImageFile(".png", OSL_IN_RAM, OSL_PF_5551);
clad_img = oslLoadImageFile(".png", OSL_IN_RAM, OSL_PF_5551);

//plus de transparence
oslDisableTransparentColor();

//boucle principale
while (!osl_quit)
{
//Permet de dessiner
oslStartDrawing();

//Lit les touches
oslReadKeys();

//si on appuie sur BAS , alors le personnage choisi est mario
if (osl_keys->pressed.down)
{
personnage_choisi = &mario_img
}

//Si on appuie sur HAUT , alors le personnage choisi est clad
else if (osl_keys->pressed.up)
{
personnage_choisi = &clad_img
}

//On déssine le personnage choisi
oslDrawImage(personnage_choisi);

//Fin du dessin
oslEndDrawing();

//Synchronise l'écran
oslSyncFrame();
}

//on quitte l'application
oslEndGfx();
oslQuit();
return 0;
}

Ce n'est qu'un exemple, mais j'ai essayé cela mais on dirait qu'il ne prend pas en compte la variabel personange_choisi <_<

Merci d'avance :p

Yodajr
14/04/2007, 23h18
Essaye de virer les &, les images sont déja des pointeurs ;)
personnage_choisi = mario_img

Poison
15/04/2007, 13h21
Essaye de virer les &, les images sont déja des pointeurs ;)
personnage_choisi = mario_img


Merci Yodajr, en fait j'ai trouvé, j'ai fait comme ceci :

//si on appuie sur BAS , alors le personnage choisi est mario
if (osl_keys->pressed.down)
{
personnage_choisi = oslLoadImageFile("mario.png", OSL_IN_RAM, OSL_PF_5551);
}

//Si on appuie sur HAUT , alors le personnage choisi est clad
else if (osl_keys->pressed.up)
{
personnage_choisi = oslLoadImageFile("clad.png", OSL_IN_RAM, OSL_PF_5551);
}

Brunni
15/04/2007, 13h34
Houlà non! Quelle horreur, tu charges une image à chaque fois, c'est super lent et en plus tu bourres la RAM pour rien parce que tu n'effaces jamais les anciennes images!
(si tu essayes de le faire plusieurs centaines de fois tu verras que ton programme plantera, une fois que la RAM est pleine)

Yodajr
15/04/2007, 13h43
Par principe, évite les oslLoad dans la boucle principale ;)

DJP
15/04/2007, 13h47
Par principe, évite les oslLoad dans la boucle principale ;)
Clair c'est a ce demander comment tu fais pour executer le code plus de 10 secondes....

Poison
15/04/2007, 13h49
lol, merci pour vos conseils ;)

EDIT : je viens de faire comme yodajr m'a dit sa marche bien, encore merci

Brunni
15/04/2007, 14h07
Si tu devais vraiment charger tes images dynamiquement (p.ex. tu n'as pas assez de mémoire pour toutes les avoir au même moment), il faudrait prendre soin de toujours effacer les images chargées avant d'en charger de nouvelles.


//NULL signifie que l'image n'existe pas: ne l'effaçons pas, ne l'affichons pas, etc. dans ce cas.
OSL_IMAGE *personnage_choisi = NULL;
[...]

//Avant de charger une nouvelle image, effaçons l'image actuelle
if (personnage_choisi != NULL) {
oslDeleteImage(personnage_choisi);
//L'image a été effacée, elle n'existe plus, donc NULL
personnage_choisi = NULL;
}

//si on appuie sur BAS , alors le personnage choisi est mario
if (osl_keys->pressed.down)
{
personnage_choisi = oslLoadImageFile("mario.png", OSL_IN_RAM, OSL_PF_5551);
}

//Si on appuie sur HAUT , alors le personnage choisi est clad
else if (osl_keys->pressed.up)
{
personnage_choisi = oslLoadImageFile("clad.png", OSL_IN_RAM, OSL_PF_5551);
}

[...]
//Equivalent à if (personnage_choisi != NULL) mais plus court à taper
if (personnage_choisi)
oslDrawImage(personnage_choisi);


Ca ne veut pas dire que ce code est bien (il est très très lent), c'est juste un exemple ;) (dans ton cas utilise le code de yodajr il est bien meilleur)

Haseo
31/05/2007, 18h01
C'est vraiment génial tout ces petits tuto^^

archilolo
18/09/2007, 22h42
Pas mal ce p'tit tuto ; sauf que moi, lorsque je laisse la fonction "oslDisableTransparentColor();", le rose (255 0 255) de mon image demeure ; et que lorsque je le retire (le oslDisableTransparentColor();), le rose se fait la malle. :hmm:

Paraît que c'est pas normal. =_=