[SNES] Transformer une font 12x16 en 8x16

Foire aux questions et tutoriels
Hiei-

[SNES] Transformer une font 12x16 en 8x16

Message non lu par Hiei- » 22 nov. 2011, 10:20

J'ai demandé à Neige s'il pouvait me faire une explication sur comment il a fait pour passer la routine d'affichage de 12x16 à 8x16 dans le jeu "Kingyô Chuihô - Tobidase Game Gakuen" (Super Famicom), puis je me suis dit que ça pourrait peut-être intéresser d'autres gens, donc je viens de lui demander l'autorisation de publier tout ça, et comme il a accepté :
neige a écrit :Je n'ai pas d'objections, même que des personnes plus compétentes que moi pourrait améliorer les explications.
Voilà donc l'explication de Neige:

Première partie :

C'est la première fois que j'écris une explication de cette ampleur donc excuse moi d'avance si cela est désordonné et confus, aussi puisque j'ai plus de facilité à programmer en anglais les nom de fonctions et de variables sont dans cette langue.

La première étape dans tout hack assembleur est de comprendre le programme original car il est très difficile de modifier un programme dont on ne comprend pas le fonctionnement. Je vais tenter d'expliquer chaque partie de la fonction originale en utilisant des concepts de haut niveaux. Si tu veut pousser plus loin, il y a plein de document de référence sur l'assembleur 65C816 et l'organisation de la VRAM sur le net.

Code : Tout sélectionner

Dlg.PrintChar_S:
                SEP     #$20 ; m
                PHB
                LDA.B   #$7E
                PHA
                PLB
                REP     #$20 ; m
Cette partie sert à initialiser le registre de la banque de données pour simplifier certains accès à la RAM.

Code : Tout sélectionner

                LDA.W   Dlg.CharToPrint
                AND.W   #$0007
                ASL     A
                STA.W   $0000 
Ici on lit le code du caractère à afficher, on ne garde que le numéro de la colonne et on multiplie par 2 puisque chaque caractère utilise 2 tiles de large dans la fonte. On sauvegarde le résultat dans une variable temporaire pour plus tard.

Code : Tout sélectionner

 
               LDA.W   Dlg.CharToPrint
                AND.W   #$FFF8
                ASL     A
                ASL     A
Maintenant on relit le code du caractère à afficher, on ne garde que le numéro de la ligne et on multiplie par 4 puisque chaque caractère utilise 4 tiles dans la fonte.

Code : Tout sélectionner

                CLC
                ADC.W   $0000
On additionne au numéro de colonne pour obtenir le numéro de la première tile du caractère dans la fonte.

Code : Tout sélectionner

                ASL     A
                ASL     A
                ASL     A
                ASL     A
                TAX
Finalement, on multiplie par 16 qui est la taille en octets d'une tile au format gameboy pour obtenir l'adresse de départ du caractère en octets dans la fonte et on le met dans le registre X qui va nous servir d'index source pour copier le caractère.

Code : Tout sélectionner

                LDA.W   Dlg.VWFCol
                AND.W   #$00FF
                STA.W   $0000
                LSR     A
                CLC
                ADC.W   $0000
                STA.W   $0000
Ici on lit le numéro de la colonne dans la fenêtre de dialogue, les instructions qui suivent équivalent à l'expression mathématique floor(Dlg.VWFCol * 1.5). On veut afficher seulement 12 pixels de large ce qui équivaut à 1.5 tile de large et puisqu'on peut directement afficher les graphiques seulement tile par tile, dans le cas des colonnes impaires on doit commencer à la dernière tile complète. Par exemple la colonne 2 commence à la tile 3, mais la colonne 3 commence à la tile 4 (et non 4.5).

Code : Tout sélectionner

                LDA     Dlg.VWFRow
                AND.W   #$00FF
                ASL     A
                ASL     A
                STA.W   $0002
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                SEC
                SBC.W   $0002
Maintenant on lit le numéro de ligne dans la fenêtre de dialogue et on multiplie par 60 (c'est à dire le nombres de caractères sur une ligne (20) * la largeur d'un caractère (1.5) * la hauteur d'un caractère (2)). On remarque que pour palier au manque de vraies instructions de multiplication sur le processeur le programme effectue plutôt des opérations équivalentes à (x * 64) – (x * 4).

Code : Tout sélectionner

                CLC
                ADC.W   $0000
On additionne au numéro de colonne pour obtenir le numéro de la première tile du caractère dans la fenêtre de dialogue.

Code : Tout sélectionner

                ASL     A
                ASL     A
                ASL     A
                ASL     A
                STA.W   Dlg.WndBufOfs
                TAY
Finalement, on multiplie par 16 qui est la taille en octets d'une tile au format gameboy pour obtenir l'adresse de départ du caractère en octets dans la fenêtre de dialogue et on le met dans le registre Y qui va nous servir d'index de destination pour copier le caractère. On le met aussi dans la variable Dlg.WndBufOfs qui va nous servir plus tard pour mettre la VRAM à jour.

Code : Tout sélectionner

                LDA.W   #$0008
                STA.W   $0000
Ici on initialise la variable qui va nous servir à compter le nombre de boucle pour la copie. On va copier 2 octets de chaque tile du caractère à la fois donc on met la taille en octets d'une tile au format gameboy divisé par 2.

Code : Tout sélectionner

                LDA.W   Dlg.VWFCol
                AND.W   #$0001
                BNE     odd_vwf_col
                JMP     even_vwf_col
Ici on lit le numéro de la colonne dans la fenêtre de dialogue et on vérifie si c'est une colonne paire ou impaire et on saute à l'endroit approprié.

Dans le programme original le traitement des colonnes impaires se situe en premier mais comme les colonnes paires commence au début de la tile je crois que ça va être plus facile à comprendre si je commence par le traitement des colonnes paires.

Code : Tout sélectionner

even_vwf_col:
                LDA.W   DlgFontGfx, X
                STA.W   DlgWndGfxBuf, Y
                LDA.W   DlgFontGfx+$10, X
                STA.W   DlgWndGfxBuf+$10, Y
                LDA.W   DlgFontGfx+$100, X
                STA.W   DlgWndGfxBuf+$1E0, Y
                LDA.W   DlgFontGfx+$110, X
                STA.W   DlgWndGfxBuf+$1F0, Y
                INX
                INX
                INY
                INY
                DEC.W   $0000
                BNE     even_vwf_col
On lit 2 octets de la tile supérieure gauche du caractère à partir de la fonte et on les copie dans la mémoire tampon de la fenêtre de dialogue, même chose pour la tile supérieure droite, inférieure gauche et inférieure droite, on augmente les index, on décrémente le compteur de boucles et on recommence tant qu'il n'est pas égal à 0. Quand on a fini, on envoie la partie de la mémoire tampon qu'on a modifié dans la VRAM mais auparavant je vais expliquer le traitement des colonnes impaires.

Puisque les colonnes impaires doivent commencer à la moitié d'une tile, on doit faire glisser les octets de 4 bits vers la droite tout en s'assurant de ne pas affecter la demi-tile du caractère précédent. Cette partie est assez difficile à comprendre en lisant seulement les explications, n'hésite pas à faire des dessins pour t'aider.

Code : Tout sélectionner

odd_vwf_col:
                LDA.W   DlgWndGfxBuf, Y
                AND.W   #$F0F0
                STA.W   DlgWndGfxBuf, Y
                LDA.W   DlgFontGfx, X
                LSR     A
                LSR     A
                LSR     A
                LSR     A
                AND.W   #$0F0F
                ORA.W   DlgWndGfxBuf, Y
                STA.W   DlgWndGfxBuf, Y
On commence par la tile supérieure gauche. On lit 2 octets de la mémoire tampon de la fenêtre de dialogue, on conserve seulement les bits de la demi-tile du caractère précédent et on les remet à leur place, on fait ça pour s'assurer que la mémoire tampon ne contient aucune données indésirable qui pourrait affecter l'affichage lorsqu'on va y combiner les bits du caractère courant. On lit 2 octets de la fonte et on les fait glisser de 4 bits vers la droite et on combine la première demi-tile du caractère courant avec la dernière demi-tile du caractère précédent.

Code : Tout sélectionner

                LDA.W   DlgWndGfxBuf+$1E0, Y
                AND.W   #$F0F0
                STA.W   DlgWndGfxBuf+$1E0, Y
                LDA.W   DlgFontGfx+$100, X
                LSR     A
                LSR     A
                LSR     A
                LSR     A
                AND.W   #$0F0F
                ORA.W   DlgWndGfxBuf+$1E0, Y
                STA.W   DlgWndGfxBuf+$1E0, Y
On fait la même chose avec la tile inférieure gauche.

Code : Tout sélectionner

                LDA.W   DlgFontGfx, X
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                AND.W   #$F0F0
                STA.W   DlgWndGfxBuf+$10, Y
C'est maintenant le tour de la tile supérieure droite. On lit 2 octets de la fonte, on les fait glisser de 4 bits vers la gauche, on ne garde que la 2ème demi-tile et on la met dans la mémoire tampon.

Code : Tout sélectionner

                LDA.W   DlgFontGfx+$10, X
                LSR     A
                LSR     A
                LSR     A
                LSR     A
                AND.W   #$0F0F
                ORA.W   DlgWndGfxBuf+$10, Y
                STA.W   DlgWndGfxBuf+$10, Y
On lit 2 octets de la fonte, on les fait glisser de 4 bits vers la droite, on ne garde que la 3ème demi-tile et on la combine à la 2ème demi-tile qui est déjà dans la mémoire tampon.

Code : Tout sélectionner

                LDA.W   DlgFontGfx+$100, X
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                AND.W   #$F0F0
                STA.W   DlgWndGfxBuf+$1F0, Y
                LDA.W   DlgFontGfx+$110, X
                LSR     A
                LSR     A
                LSR     A
                LSR     A
                AND.W   #$0F0F
                ORA.W   DlgWndGfxBuf+$1F0, Y
                STA.W   DlgWndGfxBuf+$1F0, Y
La même chose pour la tile inférieure droite.

Code : Tout sélectionner

                INX
                INX
                INY
                INY
                DEC.W   $0000
                BEQ     j_send_to_vram
                JMP     odd_vwf_col
; ---------------------------------------------------------------------------

j_send_to_vram:
                BRA     send_to_vram
On augmente les index, on décrémente le compteur de boucles et on recommence tant qu'il n'est pas égal à 0. Quand on a fini, on envoie la partie de la mémoire tampon qu'on a modifié dans la VRAM.

Code : Tout sélectionner

send_to_vram:
                REP     #$20 ; m
                LDA.W   Dlg.WndBufOfs
                LSR     A
                ADC.W   #$5008          ; VRAM:$A010
                STA.W   DMA.QueueItemToAdd.VRAMAddr
On lit l'adresse des tiles modifiées dans la fenêtre de dialogue qu'on avait sauvegardé plus haut, on divise par 2 pour obtenir une adresse VRAM et on additionne à l'adresse VRAM de base de la fenêtre de dialogue, on met le résultat dans une variable qui va être utilisé par une autre fonction plus tard.

Code : Tout sélectionner

                LDA.W   Dlg.WndBufOfs
                CLC
                ADC.W   #DlgWndGfxBuf
                STA.W   DMA.QueueItemToAdd.SrcAddr
On relit l'adresse des tiles modifiées dans la fenêtre de dialogue, on additionne l'adresse de base de la mémoire tampon de la fenêtre de dialogue et on met le résultat dans une variable.

Code : Tout sélectionner

                LDA.W   #$0020
                STA.W   DMA.QueueItemToAdd.Size
Puisqu'on copie les 2 tiles du haut en une fois on met 2 fois la taille en octets d'une tile au format gameboy dans la variable qui spécifie la taille du transfert.

Code : Tout sélectionner

                SEP     #$20 ; m
                LDA.B   #$80
                STA.W   DMA.QueueItemToAdd.VMAIN
On initialise la variable qui spécifie la valeur à utiliser pour le registre VMAIN.

Code : Tout sélectionner

                LDA.B   #$7E
                STA.W   DMA.QueueItemToAdd.SrcAddr+2
On met la banque de l'adresse de la mémoire tampon de la fenêtre de dialogue dans la variable appropriée.

Code : Tout sélectionner

                LDA.B   #$01
                STA.W   DMA.QueueItemToAdd.DMAP
On initialise la variable qui spécifie la valeur à utiliser pour le registre DMAP.

Code : Tout sélectionner

                LDA.B   #$18
                STA.W   DMA.QueueItemToAdd.DestReg
On veut écrire dans le registre $2118 qui sert à envoyer des données dans la VRAM.

Code : Tout sélectionner

                JSL.L   DMA.QueueDMATransfer_L
On appelle la fonction qui ajoute le transfert DMA spécifié par les variables DMA.QueueItemToAdd.* à une liste qui est envoyé lors de la prochaine interruption.

Code : Tout sélectionner

                REP     #$20 ; m
                LDA.W   Dlg.WndBufOfs
                LSR     A
                CLC
                ADC.W   #$50F8          ; VRAM:$A1F0
                STA.W   DMA.QueueItemToAdd.VRAMAddr
                LDA     Dlg.WndBufOfs
                CLC
                ADC.W   #DlgWndGfxBuf+$1E0
                STA.W   DMA.QueueItemToAdd.SrcAddr
                JSL.L   DMA.QueueDMATransfer_L
La même chose pour les 2 tiles du bas.

Code : Tout sélectionner

update_tilemap:
                LDA.W   Dlg.VWFCol
                AND.W   #$00FF
                STA.W   $0000
                LSR     A
                CLC
                ADC.W   $0000
                STA.W   $0000
Ici on lit le numéro de la colonne dans la fenêtre de dialogue, les instructions qui suivent équivalent à l'expression mathématique floor(Dlg.VWFCol * 1.5).

Code : Tout sélectionner

                LDA.W   Dlg.VWFRow
                AND.W   #$00FF
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                ASL     A
Maintenant on lit le numéro de ligne dans la fenêtre de dialogue et on multiplie par le nombre de tiles dans une ligne de tilemap (64).

Code : Tout sélectionner

                CLC
                ADC.W   $0000
                ADC.W   #$5C41          ; VRAM:$B882
                STA.W   $0003           ; VRAMAddr
On ajoute au numéro de colonne et à l'adresse de base de la tilemap dans la VRAM et on met le résultat une variable qui va être utilisé par une autre fonction plus tard.

Code : Tout sélectionner

                LDA.W   #Dlg.TilemapEntry1
                STA.W   $0000           ; srcAddr
On initialise l'adresse source du transfert.

Code : Tout sélectionner

                SEP     #$20 ; m
                LDA.B   #$00
                STA.W   $0002           ; srcBank
On initialise la banque de l'adresse source du transfert.

Code : Tout sélectionner

                STZ.W   $0005     ; VMAIN
                LDA.B   #$02
On initialise la variable qui spécifie la valeur à utiliser pour le registre VMAIN.

Code : Tout sélectionner

                LDA.B   #$02
                STA.W   $0006     ; numWords
On va copier 2 entrée de tilemap pour les tiles du haut (2 word, 4 octets)

Code : Tout sélectionner

                REP     #$20 ; m
                LDA.W   Dlg.WndBufOfs
                LSR     A
                LSR     A
                LSR     A
                LSR     A
                INC     A
                STA.W   Dlg.TilemapCharNum
On calcule la tile de départ du caractère en lisant l'adresse dans la mémoire tampon qu'on divise par 16 et on incrémente. On met le résultat dans une variable qu'on va utiliser plusieurs fois après.

Code : Tout sélectionner

                LDA.W   Dlg.TextPaletteIndex
                AND.W   #$00FF
                XBA
                ASL     A
                ASL     A
                ORA.W   #$2000
                STA.W   Dlg.TilemapPalNum
On prend le numéro de la palette du texte, on le glisse de 10 bits vers la gauche, on ajoute le bit de priorité et on met le résultat dans une variable.

Code : Tout sélectionner

                ORA.W   Dlg.TilemapCharNum
                STA.W   Dlg.TilemapEntry1
On combine la palette et le numéro de la tile de départ pour former l'entrée de tilemap de la tile supérieure gauche.

Code : Tout sélectionner

                LDA.W   Dlg.TilemapCharNum
                CLC
                ADC.W   #$0001
                ORA.W   Dlg.TilemapPalNum
                STA.W   Dlg.TilemapEntry2
On ajoute 1 au numéro de la tile de départ et on le combine à la palette pour former l'entrée de tilemap de la tile supérieure droite.

Code : Tout sélectionner

                LDA.W   Dlg.TilemapCharNum
                CLC
                ADC.W   #$001E
                ORA.W   Dlg.TilemapPalNum
                STA.W   Dlg.TilemapEntry3
On ajoute le nombre de tile sur une ligne de dialogue (30) au numéro de la tile de départ et on le combine à la palette pour former l'entrée de tilemap de la tile inférieure gauche.

Code : Tout sélectionner

                LDA.W   Dlg.TilemapCharNum
                CLC
                ADC.W   #$001F
                ORA.W   Dlg.TilemapPalNum
                STA.W   Dlg.TilemapEntry4
On ajoute le nombre de tile sur une ligne de dialogue + 1 (31) au numéro de la tile de départ et on le combine à la palette pour former l'entrée de tilemap de la tile inférieure droite.

Code : Tout sélectionner

                JSL.L   VRAM.QueueTransfer_L
On appelle la fonction qui ajoute le transfert VRAM spécifié par les variables $00, $03, $05 et $06 à une liste qui est envoyé lors de la prochaine interruption. Ce transfert est pour les entrées de tilemap des 2 tiles du haut du caractère.

Code : Tout sélectionner

                LDA.W   $0003
                CLC
                ADC.W   #$0020
                STA.W   $0003     ; VRAMAddr
                LDA.W   $0000
                CLC
                ADC.W   #$0004
                STA.W   $0000     ; srcAddr
                SEP     #$20 ; m
                LDA.B   #$00
                STA.W   $0002     ; srcBank
                LDA.B   #$02
                STA.W   $0006     ; numWords
                JSL.L   VRAM.QueueTransfer_L
On initialise les variables et on appelle la fonction encore une fois pour les 2 tiles du bas.

Code : Tout sélectionner

                INC     Dlg.VWFCol
                LDA.W   Dlg.VWFCol
                CMP.B   #020            ; max char on line
                BNE     no_newline
                STZ.W   Dlg.VWFCol
                INC     Dlg.VWFRow

no_newline:
                PLB
                RTS
Pour finir on incrémente le numéro de colonne, on vérifie qu'on ne dépasse pas la fenêtre, si c'est le cas, on saute au début de la prochaine ligne.

Ce n'est que la première partie, je vais essayer d'expliquer les modifications à faire pour passer de 12 à 8 pixels la semaine prochaine.

J'ai attaché les source de la fonction originale et modifiée, en les comparant les 2 versions et avec les explications (si j'ai réussi à bien expliquer) ça devrais te donner une idée de quoi changer pour avoir les caractères de 8 pixels

Les points importants à retenir sont:
  1. Les caractères de 8 pixels commencent toujours au début d'une tile, donc on n'a pas à traiter les demi-tiles.
  2. Les caractères de 8 pixels ont une tile de large.
  3. La taille de la fenêtre de dialogue passe de 20 à 30 caractères.
J'aurais voulu faire des images pour aider à clarifier le traitement de colonnes paire et impaires mais le temps m'a manqué.
Pièces jointes
DlgPrintChar_S.zip
(2.93 Kio) Téléchargé 96 fois
Dernière édition par Hiei- le 22 nov. 2011, 10:30, édité 1 fois.

Hiei-

Re: [TUTO] Exemple de modification de textes (12x16->8x16)

Message non lu par Hiei- » 22 nov. 2011, 10:23

Seconde partie :

Ceci est la suite des explications. Maintenant qu'on comprend mieux comment le jeu affiche les caractères, on peut plus facilement modifier la fonction.

La première partie est l'initialisation, on n'a pas besoin de changer quoi que ce soit ici.

Code : Tout sélectionner

Dlg.PrintChar_S:
                SEP     #$20 ; m
                PHB
                LDA.B   #$7E
                PHA
                PLB
                REP     #$20 ; m
Vient ensuite le calcul de l'adresse du caractère à l'intérieur de la fonte. Si nous avions changé la disposition des caractères dans la fonte, nous aurions changé la première partie.
:
Par exemple, si nous avions profité du fait qu'on peut maintenant mettre 16 caractères de 1 tile de large sur une ligne dans la fonte, nous aurions changé la première partie comme ceci:

Code : Tout sélectionner

                LDA.W   Dlg.CharToPrint
                AND.W   #$000F          ; numéro de colonne maintenant de 0 à 15
                                        ; plus besoin de multiplier par 2
                STA.W   $0000
                LDA.W   Dlg.CharToPrint
                AND.W   #$FFF0
                ASL     A               ; multiplier par le nombre de tiles dans un caractère (2)
                CLC
                ADC.W   $0000           ; A = adresse de la ligne + adresse de la colonne dans la ligne
Si nous avions plutôt changé le format de la fonte, nous aurions changé la dernière partie pour multiplier par la nouvelle taille d'une tile mais comme nous n'avons rien changé de tout ça, cette partie ne change donc pas.

Code : Tout sélectionner

                LDA.W   Dlg.CharToPrint
                AND.W   #$0007
                ASL     A
                STA.W   $0000
                LDA.W   Dlg.CharToPrint
                AND.W   #$FFF8
                ASL     A
                ASL     A 
                CLC
                ADC.W   $0000
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                TAX
Maintenant c'est au tour du calcul de l'adresse du caractère à l'intérieur de la fenêtre de dialogue. Comme nos caractères sont passé d'une largeur de 1½ tile à 1 tile, il y a quelques changements à faire dans cette section. Premièrement puisque maintenant une colonne dans la fenêtre de dialogue correspond à une tile, nous n'avons plus de calcul à effectuer avec la variable Dlg.VWFCol avant de l'utiliser.

Code : Tout sélectionner

                LDA.W   Dlg.VWFCol
                AND.W   #$00FF
                STA.W   $0000
Le code de la deuxième section ne change pas, on doit encore multiplier par 60 mais plus pour la même raison. Avant on avait la formule nombres de caractères sur une ligne (20) * largeur d'un caractère (1.5) * hauteur d'un caractère (2), maintenant c'est nombres de caractères sur une ligne (30) * largeur d'un caractère (1) * hauteur d'un caractère (2).

Code : Tout sélectionner

                LDA     Dlg.VWFRow
                AND.W   #$00FF
                ASL     A
                ASL     A
                STA.W   $0002
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                SEC
                SBC.W   $0002
                CLC
                ADC.W   $0000
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                STA.W   Dlg.WndBufOfs
                TAY
Dans mon dernier message j'ai écrit que la variable de compteur de boucle correspondait à la taille d'une tile au format gameboy divisé par 2 mais c'est une erreur. En fait, il s'agit du nombre de lignes dans une tile. La boucle copie la première ligne de chaque tiles, ensuite la deuxième, etc. jusqu'à ce que toutes les lignes de chaque tile soit copiées.

Code : Tout sélectionner

                LDA.W   #$0008          ; nombre de lignes dans une tile
                STA.W   $0000
Puisque maintenant aucune colonne ne commence sur une demi-tile, nous pouvons enlever la vérification de colonne paire/impaire et le traitement des colonnes impaires.

On passe à la boucle de copie. Nous devons copier seulement une tile de large donc nous enlevons le code qui copie la colonne de droite qui n'existe plus.

Code : Tout sélectionner

even_vwf_col:
                LDA.W   DlgFontGfx, X   ; tile supérieure gauche
                STA.W   DlgWndGfxBuf, Y
                LDA.W   DlgFontGfx+$100, X ; tile inférieure gauche
                STA.W   DlgWndGfxBuf+$1E0, Y
                INX
                INX
                INY
                INY
                DEC.W   $0000
                BNE     even_vwf_col
On est rendu à envoyer les graphiques à la VRAM. La seule chose qui change ici c'est que maintenant nous devons envoyer une seule colonne au lieu de deux, donc la taille à spécifier change de 32 à 16.

Code : Tout sélectionner

send_to_vram:
                REP     #$20 ; m
                LDA.W   Dlg.WndBufOfs
                LSR     A
                ADC.W   #$5008          ; VRAM:$A010
                STA.W   DMA.QueueItemToAdd.VRAMAddr
                LDA.W   Dlg.WndBufOfs
                CLC
                ADC.W   #DlgWndGfxBuf
                STA.W   DMA.QueueItemToAdd.SrcAddr

                LDA.W   #$0010          ; maintenant 16

                STA.W   DMA.QueueItemToAdd.Size
                SEP     #$20 ; m
                LDA.B   #$80
                STA.W   DMA.QueueItemToAdd.VMAIN
                LDA.B   #$7E
                STA.W   DMA.QueueItemToAdd.SrcAddr+2
                LDA.B   #$01
                STA.W   DMA.QueueItemToAdd.DMAP
                LDA.B   #$18
                STA.W   DMA.QueueItemToAdd.DestReg
                JSL.L   DMA.QueueDMATransfer_L
                REP     #$20 ; m
                LDA.W   Dlg.WndBufOfs
                LSR     A
                CLC
                ADC.W   #$50F8          ; VRAM:$A1F0
                STA.W   DMA.QueueItemToAdd.VRAMAddr
                LDA     Dlg.WndBufOfs
                CLC
                ADC.W   #DlgWndGfxBuf+$1E0
                STA.W   DMA.QueueItemToAdd.SrcAddr
                JSL.L   DMA.QueueDMATransfer_L
Passons à la mise à jour de la tilemap. Lors du calcul de l'adresse du caractère dans la VRAM, nous devons enlever la multiplication par 1.5 comme pour le calcul de l'adresse du caractère dans la fenêtre de dialogue.

Code : Tout sélectionner

update_tilemap:
                LDA.W   Dlg.VWFCol
                AND.W   #$00FF
                STA.W   $0000
                LDA.W   Dlg.VWFRow
                AND.W   #$00FF
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                ASL     A
                CLC
                ADC.W   $0000
                ADC.W   #$5C41          ; VRAM:$B882
                STA.W   $0003           ; VRAMAddr
Quand on initialise le transfert de l'entrée de tilemap du haut, nous devons indiquer que nous envoyons seulement une entrée au lieu de deux.

Code : Tout sélectionner

                LDA.W   #Dlg.TilemapEntry1
                STA.W   $0000           ; srcAddr
                SEP     #$20 ; m
                LDA.B   #$00
                STA.W   $0002           ; srcBank
                STZ.W   $0005           ; VMAIN
                LDA.B   #$01            ; Maintenant 1
                STA.W   $0006           ; numWords
Le calcul du numéro de la tile de départ et de la palette reste identique.

Code : Tout sélectionner

                REP     #$20 ; m
                LDA.W   Dlg.WndBufOfs
                LSR     A
                LSR     A
                LSR     A
                LSR     A
                INC     A
                STA.W   Dlg.TilemapCharNum
                LDA.W   Dlg.TextPaletteIndex
                AND.W   #$00FF
                XBA
                ASL     A
                ASL     A
                ORA.W   #$2000
                STA.W   Dlg.TilemapPalNum
Nous n'avons que 2 tiles pour un caractère, donc nous n'initialisons et n'envoyons que 2 entrées de tilemap.

Code : Tout sélectionner

                ORA.W   Dlg.TilemapCharNum
                STA.W   Dlg.TilemapEntry1
                LDA.W   Dlg.TilemapCharNum
                CLC
                ADC.W   #$001E
                ORA.W   Dlg.TilemapPalNum
                STA.W   Dlg.TilemapEntry3
                JSL.L   VRAM.QueueTransfer_L
Quand on envoie l'entrée de tilemap du bas, nous devons indiquer que nous envoyons seulement une entrée au lieu de deux.

Code : Tout sélectionner

                LDA.W   $0003
                CLC
                ADC.W   #$0020
                STA.W   $0003           ; VRAMAddr
                LDA.W   $0000
                CLC
                ADC.W   #$0004
                STA.W   $0000           ; srcAddr
                SEP     #$20 ; m
                LDA.B   #$00
                STA.W   $0002           ; srcBank
                LDA.B   #$01            ; Maintenant 1
                STA.W   $0006           ; numWords
                JSL.L   VRAM.QueueTransfer_L
Pour finir, lorsque nous vérifions que nous ne dépassons pas le cadre de la fenêtre de dialogue, nous devons comparer la colonne avec la nouvelle largeur en caractères de la fenêtre.

Code : Tout sélectionner

                INC     Dlg.VWFCol
                LDA.W   Dlg.VWFCol
                CMP.B   #030            ; Maintenant 30
                BNE     no_newline
                STZ.W   Dlg.VWFCol
                INC     Dlg.VWFRow

no_newline:
                PLB
                RTS
Comme tu peux voir, quand on comprend bien le fonctionnement d'un programme, il est facile de trouver exactement où faire les changements.

* Fin de l'explication *

Merci à lui pour ses explications et pour l'autorisation de les publier :)

Avatar de l’utilisateur
kogami
Dieu Floodeur
Messages : 751
Inscription : 17 juin 2004, 16:47

Re: [TUTO] Exemple de modification de textes (12x16->8x16)

Message non lu par kogami » 22 nov. 2011, 19:45

C'est très intéressant, merci de l'avoir posté.
Traduction de BS Zelda - Ancient Stone Tablets (Projet en cour)Image

Répondre