Sur DS, on trouve des entités assez particulières. On a vu l'autre fois comment jour avec le HBL, mais ce n'est pas la seule chose que l'on peut faire...
Fenêtres : les basesLa DS, comme sa petite soeur, possède nativement un système de 'fenêtres', Windows... Celles-ci ont une utilisé bien déterminée : Elles permettent de montrer ou de cacher des choses qui sont à l'écran. Alors ok, dit comme ça, on n'a pas trop envie de jouer avec... Et pourtant on peut obtenir des effets bien sympathiques !
Voilà un effet de transition classique, simple, et efficace

Cet exemple est tiré de PAlib (PAlibExamples/Transitions/WindowFade).
PAlibJe poste rapidement le code pour PAlib, tout simple, mais pas vraiment intéressant :
(c):
for (i = 32; i >= 0; i--) {
PA_WindowFade(screen, fadetype, i);
PA_WaitForVBL(); // To slow down the fades, we wait a frame...
}
Voilà, c'est simple, on choisit le type de fade, l'écran, et on fait varier la valeur de 0 à 32... 0 pour visible, 32 pour invisible. Rien de bien sorcier.
LibndsJ'invite les PAlibiens à lire aussi cette partie, car elle illustre le fonctionnement sous-jacent et il faut l'avoir intégré pour comprendre les démos qui suivent

Libnds donne quelques définitions pour les registres des fenêtres. Il suffit de rajouter SUB_ pour activer le registre pour l'autre écran...
Pour la fenêtre 0 :WIN0_X0, WIN0_X1, WIN0_Y0, WIN0_Y1
Pour la fenêtre 1 :WIN1_X0, WIN1_X1, WIN1_Y0, WIN1_Y1
Mais aussi :WIN_IN et WIN_OUT
On a en fait plusieurs choses : 2 fenêtres différentes, rectangulaires, numérotées 0 et 1, que l'on change de façon basique en définissant 2 points (coin supérieur gauche et coin inférieur droit, définis par (X0, Y0) et (X1, Y1). Mais on a aussi des fenêtres dites objets, que l'on verra dans la dernière partie

Mais à quoi servent donc les registres WIN_IN et WIN_OUT ?
Ils permettent en fait de contrôler ce que l'on verra dans la fenêtre et en-dehors. Mon exemple n'est pas parfaitement représentatif, car il cache le fond, sans plus. Mais on peut en fait utilisé une fenêtre pour à la fois cacher et afficher : cacher un fond progressivement, tout en remplaçant l'affichage par un autre... Afin de simplifier les choses, j'utilise un jeu de définitions :
(c):
#define WIN_BG0 1
#define WIN_BG1 2
#define WIN_BG2 4
#define WIN_BG3 8
#define WIN_OBJ 16
#define WIN_SFX 32
Pour WIN_IN, les 8 premiers bits concernent la fenêtre 0, et les 8 suivants la fenêtre 1... (donc ajouter par exemple (WIN_BG0<<

, etc...).
Pour WIN_OUT, c'est un peu différent. On ne peut pas définir séparément pour les 2 fenêtre, on n'a que 8 bit pour les 2. Tant pis !
Mais à quoi servent donc les 8 derniers ?? Tout simplement à définir le WIN_IN pour les OBJWIN (fenêtres objets, que nous verrons après...)
Mais tout cela ne marchera que si l'on active les fenêtres :
DISPLAY_CR => DISPLAY_WIN0_ON, DISPLAY_WIN1_ON, et DISPLAY_SPR_WIN_ON, au choix

Voilà, je pense qu'il n'est pas nécessaire de donner plus de code que ça, tout est relativement clair et simple, on définit la position du rectangle et ça marche tout seul

Pour les utilisateurs de PAlib, toutes les fonctions sont listées et expliquées ici :
Doc PAlib...Pour résumer l'utilisation avec un exemple tout con :
Activation de la fenêtre 0 : PA_EnableWin0(screen, WIN_BG0|WIN_BG1) (pour les fonds 0 et 1, ajout |WIN_TRUC pour avoir d'autres choses...)
Puis : PA_SetWin0XY (u8 screen, u8 x1, u8 y1, u8 x2, u8 y2) pour le positionnement... (valeurs de 0 à 155)
Fenêtres : HBL poweredImaginons à présent que nous changions les positions de la fenêtre dans le HBL, comme nous faisions pour le scrolling dans l'une des démos précédentes... Quel serait le résultat ?

Et oui, on peut ainsi outrepasser la limite des fenêtres (à savoir la forme rectangulaire) et obtenir un peu tout et n'importe quoi comme forme. Dans cet exemple, j'ai utilisé la fonction Sinus pour faire un effet de vague, je trouve ça sympa, mais on pourrait imaginer d'autres fonctions pour avoir des effets différentes, comme un losange, etc... Le principe reste alors le même, changer les positions de la fenêtre pendant le HBL...
Bon, on to the code !
Commençons par la fonction à mettre en HBL :
(c):
s8 width = 8;
s8 height = 16;
u16 add = 0;
s16 pos = 0;
s16 x, x0, x1; // Pour calculer...
void HBL_function(void){
s16 vcount = PA_GetVcount();
vcount++;
if(vcount > 192) vcount = 0; // Get correct vcount
x0 = ((PA_Sin((vcount)*height+add)*width)>>8);
x1 = x0+255-pos; // Autre bout de l'écran
x0 += pos;
if(x0 < 0) x0 = 0; // Ne pas tomber plus bas...
if(x1 > 255) x1 = 255;
PA_SetWin0XY(0, x0, 0, x1, 191); // Position de la fenêtre...
}
Rien de particulier, je n'ai fait que copier/coller la fonction de l'autre jour

Dans cette démo, 'add' reste toujours à 0 parce que je ne voulais pas faire la variation verticale de la vague, il suffit de faire changer la valeur à chaque VBL pour l'activer

On part d'une valeur qui oscille entre -8 et 8 (x0). Pour la valeur de gauche, on ajoute 'pos', qui permet de faire l'effet d'ouverture/fermeture (varie entre 0 et 127), tandis que pour la valeur de droite (x1), on part de l'autre côté... Afin d'éviter d'injecter de mauvaises valeurs dans les registres, on limite la position à 0-255.
Et c'est tout ! Le reste du code, dans main, est tout simple :
(c):
for(i = -8; i <= 127; i+=2){
// add+=8; add&= 511; // Move wave...
pos= i;
PA_WaitForVBL();
}
for(i = 127; i >= -8; i-=2){
// add+=8; add&= 511; // Move wave...
pos = i;
PA_WaitForVBL();
}
Voilà, on fait juste varier la valeur de 'pos' pour obtenir l'effet voulu... J'ai mis en commentaire la variation de 'add', comme je ne m'en sers pas, mais vous pouvez décommenter dans les sources et voir ce que cela fait

Bon, si à l'occasion on me le demande je ferais des exemples avec d'autres formes, mais pour l'instant j'ai un peu la flemme

Passons donc à la troisième partie de la démo, qui est la plus originale...
Fenêtres : les sprites !Je vous laisse regarder et je vous explique...
Notez qu'il est préférable d'utiliser la DS ou No$GBA pour cette rom, les autres ont un peu du mal :/ Donc, la question qui se pose, est comment fait-on pour avoir un tel effet... C'est simple : les fenêtres objets ! On peut en fait appliquer le système de fenêtre en utilisant des sprites au lieu des rectangles... Ainsi, on a un système plus flexible, mais qui utilise des slots de sprite et de la VRAM, par contre. Je ne vais pas faire un topo sur comment charger des sprites, etc... Ni sur comment les déplacer, ce n'est pas la question

Cette démo combine plusieurs choses : des sprites noirs, pleins, dont on ne voit que le contour ici. Et des sprites légèrement plus petits, qui eux sont en mode 'Window' et exactement à la même position que les autres sprites. Voici le code initialisé pour les fenêtres :
(c):
PA_EnableWinObj(0, WIN_BG3);
PA_SetOutWin(0, WIN_SFX|WIN_OBJ);
Donc, on voit qu'on fait afficher le fond 3 (celui avec DEV-FR dessus) à travers les fenêtres (mais pas dehors

), et juste les sprites en dehors (mais pas dedans...). Conséquence... On ne verra JAMAIS le centre des ronds noirs, toute cette partie est devenue invisible... et donc, par extension, quand 2 ronds se rapprochent, si une partie visible passe dans une partie invisible, elle disparait, ce qui donne un joli petit effet de 'fusion'.

Je ne code pas tout le code, il est relativement clair. C'est un code tout bête de balles qui rebondissent sur les côtés, au détail près que j'affiche 2 sprites au lieu d'un seul (sprites 0 à 63 pour les sprites fenêtres, sprites 64 à 127 pour les sprites visibles).
Pour passer un sprite en mode fenêtre avec PAlib : PA_SetSpriteMode(0, i, 2); // Mode WINDOW !
Pour passer un sprite en mode fenêtre avec libnds : utiliser ATTR0_TYPE_WINDOWED

Voilà, je vous souhaite un bon week-end, et à bientôt !