PDA

Voir la version complète : [GBA][Tutorial] Initiation à l'assembleur - Partie 2 - Mode 4 GBA


MIKEGBA
10/10/2006, 01h00
Initiation Assembleur - Partie 2 - Mode 4 GBA
Auteur : MIKEGBA

TELECHARGER LA ROM ICI (http://perso.orange.fr/michel.vachta/mapmode4.bin)

Acte 1

....bon alors la suite de ce tuto d'initiation à l'assembleur !!


Alors, ce soir, on va juste voir le "sommaire" de cette petite initiation avec juste une petite rom à télécharger, sans le source pour l'instant :p , histoire de vous mettre un peu l'eau à la bouche ...

J'ai choisi d'orienter ce tuto sur l'utilisation du mode 4 qui semble intéresser ici de plus en plus de monde.

Le petit programme que vous pouvez télécharger ici vous permet de vous déplacer dans une map de 2048*2048 pixels. Utiliser les touches de direction pour vous déplacer ..... en 60 fps bien sur !:)

On est donc en mode 4, mais ce que vous voyez, ce n'est pas un bitmap géant de 2048*2048 pixels, mais un ensemble de tile de 32*32 pixels.

Le format de fichier utilisé ici est le même que pour une map de background en mode 0 de la gba.

On a donc 3 fichiers source:
-1 fichier palette 256 couleurs
-1 fichier de tile regroupé dans un bitmap de 256*512 pixels
-1 fichier "map" de 8 ko .

Pour coder 1 tile, on a 16 bits, comme pour le mode 0 de la gba:

-le bit 0 à 9 nous indiquera le numéro du tile.
-le bit 10 nous indiquera si le tile est flippé horizontalement.
-le bit 11 nous indiquera si le tile est flippé verticalement.

-le bit 12 à 15 ne sont pas utilisé, alors que dans le mode textbackground, cela nous indiquait la palette, inutile ici puisque l'on est en mode 4 .



L'intéret de ce petit programme est qu'il permet de survoler vraiment beaucoup de chose, à la fois en assembleur , mais aussi dans l'utilisation du mode 4

On decortiquera donc dans les jours qui suivent l'ensemble des fonctions qui le compose, et on verra donc comment en assembleur, faire les choses suivantes:

-effacer un buffer, flipper les buffers, plotter 32 pixels d'une traite:w00t: , flipper des textures, savoir faire des sauts rapides en asm, décaler des textures dans les registres, flipper le contenu d'un registre,lire une structure,utiliser l'iwram, etc, etc...


....voilà voilà, la suite bientot, en esperant que ça pourra vous interresser et que ça vous donne un petit coup de main si vous vous lancer dans le mode 4 et l'asm.

Acte 2


Bon, pour ceux qui ont télécharger le programme dont on découvriar peu à peu le source, voilà donc la suite !



Mais commençons par le commencement !

En fait, notre programme, qu'est ce qu'il fait ?

Il affiche un background tilé en mode 4, ce bacground est donc composé de tile de 32*32 pixels. Ok, on en déduit donc que ce petit programme est composé de 2 fonctions principales:

-1 fonction d'affichage de map, en fonction de notre coordonée X et Y de notre caméra.


-1 fonction d'affichage de tile "software" 32*32 qui va etre appelée par notre fonction d'affichage de map.

Donc, avant de savoir afficher une map, et bien il faut déja savoir afficher un tile.


On va donc ce soir s'attarder ce soir sur l'étude de la problématique de base de l'affichage d'un tile de 32*32 pixels en mode 4.




Les problémes à résoudre pour l'affichage d'un malheureux bout d'image de 32*32 pixels en mode 4 sont toutefois relativement nombreux:

1) en mode 4, on ne peut pas plotter 1 seul pixel à la fois, car le bus vidéo ne supporte q'un adressage en écriture de 16 ou 32 bits: On ne peut donc stoquer que 2 ou 4 pixels à la fois, et comme vu dans un précédent post, on a vu qu'il fallait etre "aligné en mémoire pour faire ce stoquage. Pas question donc de stoquer 2 pixels de suite à une adresse impaire.

2) Il va falloir que l'on soit rapide, car on va quand meme devoir stoquer au total 240*160 pixels, soit un total de 38400 pixels !! alors finalement, le probleme numéro 1 n'est plus un obstacle , car de toute façon en plottant pixel par pixel on serait alors très loin des 60 fps....:D ..... et on verra par la suite qu'on aura une solution pour les stoquer par paquet de 32 pixels, quels que soit notre adresse de stoquage.

3) malheureusement pour nous, nos tiles seront parfois affichés que partiellement, car à cheval sur les bords de l'écran, il va falloir gerer ça, et le faire en amont , afin de ne pas se taper les tests pour chaque pixels....

4) On a besoin aussi de gerer les tiles flippés horizontalement et verticalement, afin d'économiser en stoquage.


Finalement, ça fait pas mal de choses à penser avant de taper notre première ligne de code !!


Alors, allons y , c'est parti !!


Pour notre routine d'affichage de tile, on a déja besoin de connaitre nos parametres d'entrée, et ce sont les suivants:

On va donc considérer, que notre routine d'affichage de map, lorsqu'elle apellera la routine d'affichage de tile, fournira en entrée les variables suivantes:

-registre r9 contiendra l'adresse en mémoire de notre tile
-registre r5 contiendra l'info de fliping horizontal du tile ( 1=oui / 0 =non )
-registre r10 contiendra la coordonée X d'affichage du tile ( de -31 à 239 )
-registre r7 contiendra la coordonée Y d'affichage du tile ( de -31 à 159 )
-registre r0 contient pour l'instant la valeur 256, qui est la largeur de la page de texture ou se trouve nos tile ( je rapelle qu'on travaille avec une source de tile regroupé dans une page de texture de 256*512 pixels )


en 1er lieu, on sauvegarde dans la pile, notre registre de retour, et on initialise dans r1 la hauteur de notre tile à 32 pixels.


AFFICHE_TILE: stmfd sp!,{r14}
mov r1,#32 /* initialisation de la hauteur du tile */



On va ensuite commencer par résoudre notre problematique de taille de tile, c'est à dire savoir si on est à chaval ou pas sur un bord de l'écran. On commence par le plus facile, c'est à dire les tests en Y. :) .On va donc corriger notre hauteur de tile et aussi sa coordonée Y d'affichage. Par exemple, si notre coordonée d'affichage en entrée Y était de -5, alors la coordonée d'affichage Y devient 0 et la hauteur diminue à 32-5 soit 27 pixels de haut.
Il faut aussi dans ce cas dés à présent modifier en conséquence l'adresse de la source de notre texture de tile, puisqu'on ne va pas afficher ses 5 premieres lignes....

Egalement, si notre coordonée d'affichage Y=155, alors la hauteur du tile n'est plus que de 4 pixels ( puisque il y'a 160 lignes sur l'écran lcd )

le code suivant de 9 lignes d'asm fait tout ça pour nous.


DETERMINATION_TILE_Y: cmp r7,#0 /* test si coordonée négative */
addmi r1,r7,#32 /* si négatif on calcule notre nouvelle hauteur de tile */
rsbmi r7,r7,#0 /* si négatif on calcule notre nouvelle adresse source de tile */
mulmi r6,r7,r0 /* avec la formule source=source+( -Y*256 ) on avait en entrée r0=256 */
addmi r9,r9,r6
movmi r7,#0 /* on initialise à 0 notre Y d'affichage */
bmi DETERMINATION_TILE_X /* et on va s'occuper maintenant de la correction des x.... */

cmp r7,#128 /* sinon, si Y>128, on ne change que la hauteur d'affichage du tile */
rsbgt r1,r7,#160

DETERMINATION_TILE_X: la suite demain !:p


Juste un petit commentaire au passage, pour signaler qu'en arm, on peut subordonnée l'éxéxcution d'une instruction à une condition.

exemple: addmi r9,r9,r6 ne s'éxécutera que SI le résultat du test précédent vérifiait la condition "plus petit que" ( suffixe mi ).

Dans le code, le test était cmp r7,#0, c'est à dire compare r7 à la valeur 0. Le résultat du test est conservé jusqu'au prochain test, on peut donc éxécuter des instructions conditionnées des dizaines de lignes plus loin , tant que l'on a pas lancé de nouveaux tests.:)

Voilà, c'est tout pour ce soir, c'est déja pas mal.... ça va un poil se compliquer avec les corrections des X ! :ph34r:

...bon, je conseille vivement aussi de télécharger le pdf de la doc sur l'arm7 pour la bonne compréhension de ce petit tuto, vous y trouverez notemment tous les suffixe pour les conditions par exemple....:rolleyes:


Acte 3

Ok, on poursuit !

On passe maintenant à la correction de la coordonée X d'affichage du tile. Cette fois ci c'est légerement plus compliqué, car on a vu que si on veut stoquer par paquet de 4 pixels, et on le fera meme directement par paquet de 32 , on ne peut stoquer que sur des adresses multiples de 4 !

Donc, il nous faut trouver la coordonée X multiple de 4 qui précède notre X réel.

par exemple, si notre coordonée X d'affichage est 7, alors on doit transformer ce 7en 4 .SI c'est 33, alors le X devient 32, etc...

Pour trouver le multiple de 4 , l'instruction BIC est notre ami. BIC met à 0 les bits que l'on veut.

si je fais bic r1,r2,#3, alors dans r1 on aura le contenu de r2 masqué avec la valeur #3 ( #3 en binaire= 00000011 ), les 2 derniers bits de r2 sont mis à 0, ce qui revient à avoir un multiple de 4 .... :) )

le contenu de r2 n'est pas changé, donc si je fais ensuite sub r3,r2,r1, j'aurais donc dans r3 la différence entre mon X d'origine et mon X multiple de 4.



Bon, alors voilà, vous vous dites, pourquoi afficher à une coordonée x=4 alors qu'on veut afficher notre tile à x=7 ?? il est devenu fou ?:hp:

Alors voilà venu donc le moment de dévoiler la clef de l'affichage:

-> Vu que l'on décale l'adresse d'écriture de 3 pixels vers la gauche ( on passe de x=7 à x=4 ), et bien on va dans ce cas décaler notre texture SOURCE de 3 pixels vers la droite et ainsi tout le monde sera aligné comme il faut !

On verra par la suite comment on va décaler la texture source grace à nos index de décalage que l'on va commencer par calculer.

On calcule l'index de décalage grace à la différence entre notre X d'origine et notre X multiple de 4. Si on a x=11, alors le x multiple de 4=8, donc notre différence est donc de 11-8 = 3. On sait que notre décalage est de 3 pixels, mais ce que l'on veut c'est le nombre de bits à décaler. Comme on est en mode 4, 1 pixel=8 bits, donc on multipliera par 8 pour avoir l'index de décalage final soit ici 3x8= 24 !
Pour multiplier par 8, on fera bien sur un décalage de 3 bits vers la gauche ( lsl #3)



Place au code maintenant !!



DETERMINATION_TILE_X: bic r3,r10,#3 /* coordonée x alignée (multiple de 4 précédent ) */

sub r11,r10,r3 /* ici on va calculer dans r11 et r12 des index de décalages de texture */
/* on en verra l'utilité dans la suite du code */
mov r11,r11, lsl #3 /* r11=décalage de bit à faire (0,8,16 ou 24 ) */
rsb r12,r11,#32 /* r12=décalage de bit complément à 32 */

ldr r10,Adr_MEMOIRE_VIDEO /* Calcul de l'adresse vidéo de destination */
ldr r10,[r10] /* ici on récupère déja dans r10 l'adresse du buffer qui sera 0x06000000 ou 0x0600a000 */

mov r2,r7, lsl #8 /* ici on multiplie notre coordonée Y corrigée par 240 */
sub r2,r2,r7, lsl #4 /* et on l'ajoute à l'adresse de notre buffer vidéo */
add r10,r10,r2
cmp r3,#0 /*enfin, si notre coordonée X corrigée est supérieure à 0 */
addge r10,r10,r3 /* alors, on l'ajoute, sinon on laisse à 0 ( on ne va tout de meme pas plotter devant l'écran !!!!!) */




Acte 4

Bon, récapitulons:

Après ces quelques lignes de code, on a déja calculé pas mal de paramètres pour notre plotage de tiles, et on a donc maintenant:


r10: adresse vidéo d'écriture de notre tile
r3: coordonée X multiple de 4 de notre tile
r11 et r12 : nombre de décalage de bits à droite et à gauche à faire dans notre texture source pour aligner correctement la texture avec l'écran.
r1: hauteur du tile ( nombre de ligne à tracer, en principe 32 sauf si notre tile est à cheval sur le haut et le bas de l'écran )

Il reste encore un paramètre important à calculer, avant que l'on ne rentre véritablement dans la boucle d'affichage. On a vu que l'on voulait ploter les tile directement par paquet de 32 pixels.
On pourrait donc maintenant le faire, cependant, on aurait de joli bugs d'affichage pour les cas ou le tile est à cheval sur le coté droit ou gauche de l'écran.

Imaginons que l'on doivent plotter le tile à X= 232, il ne faut pas que l'on plotte 32 pixels, mais seulement 8 !! Idem, si la coordonée est = -8, on en ploteras que 24.

On est donc devant un beau casse tete, d'autant, qu'il existe si on fait bien les compte 17 cas de figure différents:

-1er cas: le tile est completemnt dans l'écran.
-8 cas ou le tile est à cheval sur le bord gauche de l'écran ( 4,8,12,16,20,24,28 ou 32 pixels ) à plotter.
-8 cas ou le tile est à cheval sur le bord droit de l'écran....

Il est évident, vu que l'on veut une routine d'affichage rapide..., que l'on ne vas pas y'aller en bourrin à faire 17 tests....

On va donc rester serein, et commencer par calculer dans quel cas on se trouve, et ça on peut le faire en quelques lignes d'assembleur

allons y !!:)



SUITE_TILE: mov r4,#0 /* r4 contiendra l'info sur le cas dans lequel on se trouve*/
bge CAS_POSITIF /* on se réfere ici à notre test précédent ou on testait le signe de r3, notre coordonée d'affichage en x. */


/* si r3 est négatif, dans ce cas, on initialise r4 ( qui contiendra notre cas ) à une
valeur comprise entre 1 et 8. Pour ce faire, on transfere dans r4 la valeur absolue de r3
( qui est négatif ), grâce à l'instruction rsb.
rsb permet de soustraire d'une constante un registre.
ici on soustrait r3 de 0 et on met le résultat dans r4 ( r4=0-r3)
on divise ensuite r4 par 4, avec un décalage binaire de 2 bits vers la droite pour
avoir une valeur entre 1 et 8 ( puisque r3 était un multiple de 4 de 1 à 32...:rolleyes: ) */


CAS_NEGATIF: rsb r4,r3,#0
mov r4,r4, lsr #2
b STORE_TILE


/* si r3 est positif, dans ce cas, on initialise r4 ( qui contiendra notre cas ) à une
valeur comprise entre 9 et 16 ou 0 !!
En effet, si r3<208, alors on laisse notre cas à 0, cela signifie que notre tile sera
affiché normalement, car il n'est pas à chavel sur un bord d'écran.
Sinon, on regarde combien on a de pixels à plotter ( en regardant de combien on dépasse
x=208, et comme tout à l'heure on divise par 4 avace décalage de 2 bits vers la droite, ce qui donne une avleur entre 0 et 7.
On ajoute ensuite 9, car on veut une valeur entre 9 et 16


CAS_POSITIF: cmp r3,#208
subge r4,r3,#208
movge r4,r4, lsr #2
addge r4,r4,#9



A ce stade , le registre r4 contient maintenant une valeur comprise entre 0 et 16 qui correspond à toutes les possibilités d'affichage ! Si on regarde tous les cheminements possibles du code, on met pas plus de 5 ou 6 instructions asm pour faire ça.... et ce calcul restera acquis pour les 32 lignes d'affichage du tile:)


Pour la fin de l'acte 4, juste une dernière ligne de code.

La suite du code va nécéssiter l'utilisation de nombreux registres, et on en a malheureusement pas un nombre infini à notre disposition.

On va donc"compresser" dans un meme registre le contenu de 2 autres, que l'on extraiera par la suite selon nos besoin ( on verra plus tard )




STORE_TILE: orr r14,r5,r4, lsl #16 /* mix dans r14 info fliping et case */




le registre r14 contient maintenant dans la partie droite la valeur du registre r5 ( qui valait 1 ou 0 , c'est notre info sur le fliping horizontal du tile ), et dans sa partie gauche la valeur du registre r4 ( qui a une valeur entre 0 et 16 )

Cela n'est bien sur possible car l'on sait que chaque registre n'utilisait en réalité qu'une valeur utile de 16 bits maximum chacun...:whst:

Voilà, c'est tout pour cette fois, mais reposez vous les neurones, car ça va secouer un peu plus dans la prochaine partie ou l'on rentre enfin dans la boucle d'affichage et on commencera par le fliping horizontal des tiles !!:D


Acte 5

Bien, bien, après cette partie d'initialisation, on passe vraiment à la boucle d'affichage proprement dite. ( la partie qui intéresse le plus Pitt !! )

Notre boucle va se répetter autant de fois qu'on a de ligne a tracer, donc pour un tile au milieu de l'écran 32 ligne, et moins si notre tile est à cheval sur un bord de l'écran en haut ou en bas, mais ça on l'a déja calculé precedemment.

-Dans cette boucle on va:

- charger nos 32 pixels à plotter, si besoin les flipper si l'on a à faire à un tile qui est flippé horizontalement ( et pour cela on teste notre info de flipping )

- faire scroller notre texture à l'intérieur des registre d'autant de pixel qu'il le faut pour etre aligné avec une adresse multiple de 4, grâce aux index de décalage qu'on a calculé precedemment.

- brancher notre routine sur l'un des 15 cas possible d'affichage

- et enfin afficher nos 32 pixels.


Tout dabords, le flipping:
si l'on considere nos 32 pixels numérotés de 1 à 32, voilà comment ils vont etre répartis dans les registres r0 à r7:

r0 : p1,p2,p3,p4
r1 : p5,p6,p7,p8
r2 : p9,p10,p11,p12
r3 : p13,p14,p15,p16
r4 : p17,p18,p19,p20
r5 : p21,p22,p23,p24
r6 : p25,p26,p27,p28
r7 : p29,p30,p31,p32

En cas de flip horizontal, on veut donc inverser l'ordre d'affichage, et afficher de gauche à droite les pixels 32 à 1 et non plus 1 à 32

On s'appercoit donc qu'on va devoir swapper le registre r0 avec r7, r1 avec r6, r2 avec r5, r3 avec r4

....et à l'intérieur de chaque registre il faudra également swapper les 4 pixels, pour arriver finalement au résultat suivant :

r0 : p32,p31,p30,p29
r1 : p28,p27,p26,p25
r2 : p24,p23,p22,p21
r3 : p20,p19,p18,p17
r4 : p16,p15,p14,p13
r5 : p12,p11,p10,p9
r6 : p8,p7,p6,p5
r7 : p4,p3,p2,p1


la permutation des registres ne pose pas de soucis, là ou ça se corse, c'est la permutation des 4 pixels à l'intérieur de chaque registre. La solution dans le code plus bas, ou l'on voit que la permutaion des valeurs 8 bits dans 1 registre peut se faire en 3 instructions...


La phase suivante de scrolling de la texture dans les 8 registres vers la gauche, va donc nécéssiter l'utilisation d'un 9em registre. Et oui, si l'on décale 1 registre vers la gauche, il faut bien que l'on récupere les pixels "perdus" dans un 2em registre.

l'exemple suivant permettra de mieux comprendre.

si on considere le registre r1 avec les pixels p0,p1,p2,p3 et le registre r2 avec les pixels p4,p5,p6,p7

On veut par exemple faire scroller les pixels de 2 unités vers la gauche, on aura à la fin :

r0: ?,?,p0,p1
r1: p2,p3,p4,p5
r2: p6,p7,?,?

On aura eu donc recour au registre r0 pour récupérer les pixels p0 et p1 !

Dans le code ci-dessous, on passe en fait de 8 registres r0 à r7 à 9 registres r0 à r8.

Ce qu'il faut noter dans cette phase , c'est que les instruction de décalage ne sont pas faite avec des constante, comme par exemple un mov r7,r7, lsl #16, mais le nombre de décalage est fait par un registre: mov r7,r7, lsl r11, ce qui veut dire si r11 contient par exemple la valeur #16, fait un décalage vers la gauche de 16 bits.


Voilà, rendez vous demain pour le dernier acte, qui va concerner le branchement en fonction de nos différents cas d'affichage. Le code source complet du programme sera aussi en téléchargement à partir de demain !




BOUCLE_AFFICHAGE:stmfd sp!,{r0,r1,r9} /* Point de départ de la boucle, on empile 3 registres


ldmia r9,{r0-r7} /* on charge nos 32 pixels dans les registres r0 à r7 à partie de l'adresse source de la texture pointée par r9

tst r14,#1 /* on teste notre info de flipping */
beq NO_TILE_FLIPING /* si pas de flip alors on passe */

TILE_FLIPING: mov r8,r7 /* 1) phase de permutaion des registres
mov r7,r0
mov r0,r8

mov r8,r6
mov r6,r1
mov r1,r8

mov r8,r5
mov r5,r2
mov r2,r8

mov r8,r4
mov r4,r3
mov r3,r8


mov r8,#0xff00 /* 2) phase de permutations des pixels à l'intérieur de chaque registre */
orr r8,r8,r8, lsl #16 /* ou l'on se sert d'un masque inittialisé dans r8 à 0xff00ff00

and r9,r8,r0, ror #16 /* permutation des pixels dans les 8 registre grace à une combinaison and,and,orr mixée avec des rotations...
and r0,r8,r0, ror #8
orr r0,r0,r9, lsr #8

and r9,r8,r1, ror #16
and r1,r8,r1, ror #8
orr r1,r1,r9, lsr #8

and r9,r8,r2, ror #16
and r2,r8,r2, ror #8
orr r2,r2,r9, lsr #8

and r9,r8,r3, ror #16
and r3,r8,r3, ror #8
orr r3,r3,r9, lsr #8

and r9,r8,r4, ror #16
and r4,r8,r4, ror #8
orr r4,r4,r9, lsr #8

and r9,r8,r5, ror #16
and r5,r8,r5, ror #8
orr r5,r5,r9, lsr #8

and r9,r8,r6, ror #16
and r6,r8,r6, ror #8
orr r6,r6,r9, lsr #8

and r9,r8,r7, ror #16
and r7,r8,r7, ror #8
orr r7,r7,r9, lsr #8



NO_TILE_FLIPING: mov r8,r7, lsr r12 /* scrolling de la texture dans les registres */

mov r7,r7, lsl r11
orr r7,r7,r6, lsr r12

mov r6,r6, lsl r11
orr r6,r6,r5, lsr r12

mov r5,r5, lsl r11
orr r5,r5,r4, lsr r12

mov r4,r4, lsl r11
orr r4,r4,r3, lsr r12

mov r3,r3, lsl r11
orr r3,r3,r2, lsr r12

mov r2,r2, lsl r11
orr r2,r2,r1, lsr r12

mov r1,r1, lsl r11
orr r1,r1,r0, lsr r12

mov r0,r0, lsl r11


Acte 6


:D Bon, aprés une courte interruption ( joke inside ), suite et fin de cette routine d'affichage de tiles software en mode 4 !!

On a donc à cet stade dans nos registre r0 à r8 notre ligne de texture correctement flippée si nécéssaire et décalée comme il faut pour corrspondre à une adresse de storage multiple de 4.

On sait également que dans la partie gauche du registre r14, on a l'info de notre cas d'affichage , et en fonction de cette info, on va brancher le programme sur une des 15 routines d'affichage qui correspond au cas qui nous intéresse.
On va donc faire une sorte d'équivalent en C à un switch/case, à la différence énorme que l'on ne vas faire AUCUN TEST pour brancher sur la routine voulue, ce qui nous permet d'économiser un temps cpu considérable.

Pour ce faire , on va "jouer" avec le registre r15, ( pc ) qui est notre programme counter. Ce registre contient en permanence l'adresse de la prochaine instruction qui doit etre éxécutée par le cpu. L'astuce consiste donc à modifier ce registre r15 pour lui indiquer "ou aller" à la prochaine instruction. Si vous jetez un coup d'oeil au bout de code ci dessus, on s'apercoit que chacune des 15 routines fait 4 instructions. On sait que chaque instruction arm est codée sur 32 bits, soit 4 octets, donc chaque routine de 4 instruction occupe donc 8*4= 32 octets.

On commence donc à isoler notre info sur la routine à éxécutée contenue dans la partie gauche de r14, et on met dans r9

mov r9,r14, lsr #16

on ajoute ensuite à notre r15, cette valeur multipliée par 16 ( x4 pour le nombre de ligne ASM et x4 pour le fait q'une instruction=4 octets ), r15 contient maintenant l'adresse ou il doit sauter à la prochaine instruction:

add pc,pc,r9, lsl #4

....et voilà le tour est joué, en 2 lignes d'asm, on a fait un branchement conditionné à l'état d'une valeur.... pas besoin de faire une suite de

cmp r14,#0
beq .......
cmp r14,#1
beq......

etc....

...et c'est encore plus rapide que la lecture d'une table de saut , puisqu'il n'ya pas de valeur à lire dans une table.:p

Bien sur cette technique ne s'applique que dans le cas ou chaque routine fait strictement le meme nombre d'instruction. M'enfin meme si c'est pas le cas , y'a toujours moyen de contourner en branchant de cette facon sur une table d'instruction qui renverra elle meme ensuite à la bonne adresse......B)

Voilà, vous pouvez voire enfin que chaque routine individuelle, n'est que le storage de nos 32 pixels, en tenant compte des pixels présents à l'écran pour ne pas écraser les pixels devant le tile.
A la fin de chaque routine de plotage on branche ensuite vers le label END_CASE: ou l'on va mettre à jour toutes nos variable pour afficher la ligne suivante du tile.

On met à jour l'adresse d'écriture dans notre buffer vidéo ( registre r10), on décrémente le nombre de ligne à afficher ( registre r1 ).... et enfin on met à jour également notre adresse de lecture dans notre texture source ( registre r9 )

C'est donc là, qu'on s'occupe du flipping vertical du tile !! en effet, sans flipping, on aurait mis à jour simplement en ajoutant la valeur #256 , car la page de texture fait 256 pixels de large.

Donc, pour descendre d'une ligne dans la texture, on ajoute #256, et si on veut remonter ( flip vertical ), alors on ajoute #-256 .

Et comme on veut pas faire de tests, on a initialisé avant dans le registre r0 , avant d'entrer dans la routine, la valeur adéquate ( #256 ou # -256 )

et on a donc la ligne add r9,r9,r0 ( tu vois Pitt, je te l'avais dit qu'on faisait le flip vertical en une seule ligne :D )

Ci dessous la suite et donc la fin de cette routine d'affichage de tile software .

Voilà donc la fin de ce petit tuto d'initiation à l'assembleur et au mode 4, j'espere qu'il aura pu vous être unpetit peu utile, ou que au moins cela vous aura intéréssé.

a bientot pour de prochaines aventures !!:)





CALCUL_BRANCHEMENT_CASE: mov r9,r14, lsr #16

add pc,pc,r9, lsl #4
nop /* instruction dummy pour occuper 32 bits */


CASE_0: ldr r9,[r10]
orr r0,r0,r9 stmia r10,{r0-r8}
b END_CASE


CASE_1: ldr r9,[r10]
orr r1,r1,r9
stmia r10,{r1-r8}
b END_CASE


CASE_2: ldr r9,[r10]
orr r2,r2,r9
stmia r10,{r2-r8}
b END_CASE


CASE_3: ldr r9,[r10]
orr r3,r3,r9
stmia r10,{r3-r8}
b END_CASE

CASE_4: ldr r9,[r10]
orr r4,r4,r9
stmia r10,{r4-r8}
b END_CASE


CASE_5: ldr r9,[r10]
orr r5,r5,r9
stmia r10,{r5-r8}
b END_CASE


CASE_6: ldr r9,[r10]
orr r6,r6,r9
stmia r10,{r6-r8}
b END_CASE


CASE_7: ldr r9,[r10]
orr r7,r7,r9
stmia r10,{r7-r8}
b END_CASE


CASE_8: ldr r9,[r10]
orr r8,r8,r9
str r8,[r10]
b END_CASE


CASE_9: ldr r9,[r10]
orr r0,r0,r9

stmia r10,{r0-r7}
b END_CASE


CASE_9A: ldr r9,[r10]
orr r0,r0,r9

stmia r10,{r0-r6}
b END_CASE


CASE_10: ldr r9,[r10]
orr r0,r0,r9

stmia r10,{r0-r5}
b END_CASE


CASE_11: ldr r9,[r10]
orr r0,r0,r9
stmia r10,{r0-r4}
b END_CASE

CASE_12: ldr r9,[r10]

orr r0,r0,r9
stmia r10,{r0-r3}
b END_CASE


CASE_13: ldr r9,[r10]

orr r0,r0,r9
stmia r10,{r0-r2}
b END_CASE


CASE_14: ldr r9,[r10]

orr r0,r0,r9
stmia r10,{r0-R1}
b END_CASE

CASE_15: ldr r9,[r10]
orr r0,r0,r9
str r0,[r10]
NOP



END_CASE: ldmfd sp!,{r0,r1,r9}
add r9,r9,r0
add r10,r10,#240 subs r1,r1,#1
bne BOUCLE_TILE

ldmfd sp!,{r15}

Pitt
10/10/2006, 16h54
....voilà voilà, la suite bientot, en esperant que ça pourra vous interresser et que ça vous donne un petit coup de main si vous vous lancer dans le mode 4 et l'asm.

Je me sens visé :p
Par contre, c'est normal que ça tourne à 72% (grand max) dans VBA ?
Sinon, bah bien sur que j'attends ça avec impatience :D

EDIT: rien dit :

..... en 60 fps bien sur !

:ph34r:

Brunni
10/10/2006, 17h08
Huhu tout un programme en perspective :) Vivement la suite et merci beaucoup pour l'initiative ;)

Dr.Vince
10/10/2006, 21h19
merci pour le tuto

Acid burns
11/10/2006, 11h28
MIKEGBA ce tuto est vraiment EXCELLENT merci pour cette initiative ;)

Pitt
11/10/2006, 22h03
:w00t: merci ! Ce tuto est vraiment génial, continue comme ça !

Je voudrais juste savoir un truc concernant les suffixes :

Si je fais ça :

.loop:
cmp r1, r2
subge r1, r1, r2
addge r3, r3, #1
bge .loop

sub r1, r1, r2 et add r3, r3, #1 vont bien s'exécuter tant que r1 est plus grand que r2 ?

Et puis aussi, je n'ai pas très bien compris le stmfd sp!,{r14} Tu pourrais réexpliquer, stp ?

MIKEGBA
11/10/2006, 23h03
:w00t: merci ! Ce tuto est vraiment génial, continue comme ça !

Je voudrais juste savoir un truc concernant les suffixes :

Si je fais ça :

.loop:
cmp r1, r2
subge r1, r1, r2
addge r3, r3, #1
bge .loop

sub r1, r1, r2 et add r3, r3, #1 vont bien s'exécuter tant que r1 est plus grand que r2 ?

Et puis aussi, je n'ai pas très bien compris le stmfd sp!,{r14} Tu pourrais réexpliquer, stp ?

bon, alors on va un peu parler de la façon dont fonctionne vraiment les conditions ( avant la suite du tuto vers minuit.....:D )


Alors, l'arm7 possede un registre qu'on apelle le CPSR, le registre r16 .

Ce registre contient dans les bits 28 à 31 des flags de condition qui sont allumé ou éteint à chaque fois que tu fais une comparaison ou un test, par exemple ton instruction cmp r1,r2 qui compare r1 à r2.

A chaque fois que ton cpu éxécute une instruction conditionée , comme par exemple un subge, pour savoir si il doit l'éxécuter , il va "regarder" les flags de conditions du registre r16.

Ces flags, tu peux les voir dans vba, quand tu fais "disassemble", ce sont les flags apelés Z,C,N et V qui correpondent donc au bit 28 à 31 de r16.


Donc pour ton exemple, quand tu fais cmp r1,r2, le cpu va allumer ou éteindre les flag z,c,n et v contenus dans le registre r16.

Tant que tu ne refais pas d'autres comparaison, ces flags restent inchangés, donc tu peux te resservir du résultat de cette comparaison autant de fois que tu veux, meme 15 lignes plus tard.... tant que tu ne fais rien qui ne modifie l'état des flag du registre r16 ...:whst: sinon, attention les dégats:D


Pour l'instruction stmfd sp!,{r14} , c'est pas compliqué

sp, c'est en fait le registre r15, ce registre est en fait un pointeur qui indique l'adresse de la pile.

r14, apellé aussi lr ( pour Link Register ), est un registre comme les autres dont on se sert souvent pour connaitre l'adresse de retour de fin de fonction.

ainsi , quand tu fais bl TOTO, tu indique à ton programme d'aller au label TOTO, mais en meme temps ça sauvegarde dans r14 l'adresse de retour, si on compare au langage BASIC, c'est un GOSUB !

à la fin de ta fonction TOTO, pour revenir là ou tu en étais, tu n'auras plus qu'à mettre l'instruction bx lr ( ou bx r14 ), ce qui signifie branche à l'adresse indiquée par le registre r14.

Sauf que tu verras que dans la fonction AFFICHETILE, je vais avoir besoin d'utiliser TOUS les registres disponible, dont r14, donc je le sauvegarde dans la pile, et je n'aurais plus qu'à le dépiler à la fin de ma fonction AFFICHETILE pour le restaurer.

pour empiler, on utilise donc l'instruction stmfd sp!,{r14} et pour dépiler je ferais ldmfd sp!,{r14}

le point d'exclamation sert à incréménter / ou décrémenter l'adresse de la pile à chaque fois que tu empile ou dépile.

dienben
12/10/2006, 11h24
Hello,

Félicitation et un grand merci pour ce tuto!

Par contre, petite question: y a t il vraiment une utilité à programmer en assembleur (autre que pour le plaisir de coder :ange: ). Je m'explique: au vue de la complexité du truc, connaissez vous des jeux qui se permettent ce type d'approche?

Excusez moi si ma question vous parais stupide...

En tout cas un grand bravo, çà m'a dérouillé de jeter un oeuil au code (çà fais presque 4 ans que je n'ai pas fait d'assembleur)...

A + et bonne continuation!

Dienben

Lestat
12/10/2006, 14h47
bah oui, celui qu'a fait mike par exemple (le petit jeu de course que j'ai pas encore trouvé et qui devait sortir en juillet...)

Bah, comme approche c'est plutôt sympa, et sur l'ancien pa il y a aussi un space invader que mike avait fait...c'est livré avec les sources aussi :)

(pis bonjour, et merci au passage ^^)

"passage : merci à toi aussi :)"

Pitt
12/10/2006, 23h06
sp, c'est en fait le registre r15, ce registre est en fait un pointeur qui indique l'adresse de la pile.

:huh: Ca serait pas plutôt r13 ? Je croyais que r15 c'était pc, r14 lr et r13 sp, non ?

pour empiler, on utilise donc l'instruction stmfd sp!,{r14} et pour dépiler je ferais ldmfd sp!,{r14}

OK, d'accord. En fait, je connaissais pas du tout la pile, donc forcément =_= . Juste une précision : à quoi correspond fd ? à quoi correspondent les autres suffixes ?

Bon, bah sinon, encore merci pour ton tuto, c'est vraiment génial. A part ça, je suis en train de bosser sur une fonction de tracé de lignes type Bresenham. En as-tu déjà fait une ? Parce que si oui, j'aimerais bien qu'on compare les deux (quand j'aurais fini ... >_< ) pour voir si je commence à me dépatouiller avec l'assembleur.

Bon aller ! Encore une petite dernière pour la route ... Y-a-t-il un coprocesseur sur la GBA ? Si oui, à quoi sert-il et comment peut-on l'utiliser ?

Ca y est ! J'ai épuisé mon stock de questions tordues ... :D J'attends la suite du tuto avec impatience :w00t:

thoduv
12/10/2006, 23h42
Bon aller ! Encore une petite dernière pour la route ... Y-a-t-il un coprocesseur sur la GBA ? Si oui, à quoi sert-il et comment peut-on l'utiliser ?
Y'a pas ! ^^
C'est sur DS qu'y'a un CP15 qui gère un peu les permissions mémoires, le cache et tout...

MIKEGBA
13/10/2006, 00h25
:whst: oui,oui, c'est bien r13 .... pas r15 !!

r15, c'ets bien le pc, dailleurs on va en reparler pour les sauts !!

tu vas voire, ça peut faire des trucs puissants, les manips sur r15 !:)

stmfd / ldmfd => ça définit le sens de la pile , montant ou descendant..... mais t'embrouille pas avec ça ;)

sinon , des lignes en bresenham, nan j'en ai pas fait !



...bon la suite du tuto bientot en ligne !!:)


@ Dienben : des jeux sur gba 100% asm:

vrally3, asterix xxl, stuntman, driver 3 et euh oui gt racers :rolleyes:

l'intéret ? ben oui, c'est des jeux qui bouffent tous un max de cpu ( 3d oblige ) et aussi le plaisir de coder.

Sur que sur DS, y'en aura plus des masses en ASM des jeux, vu la puissance de la console, mais moi je continue sur cette voie, meme si le temps de dev est un peu plus long .... :lol:

MIKEGBA
13/10/2006, 01h44
ACTE 3 du tuto mis à jour !!! voir post initial !!!

Pitt
13/10/2006, 09h22
OK. Merci à tous les deux ! Je vais jeter un oeil à ton tuto, mais je regarderais ça plus en détail ce soir.

EDIT! en fait, j'ai pas pu m'empêcher de regarder :D Bien balaise les masques de bits :blink: . Sinon, bah toujours aussi intéressant ^^

Pitt
15/10/2006, 19h08
Hello world !

J'aurais besoin d'une info : si je fais ça, ça fait quoi :D ?

strh r7, [r0], #2

Sinon, à quand la suite du tuto ?
Merci d'avance


Au fait MikeGBA, pour faire une division, on peut appeler le BIOS, non ? Avec un "swi 6", ça devrait le faire, mais faut voir à quelle vitesse par contre, j'ai pas testé.

Et puis sinon, la "doc arm re-ejected" qui est, je crois, spécialisée pour la GBA, parle des instructions du coprocesseur :blink: Vous êtes vraiment surs que la GBA n'a pas de coproc ?

thoduv
15/10/2006, 19h37
Et puis sinon, la "doc arm re-ejected" qui est, je crois, spécialisée pour la GBA, parle des instructions du coprocesseur :blink: Vous êtes vraiment surs que la GBA n'a pas de coproc ?

Sûr et certain ! :)

Pitt
15/10/2006, 19h41
Sur et certain ! :)

:D Bon bah tant pis alors ... ^^

MIKEGBA
15/10/2006, 21h04
Hello world !

J'aurais besoin d'une info : si je fais ça, ça fait quoi :D ?

strh r7, [r0], #2

Sinon, à quand la suite du tuto ?
Merci d'avance



hello !! strh r7,[r0],#2

alors, ça stoque les 16 premiers bits de r7 ( strh ) , h pour "halfword".

ça stoque donc les 16 prmiers bits de r7 à l'adresse désignée par le contenu de r0, et ensuite çà incrémente r0 de 2 unités ( add r0,r0,#2 )


ça équivaut à:

strh r7,[r0]
add r0,r0,#2

...mais optimisé en une seule instruction .


Sinon, la suite du tuto ce soir....tard ou demain matin !!:D


ps: je confirme çe qu'à dit thoduv, pas de coproc dans la gba.

Sinon, pour la division, oui l'appel aux focntion du bios ça marche, mais bon ça va si tu en as pas beaucoup par frame, car c'est pas très rapide.

Pitt
15/10/2006, 21h38
OK d'accord merci. J'avais trouvé ça dans une source de tracé de triangle, plus précisément dans l'algo de lignes horizontales.

Je suis justement en train de faire ce genre de truc et je galère depuis 2h à chercher de la doc sur le tracé de triangles :cry: ... Si quelqu'un a ça quelque part, ou même une astuce, qu'il hésite pas ^^

Sinon, vivement la suite de ton tuto ! Juste pour savoir, on aborde quand la partie "lire le keypad" ? :ange: Bon, allez, je te laisse bosser ^^

MIKEGBA
15/10/2006, 22h50
OK d'accord merci. J'avais trouvé ça dans une source de tracé de triangle, plus précisément dans l'algo de lignes horizontales.

Je suis justement en train de faire ce genre de truc et je galère depuis 2h à chercher de la doc sur le tracé de triangles :cry: ... Si quelqu'un a ça quelque part, ou même une astuce, qu'il hésite pas ^^

Sinon, vivement la suite de ton tuto ! Juste pour savoir, on aborde quand la partie "lire le keypad" ? :ange: Bon, allez, je te laisse bosser ^^


euh , lire le keypad.... c'est dans longtemps..... alors si t'en as besoin , c'est pas le plus compliqué, enfin voilà:


KEY_DOWN =128
KEY_UP=64

mov r0,0x4000000 /* initialise r0 sur l'adresse de base des registres hardware gba

ldr r1,[r0,#0x130] /* charge dans r1 la valeur du keypad ( registre 0x4000130 )
/* ici, #0x130 est un offset

si on veut ensuite tester si on a appuyé sur la touche bas ( KEY_DOWN)

tu fais un : ands r2,r1,#KEY_DOWN

j'ai mis un "S" après le and, car cela permet de faire un test en meme temps !

Donc ça revient à masquer le registre r2 avec la valeur #KEY_DOWN ( 128 ) , mettre le résultat dans r2 ( mais en fait ça on s'en fout ), ET SURTOUT ça initialise nos flags de conditions ( dont j'ai parlé precedemment ) en fonction du résultat.

si ensuite on veut par exemple ajouter 1 à une coordonée Y si on a appuyé sur la touche bas on ferait: ( si on suppose que r3 contient une coordonnée y )

addeq r3,r3,#1 /* si la condition est vrai, alors ajoute 1 à r3 */

je récapitule petit bout de code:


mov r0,#0x4000000
ldr r1,[r0,#0x130]
ands r2,r1,#KEY_DOWN
addeq r3,r3,#1

ands r2,r1,#KEY_UP
subeq r3,r3,#1

Pitt
16/10/2006, 19h11
Merci ^^ C'est sympa !
J'avais pas pigé que mettre ands (ou autre chose d'ailleurs ...) permettait de faire un test en même temps ... c'est balaise comme truc :blink: . Par contre, c'est bien le résultat de l'addition qui est testé ?

A part ça, il arrive quand l'acte 4 :-' ?



Je reviens avec mon lot de questions tordues :D :

* Y-a-t'il un moyen plus rapide que ça d' échanger 2 registres ?


eor r1, r1, r0
eor r0, r0, r1
eor r1, r1, r0


* Peut-on détecter, avec un subs r2, r1, r0 que r2 est plus grand OU EGAL à 0 ou plus petit que 0 ? En gros, y-a-t'il plus rapide que ça ?


sub r2, r1, r0
cmp r2, #0
movle r3, #0
subgt r3, r2, #1


* A quoi correspondent les suffixes que l'on peut ajouter à ldm et stm ? En gros, ils permettent de choisir si on incrémente/décrémente avant/après depuis la pile/autre chose, c'est ça ou je suis très loin :D ? (vive l'explication foireuse ... :whst: )

MIKEGBA
16/10/2006, 20h41
Merci ^^ C'est sympa !
J'avais pas pigé que mettre ands (ou autre chose d'ailleurs ...) permettait de faire un test en même temps ... c'est balaise comme truc :blink: . Par contre, c'est bien le résultat de l'addition qui est testé ?



Nooooon, malheureux !! ce qui est testé quand tu fais ands, c'est le résultat du and ! :)




* Y-a-t'il un moyen plus rapide que ça d' échanger 2 registres ?


eor r1, r1, r0
eor r0, r0, r1
eor r1, r1, r0




-> non , y'a pas plus rapide, pas possible en moins de 3 instructions.


* Peut-on détecter, avec un subs r2, r1, r0 que r2 est plus grand OU EGAL à 0 ou plus petit que 0 ? En gros, y-a-t'il plus rapide que ça ?


sub r2, r1, r0
cmp r2, #0
movle r3, #0
subgt r3, r2, #1


-> oui tu fais :


subs r2, r1, r0
movle r3, #0
subgt r3, r2, #1


l'acte 4 arrive ce soir un peu tard !:whst:

Pitt
16/10/2006, 22h09
Merci pour tes réponses ^^


Nooooon, malheureux !! ce qui est testé quand tu fais ands, c'est le résultat du and ! :)


Euh oui pardon :ph34r: le pire c'est que c'est ce que je voulais dire :D ...


l'acte 4 arrive ce soir un peu tard !:whst:


Nooooon !! Je pourrais le lire que demain soir :cry: :D :lol:

Nouvelle petite question:

Si je compare r0 et r1, et que j'ai 2 codes:

- un qui doit s'exécuter lorsque r1 > r0
- un qui doit s'exécuter lorsque r1 <= r0

Vaut-il mieux utiliser les conditions

ex.:
cmp r1, r0
movgt r3, r4
movgt r4, r5
...
movle r4, r5
movle r7, r6
...


ou des branchements conditionnels ?

ex.:
cmp r1, r0
ble autre
mov r3, r4
mov r4, r5
...

b suite

autre:

mov r4, r5
mov r7, r6
...

suite:


Et à partir de combien d'instructions par "code" est-il plus interessant d'utiliser des branchements ?

Je sais pas si j'ai été clair >_< ...

MIKEGBA
17/10/2006, 01h13
ACTE 4 EN LIGNE.....



Sinon Pitt, pour tes branchements conditionnels, si une conditions impose beaucoup de changements, alors préfère les branchement, si peu de changement ( 3 ou 4 ), alors tu initialise à la volée addmi, submi, etc....

Pitt
17/10/2006, 22h36
Un seul truc à dire: ce tuto est vraiment génial, continue comme ça ! ^^

Au fait, je viens de penser, tu vas les inclure comment les gfx ? Il y a des softs spécialisés ou bien tu convertis en .bin avant d'utiliser un incbin ?

..... et on verra par la suite qu'on aura une solution pour les stocker par paquets de 32 pixels, quelle que soit notre adresse de stockage.
Qu'est-ce que tu voulais dire par là ? Que quand on plotte par 32, on peut prendre une adresse impaire ? Ou que l'on peut plotter par 32 sur n'importe quelle adresse "valide" ?

Et sinon, j'avais juste pour les suffixes de ldm/stm ? :whst:

MIKEGBA
18/10/2006, 16h28
Qu'est-ce que tu voulais dire par là ? Que quand on plotte par 32, on peut prendre une adresse impaire ? Ou que l'on peut plotter par 32 sur n'importe quelle adresse "valide" ?



Non, quand tu fais un stmia r0,{r1-r9} ( qui sera la commande pour stoquer les pixels, on est logé à la meme enseigne que pour un str, l'adresse de destination doit toujours etre multiple de 4.

:D Mais relis bien l'acte 3 : Vu que l'on est obligé de ploter à une adresse multiple de 4 ( et ça on ne peut rien y faire ), alors je fait slider la texture dans les registres r1 à r9, ce qui revient à décaler les pixels et les aligner sur le x d'affichage désiré ( puisque l'inverse n'est pas possible ). Et pour savoir de combien il faut décaler les registres, j'ai donc calculé mes index de décalages.

La partie sur comment faire scroller la texture dans les registres, c'est pour bientot.

Mais relit la partie 3 , tu verras.:whst:

Pitt
18/10/2006, 16h41
>_< :whst: Je suis déjà dehors ...
Ok, ce coup-ci j'ai compris <_< ^^

MIKEGBA
18/10/2006, 16h57
>_< :whst: Je suis déjà dehors ...
Ok, ce coup-ci j'ai compris <_< ^^

:( non stp, sors pas !!! t'es déja casiment le seul fou a être rentré !!! :lol:

Pitt
18/10/2006, 18h03
:lol: C'est vrai que je dois être le seul dingue à trouver l'asm plus interressant que le C/C++ >_< Nan, t'inquiète pas, ça m'interresse toujours autant :D
Sinon, t'as vraiment pas envie d'en parler des suffixes de ldm/stm ? :ange: C'est tabou dans le dev asm ? :D Bon, je te laisse bosser sur l'acte 5, j'en ai besoin :devil: :p.

Pitt
18/10/2006, 22h08
Bon, j'aurais besoin de tes services :hum: :
En fait, j'ai trouvé un algo de tracé de polygones mais je n'arrive pas à le comprendre :huh: . Pourrais-tu m'expliquer en gros comment il fonctionne ? (C'est du Goldroad) :-'


@textarea $03000000

pfb_startadr @DCD pfb_start
pfb_stopadr @DCD pfb_stop

@textarea $02000000

pfb_start @dup dcb 160,0
pfb_stop @dup dcb 160,0

fillPoly

stmfd sp!,{r0-r4,lr}

ldr r0,[pfb_startadr]
ldr r1,[pfb_stopadr]

;**** fülle polygon

mov r2,#0
dlbu
ldrb r3,[r0],1
ldrb r4,[r1],1

cmp r3,#$ff
beq nov
cmp r4,#$ff
moveq r4,r3


bl drawHLine

nov
cmp r2,#160
add r2,r2,#1
bne dlbu

ldmfd sp!,{r0-r4,pc}


Ca serait vraiment sympa de ta part, parce que là je comprends que dalle ...
:(

MIKEGBA
18/10/2006, 22h43
ah oui, goldroad, très très bien cet assembleur, tu peux tout faire sur gba avec !

Sinon, ben pour ton bout de code, faudrait qu'on ait aussi le code de DrawHline pour le comprendre également savoir ce que sont ces 2 variables.

On a visiblement des coordonées de départ, d'arrivée, mais de koi ?



le bloc "nov", met à jour pour une nouvelle ligne et le bloc "dlbu" charge les parametres de la ligne et lance la routine DrawHline.


poste la routine DrawHline, ça permettra d'y voir plus clair. ;)

Brunni
18/10/2006, 23h01
Moi aussi ça m'intéresse, même si je ne poste pas parce que je n'ai pas trop le temps maintenant ;)
Merci bcp pour ces tutos ^^

Pitt
19/10/2006, 22h06
Merci pour tes réponses ! Je suis vraiment désolé de t'embêter avec ça, mais j'ai vraiment essayé de comprendre, ... rien à faire, j'y arrive pas :-' !

Voilà le code de drawHLine : si je ne m'abuse, c'est du mode 0 ; en tout cas, je comprends pas trop comment il calcule les points "opposés" à relier ... D'ailleurs, je vois pas trop à quoi sert le buffer ... c'est peut-être pour stocker les différents poly :cry: :(

;************************************************* **********
;*
;* draw HLine
;*
;* r2 = y
;* r3 - r4 = x1 - x2
;*
;* r7 = color
;*
;************************************************* **********


drawHLine
stmfd sp!,{r3-r6,lr}

cmp r4,r3 ;x1 <= x1
exgle r3,r4 ;swap
beq endHLine ;0 len

mov r6,#$6000000
add r6,r6,r3 lsl 1 ;+x*2
add r6,r6,r2 lsl 9 ;+y*256*2
sub r6,r6,r2 lsl 5 ;-y*16*2

;mov r5,#$ff
;orr r5,r5,#$3f00

dHPix
strh r7,[r6],2
cmp r3,r4
add r3,r3,#1
bne dhPix


endHLine
ldmfd sp!,{r3-r6,pc}

Si tu préfères, je peux te passer le source complet, ça irait peut-être plus vite >_<

Un truc qui m'étonne : il est, il me semble, assez long d'accéder à un emplacement mémoire avec l'asm ARM ; est-il vraiment judicieux d'utiliser un buffer complet placé en mémoire ?

Sinon, c'est vrai que Goldroad m'a l'air génial je vais examiner tout ça de plus près après ^^


Je l'ai rajouté, ça te sera peut-être plus utile ...

MIKEGBA
20/10/2006, 00h00
Ok.

Bon, ben c'est du mode bitmap , en mode 3.

c'est un mode 16 bits. Chaque point sur 16 bits, pas de palette.

Il utilise pas de buffer, il plotte directement les points... 1 par 1.

r3 et r4 sont les coordonées en X à relier.

Il commence par les comparer pour voir le quel est à droite , le quel est à gauche, et au besoin il les swappe de façon à ce que r3 soit le point de gauche.

-il calcule ensuite l'adresse de début en fonction du Y ( registre r2 ): il multiplie 240*r2, le tout multiplié par 2 puisque chaque point occupe 16 bits., et il ajoute ça à l'adresse de début de la ram vidéo.


il entre ensuite dans sa boucle pour plotter les point 1 par 1 de x=r3 à x=r4.

il arrete quand r3=r4....

Il y'a déja moyen de gagner 1 instruction dans la boucle... ( soit déja 25% ), vu que sa boucle fait 4 instructions.




sub r3,r4,r3 ;calcul de la longueur de la ligne

dHPix
strh r7,[r6],2
subs r3,r3,#1
bne dhPix



...sans parler du fait que ça irait 2 fois plus vite en plottant par 2.:p

...sinon y'a la piste aussi du débouclage , pour éviter les subs / bne, qui vont faire perdre pas mal de temps sur les grandes lignes.

EDIT le matin à tête reposée !:D

Bon alors Pitt, prends exemple sur ce code pour tout ce qu'il ne faut pas faire pour dessiner des triangles !!!:lol:

Effectivement, il utilise un buffer pour stoquer dans un tableau les coordonnées x de début et fin de ligne d'un poly complet..... pour ensuite relire ce tableau au moment de tracer les lignes -> c'est une très grosse perte de temps. Je te déconseille aussi d'utiliser les divisions du bios pour calculer les deltas , préfere les multiplications par des inverses ( avec un tableau d'inverse ).

Pareil, sinon, pour chaque boucle, préfere compter de -1 en -1 au lieu de +1 en +1 pour éviter de faire un add, suvi d'un cmp et d'un bne ( voir boutr de code plus haut ).

Pitt
20/10/2006, 20h15
:blink: OK bon bah finalement je vais me débrouiller sans, parce que si je m'inspire de ça, ça risque de pas être terrible <_< M'a l'air d'un bon bourrin le mec :lol: . Merci beaucoup de tes conseils, je vais voir ce que je peux faire ... ^^

Juste un truc (:D), y-a t'il une méthode simple (enfin rapide ^^ ) pour trier 3 duos de registres dans l'ordre décroissant ? :ph34r: En gros, j'ai dans 6 registres les coordonnées de 3 points et je voudrais les trier par y décroissant. >_<
Bon, j'ai commencé vite-fait une fonction, et c'est du genre 6-7 branchements et beaucoup de eor :ph34r: . Je vais la poster dès que j'aurais fini, pour que tu me dises ce que tu en penses :rolleyes: .

MIKEGBA
20/10/2006, 20h22
:blink: OK bon bah finalement je vais me débrouiller sans, parce que si je m'inspire de ça, ça risque de pas être terrible <_< M'a l'air d'un bon bourrin le mec :lol: . Merci beaucoup de tes conseils, je vais voir ce que je peux faire ... ^^

Juste un truc (:D), y-a t'il une méthode simple (enfin rapide ^^ ) pour trier 3 duos de registres dans l'ordre décroissant ? :ph34r: En gros, j'ai dans 6 registres les coordonnées de 3 points et je voudrais les trier par y décroissant. >_<
Bon, j'ai commencé vite-fait une fonction, et c'est du genre 6-7 branchements et beaucoup de eor :ph34r: . Je vais la poster dès que j'aurais fini, pour que tu me dises ce que tu en penses :rolleyes: .

ok, vas y poste ça, mais bon pour afficher un poly, t'as juste besoin de trouver le point le plus haut, les autres point y'a pas besoin de les classer...

Sinon, je te conseille de bosser avec des index, tu tries des index, pas des paires de coordonées completes.

Pitt
20/10/2006, 21h30
ok, vas y poste ça, mais bon pour afficher un poly, t'as juste besoin de trouver le point le plus haut, les autres point y'a pas besoin de les classer...

Comment ça seulement le point le + haut ? Je vois pas comment parcourir le triangle sans avoir trié les points :ph34r: :-'
Parce que je comptais faire ça:
* trouver les points haut, milieu, bas.
* parcourir haut-milieu et stocker chaque coordonnée (dans la pile ?)
* idem pour milieu-bas
* parcourir bas-haut et relier cha que point au point précédemment stocké (dépiler ?)

Tu as plus rapide :blink: ?

Sinon, je te conseille de bosser avec des index, tu tries des index, pas des paires de coordonées completes.

euh ... ... ... c'est quoi des index :ph34r: ? :D

Sinon voilà mon "trieur" (légèrement optimisé depuis la dernière :lol: ) :

@ Avec:
@ r0, r1, r2 : x0, x1, x2
@ r3, r4, r5 : y0, y1, y2

TRIER_POINTS:

cmp r3, r4
eorlt r3, r3, r4
eorlt r4, r4, r3
eorlt r3, r3, r4
eorlt r0, r0, r1
eorlt r1, r1, r0
eorlt r0, r0, r1

cmp r4, r5
eorlt r4, r4, r5
eorlt r5, r4, r4
eorlt r4, r4, r5
eorlt r1, r1, r2
eorlt r2, r1, r1
eorlt r1, r1, r2

cmp r3, r4
eorlt r3, r3, r4
eorlt r4, r4, r3
eorlt r3, r3, r4
eorlt r0, r0, r1
eorlt r1, r1, r0
eorlt r0, r0, r1

Pitt
25/10/2006, 19h49
Je up pour savoir où tu en es dans la rédaction de la suite du tuto ? :D

MIKEGBA
26/10/2006, 21h24
Je up pour savoir où tu en es dans la rédaction de la suite du tuto ? :D

:D Hello demain soir la suite !!!

...suis pas mal occupé en ce moment !:w00t:

...sinon pour tes triangles :

quand je parlais d'index, c'était justement pour éviter de faire un tri à la fois de tes X et de tes Y.

si tu veux vraiment trier tes points du plus haut au plus bas , tu n'a qu'à comparer les y , comme tu le fais déja dans ton petit bout de code, mais ensuite t'es pas obligé de swapper tous tes registres qui contiennent les X et les Y, tu swappes juste des index qui font référence à tes coordonées.

Sinon, je t'assure que tu as juste à chercher le point le plus haut pour afficher un triangle. Heureusement dailleurs, car imagine quand tu passeras au Quads, voire meme des polys à 5 ou 6 points ( ce qui arrivera quand tu auras des polys à cheval sur des bords d'écran ), le temps cpu nécéssaire au tri complet de 4 ou 5 points va condidérablement augmenter....

Voili , voilo, alors la suite du tuto demain soir !!;)

Pitt
26/10/2006, 22h56
Hello !

Ca fait plaisir de te revoir :D ! Vivement demain soir alors (P.S.: t'as pas de vacances =_= >_< ). En fait, je veux bien te croire pour les triangles, ... mais je vois pas comment faire :p ! C'est pas grave, j'y arriverais, ... un jour ! Sinon, je vois ce que tu appelles index. J'y pensais, mais je savais pas que ça s'appellait comme ça ^^ .

MIKEGBA
27/10/2006, 23h05
tuto Mis A Jour !!!:D

Pitt
28/10/2006, 12h59
Bon je passe en coup de vent pour te dire que j'ai bouffé mon forfait bas débit >_< donc t'inquiète pas si il n'y a pas de commentaires :p (je pourrais pas me reconnecter avant mercredi >_< ). Mais je vais quand même le lire hors connection =_= ...
A+

Pitt
01/11/2006, 11h40
Hello, me revoilà :devil: !

Bon concernant la suite du tuto, c'est génial (merki encore ^^ ) ; par contre, tu n'aurais pas oublié le flip vertical ? Il me semble que tu en parlais dans l'acte I, non ? :ange: Tiens, tant qu'on y est, est-ce que tu pourrais (après, c'est pas pressé ^^ ) faire un petit bilan sur le nombre de cycles que prennent chaque instruction, histoire de voir jusqu'où on peut optimiser :devil: ...

A part ça, j'ai compris à quoi servait réellement l'assembleur ... j'ai regardé ce que GCC produisait comme code assembleur ... :blink: :blink: :blink: :berk: . Il doit pas connaitre les registres, il utilise que la mémoire :p (d'ailleurs, c'est quoi fp, c'est un registre ?) Ma version de la même fonction doit être 2 fois plus petite/rapide, et pourtant ... :lol:

Sinon, pour l'orientation du tuto, jusqu'où pourrait-t-on pousser notre background "software" ? Pourrait-t-on lui appliquer des rotations/redimensionnements ? :ph34r: Et pourrait-t-on en gérer plusieurs, avec transparence ? :whst:

Sinon, queston subsidiaire, le Thumb est-il vraiment utile ? On voit souvent ROM/EWRAM = Thumb, IWRAM = Arm ... C'est pas un peu réducteur ? :lol:

Bon voilà, c'est à peu près tout :lol: M'enfin c'est déjà pas mal :p .

MIKEGBA
01/11/2006, 13h13
Hello, me revoilà

Bon concernant la suite du tuto, c'est génial (merki encore ^^ ) ; par contre, tu n'aurais pas oublié le flip vertical ? Il me semble que tu en parlais dans l'acte I, non ? :ange: Tiens, tant qu'on y est, est-ce que tu pourrais (après, c'est pas pressé ^^ ) faire un petit bilan sur le nombre de cycles que prennent chaque instruction, histoire de voir jusqu'où on peut optimiser :devil: ...

A part ça, j'ai compris à quoi servait réellement l'assembleur ... j'ai regardé ce que GCC produisait comme code assembleur ... :blink: :blink: :blink: :berk: . Il doit pas connaitre les registres, il utilise que la mémoire :p (d'ailleurs, c'est quoi fp, c'est un registre ?) Ma version de la même fonction doit être 2 fois plus petite/rapide, et pourtant ...

Sinon, pour l'orientation du tuto, jusqu'où pourrait-t-on pousser notre background "software" ? Pourrait-t-on lui appliquer des rotations/redimensionnements ? :ph34r: Et pourrait-t-on en gérer plusieurs, avec transparence ?

Sinon, queston subsidiaire, le Thumb est-il vraiment utile ? On voit souvent ROM/EWRAM = Thumb, IWRAM = Arm ... C'est pas un peu réducteur ? :lol:

Bon voilà, c'est à peu près tout :lol: M'enfin c'est déjà pas mal :p .

Hello Pitt !!

Ben non, j'ai pas oublié le flip vertical, ça vient à la fin du prochain acte, vu que y'a qu'une seule instruction dans la boucle pour ça !!:D ( oui,oui, je t'assure )

J'espère poster la dernière partie pour ce soir, mais faut vraiment que j'avance aussi sur mon dev :( :w00t:

Pour les rotations scaling du background, ben ç'est pas un soucis ça, le mode bitmap est un mode comme les autres et tu peux jouer avec les rotations/scalling hardware de la gba pour ça.

Pour le nbre de background: le code que tu vois la , c'est un code pour une première couche, c'est à dire que je m'occupe pas de ce qu'il y'a en dessous, je m'occupe juste de pas écraser les pixels du tile de gauche à ce lui qui est affiché ( les tiles de la map complete sont affichés de gauche à droite et de haut en bas )

Pour la transparance, avec un deuxieme bacground par dessus, faut juste modifier la routine de plot du background qui viendrait par dessus celui là ( faut tester les trous pour la transparance ), mais ça se fait sans soucis, si ce n'est le temps cpu. ça passerait encore à 60 fps, mais il ne resterait plus de temps cpu pour coder un jeu après ça, et on passerait donc à 30 fps pour un jeu complet.

-Je parle de backround transparant hein !!, pas de background avec de l'alpha :lol:

-Sinon, aussi à la limite du peux utiliser aussi les sprites hardware pour faire un 2em background ( j'avais fait ça dans qix.... je vais retrouver la rom :unsure: )


En ce qui concerne l'utilisation du thumb/arm, pour ma part je programme 100% en arm, que le code soit en IWRAM ou en ROM.

Mais en gros, on peut résumer ça comme ça:

-Les avantages du code arm, c'est que l'on dispose de plus de registres, et d'un jeu d'instruction ou l'on peut passer plus d'arguments en une seule instruction ( je te renvoie à la doc du cpu pour ça ).

-Le code arm est plus lent en ROM que le thumb car c'est un code 32 bits, alors que le bus de la ROM est sur 16 bits, donc pour charger une instruction arm 32 bits, il faut 2 cycles, alors que dans le meme temps on peut donc charger 2 instructions thumb qui sont elles sur 16 bits.

-Par cointre lorsque le code est placé en Iwram, vu que le bus est sur 32 bits, on revient à des temps de chargement identique entre arm et thumb, mais l'avantaage passe toutefois à l'arm dans ce cas grace à plus de registres dispo et d'arguments passables en une instruction.


Pour ma part j'ai choisi dans tous les cas une programmation en arm, car de toute façon tout ce qui est gros consommateur cpu, je le met en iwram, le reste qui est en général de la routine de "gestion", je le laisse en rom. Sur ce type de routine, je n'aurais de toute façon que très peu de temps cpu à regagner en passant en thumb sur la globalité de mon programme. Pour info par exemple, 90% du temps cpu dans gt racers se passe en iwram en gros. ça me permet aussi de garder une uniformité du code pour l'ensemble de mon programme.

Bon l'inconvénient du code arm , et ça dans tout les cas de figure ( rom ou iwram ), c'est qu'il prend donc 2 fois plus de place que le thumb, donc faut gerer ça aussi. ( surtout dans les 32 ko de l'iwram :D )

Voilà, à bientot... pour la dernière partie.

Pitt
01/11/2006, 14h33
Hello Pitt !!

Ben non, j'ai pas oublié le flip vertical, ça vient à la fin du prochain acte, vu que y'a qu'une seule instruction dans la boucle pour ça !!:D ( oui,oui, je t'assure )

:blink: :blink: :blink: Je demande à voir :D


J'espère poster la dernière partie pour ce soir, mais faut vraiment que j'avance aussi sur mon dev :( :w00t:

T'es vraiment sur de vouloir arrêter le tuto :cry: ? Ca serait vraiment dommage ...
Sans vouloir être trop curieux, quel dev ? :D

Pour les rotations scaling du background, ben ç'est pas un soucis ça, le mode bitmap est un mode comme les autres et tu peux jouer avec les rotations/scalling hardware de la gba pour ça.

Pour le nbre de background: le code que tu vois la , c'est un code pour une première couche, c'est à dire que je m'occupe pas de ce qu'il y'a en dessous, je m'occupe juste de pas écraser les pixels du tile de gauche à ce lui qui est affiché ( les tiles de la map complete sont affichés de gauche à droite et de haut en bas )

Pour la transparance, avec un deuxieme bacground par dessus, faut juste modifier la routine de plot du background qui viendrait par dessus celui là ( faut tester les trous pour la transparance ), mais ça se fait sans soucis, si ce n'est le temps cpu. ça passerait encore à 60 fps, mais il ne resterait plus de temps cpu pour coder un jeu après ça, et on passerait donc à 30 fps pour un jeu complet.

-Je parle de backround transparant hein !!, pas de background avec de l'alpha :lol:

:lol: Merki pour l'explication !

-Sinon, aussi à la limite du peux utiliser aussi les sprites hardware pour faire un 2em background ( j'avais fait ça dans qix.... je vais retrouver la rom :unsure: )


:w00t: Là aussi, je demande à voir ! :D

En ce qui concerne l'utilisation du thumb/arm, pour ma part je programme 100% en arm, que le code soit en IWRAM ou en ROM.

Mais en gros, on peut résumer ça comme ça:

-Les avantages du code arm, c'est que l'on dispose de plus de registres, et d'un jeu d'instruction ou l'on peut passer plus d'arguments en une seule instruction ( je te renvoie à la doc du cpu pour ça ).

-Le code arm est plus lent en ROM que le thumb car c'est un code 32 bits, alors que le bus de la ROM est sur 16 bits, donc pour charger une instruction arm 32 bits, il faut 2 cycles, alors que dans le meme temps on peut donc charger 2 instructions thumb qui sont elles sur 16 bits.

-Par cointre lorsque le code est placé en Iwram, vu que le bus est sur 32 bits, on revient à des temps de chargement identique entre arm et thumb, mais l'avantaage passe toutefois à l'arm dans ce cas grace à plus de registres dispo et d'arguments passables en une instruction.


Pour ma part j'ai choisi dans tous les cas une programmation en arm, car de toute façon tout ce qui est gros consommateur cpu, je le met en iwram, le reste qui est en général de la routine de "gestion", je le laisse en rom. Sur ce type de routine, je n'aurais de toute façon que très peu de temps cpu à regagner en passant en thumb sur la globalité de mon programme. Pour info par exemple, 90% du temps cpu dans gt racers se passe en iwram en gros. ça me permet aussi de garder une uniformité du code pour l'ensemble de mon programme.

Bon l'inconvénient du code arm , et ça dans tout les cas de figure ( rom ou iwram ), c'est qu'il prend donc 2 fois plus de place que le thumb, donc faut gerer ça aussi. ( surtout dans les 32 ko de l'iwram :D )

Voilà, à bientot... pour la dernière partie.

OK; bon bah t'as répondu à tout !!! :devil: :whst:
Merci beaucoup de ton aide.

MIKEGBA
20/11/2006, 20h56
:whst: Bon, suite et fin du tuto mis à jour dans le premier post !!:D

ps: avoue Pitt, t'y croyais plus hein !:lol:

Pitt
20/11/2006, 22h37
:whst: Bon, suite et fin du tuto mis à jour dans le premier post !!:D

ps: avoue Pitt, t'y croyais plus hein !:lol:

:blink: :blink: :blink:
T'ES PAS MORT ???
:p

Je me tatais justement de t'envoyer un MP :lol: M'en vais lire ça tranquillement ! ^^

P.S.: C'est quoi ton nouvel avatar ? C'est pas de la GBA, quand même ? :w00t:

thoduv
20/11/2006, 23h04
:P.S.: C'est quoi ton nouvel avatar ? C'est pas de la GBA, quand même ? :w00t:
Ouais je viens de voir ca aussi... Si c'est de la GBA... je me mets tout de suite à l'assembleur et je suis ce tuto ! :blink:

Pitt
20/11/2006, 23h09
Ouais je viens de voir ca aussi... Si c'est de la GBA... je me mets tout de suite à l'assembleur et je suis ce tuto ! :blink:

:lol:
MIKEGBA, si tu veux promouvoir l'asm, t'as plus qu'à répondre "oui" ... et c'est tout ! :)

[EDIT]Tu te mets au dev DS ? Nan parce vu que ton image s'appelle dsracing001 ... :w00t:

Pitt
23/11/2006, 20h28
Hello !

J'ai lu tout ça, et j'ai pas de questions (! :lol:) pour le moment. Juste un truc, tu pourrais nous laisser le source ? ^^
Sinon, je crois bien que j'ai compris le terme "puissance des manipulation sur pc" :lol: C'est à peu près combien de fois plus rapide qu'en C ton switch ? 3x ? :blink:

C'est bien dommage que le tuto soit terminé :( ... mais tu as bien dit "a bientot pour de prochaines aventures !!", non ? :devil: :whst: :lol:
Bon, bah bon courage pour ton dev (DS ? :p) ! ^^

@++

MIKEGBA
23/11/2006, 21h05
Hello !

J'ai lu tout ça, et j'ai pas de questions (! :lol:) pour le moment. Juste un truc, tu pourrais nous laisser le source ? ^^
Sinon, je crois bien que j'ai compris le terme "puissance des manipulation sur pc" :lol: C'est à peu près combien de fois plus rapide qu'en C ton switch ? 3x ? :blink:

C'est bien dommage que le tuto soit terminé :( ... mais tu as bien dit "a bientot pour de prochaines aventures !!", non ? :devil: :whst: :lol:
Bon, bah bon courage pour ton dev (DS ? :p) ! ^^

@++



Hello Pitt !

Pour le branchement en manipulant le pc, et bien plus le nombre de cas est important et plus le gain en vitesse par rapport à un switch sera important.

C'est bien sur moins flagrant la différence par rapport à des tables de saut.

Sinon, ce type de branchement est super utile pour des déroulages de boucles.


Tuto terminé ? en fait, d'un point de vue "formel", oui.... mais je pense que si tu as des questions sur l'asm ( enfin... les autres aussi ont le droit d'avoir des questions :D ), ça serait pas mal de les poser ici sur ce topic, ou si vous avez des astuces à faire partager, postez les là, et puis d'autre que moi peuvent aussi apporter des réponses :rolleyes: .

Donc voilà, ce topic peut continuer à vivre au fil de vos questions ou de vos techniques que vous voulez exposer.



ps: Mais dis donc Pitt, tu le vois ou le nom de l'image dans l'avatar ??:blink: Je vais devoir t'apeller Columbo maintenant !!! :lol:

Sinon, ben oui, ancien avatard, screen de gt racers gba, et le nouveau screen moteur DS.

Pour Thoduv, seul l'angle de vue différe entre les 2 versions, l'univers affiché est le meme.. Bon, ce qui change aussi , c'est le framerate..... 20 fps sur gba.... 60 fps sur DS .... ( et encore si la DS rafraichissait à 180 fps.... ça passerait encore !!:D )

Pitt
23/11/2006, 21h39
Si un admin passe par là, qu'il me renomme en 'Columbo' :lol: Nan, nan, faites pas ça ! ^^ J'ai bien pris note pour l'évolution du topic, je me doute que tu es toujours prêt à répondre aux questions d'asm. ^^

Donc @+, et bon dev ^^

Nesgba
12/05/2007, 13h21
euh... je suis loin d'etre une bete en asm mais a vue de nez ce code n'est pas super optimisé :disgust1: (la phrase qui tue un programmeur :D).

apparement tu reteste systematiquement le decalage sur les x et y pour TOUT les tiles ? pas super bon tout ca.


et je reve ou tu te traine le decalage sur tout les pixels ? si tel est le cas je peut te certifier que cette methode n'est pas la bonne (en C avec timer a l'appuis).

tu devrai calculer non pas 1 mais 2 décalages, celui du debut de ligne et celui de fin de ligne, ensuite tout les pixels que tu affiche entre les 2 sont alignés sur 4 !! (et plotter des pixels bien alignées en memoire, ca roxe a donf) donc pour faire bref plus ta ligne est longue plus cette methode met sa rouste a l'autre :fleur: (perso j'ai une differance nottable sur des tiles soft de 16x16 alors imagine sur des tiles de 32x32 et mieu encore... sur un moteur 3d complet)

qui dit pixels alignées et texture source non interpolée dit... utilisation possible du DMA ;)
(non ne croyez pas avoir decouvert un systeme d'affichage qui va revolutionner les moteur mode 4, comme je l'ai maintes fois répété sur ce forum le dma appellé beaucoup de fois pour copier peu de données c'est bidon, ca se fait boussiller par une routine de copie soft debouclée v_v ).


a+ vive le C

Arcadia
12/05/2007, 14h51
...mais a vue de nez ce code n'est pas super optimisé :disgust1:
On reconnaitrait le nes entre 1000 avec ce genre de phrase ^^

D'ailleurs, ta présence est bien trop rare sur ce forum mon ami :cry: