Je suis en train d'apprendre l'assembleur et je bloque sur des trucs idiots. J'utilise winape et je voudrais afficher un sprite a l'écran. Pour ça j'ai prévu une boucle qui lit un tableau et qui change le pixel correspondant en mémoire vidéo. C'est là qu'est mon pbm. J'ai gaillardement fait une fonction qui m'initialise le tableau :
Code :
Init_Gfx Gfx_vide Db 0,0,1,1,1,1,1,0,0,0,0,0,1,1,1,1,1,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,1,0,1,0,0,0,0,... 0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,... 0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,... 0,0,0,1,0,1,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,1,0,0 ret
et j'ai (tout aussi gaillardement d'ailleurs) l'erreur : Line too long
Comment fait on en asm pour initialiser un tableau ?
Par avance merci de votre aide.
JMD
_________________ There is the theory of Möbius. A twist in the fabric of space where time becomes a loop
Dernière édition par JMD le 18 Août 2010, 22:18, édité 2 fois.
Oui, je prévois que les 0 et les 1 représentent l'encre a affecter au pixel. Mon idée était que le 0 représente le transparent (change pas la valeur du pixel) et les valeurs supérieures soient directement celles à appliquer
Mes sprites feront 10 de large et 20 de haut en mode 0.
mais à ton commentaire, j'ai l'impression que je me dirige vars mon pbm 2
Je n'en suis qu'au début mais je posterait dans tous les cas les sources dés que je suis arrivé a mon 1er objectif : a mon avis, il risque d'y avoir a redire
_________________ There is the theory of Möbius. A twist in the fabric of space where time becomes a loop
Ca me paraît un peu compliqué, ta méthode de stockage . A mon avis, tu ferais mieux de faire une capture de tes sprites provenant d'un fichier .SCR soit avec une petite moulinette, soit avec Winape (on peut avec le chercheur de sprites exporter ces derniers en valeurs DB).
La structure de la mémoire vidéo du CPC est un peu tordue, il vaut mieux y aller pas à pas, en commençant par l'organisation des octets. Tu n'as pas besoin de connaître le codage des pixels pour faire un affichage simple de sprites. Ca devient utile soit quand tu fais des superpositions ou des mélanges.
Dans Amstrad Cent Pour Cent, il y avait 2 articles qui expliquait comment faire des scrollings software.
Ces 2 articles ont été ma bible pendant tout un été : je ne connaissais rien a l'assembleur, et 2 mois après, j'avais tout compris sur la manipulation des pixels, initialisation de tableaux, boucles, déplacement de graphisme a l'écran,... Pour moi, ça avait été l'élément déclencheur ; peut-être devrais-tu procéder ainsi toi aussi ?
En plus l'ete est pas encore totalement termine
EDIT: de tête, je me souviens même du nom des articles : L HOMME AU SCROLL MIGNON / LA FEMME AU SCROLL INFAME .... décidément, l'informatique d'aujourd'hui n'est plus aussi attachante que ce qu'elle était a l'époque !!! qui pourrait encore se souvenir de ça ?
Inscription : 12 Juin 2008, 20:29 Message(s) : 1709
jmd, comme disais T&J, le plus simple est de faire un sprite avec ocp art studio, sélectionner en window, le sauvegarder en .win et ensuite sous l'assembleur de winape tu code :
Sprite1label incbin "sprite.win"
Ensuite autres éléments que tu dois maîtriser c'est le format des pixels/octets en fonction du mode sur le cpc... le mask avec le décors sera aussi à réfléchir en fonction du mode !
en résumé très rapide (si mes souvenirs sont bons) :
mode 2 - 2 couleurs pour un octet, les couleurs/pixels sont affichés comme cela :
un octet = 8 pixels 0000 0000 = tous les pixels en couleur 0 0010 0000 = pixel 3 en couleur 1
mode 1 - 4 couleurs pour un octet les couleurs/pixels sont affichés comme cela :
un octet = 4 pixels numéro bits 0 1 2 3 4 5 6 7 valeurs 0 0 0 0 0 0 0 0 = tous les pixels en encre 0 p1p2p3p4 p1p2p3p4
la couleur du pixel 1 va être déterminé par les bits 0 et 4 la couleur du pixel 2 va être déterminé par les bits 1 et 5 etc...
en fait on prend un pixel 0010 0000 pixel 3 en couleur 10 ce qui correspond à l'encre 3
0011 0110 pixel 1 en couleur 00 ce qui correspond à l'encre 0 pixel 2 en couleur 01 ce qui correspond à l'encre 1 pixel 3 en couleur 11 ce qui correspond à l'encre 3 pixel 4 en couleur 10 ce qui correspond à l'encre 2
mode 0 - 16 couleurs pour un octet les couleurs/pixels sont affichés comme cela :
un octet = 2 pixels 0010 0000 pixel 1 en encre = 0010 = 2 pixel 2 en encre 0 etc...
Inscription : 28 Août 2008, 23:41 Message(s) : 257
Pour compléter les remarques de mes camarades ci-dessus, notamment par rapport à ton idée d'encre transparente, j'imagine que tu souhaites que ton sprite passe sur un décor (ou derrière ).
Le mieux est déjà que tu te familiarises avec la structure de la mémoire vidéo (trouver l'adresse en fonction de x et y), et comment les pixels sont affichés selon le mode graphique, comme te l'ont expliqué megachur, t&j, de façon à bouger un sprite sur un fond vide. (car il faudra que tu l'effaces de l'ancienne position avant de l'afficher sur une nouvelle)
Seulement après tu pourras aborder des notions de masquage, permettant de faire passer un sprite sur un décor ou d'autres sprites. Ce qui implique d'être à l'aise avec les AND et les OR. Il y a plusieurs moyens de faire un masquage. En perdant une couleur, tu économises de la mémoire. Mais tu peux conserver toutes les couleurs de ton sprite en créant un "sprite de masquage" qui permettra de faire un "trou" dans le décor à l'endroit ou les pixels du sprite doivent s'intégrer. Et bien sûr tu rentres aussi dans les notions inévitables de restitution du décor lorsque le(s) sprite(s) bougent, à moins d'aborder d'autres notions comme le dual playfield (mais tu verras ça plus tard).
En fait, tout ça me fait comprendre que c’est un peu plus dur que ce à quoi je m’attendais et que j’ai pas mal de choses à réapprendre. Ce qui est déroutant, c’est le temps nécessaire pour certaines choses que je considérais comme ‘facile’ ! Je suis allé télécharger le manuel du Z80 et quelques exemples et avec un peu de temps et quelques mal de tête …. Mais bon, ça va tant que je suis en vacances :s
En tout cas, merci pour votre aide et vos encouragements ; je pense que je vous solliciterais encore quelques fois !
_________________ There is the theory of Möbius. A twist in the fabric of space where time becomes a loop
J'ai essayé de comprendre le principe des adresses mémoires du mode 0 du CPC. Aprés moultes batailles, j’ai pondu ce petit prog qui a pour but de colorier en rouge l’écran, ligne par ligne en partant par le bas. J’ai donc une proc principale qui appelle une boucle qui colorie chaque ligne. Pour ça, elle appelle une fonction qui lui définit l’adresse de la ligne puis une boucle définit les 160 pixels (80 octets). Tout va bien (et j’en suis assez fiers ) sauf que les 8 premières lignes bugguent. Ça sent l'erreur bête… le mal de tête me vient : pouvez vous m’aider ?
Code :
Org &8000 Nolist ; pour Maxam
;###### MAIN ###### Main call Init ; sauvegarde tout ce qui doit l’être et initialise les paramètres call EffaceEcran call Fin ; remet tout en ordre ret ; bye bye
;###### Init ###### Init Ecran Equ &c000 ; definit l'adresse de l'ecran di ; desactive les interruptions ld (Fin+1),sp ; sauvegarde la pile en memoire (en parametre de la 1ere instruction de Fin)
ld A,0 ; mode 0 call &BC0E ; definition du mode
call Init_Gfx ; definit les graphismes ret ; on a fini
;###### Fin ###### Fin ld sp,0 ; restitu la pile sauvegarde par init ei ; reactive les interuptions ret
;###### EffaceEcran ###### ;###### colori l'ecran en partant de la derniere ligne ###### EffaceEcran ld b,&CC ; la valeur a donner aux pixels ld c,200 ; definit le nb de boucles (lignes) Boucle_EE_effL ld d,80 ; definit le nb de boucles (colonnes) ld a,c ; met dans a la ligne a chercher push bc ; sauvegarde bc push de ; sauvegarde de call Calc_AddrLigne ; cherche l'adresse de la ligne dans HL pop de ; recupere de pop bc ; recupere bc Boucle_EE_effC ld (hl),b ; ecrit les 2 pixels inc hl ; position pixel ecran suivante dec d ; decremente le nb de boucles (colonnes) JP NZ,Boucle_EE_effC ; tant qu'on est pas a 0 , on recommance dec c ; decremente le nb de boucles(lignes) JP NZ,Boucle_EE_effL ; tant qu'on est pas a 0 , on recommance ret
;###### Calc_AddrLigne ###### ;###### Calcule l'adresse memoire de la ligne ###### ;###### IN = a numero de ligne (en pixels) ###### ;###### OUT = HL adresse memoire de la ligne ###### Calc_AddrLigne ld b,a SRA b ; divise par 2 res 7,b ; fixe a 0 le bit decale SRA b ; divise par 2 (soit div par 4) SRA b ; divise par 2 (soit div par 8) ld e,b ; copy le nb de series dans e SLA b ; remultipli par 2 SLA b ; remultipli par 2 (soit par 4) SLA b ; remultipli par 2 (soit par 8) Sub b ; A=A-B ld hl,Ecran ; adresse de base de l'ecran ; calcule l'adresse de base de la serie ld bc,&800 CAL_add_blockL add hl,bc ; ajoute &800 (change de block de lignes) dec a ; decremente A JP NZ,CAL_add_blockL ; recommence tant qu'on n'a pas fini LD bc,&50 ; CAL_add_ligne add hl,bc ; ajoute &50 (change de ligne dans le bloc) dec e ; decremente e JP NZ,CAL_add_ligne ; recommence tant qu'on n'a pas fini ret
Par avance merci !
JMD
_________________ There is the theory of Möbius. A twist in the fabric of space where time becomes a loop
Salut, Sachant que tu vas de bas en haut, je ferais plus simple... :
Code :
org &8000 ; en &8000 nolist ; ... xor a ; a=0 call &bc0e ; mode 0 ld hl,&ff80 ; adresse de la ligne directement tout en bas... ld b,200 ; 200 lignes boucle1 push bc ; save bc push hl ; save hl ld b,80 ; 80 de large boucle2 ld (hl),&cc ; on affiche inc hl ; on incremente hl djnz boucle2 ; ca boucle en largeur... pop hl ; on restore l'ancien valeur de debut de ligne (hl) call &bc29 ; hl=adresse de la ligne du dessus... (&bc26 = ligne du dessous) pop bc ; on restore djnz boucle1 ; on boucle la hauteur pour passer a ligne du dessus. ret ; finito.
Inscription : 12 Juin 2008, 20:29 Message(s) : 1709
Hello,
en fait, c'est tout simple...
tu fais un di
donc tu désactives les interruptions (&38)...
le call &bc0e essaye de changer de rom... seulement quand tu appelles une "fonction" de la rom, il ne faut pas !!! même si par bonheur cela pouvait s'exécuter et revenir, le mode ne serait changé qu'au moment où tu réactiveras les interruptions...car c'est dans la routine d'interruption de la rom je crois qu'il y a le changement des couleurs et de mode (? quelqu'un se rappelle ?)
également on fait un di et une sauvegarde de la pile, uniquement si on veut mettre notre propre routine d'interruption (ou changer l'adresse de la pile)...en effet, on peut tout à fait faire des push et des pops même si les interruptions sont pas désactives ! ce qui ne marchera pas dans ce cas là, c'est un changement d'adresse sauvage de la pile (ld sp,mémoire) car lorsque tu ferras le ret de ton programme, tu ne pourras revenir au basic car le ret fait en fait un pop et on s'attend à avoir l'adresse de retour du call programme dans la pile (qui est mis dans le registre pc du z80) et comme ce sera n'importe quoi -> plantage également, il faut juste faire attention à pas faire plus d'un certains nombres de push (la pile par défaut est mise en &c000 par la rom amstrad -> jusqu'à je crois &be80 (? quelqu'un se rappelle ?) ce qui fait quand même 192 push de suite sans pop !!!
donc pas besoin de faire de l'affichage entre un di et ei avec sauvegarde la pile si tu n'en as pas besoin...
supprime cela, tu verras que ton programme va marcher !
sinon, tu verras, il y a bcp rapide avec une table pour calculer l'adresse mémoire, mais ta routine semble un bon début si elle marche bien !!!
bon courage pour la suite !!!
c'est déjà super propre comme code !
JMD a écrit :
Code :
Org &8000 Nolist ; pour Maxam
;###### MAIN ###### Main call Init ; sauvegarde tout ce qui doit l’être et initialise les paramètres call EffaceEcran call Fin ; remet tout en ordre ret ; bye bye
;###### Init ###### Init Ecran Equ &c000 ; definit l'adresse de l'ecran di ; desactive les interruptions ld (Fin+1),sp ; sauvegarde la pile en memoire (en parametre de la 1ere instruction de Fin)
ld A,0 ; mode 0 call &BC0E ; definition du mode
call Init_Gfx ; definit les graphismes ret ; on a fini
;###### Fin ###### Fin ld sp,0 ; restitu la pile sauvegarde par init ei ; reactive les interuptions ret
Bon, Megachur a raison, mais cela n'est pas la raison pour laquelle tu ne vois pas ta dernière ligne. Tu as aussi un problème au niveau des boucles qui a partir des compteurs A et E (nb lignes et nb lignes caractère) calculent l'adresse video. Si A ou E = 0, normalement, il ne devrait rien se passer. Or là, tu as forcément des additions ! 0-1 = 255 <> 0 (le test JR Z ne fonctionne donc pas au moment voulu, mais bien plus tard ).
Pour que ça marche, il faudrait rajouter deux tests :
ld hl,Ecran ; adresse de base de l'ecran ; calcule l'adresse de base de la serie
AND A JR Z,no_800
ld bc,&800 CAL_add_blockL add hl,bc ; ajoute &800 (change de block de lignes) dec a ; decremente A JP NZ,CAL_add_blockL ; recommence tant qu'on n'a pas fini
no_0800 LD A,E AND A RET Z
LD bc,&50 ; CAL_add_ligne add hl,bc ; ajoute &50 (change de ligne dans le bloc) dec e ; decremente e JP NZ,CAL_add_ligne ; recommence tant qu'on n'a pas fini
J'espère que cette fois mon message va être enregistré ...
Markerror, si je comprend bien, le but est, quand A = 0 de bypasser le test et de passer directement a l’instruction suivante. De cette manière, on ne fait pas l’addition.
Je l’ai intégré à mon code et j’ai enlevé les di/ei (merci Megachur) et ça donne ça :
Code :
Org &8000 Nolist ; pour Maxam
;###### MAIN ###### Main call Init ; sauvegarde tout ce qui doit l’être et initialise les paramètres call EffaceEcran
call Fin ; remet tout en ordre ret ; bye bye
;###### Init ###### Init Ecran Equ &c000 ; definit l'adresse de l'ecran ld (Fin+1),sp ; sauvegarde la pile en memoire (en parametre de la 1ere instruction de Fin)
ld A,0 ; mode 0 call &BC0E ; definition du mode
ret ; on a fini
;###### Fin ###### Fin ld sp,0 ; restitu la pile sauvegarde par init ret
;###### EffaceEcran ###### ;###### colori l'ecran en partant de la derniere ligne ###### EffaceEcran ld b,&CC ; la valeur a donner aux pixels ld c,200 ; definit le nb de boucles (lignes) Boucle_EE_effL ld d,80 ; definit le nb de boucles (colonnes) ld a,c ; met dans a la ligne a chercher push bc ; sauvegarde bc push de ; sauvegarde de call Calc_AddrLigne ; cherche l'adresse de la ligne dans HL pop de ; recupere de pop bc ; recupere bc Boucle_EE_effC ld (hl),b ; ecrit les 2 pixels inc hl ; position pixel ecran suivante dec d ; decremente le nb de boucles (colonnes) JP NZ,Boucle_EE_effC ; tant qu'on est pas a 0 , on recommance dec c ; decremente le nb de boucles(lignes) JP NZ,Boucle_EE_effL ; tant qu'on est pas a 0 , on recommance ret
;###### Calc_AddrLigne ###### ;###### Calcule l'adresse memoire de la ligne ###### ;###### IN = a numero de ligne (en pixels) ###### ;###### OUT = HL adresse memoire de la ligne ###### Calc_AddrLigne ld b,a SRA b ; divise par 2 res 7,b ; fixe a 0 le bit decale SRA b ; divise par 2 (soit div par 4) SRA b ; divise par 2 (soit div par 8) ld e,b ; copy le nb de series dans e SLA b ; remultipli par 2 SLA b ; remultipli par 2 (soit par 4) SLA b ; remultipli par 2 (soit par 8) Sub b ; A=A-B ld hl,Ecran ; adresse de base de l'ecran
; si A = 0, on zappe les tests sans rien ajouter ! AND a ; permet de tester si A=0 JR Z,CAL_add_ligne_BP ; si c'est bien egal a 0 -> on zappe
; calcule l'adresse de base de la serie CAL_add_blockL ld bc,&800 add hl,bc ; ajoute &800 (change de block de lignes) dec a ; decremente A JP NZ,CAL_add_blockL ; recommence tant qu'on n'a pas fini
; si E= 0, on quitte direct CAL_add_ligne_BP ld a,e AND a ; permet de tester si A=0 ret z ; si on a bien 0, on a fini ! sinon, on calcule
LD bc,&50 ; CAL_add_ligne add hl,bc ; ajoute &50 (change de ligne dans le bloc) dec e ; decremente e JP NZ,CAL_add_ligne ; recommence tant qu'on n'a pas fini ret
Et ça marche , même si je vois au tout début un bout de ligne en haut s’afficher : je dois avoir encore un bug quelque part.
Tatayoyode, c’est vrai que ton code est beaucoup plus court et en plus, il a l’air plus rapide. Merci !
nb : peut etre devrait je renommer le topic pour qu'il puisse être utile à d'autre ?
_________________ There is the theory of Möbius. A twist in the fabric of space where time becomes a loop
Bon, y a effectivement un petit bug, assez logique en fait . C'est encore lié au compteur du nombre de ligne. C=200 en début de code. La routine affiche 201 lignes (de 200 à 0) et non 200. Et la ligne 200 correspond à une adresse video qui n'est pas affiché proprement à l'écran, et qui déborde sur la deuxième ligne écran.
si C=200, la routine de calcul rend &C7D0. Tu rajoutes la longueur d'une ligne (&50) à &C7D0, on obtient &C820. La routine affiche donc &20 octets sur la deuxième ligne vidéo.
Pour t'en rendre compte, rajoute un CALL &BB18 (attente d'une touche) après l'affichage de chaque ligne.
La solution est la suivante, commencer la routine de calcul de l'adresse vidéo par faire un DEC A, afin de faire le calcul sur 199 a 0, et pas 200 a 0.
Tatayoyode, le vecteur &BC26, c'est gentil, mais ça n'apprend rien sur la structure de la mémoire vidéo, et je suppose que c'est ça que JMD voulait aborder dans cette routine .
Utilisateur(s) parcourant ce forum : Aucun utilisateur inscrit et 21 invité(s)
Vous ne pouvez pas publier de nouveaux sujets dans ce forum Vous ne pouvez pas répondre aux sujets dans ce forum Vous ne pouvez pas éditer vos messages dans ce forum Vous ne pouvez pas supprimer vos messages dans ce forum Vous ne pouvez pas insérer de pièces jointes dans ce forum