La grafica 2D del Nintendo DS


Le palette estese (background)

Nelle sezioni precedenti abbiamo già accennato alla possibilità di utilizzare un maggior numero di palette (e quindi di colori) sia per i background che per gli sprite. Vediamo in dettaglio quali sono le possibilità che da il Nintendo DS: le funzionalità di cui tratteremo sono disponibili senza distinzioni sia sul MAIN engine che sul SUB engine.

Per quanto riguarda i background, vi è la possibilità di usare contemporaneamente fino a 16 palette distinte, di 256 colori ognuna, per ognuno dei 4 background, portando quindi il numero di colori contemporanei visualizzabili a 4096 per ogni background, 16384 distinti colori in totale, in teoria. Però le palette estese possono essere utilizzate solo nei modi testo e esteso, ovvero solo in quei modi dove è possibile specificare sia una tessera (e quindi in tutti i modi a tessere in genere, e non nei modi bitmap) che una palette (e questo taglia fuori i background in modo rotazionale poiché questo specifica, nella mappa delle tessere, esclusivamente il numero di tessera da visualizzare e niente di più).

Attivando le palette estese quindi sarà possibile specificare, attraverso la mappa del background, quale palette va utilizzata insieme ad ogni determinata tessera. Appunto a questo fine viene definita in libnds (in background.h) la seguente macro:

TILE_PALETTE(n)

che viene usata in modo analogo ai flag di mirror e flip, serve cioè a calcolare quale valore a 16 bit inserire nella mappa del background per ogni tessera.

In libnds (in video.h) è poi definita la seguente costante da utilizzare nelle funzioni videoSetMode() o videoSetModeSub() per attivare le palette estese per i background rispettivamente sul MAIN engine o sul SUB engine:

DISPLAY_BG_EXT_PALETTE

Queste palette estese richiedono 512 byte ognuna, quindi l'intero set di 16 palette per ognuno dei 4 background richiede un totale di 32 KB, ma la consolle non è equipaggiata di una memoria di tali dimensioni dedicata a questo esclusivo fine: per poter attivare questa caratteristica si deve quindi utilizzare un banco di memoria video appositamente configurato, o eventualmente due. Per questa funzionalità sono disponibili solamente i banchi E (da 64 KB, di cui solo i primi 32 KB verranno usati), F e G (da 16 KB ognuno) per le palette estese del MAIN engine, ed esclusivamente il banco H (da 32 KB) per le palette estese del SUB engine.

Un'altra cosa che in realtà può risultare fastidiosa è che attivare le palette estese vuol dire attivarle per tutti i background, non solo per quelli nei quali desideriamo utilizzarle. Quindi se volessimo avere una palette unica in uno specifico background testo o esteso a 256 colori, allora saremo comunque costretti a caricare questa palette nella memoria delle palette estese di quel background.

Quindi attivando le palette estese verrà ignorata la palette standard dei background, con le seguenti tre eccezioni:
- l'elemento 0 della palette standard dei background sarà comunque il colore che verrà dato ai pixel che risulteranno trasparenti in tutti i background, in pratica come se avessimo un ultimo fondale (detto anche backdrop), tutto di questo colore, dietro ai 4 background.
- nel modo rotazionale a 256 colori viene usata sempre e solo la palette standard dei background, anche quando le palette estese sono attive.
- nel modo testo a 16 colori per tessera saranno i 256 colori definiti nella palette standard dei background ad essere utilizzati come 16 distinte palette da 16 colori ognuna. (E se questo fosse l'unico modo con palette estese che intendete utilizzare allora potrete evitare di dedicare dei banchi di memoria video aggiuntivi)

Infine è da rimarcare che quando i banchi di memoria video sono impostati nelle varie modalità di palette estese, essi non hanno indirizzi di memoria ai quali è possibile fare riferimento per accedere e impostare i colori nelle palette, indirizzi che invece hanno quando tali banchi sono impostati nelle altre modalità. Per poter quindi impostare le palette è necessario cambiare temporaneamente modalità a tali banchi (conviene selezionare la modalità LCD nella quale ogni banco ha un suo univoco indirizzo), scrivere ai loro indirizzi ora accessibili le informazioni riguardo i colori delle palette, ed infine nuovamente impostare la modalità palette estese per i banchi in oggetto.

In libnds (in video.h) sono definite le seguenti costanti per l'accesso ai banchi di memoria video al fine di scrivere le palette dei background:

VRAM_E_EXT_PALETTE
VRAM_F_EXT_PALETTE
VRAM_G_EXT_PALETTE
VRAM_H_EXT_PALETTE

Ognuna di queste costanti è un puntatore a vettore dove ogni elemento è una palette, dopo le 16 palette del background 0 ci sono le 16 del background 1 e così via. Ogni palette è un vettore di 256 halfword che rappresentano un colore espresso su 15 bit. Il 16° bit di ogni halfword, il più significativo, viene ignorato.

Una ultimissima nota: è possibile forzare il background 0 ad usare le stesse palette estese del background 2 e/o forzare il background 1 ad usare le stesse palette estese del background 3. Attivando entrambe le forzature sarà quindi possibile utilizzare solo 2 set di 16 palette estese invece di 4 set, richiedendo 16 KB invece di 32 KB. Può essere il modo di risparmiare uno dei due banchi di memoria video, F o G, magari per dedicarlo alle palette estese degli sprite.

In libnds (in background.h) sono definite appositamente le due costanti

BG_PALETTE_SLOT0
BG_PALETTE_SLOT2

che possono essere usate per selezionare quali palette estese userà il background 0, e le due costanti

BG_PALETTE_SLOT1
BG_PALETTE_SLOT3

che possono essere usate per selezionare le palette estese che dovrà utilizzare il background 1.

Le palette estese (sprite)

Le palette estese per gli sprite sono molto simili a quelle dei background e si possono attivare o meno indipendentemente dal fatto che siano attive o no per i background. Per gli sprite esiste però un solo set di 16 palette estese a 256 colori ognuna e quindi la memoria totale richiesta è di 8 KB. Anche in questo caso non essendo presente nella consolle una memoria dedicata a questa funzione sarà necessario utilizzare un banco di memoria video: si può scegliere tra il banco F o G (da 16 KB ognuno, verranno comunque utilizzati solo i primi 8 KB) per il MAIN engine e si può solo utilizzare il banco I (anche questo da 16 KB) per il SUB engine. Per le palette estese degli sprite a 16 colori invece si useranno i 256 colori della palette standard degli sprite, analogamente a quanto avviene per i background nei modi a tessere a 16 colori. Se le palette estese sono attive per gli sprite allora tutti gli sprite attivi dovranno fare riferimento ad una di esse attraverso la proprietà ATTR2_PALETTE(n) nell'attributo 2 dell'OAM. Ovvero non si potrà avere contemporaneamente attive le palette estese degli sprite e sprite che usino la palette standard.

In libnds (sempre in video.h) è definita la seguente costante da utilizzare nelle funzioni videoSetMode() e videoSetModeSub() per attivare le palette estese per gli sprite:

DISPLAY_SPR_EXT_PALETTE

Sono inoltre definite le seguenti costanti per l'accesso ai banchi di memoria video al fine di scrivere le palette degli sprite:

VRAM_F_EXT_SPR_PALETTE
VRAM_G_EXT_SPR_PALETTE
VRAM_I_EXT_SPR_PALETTE

Nell'esempio che segue useremo le palette estese dei background e degli sprite sul MAIN engine per visualizzare il medesimo sprite a 256 colori usando tutte e 16 le palette estese degli sprite su un background fatto sempre della stessa tessera a 256 colori ma ripetuta alternando due palette diverse. Useremo il background 0 e solo 2 set di 16 palette e quindi un solo banco da 16 KB, il banco G. Il background 0 quindi userà le palette del background 2. Toccando il touchscreen gli sprite si riposizioneranno e cambieranno colore casualmente, usando una palette diversa.

#include <nds.h>

// una comoda define per gli sprite
#define TILE16_1D_128K(n) ((n)>>2)

// definiamo il nostro array di sprite (una copia)
OAMTable Sprites;

void RandomizeSprites (void) {

  int i;
  
  // ognuno dei 128 sprite
  for (i=0;i<128;i++) {
  
    // normale, 16 colori, quadrato
    Sprites.oamBuffer[i].attribute[0]=ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_256
                                     |ATTR0_SQUARE | OBJ_Y(rand()%(192-8));
    // 8x8 pixel di dimensione
    Sprites.oamBuffer[i].attribute[1]=ATTR1_SIZE_8 | OBJ_X(rand()%(256-8));
    
    // tessera 0, palette a caso
    Sprites.oamBuffer[i].attribute[2]=ATTR2_PRIORITY(0) | ATTR2_PALETTE (rand()%16)
                                     |(TILE16_1D_128K(0) & 0x03ff);
  }
}

int main(void) {

  // impostiamo la memoria video per il background (banco A)
  vramSetBankA (VRAM_A_MAIN_BG);
  
  // impostiamo la memoria video per gli sprite (banco E)
  vramSetBankE (VRAM_E_MAIN_SPRITE);
  
  // impostiamo accessibile la memoria video dove memorizzeremo
  // le palette estese del background (banco G)
  vramSetBankG (VRAM_G_LCD);
  
  // carichiamo dei colori nella palette estesa numero 1 dello slot 0
  // 1=blu, 2=rosso
  VRAM_G_EXT_PALETTE[0][1][1] = RGB5 (0,0,15);
  VRAM_G_EXT_PALETTE[0][1][2] = RGB5 (15,0,0);
  
  // carichiamo dei colori nella palette estesa numero 3 dello slot 0
  // 1=verde, 2=grigio
  VRAM_G_EXT_PALETTE[0][3][1] = RGB5 (0,15,0);
  VRAM_G_EXT_PALETTE[0][3][2] = RGB5 (8,8,8);

  // impostiamo la memoria video per le palette estese del background (banco G)
  vramSetBankG (VRAM_G_BG_EXT_PALETTE_SLOT23);
  
  // impostiamo accessibile la memoria video dove memorizzeremo
  // le palette estese degli sprite (banco F)
  vramSetBankF (VRAM_F_LCD);
  
  // carichiamo dei colori diversi nell'elemento 1 di ogni palette estesa degli sprite
  int i;
  for (i=0;i<16;i++)
    VRAM_F_EXT_SPR_PALETTE[i][1] = RGB5 ((i>>3)*31,((i & 0x06)>>1)*15+1,(i&0x01)*31);

  // impostiamo la memoria video per le palette estese degli sprite (banco F)
  vramSetBankF (VRAM_F_SPRITE_EXT_PALETTE);

  // impostiamo il modo 0 sul MAIN engine, il BG 0, attiviamo gli sprite e
  // le palette estese dei background e degli sprite
  videoSetMode ( MODE_0_2D | DISPLAY_BG0_ACTIVE | DISPLAY_SPR_ACTIVE
               | DISPLAY_SPR_1D | DISPLAY_SPR_1D_SIZE_128
               | DISPLAY_BG_EXT_PALETTE | DISPLAY_SPR_EXT_PALETTE );
  
  // creiamo una tessera colorata con i colori 1 e 2 (64 bytes)
  u8 TesseraColorata[8*8] = 
  {
    0,0,0,0,0,0,0,0,
    0,1,1,1,1,1,1,0,
    0,1,1,2,2,1,1,0,
    0,1,2,1,2,2,1,0,
    0,1,2,2,1,2,1,0,
    0,1,1,2,2,1,1,0,
    0,1,1,1,1,1,1,0,
    0,0,0,0,0,0,0,0
  };
  
  // creiamo uno sprite 8x8, 256 colori
  u8 Sprite[8*8] = 
  {
    0,0,1,1,1,1,0,0,
    0,1,1,1,1,1,1,0,
    1,1,1,1,1,1,1,1,
    1,1,1,0,0,1,1,1,
    1,1,1,0,0,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,0,
    0,0,1,1,1,1,0,0
  };
  
  // copiamo la tessera del background in memoria video
  swiCopy(TesseraColorata, (u8*)BG_TILE_RAM(1), 64);
  
  // copiamo la tessera dello sprite in memoria video
  swiCopy(Sprite, SPRITE_GFX, 64);

  // impostiamo il colore 0 della palette standard al nero
  BG_PALETTE [0] = RGB5(0,0,0);
  
  // riempiamo la mappa usando sempre la stessa tessera colorata,
  // alternando però le palette estese
  for (i=0;i<32*32;i++)
    ((u16*)BG_MAP_RAM(0)) [i] = 0 | TILE_PALETTE (((i&0x1)^((i&0x20)>>5))?1:3);
    
  // impostiamo il modo del BG 0, usando le palette del BG 2
  REG_BG0CNT = BG_32x32|BG_COLOR_256|BG_PALETTE_SLOT2|BG_MAP_BASE(0)|BG_TILE_BASE(1);
  
  // associamo il MAIN engine allo schermo inferiore, il touchscreen
  lcdMainOnBottom ();
  
  // posiziona gli sprite a caso
  RandomizeSprites();
  
  // setto il flag per indicare che l'OAM è da aggiornare
  int OAMRefresh=1;

  while(1) {
  
    // leggiamo lo stato dei tasti e del touch screen
    scanKeys();
    
    // abbiamo appena toccato il touch screen?
    if (keysDown() & KEY_TOUCH) {
     
      // posiziona gli sprite a caso
      RandomizeSprites();
      
      // setto il flag per indicare che l'OAM è da aggiornare
      OAMRefresh=1;
    }
 
    // aspettiamo il prossimo refresh
    swiWaitForVBlank();
    
    // la nostra copia dell'OAM è cambiata?
    if (OAMRefresh) {
     
      // flush della cache dei dati
      DC_FlushAll();
      
      // copia dell'OAM via DMA
      dmaCopy (&Sprites, OAM, sizeof(Sprites));
      
      // resetto il flag per indicare che l'OAM è aggiornato
      OAMRefresh=0;
    }
  }
}

E' necessario chiarire l'utilizzo della costante VRAM_G_BG_EXT_PALETTE_SLOT23 nella funzione vramSetBankG(). Come ho già scritto, nella tabella delle modalità di funzionamento delle memorie video che è stata riportata non sono state inserite tutte le modalità possibili, ed infatti questa modalità, e tante altre, mancano. La maggior parte delle modalità di cui non abbiamo parlato servono a definire a quale indirizzo fisico verranno associati i banchi di memoria, questo perché ad esempio se volessimo utilizzare 256 KB di memoria video per gli sprite dovremmo impostare due banchi da 128 KB alla modalità VRAM_x_MAIN_SPRITE ma dovremo specificare quale banco sarà utilizzato per contenere la prima metà della memoria degli sprite e quale banco la seconda metà, evidentemente.

In questo caso però la modalità non serve al nostro programma per sapere dove scrivere le informazioni della palette in memoria (infatti facilmente accediamo alla memoria del banco G attraverso il vettore VRAM_G_EXT_PALETTE quando è in modalità LCD mentre lo stesso banco è poi inaccessibile quando è in modalità palette estese) quanto al motore grafico per capire se in quel banco di memoria dedicato alle palette estese dei background abbiamo memorizzato le palette dei background 0 e 1 oppure quelle dei background 2 e 3. E nel nostro programma abbiamo voluto utilizzare solamente le palette dei background 2 e 3, per risparmiare memoria, ed infatti abbiamo forzato il nostro background 0 ad utilizzare le palette del background 2, attraverso l'apposito flag.

Ne consegue che in libnds sono anche definite le seguenti 4 modalità, oltre a quelle già viste.

Memoria (dimensione) Modalità utilizzabili
VRAM_BANK_F (16 KB) VRAM_F_BG_EXT_PALETTE_SLOT01
VRAM_F_BG_EXT_PALETTE_SLOT23
VRAM_BANK_G (16 KB) VRAM_G_BG_EXT_PALETTE_SLOT01
VRAM_G_BG_EXT_PALETTE_SLOT23

L'effetto speciale Alpha Blending

I motori grafici del Nintendo DS, come abbiamo visto, sono in grado di visualizzare immagini utilizzando fino a 4 background di vario tipo e a 16, 256 o 32768 colori e fino a 128 sprite anche questi a 16, 256 o 32768 colori. Quello però che non è ancora stato detto è che questi motori grafici sono anche in grado di 'mescolare' i colori dei background e degli sprite per ottenere fino a 262144 colori diversi (18 bpp, gli schermi della consolle sono in grado di visualizzarli) e interessanti effetti. Si chiama Alpha Blending e permette di specificare che determinati background (e/o determinati sprite) possano mescolare il colore dei loro pixel quando si trovano sovrapposti ad altri determinati background o sprite.

L'effetto Alpha Blending si attiva attraverso un registro apposito, uno per ogni motore grafico, accessibili attraverso le seguenti costanti definite in libnds (in video.h):

REG_BLDCNT
REG_BLDCNT_SUB

Attraverso il registro si specificherà quali background saranno interessati dall'effetto, e se sarà attivo anche per gli sprite, e se questo effetto dovrà anche essere applicato a quei pixel che non risulteranno coprire niente altro, che quindi non avrebbero niente con cui mescolare il proprio colore.

Si definiscono quindi due gruppi (il gruppo sorgente e il gruppo destinazione) composti ognuno dagli elementi che desideriamo interessare tra i background, gli sprite -visti però come un unico elemento- e il fondale (il backdrop: il niente che sta dietro ai background e gli sprite). L'effetto di Alpha Blending avverrà tra ogni pixel dell'elemento di maggior priorità del gruppo sorgente e il pixel dell'elemento sottostante (cioè di priorità minore rispetto al precedente elemento) di maggior priorità nel gruppo destinazione, fatto salvo l'elemento sorgente stesso.

Questo comporta per esempio che -purtroppo- non sarà possibile avere l'Alpha Blending tra due sprite, essendo entrambi in realtà lo stesso elemento. Blend tra sprite e background e tra un background e un altro, invece, sono perfettamente regolari.

Vengono definite in libnds (sempre in video.h) le seguenti costanti per indicare i sei elementi per ogni gruppo (chiamati impropriamente il gruppo sorgente e il gruppo destinazione):

BLEND_SRC_BG0
BLEND_SRC_BG1
BLEND_SRC_BG2
BLEND_SRC_BG3
BLEND_SRC_SPRITE
BLEND_SRC_BACKDROP

BLEND_DST_BG0
BLEND_DST_BG1
BLEND_DST_BG2
BLEND_DST_BG3
BLEND_DST_SPRITE
BLEND_DST_BACKDROP

ed infine le costanti per attivare o disattivare l'effetto Alpha Blending:

BLEND_ALPHA
BLEND_NONE

E' poi presente un altro registro (a sola scrittura, uno per ogni motore grafico) attraverso il quale si specificherà in quale quantità il primo e il secondo elemento concorreranno a formare il risultato di questa 'somma': entrambi i valori sono frazionari e specificano quanti sedicesimi di ogni intensità delle tre componenti del colore (RGB) considerare. La somma tra i sedicesimi del primo e quelli del secondo gruppo non deve obbligatoriamente dare 16, anzi vi sono interessanti effetti ottenibili anche attraverso il superamento di questa soglia. Le costanti definite in libnds per questo registro sono:

REG_BLDALPHA
REG_BLDALPHA_SUB

Il byte meno significativo del registro deve contenere il coefficiente di intensità specificato per gli elementi del gruppo sorgente mentre il byte più significativo deve contenere il coefficiente di intensità specificato per gli elementi del gruppo destinazione. Un valore superiore a 16 verrà interpretato come un 16 a tutti gli effetti. Oltre a questo, il byte meno significativo specifica anche il canale alfa (la semitrasparenza, valori tra 0 e 16 sedicesimi) di tutti gli sprite dichiarati come semitrasparenti, sia attivo o meno l'effetto speciale di Alpha Blending.

Nel semplice esempio che segue utilizzeremo l'effetto di Alpha Blending tra uno sprite, che può essere spostato attraverso il touchscreen, e un semplice background.

#include <nds.h>

// una comoda define per gli sprite
#define TILE16_1D_128K(n) ((n)>>2)

int main(void) {

  // il nostro array di sprite (sull'OAM)
  OAMTable* Sprites = (OAMTable*)OAM;
  
  // azzeriamo l'OAM (disabilitiamo tutti gli sprite)
  int i;
  for (i=0;i<128;i++)
    Sprites->oamBuffer[i].attribute[0]=ATTR0_DISABLED | OBJ_Y(192);
    
  // impostiamo la memoria video per il background (banco A)
  vramSetBankA (VRAM_A_MAIN_BG);
  
  // impostiamo la memoria video per gli sprite (banco E)
  vramSetBankE (VRAM_E_MAIN_SPRITE);
  
  // impostiamo il modo 0 sul MAIN engine, il BG 0, attiviamo gli sprite
  videoSetMode ( MODE_0_2D | DISPLAY_BG0_ACTIVE | DISPLAY_SPR_ACTIVE
               | DISPLAY_SPR_1D | DISPLAY_SPR_1D_SIZE_128);
  
  // creiamo una tessera a 256 colori (64 bytes)
  u8 TesseraColorata[8*8] = 
  {
    1,1,2,2,0,0,1,1,
    0,1,1,2,2,0,0,1,
    0,0,1,1,2,2,0,0,
    2,0,0,1,1,2,2,0,
    2,2,0,0,1,1,2,2,
    1,2,2,0,0,1,1,0,
    1,1,2,2,0,0,1,1,
    0,1,1,2,2,0,0,1
  };
  
  // creiamo uno sprite 16x16, 256 colori
  u8 Sprite[8*8*4] = 
  {
    0,0,0,0,0,0,1,1,
    0,0,0,0,1,1,1,1,
    0,0,0,1,1,1,1,1,
    0,0,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    
    1,1,0,0,0,0,0,0,
    1,1,1,1,0,0,0,0,
    1,1,1,1,1,0,0,0,
    1,1,1,1,1,1,0,0,
    1,1,1,1,1,1,1,0,
    1,1,1,1,1,1,1,0,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,1,1,1,1,1,1,1,
    0,0,1,1,1,1,1,1,
    0,0,0,1,1,1,1,1,
    0,0,0,0,1,1,1,1,
    0,0,0,0,0,0,1,1,
    
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,1,
    1,1,1,1,1,1,1,0,
    1,1,1,1,1,1,1,0,
    1,1,1,1,1,1,0,0,
    1,1,1,1,1,0,0,0,
    1,1,1,1,0,0,0,0,
    1,1,0,0,0,0,0,0
  };
  
  // copiamo la tessera del background in memoria video
  swiCopy(TesseraColorata, BG_TILE_RAM(1), 64);
  
  // copiamo le tessere dello sprite in memoria video
  swiCopy(Sprite, SPRITE_GFX, 256);

  // impostiamo i colori 0, 1 e 2 della palette dei background
  BG_PALETTE [0] = RGB5(0,0,0);
  BG_PALETTE [1] = RGB5(31,0,0);
  BG_PALETTE [2] = RGB5(0,0,31);
  
  // impostiamo il colore 1 della palette degli sprite
  SPRITE_PALETTE[1] = RGB5(0,31,8);

  // riempiamo la mappa del background usando la tessera 0
  for (i=0;i<32*32;i++)
    ((u16*)BG_MAP_RAM(0)) [i] = 0;
    
  // impostiamo il modo del BG 0
  REG_BG0CNT = BG_32x32 | BG_COLOR_256 | BG_MAP_BASE(0) | BG_TILE_BASE(1);
  
  // associamo il MAIN engine allo schermo inferiore, il touchscreen
  lcdMainOnBottom ();
  
  // attiviamo il blending degli sprite sul BG 0
  REG_BLDCNT = BLEND_ALPHA | BLEND_SRC_SPRITE | BLEND_DST_BG0;
  
  // impostiamo il blend a 10/16 sprite e 16/16 BG0
  REG_BLDALPHA = 10 | (16 << 8);
  
  // inizializziamo la posizione dello sprite al centro dello schermo
  int sp_x = (SCREEN_WIDTH  - 16) / 2;
  int sp_y = (SCREEN_HEIGHT - 16) / 2;

  while(1) {
  
    // leggiamo lo stato dei tasti e del touch screen
    scanKeys();
    
    // il pennino è appoggiato sul touch screen?
    if (keysHeld() & KEY_TOUCH) {
     
      // leggi la posizione del pennino
      touchPosition touch; touchRead(&touch);
     
      // posiziona il centro dello sprite dove è stato premuto
      sp_x = touch.px - 8;
      sp_y = touch.py - 8;
    }
    
    // posizioniamo lo sprite nella posizione attuale
    Sprites->oamBuffer[0].attribute[0]=ATTR0_NORMAL | ATTR0_TYPE_NORMAL | ATTR0_COLOR_256
                                      |ATTR0_SQUARE | OBJ_Y(sp_y);
    Sprites->oamBuffer[0].attribute[1]=ATTR1_SIZE_16 | OBJ_X(sp_x);
    Sprites->oamBuffer[0].attribute[2]=ATTR2_PRIORITY(0) | (TILE16_1D_128K(0) & 0x03ff);
   
    // aspettiamo il prossimo refresh
    swiWaitForVBlank();
   }
}


Sverx, 3 Luglio 2009. Ultima modifica il 12 Agosto 2009.


Domande? Dubbi? Suggerimenti? Vuoi scambiare due parole con me? Ho preparato un forum apposta!

Torna all'indice per accedere alle altre sezioni.

riferimenti:

http://nocash.emubase.de/gbatek.htm#dsmemorycontrolvram

http://nocash.emubase.de/gbatek.htm#dsvideoextendedpalettes

http://nocash.emubase.de/gbatek.htm#dsvideobgmodescontrol

http://nocash.emubase.de/gbatek.htm#lcdiocolorspecialeffects