CPC Rulez
https://cpcrulez.fr/forum/

Usage du VSYNC (&BD19)
https://cpcrulez.fr/forum/viewtopic.php?f=4&t=6031
Page 1 sur 1

Auteur :  DjPoke [ 28 Nov 2017, 04:58 ]
Sujet du message :  Usage du VSYNC (&BD19)

Bonjour à tous,

Je suis en train de tenter de programmer un petit jeu vu de dessus, et je rencontre un problème de clignotement de mon unique sprite.

Je m'explique :
1) J'affiche un écran, en mode 1, qui servira de décors.
2) Je commence une boucle ici :
3) Je capture la zone de décors où je vais afficher mon sprite.
4) J'affiche mon sprite, en mode transparent. (routine de base, pas très rapide, normale, voir plus bas...)
5) En théorie, tant qu'il me restera des sprites à afficher, je bouclerai sur l'étape 2.
6) CALL &BD19 (Vsync)
7) Je restitue les morceaux de décors que j'ai capturés dans l'ordre inverse de celui où je les ai capturés.
8) Je met à zero mon compteur de sprites, et je recommence tout à l'étape 2.

Le problème que je rencontre, c'est que même avec un seul sprite affiché, lors de son déplacement horizontal, à peu près au milieu de l'écran,
il se coupe en deux. Je comprend qu'il s'agit d'un mauvais usage du Vsync de ma part.

Si je supprime le Vsync, ça clignotte. Logique, puisque la routine qui restitue les décors (sans transparence) est presque aussi lente que celle qui affiche les sprites.
Cela risque d'être pire quand je vais rajouter quelques sprites...

Du coup, je me demande ce que je dois faire. Comment faisait Claude Le Moullec, par exemple, pour faire ses jeux en BASIC/ASM sans que cela clignote dans tous les sens ?

Code :
; --------------------------------------------------------------------------------
; Draw a 'Mode 1' transparent sprite
; Entry: B = width, C = height, DE = Sprite address, HL = screen address
; --------------------------------------------------------------------------------
CM_DrawSpriteTransparentMode1:
; --------------------------------------------------------------------------------
PUSH BC
PUSH HL
CM_DrawLineTransparentMode1:
; === PIXEL 1 ===
LD A, (DE)
LD C, A
AND #11
CP 0
JR Z, CM_Goto11End
LD C, A
LD A, (HL)
AND #EE
OR C
LD (HL), A
CM_Goto11End:
; === PIXEL 2 ===   
LD A, (DE)
LD C, A
AND #22
CP 0
JR Z, CM_Goto22End
LD C, A
LD A, (HL)
AND #DD
OR C
LD (HL), A
CM_Goto22End:
; === PIXEL 3 ===
LD A, (DE)
LD C, A
AND #44
CP 0
JR Z, CM_Goto44End
LD C, A
LD A, (HL)
AND #BB
OR C
LD (HL), A
CM_Goto44End:
; === PIXEL 4 ===
LD A, (DE)
LD C, A
AND #88
CP 0
JR Z, CM_Goto88End
LD C, A
LD A, (HL)
AND #77
OR C
LD (HL), A
CM_Goto88End:
INC DE
INC HL
DJNZ CM_DrawLineTransparentMode1
POP HL
POP BC
DEC C
RET Z
LD A, H
ADD #08
LD H, A
AND #80
CP 0
JP NZ, CM_DrawSpriteTransparentMode1
PUSH DE
LD DE, #C050
ADD HL, DE
POP DE
JP CM_DrawSpriteTransparentMode1

Auteur :  marcel [ 28 Nov 2017, 07:22 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

Bon alors déjà t'es pas obligé de traiter tes pixels un par un. Ensuite le cp 0 est inutile le and va déjà positionnér les flags.

Pour traiter l'octet d'un coup faudrait un truc du genre
LD a,(de)
And (hl)
Inc hl
Or (hl)
Inc hl
LD (de),à
Inc de

Ton sprite contient un objet de masque inverse, un octet de donnée,etc

Auteur :  Megachur [ 28 Nov 2017, 07:39 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

généralement ce que tu décris est provoqué par le fait qu'on change la mémoire de l'écran au moment où elle est affichée.

donc, il faut passer par un double buffer : tu travailles sur un écran 1 (exemple en &c000) pendant que l'écran 2 (exemple en &8000) est affiché
et inversement après le call &bd19 (qui ne sert qu'à attendre le début d'affichage de l'écran pour faire simple) !

soit que ton code ne soit pas exécuter au moment de l'affichage

tu peux vérifier avec un émulateur type winape en pas à pas avec l'affichage de la position dans la frame, je crois que c'est une case à cocher sur le panneau de configuration/registres de mémoire !?

Auteur :  DjPoke [ 28 Nov 2017, 14:23 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

@marcel :

Je n'ai jamais compris la technique des masques.
J'utilise d'ailleurs "Retro Game Asset Studio", qui me génère des sprites codés en assembleur, avec à la fin leurs masques, mais je n'ai pas trouvé d'exemple en .asm pour les tester. Si quelqu'un dispose d'un lien vers une routine pour afficher les sprites provenant de ce logiciel avec leurs masques... ça serait sympa de le mettre ici, merci. :)

@Megachur :
Je suis d'accord, le double buffer serait le mieux, et j'y pense de plus en plus. Mais je ne comprend pas un truc. Comment commuter la mémoire vidéo en &4000 (ou &8000) sans perdre mes sprites, qui sont eux-même en &4000 ? J'imagine qu'il y a une astuce avec la mémoire étendue du 6128 ? Un lien serait le bienvenu là aussi, merci. :)

EDIT: Je viens de voir que je pouvais assembler mon .BIN principal en &389, et le lancer avec une ligne de programme BASIC. Avant, je croyais être limité à &1800. Donc, pour le problème de mémoire pour les sprites en &4000, c'est réglé, j'ai tout remanié. De &4000 à &7fff, c'est libre ! Je vais donc pouvoir bosser en double buffer. ;)

Par contre, je me demande vraiment comment concilier la table de masques générée par "Retro Game Asset Studio" avec ton code source, marcel. Cela doit être facile, mais mon ignorance me joue des tours.

Auteur :  DjPoke [ 30 Nov 2017, 17:48 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

Pour précision, le logiciel en question fournit une table de 256 octets pour les masques.
J'ai déjà entendu parler de cette fameuse table, mais je n'ai jamais trouvé un lien vers un code source pour l'exploiter.

Je vais chercher sur le site ici-même, hors forum, on ne sais jamais...

Auteur :  marcel [ 30 Nov 2017, 17:58 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

Ah alors c'est une table d'indirection si tu n'as qu'une table de 256 octets
Il y a plein de techniques différentes pour les masques
Mais dis moi, si tu n'est pas à l'aise avec l'assembleur (et les masques) pourquoi ne pas utiliser cpctelera par exemple?

Auteur :  DjPoke [ 30 Nov 2017, 19:54 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

Ce n'est pas l'assembleur qui me gène, c'est plutôt que je ne dispose pas de la documentation nécessaire sur la machine.

A l'époque, déjà, je devais me débrouiller avec quelques bouquins de micro-application (peek & pokes, les routines de l'amstrad cpc, et un de leurs bouquins sur l'assembleur), sans jamais trouver où acheter "la bible du cpc", par exemple.

J'ai vu pas mal de trucs défiler dans les revues du genre Amtrad Cent Pour Cent, mais je ne me suis pas penché sur tous les trucs de bidouilleurs de haut niveau de l'époque. Je me suis contenté d'expérimenter les bases.

Quant à maintenant, ce n'est pas que je veux renouer avec l'assembleur, mais plutôt que je suis sur un projet assez immense.
Le principe est simple :
On assemble visuellement des modules, chaque module contient un morceau de code, on fait un rendu du source global, et on lance le compilateur correspondant.
J'ai commencé par faire des modules pour "AppGameKit 2" et pour "PureBasic", et cela rend bien. Puis, pour vérifier l'universalité de mon programme, je teste la génération d'un source ASM Amstrad CPC, lui-même ajouté par ligne de commande dans une disquette virtuelle, elle-même lancée dans un émulateur... et cela fonctionne !

Voici un screenshot de "CodeMug" (qui devrait être gratuit et open source) :
Image

Auteur :  marcel [ 30 Nov 2017, 20:21 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

Faire du masquage n'a rien de spécialement spécifique à la machine (enfin pas plus que ton premier code)

En mode 0 t'as les bits du pixel gauche dans les bits impaires et ceux du pixel droit dans les bits pairs

octet=GDGDGDGD (je te passe l'ordre des bits, aucun intérêt pour du masquage)

Donc en admettant que la couleur 0 soit transparente, tu as 4 cas pour ton sprite

Et si ta table de 256 octets contient ce que je pense, ça donne ça

GDGDGDGD : 2 pixels utilisés -> le masque sera 00000000 pour enlever tous les pixels de l'écran
G0G0G0G0: que le pixel gauche -> masque à 1010101 pour ne garder que le pixel droit de l'écran
D0D0D0D: que le pixel droit -> 10101010 pour ne garder que le pixel gauche de l'écran
00000000: aucun pixel -> 11111111 pour garder tous les pixels de l'écran (vu que y en aura pas dans le sprite)


pour chaque octet de ton sprite tu n'as besoin que de quelques lignes d'assembleur, aucune comparaison ou saut...

de=adresse des données du sprite
b=adresse de la table de conversion / 256 (il faut bien penser à aligner la table sur une adresse multiple de 256)
hl=adresse de destination écran

ld a,(de) ; récupère l'octet du sprite dans a
ld c,a
ld a,(bc) ; récupère le masque dans la table en fonction de l'octet du sprite
and (hl) ; enlève les pixels de l'écran en fonction des données du sprite
or c ; fusionné avec le sprite
ld (hl),a ; écrit à l'écran l'octet
inc de
inc hl ; incrémentation des adresses

reste à compter les pixels, revenir à la ligne, etc.

Ce qu'il y a de bien avec cette routine, c'est que ça prend le même temps pour du mode 0, mode 1 ou mode 2

Auteur :  DjPoke [ 01 Déc 2017, 09:36 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

marcel a écrit :
Donc en admettant que la couleur 0 soit transparente, tu as 4 cas pour ton sprite.
Et si ta table de 256 octets contient ce que je pense, ça donne ça


Merci de ton aide précieuse. Si je comprend bien, on a besoin d'un octet de masque pour un octet du sprite ?
Car j'ai l'impression que la table fournie par RGAS ne correspond pas, dans ce cas.

J'ai dessiné 16 sprites, de chacun 4x16 octets (16x16 pixels en Mode 1).
Et j'ai malgré tout une seule table de 256 octets.

La voici, avec une petite phrase en Anglais en entête :
Code :
.maskLookupTable ; lookup table for masks, indexed by sprite byte. AND with screen data, then OR with pixel data.
defb &FF,&EE,&DD,&CC,&BB,&AA,&99,&88,&77,&66,&55,&44,&33,&22,&11,&00,&EE,&EE,&CC,&CC,&AA,&AA,&88,&88,&66,&66,&44,&44,&22,&22,&00,&00
defb &DD,&CC,&DD,&CC,&99,&88,&99,&88,&55,&44,&55,&44,&11,&00,&11,&00,&CC,&CC,&CC,&CC,&88,&88,&88,&88,&44,&44,&44,&44,&00,&00,&00,&00
defb &BB,&AA,&99,&88,&BB,&AA,&99,&88,&33,&22,&11,&00,&33,&22,&11,&00,&AA,&AA,&88,&88,&AA,&AA,&88,&88,&22,&22,&00,&00,&22,&22,&00,&00
defb &99,&88,&99,&88,&99,&88,&99,&88,&11,&00,&11,&00,&11,&00,&11,&00,&88,&88,&88,&88,&88,&88,&88,&88,&00,&00,&00,&00,&00,&00,&00,&00
defb &77,&66,&55,&44,&33,&22,&11,&00,&77,&66,&55,&44,&33,&22,&11,&00,&66,&66,&44,&44,&22,&22,&00,&00,&66,&66,&44,&44,&22,&22,&00,&00
defb &55,&44,&55,&44,&11,&00,&11,&00,&55,&44,&55,&44,&11,&00,&11,&00,&44,&44,&44,&44,&00,&00,&00,&00,&44,&44,&44,&44,&00,&00,&00,&00
defb &33,&22,&11,&00,&33,&22,&11,&00,&33,&22,&11,&00,&33,&22,&11,&00,&22,&22,&00,&00,&22,&22,&00,&00,&22,&22,&00,&00,&22,&22,&00,&00
defb &11,&00,&11,&00,&11,&00,&11,&00,&11,&00,&11,&00,&11,&00,&11,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00,&00


Il est à noter que "Retro Game Asset Studio" a été intégré à la suite "CPCTelera", mais que je ne trouve pas la documentation de RGAS.

Si je ne trouve rien pour n'utiliser que ces 256 octets, je pourrais programmer quelque chose pour créer un masque par octet, mais tel que j'ai fait les choses (avec le double buffer), je ne dispose que de 8k de libre pour les sprites. (&8000 à &9fff)
Mon sprite prendrait déjà 2k { [ ( 4 x 16 ) x 16 ] x 2} sur 8k, à lui tout seul...

Auteur :  marcel [ 01 Déc 2017, 10:59 ]
Sujet du message :  Re: Usage du VSYNC (&BD19)

En fait la table est commune à tous les sprites
On économise de la place
C'est pour ça que la routine a besoin de trois pointeurs
Un vers les données du sprite
Un vers la table de conversion
Un vers l'écran
Tu peux toujours utiliser xh,xl du registre ix comme compteur pour largeur et hauteur

PS: le descriptif correspond bien à mon code. D'abord charger l'index vers la table grâce à la donnée du sprite. Ensuite le and et le or (que j'avais oublié j'ai corrigé et édité la routine au dessus

Page 1 sur 1 Le fuseau horaire est UTC+1 heure
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/