Dans cette démo, nous allons vous montrer comment prendre un screenshot en utilisant la technique "reg_capture", puis l'appliquer sur un objet en 3D.
Note : cette démo est entièrement codée sous libnds.
Code découpé et expliqué(c):
#include <nds.h>
#include <stdlib.h>
#include <stdio.h>
On commence simple, en incluant les headers qui nous seront utiles.
(c):
#include "texture_bin.h"
On inclut la texture qui sera affichée sur le poly avant qu'aucun screenshot ne soit pris. Elle fait 256*256 et a été convertie avec gfx2gba en utilisant ces paramètres :
"gfx2gba -c32k *.bmp"
(c):
u8* screenbuffer;
On déclare un buffer qui servira à stocker le screenshot. Pour l'instant, ce n'est qu'un pointeur, on lui allouera de la mémoire plus tard.
(c):
float zoom=2.0f;
float rotateX = 0.0;
float rotateY = 0.0;
int textureID;
Diverses variables utiles pour la partie 3D de la démo.
(c):
void screen(u8* buff) {
REG_DISPCAPCNT=DCAP_BANK(3)|DCAP_ENABLE|DCAP_SIZE(3);
while(REG_DISPCAPCNT & DCAP_ENABLE);
dmaCopy(VRAM_D, buff, 256*192*2);
}
Fonction servant à prendre une capture d'écran et à la stocker dans un buffer.
REG_DISPCAPCNT <= sert à prendre un screenshot; voici les paramètres qu'il requiert :
DCAP_BANK(x) : choix de la Vram utilisée pour la capture. Elle doit être en mode LCD. 0 : Vram A, 1 : B, 2 : C, 3 : D
J'utilise ici la D.
DCAP_SIZE(x) : taille de la capture.
0:128x128, 1:256x64, 2:256x128, 3:256x192
Ici, on veut tout l'écran, donc on met 3
dmaCopy <= La capture est enregistrée dans la Vram D, donc on la copie vers le buffer qui a été donné en argument à la fonction
(c):
int main() {
Fonction principale.
(c):
screenbuffer=(u8*)malloc(256*192*2);
On alloue de la mémoire au buffer avec un malloc.
(c):
powerON(POWER_ALL);
/* On met l'écran du haut en mode 0 3D et celui du bas en mode 0 2D
parce que le blanc c'est moche et que la console ça rox */
videoSetMode(MODE_0_3D);
/* Vram A, B et C : textures (on n'a pas besoin d'autant d'espace, mais bon...);
Vram D : mode LCD (au moins une Vram doit être en mode LCD pour que la capture puisse fonctionner...
pas nécessairement la D comme dit plus haut) */
vramSetMainBanks(VRAM_A_TEXTURE,VRAM_B_TEXTURE,VRAM_C_TEXTURE,VRAM_D_LCD);
// On init l'IRQ
irqInit();
irqEnable(IRQ_VBLANK);
On init la console.
(c):
glInit();
glEnable(GL_TEXTURE_2D);
glClearColor(0,0,0,31);
glViewPort(0,0,255,191);
gluLookAt(0.0,0.0,1.0,0.0,0.0,0.0,0.0,1.0,0.0);
On init la 3D.
(c):
glGenTextures(1, &textureID);
glBindTexture(0, textureID);
glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_256 , TEXTURE_SIZE_256, 0, TEXGEN_TEXCOORD, (u8*)texture_bin);
On charge la texture qui va recouvrir notre poly au début.
Et, enfin, la boucle principale :
(c):
while(1) {
// Screenshot
if((keysUp() & KEY_A))
{
// On prend le screenshot
screen(screenbuffer);
// On reset les textures
glResetTextures();
// On charge la nouvelle texture
glBindTexture(0, textureID);
/* Comme vous pouvez le voir, la texture est en 256*256 alors que l'écran fait 256*192...
C'est un peu gênant mais pas un réel problème, il faudra juste faire attention
à bien adapter aux proportions lors du choix des coordonnées de la texture. */
glTexImage2D(0, 0, GL_RGB, TEXTURE_SIZE_256 , TEXTURE_SIZE_256, 0, TEXGEN_TEXCOORD, (u8*)screenbuffer);
// On met un fond de couleur aléatoire pour changer un peu....
glClearColor(rand()&31,rand()&31,rand()&31,31);
/* Cette valeur est une valeur très approchée permettant dans cette scène d'avoir le quad
quasi-exactement aligné avec la caméra. Cependant, il changera pour chaque scène... */
zoom=1.09f;
// On met la rotation à 0
rotateX=0;
rotateY=0;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(35, 256.0 / 192.0, 0.1, 100);
glColor3f(1,1,1);
glPushMatrix();
glMatrixMode(GL_TEXTURE);
glMatrixMode(GL_MODELVIEW);
glPolyFmt(POLY_ALPHA(31) | POLY_CULL_NONE);
glPushMatrix();
glLoadIdentity();
// On met les touches à jour....
scanKeys();
// Rotations....
if((keysHeld() & KEY_UP)) rotateX += 3;
if((keysHeld() & KEY_DOWN)) rotateX -= 3;
if((keysHeld() & KEY_LEFT)) rotateY += 3;
if((keysHeld() & KEY_RIGHT)) rotateY -= 3;
// Déplacements....
if((keysHeld() & KEY_R)) zoom += 0.15;
if((keysHeld() & KEY_L)) zoom -= 0.15;
// Translation (pour le déplacement)
glTranslate3f32(0, 0, floattof32(-zoom));
// Rotation
glRotateX(rotateX);
glRotateY(rotateY);
// On applique notre texture
glBindTexture(0, textureID);
// On dessinne la face sur laquelle sera la texture
glBegin(GL_QUADS);
/* Un screen a été pris, alors on adapte la face aux proportions de l'écran de la DS
(la hauteur de l'écran est 75% de sa largeur) */
glTexCoord2f(0.0f, 0.75f); glVertex3f(-1.0f, -0.75f, 0.0f);
glTexCoord2f(1.0f, 0.75f); glVertex3f( 1.0f, -0.75f, 0.0f);
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 0.75f, 0.0f);
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 0.75f, 0.0f);
glEnd();
glPopMatrix(1);
glFlush(0);
swiWaitForVBlank();
}
Désolé si c'est un peu mal rédigé et peu explicite par moment, mais j'ai été pris par le temps...
Enfin, voici une archive avec les sources :
http://www.dev-fr.org/screenshot.rar