; Programme test VGA. ; Anime quatre balles rebondissant sur l'écran en utilisant ; la permutation des pages. L'écran scroll de manière fluide à ; à l'horizontale et à la verticale. ; assemblé avec TASM 4.0, lié avec TLINK 6.10 ; testé par Jim Mischel 11/21/94 ; stack segment para stack 'STACK' db 512 dup(?) stack ends ; MEDRES_VIDEO_MODE equ 0 ;définit le mode vidéo 640x350 VIDEO_SEGMENT equ 0a000h ;segment de la mémoire vidéo pour ;les modes graphiques de vrai VGA LOGICAL_SCREEN_WIDTH equ 672/8 ;largeur en octets et hauteur en ;ligne LOGICAL_SCREEN_HEIGHT equ 384 ;d'affichage de l'écran virtuel ;avec lequel nous allons travailler PAGE0 equ 0 ;drapeau de la page 0 lors de la ;permutation de la page PAGE1 equ 1 ;drapeau de la page 1 lors de la ;permutation de la page PAGE0_OFFSET equ 0 ;offset de départ de la page 0 dans ;la mémoire VGA PAGE1_OFFSET equ LOGICAL_SCREEN_WIDTH * LOGICAL_SCREEN_HEIGHT ;offset de départ de la page 1 (ces deux pages ; sont des écrans virtuels de 672x384) BALL_WIDTH equ 24/8 ;largeur de la balle en octets de la ; mémoire vidéo BALL_HEIGHT equ 24 ;hauteur de la balle en lignes ;d'affichage BLANK_OFFSET equ PAGE1_OFFSET * 2 ;début de l'image vide ;dans la mémoire VGA BALL_OFFSET equ BLANK_OFFSET + (BALL_WIDTH * BALL_HEIGHT) ;offset de départ de l'image de la balle dans la mémoire VGA NUM_BALLS equ 4 ;nombre de balles à animer ; ; Le registre VGA équivaut à : ; SC_INDEX equ 3c4h ;registre index de SC MAP_MASK equ 2 ;registre map mask de SC GC_INDEX equ 3ceh ;registre index de GC GC_MODE equ 5 ;registre mode de GC CRTC_INDEX equ 03d4h ;registre index de CRTC START_ADDRESS_HIGH equ 0ch ;octet de poids fort de l'adresse de ;départ de CRTC START_ADDRESS_LOW equ 0dh ;octet de poids faible de l'adresse ;de départ de CRTC CRTC_OFFSET equ 13h ;registre offset de CRTC INPUT_STATUS_1 equ 03dah ;registre status de VGA VSYNC_MASK equ 08h ;bit vertical sync du registre status 1 DE_MASK equ 01h ;bit display enable du registre status 1 AC_INDEX equ 03c0h ;registre index d'AC HPELPAN equ 20h OR 13h ;registre horizontal pel panning ;d'AC ;(le bit 7 est supérieur pour garder l'adressage ;de la palette RAM actif) dseg segment para common 'DATA' CurrentPage db PAGE1 ;page à afficher CurrentPageOffset dw PAGE1_OFFSET ; ; Valeurs de l'image de la balle multicolore des quatre plans. ; BallPlane0Image label byte ;image du plan bleu db 000h, 03ch, 000h, 001h, 0ffh, 080h db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h db 4 * 3 dup(000h) db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh db 4 * 3 dup(000h) db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h db 4 * 3 dup(000h) BallPlane1Image label byte ;image du plan vert db 4 * 3 dup(000h) db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh db 8 * 3 dup(000h) db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h db 001h, 0ffh, 080h, 000h, 03ch, 000h BallPlane2Image label byte ;image du plan rouge db 12 * 3 dup(000h) db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h db 001h, 0ffh, 080h, 000h, 03ch, 000h BallPlane3Image label byte ;intensité activée pour tous les plans ; afin de produire des couleurs de forte intensité db 000h, 03ch, 000h, 001h, 0ffh, 080h db 007h, 0ffh, 0e0h, 00fh, 0ffh, 0f0h db 01fh, 0ffh, 0f8h, 03fh, 0ffh, 0fch db 03fh, 0ffh, 0fch, 07fh, 0ffh, 0feh db 07fh, 0ffh, 0feh, 0ffh, 0ffh, 0ffh db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh db 0ffh, 0ffh, 0ffh, 0ffh, 0ffh, 0ffh db 0ffh, 0ffh, 0ffh, 07fh, 0ffh, 0feh db 07fh, 0ffh, 0feh, 03fh, 0ffh, 0fch db 03fh, 0ffh, 0fch, 01fh, 0ffh, 0f8h db 00fh, 0ffh, 0f0h, 007h, 0ffh, 0e0h db 001h, 0ffh, 080h, 000h, 03ch, 000h ; BallX dw 15, 50, 40, 70 ;tableau des coordonnées ; de la balle x BallY dw 40, 200, 110, 300 ;tableau des coordonnées ; de la balle y LastBallX dw 15, 50, 40, 70 ;coordonnées précédentes ; de la balle x LastBallY dw 40, 100, 160, 30 ;coordonnées précédentes ; de la balle y BallXInc dw 1, 1, 1, 1 ;facteur de déplacement x ; de la balle BallYInc dw 8, 8, 8, 8 ;facteur de déplacement y ; de la balle BallRep dw 1, 1, 1, 1 ;nombre de fois à maintenir ; en mouvement la balle ; conformément aux ; incréments courants BallControl dw Ball0Control, Ball1Control ;pointeurs sur les ;emplacements dw Ball2Control, Ball3Control ;courants dans les ;chaînes ; de contrôle de la balle BallControlString dw Ball0Control, Ball1Control ;pointeurs sur ;le début dw Ball2Control, Ball3Control ;des chaînes de ;contrôle de la balle ; Chaînes de contrôle de la balle. ; Ball0Control label word dw 10, 1, 4, 10, -1, 4, 10, -1, -4, 10, ;1, -4, 0 Ball1Control label word dw 12, -1, 1, 28, -1, -1, 12, 1, -1, 28, ;1, 1, 0 Ball2Control label word dw 20, 0, -1, 40, 0, 1, 20, 0, -1, 0 Ball3Control label word dw 8, 1, 0, 52, -1, 0, 44, 1, 0, 0 ; ; Chaîne du contrôle du scrolling. ; ifdef MEDRES_VIDEO_MODE PanningControlString dw 32, 1, 0, 34, 0, 1, 32, -1, 0, 34, 0, ; -1, 0 else PanningControlString dw 32, 1, 0, 184, 0, 1, 32, -1, 0, 184, ;0, -1, 0 endif PanningCintrolString dw PanningControlString ;pointeur sur l'emplacement ;courant dans la chaîne de ;contrôle du scrolling PanningRep dw 1 ;pas du scrolling conformément ;aux incréments ;du scrolling courant PanningXInc dw 1 ;facteur x de scrolling PanningYInc dw 0 ;facteur y de scrolling HPan db 0 ;paramétrage de horizontal de pel pan PanningStartOffset dw 0 ;ajustement de l'offset de départ pour ;effectuer un scrolling vertical ;& un scrolling horizontal dseg ends ; ; Macro pour positionner le registre indexé P2 du circuit avec le registre index ; P1 à AL. ; SETREG macro P1, P2 mov dx,P1 mov ah,al mov al,P2 out dx,ax endm ; cseg segment para public 'CODE' assume cs:cseg, ds:dseg start proc near mov ax,dseg mov ds,ax ; ; Sélectionne le mode graphique. ; ifdef MEDRES_VIDEO_MODE mov ax,010h else mov ax,0eh endif int 10h ; ; ES pointe toujours sur la mémoire VGA ; mov ax,VIDEO_SEGMENT mov es,ax ; ; Affiche une bordure autour de l'écran dans les deux pages. ; mov di,PAGE0_OFFSET call DrawBorder ;page 0 border mov di,PAGE1_OFFSET call DrawBorder ;page 1 border ; ; Affiche les valeurs de la balle dans les quatre plans de la mémoire VGA invisible ; mov al,01h ;active le plan 0 SETREG SC_INDEX, MAP_MASK mov si,offset BallPlane0Image mov di,BALL_OFFSET mov cx,BALL_WIDTH * BALL_HEIGHT rep movsb mov al,02h ;active le plan 1 SETREG SC_INDEX, MAP_MASK mov si,offset BallPlane1Image mov di,BALL_OFFSET mov cx,BALL_WIDTH * BALL_HEIGHT rep movsb mov al,04h ;active le plan 2 SETREG SC_INDEX, MAP_MASK mov si,offset BallPlane2Image mov di,BALL_OFFSET mov cx,BALL_WIDTH * BALL_HEIGHT rep movsb mov al,08h ;active le plan 3 SETREG SC_INDEX, MAP_MASK mov si,offset BallPlane3Image mov di,BALL_OFFSET mov cx,BALL_WIDTH * BALL_HEIGHT rep movsb ; ; Affiche une image vide de la taille de la balle dans la mémoire VGA invisible. ; mov al,0fh ;active tous les plans de mémoire, ;car le blanc SETREG SC_INDEX, MAP_MASK ;doit effacer tous les plans mov di,BLANK_OFFSET mov cx,BALL_WIDTH * BALL_HEIGHT sub al,al rep stosb ; ; Met VGA en mode write 1, pour copier en bloc l'image de la balle et l'image vide ; mov dx,GC_INDEX mov al,GC_MODE out dx,al ;le registre index GC pointe sur le ;mode GC inc dx ;pointe sur le registre Data de GC jmp $+2 ;delay to let bus settle in al,dx ;récupère l'état courant du mode GC and al,not 3 ;efface les bits du mode write or al,1 ;paramètre le champ du mode write à 1 jmp $+2 out dx,al ; ; Positionne le registre offset VGA en mots pour définir la largeur d'écran logique ; mov al,LOGICAL_SCREEN_WIDTH / 2 SETREG CRTC_INDEX, CRTC_OFFSET ; ; Déplace les balles en effaçant chaque balle, en les déplaçant, et les réaffichant ; puis permute les pages une fois qu'elles sont toutes déplacées. ; BallAnimationLoop: mov bx,( NUM_BALLS * 2 ) - 2 EachBallLoop: ; ; Efface l'ancienne image de la balle dans cette page (à l'emplacement de la plus ;récente). ; mov si,BLANK_OFFSET ;pointe sur l'image vide mov cx,[LastBallX+bx] mov dx,[LastBallY+bx] call DrawBall ; ; Paramètre le plus récent emplacement de la balle. ; mov ax,[BallX+bx] mov [LastballX+bx],ax mov ax,[BallY+bx] mov [LastballY+bx],ax ; ; Change les valeurs de déplacement de la balle s'il est temps de le faire. ; dec [BallRep+bx] jnz MoveBall mov si,[BallControl+bx] ;il est temps de changer ;les valeurs de déplacement lodsw ;récupère le nouveau facteur de ;répétition depuis la chaîne de contrôle and ax,ax ;à la fin de la chaîne de contrôle? jnz SetNewMove mov si,[BallControlString+bx] ;réinitialise la ;chaîne de contrôle lodsw ;récupère le nouveau facteur de répétition SetNewMove: mov [BallRep+bx],ax ;paramètre le nouveau facteur ;de répétition du mouvement lodsw ;paramètre le nouveau incrément de déplacement ; x mov [BallXInc+bx],ax lodsw ;paramètre le nouveau incrément de déplacement ; y mov [BallYInc+bx],ax mov [BallControl+bx],si ;sauve le nouveau pointeur ; de chaîne ; ; Déplace la balle. ; MoveBall: mov ax,[BallXInc+bx] add [BallX+bx],ax ;déplace dans la direction x mov ax,[BallYInc+bx] add [BallY+bx],ax ;déplace dans la direction y ; ; Affiche la balle à son nouvel emplacement. ; mov si,BALL_OFFSET ;pointe sur l'image de la balle ; mov cx,[BallX+bx] mov dx,[BallY+bx] call DrawBall ; dec bx dec bx jns EachBallLoop ; ; Configure le prochain état du scrolling (mais ne le programme pas encore ; dans VGA). ; call AdjustPanning ; ; Attend l'activation de l'affichage (les données de pixels étant affichées) ; nous savons que nous approchons d'une synchronisation verticale ; où l'adresse de départ est verrouillée et utilisée. ; call WaitDisplayEnable ; ; Permute la nouvelle page en changeant l'adresse de départ. ; mov ax,[CurrentPageOffset] add ax,[PanningStartOffset] push ax SETREG CRTC_INDEX, START_ADDRESS_LOW mov al,byte ptr [CurrentPageOffset+1] pop ax mov al,ah SETREG CRTC_INDEX, START_ADDRESS_HIGH ; ; Attend une synchronisation verticale ; call WaitVSync ; ; Paramètre à présent le scrolling horizontal. ; mov al,[HPan] mov dx,INPUT_STATUS_1 in al,dx ;réinitialise l'adressage d'AC sur ;le registre index mov dx,AC_INDEX mov al,HPELPAN out dx,al ;positionne l'index AC sur le ;registre pel pan mov al,[HPan] out dx,al ;paramètre le nouveau pel panning ; ; Permute la page à afficher avec la page invisible ; xor [CurrentPage],1 jnz IsPage1 mov [CurrentPageOffset],PAGE0_OFFSET jmp short EndFlipPage IsPage1: mov [CurrentPageOffset],PAGE1_OFFSET EndFlipPage: ; ; quitte si une touche a été pressée. ; mov ah,1 int 16h jnz Done jmp BallAnimationLoop ; ; Terminé, réinitialise le mode écran et quitte. ; Done: mov ah,0 int 16h ; mov ax,3 ;réintialise le mode texte int 10h ; mov ah,4ch ;quitte vers DOS int 21h ; start endp ; ; Routine pour afficher une image de la taille de la balle dans tous les plans, ;copiant depuis l'offset SI dans la mémoire VGA à l'offset CX,DX (x,y) dans la mémoire ; VGA dans la page courante. ; DrawBall proc near mov ax,LOGICAL_SCREEN_WIDTH mul dx ;offset de départ de la ligne ;d'affichage de l'image supérieure add ax,cx ;offset de la partie supérieure ;gauche de l'image add ax,[CurrentPageOffset] ;offset de départ de la ; page mov di,ax mov bp,BALL_HEIGHT push ds push es pop ds ;déplacement de la mémoire VGA à la ;mémoire VGA DrawBallLoop: push di mov cx,BALL_WIDTH rep movsb ;affiche une ligne d'affichage de ;l'image pop di add di,LOGICAL_SCREEN_WIDTH ;pointe sur la ligne d ;'affichage de la prochaine destination dec bp jnz DrawBallLoop pop ds ret DrawBall endp ; ; WaitVSync proc near mov dx,INPUT_STATUS_1 WaitNotVSyncLoop: in al,dx and al,VSYNC_MASK jnz WaitNotVSyncLoop WaitVSyncLoop: in al,dx and al,VSYNC_MASK jz WaitVSyncLoop ret WaitVSync endp ; ; Attend l'activation de l'affichage (pixels à afficher sur l'écran ; indiquant que nous sommes à la moitié de l'affichage d'une image). ; WaitDisplayEnable proc near mov dx,INPUT_STATUS_1 WaitDELoop: in al,dx and al,DE_MASK jnz WaitDELoop ret WaitDisplayEnable endp ; ; Effectue un scrolling horizontal/vertical. ; AdjustPanning proc near dec [PanningRep] ;est-il temps de récupérer de ;nouvelles valeurs de scrolling? jnz DoPan mov si,[PanningControl] ;pointe sur l'emplacement ;courant dans la chaîne ;de contrôle du scrolling lodsw ;récupère le facteur de répétition ;du scrolling and ax,ax ;à la fin de la chaîne de contrôle ;du scrolling? jnz SetnewPanValues mov si,offset PanningControlString ;réinitialise ;au début de la chaîne lodsw ;récupère le facteur de répétition du ; scrolling SetNewPanValues: mov [PanningRep],ax ;paramètre une nouvelle valeur ; de répétition du scrolling lodsw mov [PanningXInc],ax ;valeur du scrolling ;horizontal lodsw mov [PanningYInc],ax ;valeur du scrolling ;vertical mov [PanningControl],si ;sauve l'emplacement ;courant dans la chaîne ;de contrôle du scrolling ; Effectue un scrolling en fonction des valeurs indiquées. ; DoPan: mov ax,[PanningXInc] ; scrolling horizontal and ax,ax js PanLeft ;négatif signifie scrolling gauche ; jz CheckVerticalPan mov al,[HPan] inc al ;scrolling droit; si pel pan ;atteint cmp al,8 ;8, il est temps de passer au ;prochain octet jb SetHPan ;avec pel pan de 0 sub al,al ;et un offset de départ qui est ;supérieur inc [PanningStartOffset] ; à 1 jmp short SetHPan PanLeft: mov al,[HPan] dec al ;scrolling gauche; si pel pan ;atteint -1, jns SetHPan ;il est temps de passer au prochain mov al,7 ;octet avec PEL Pan de 7 et un dec [PanningStartOffset] ; offset de départ qui ;est inférieur à 1 SetHPan: mov [HPan],al ;sauve la nouvelle valeur de pel pan CheckVerticalPan: mov ax,[PanningYInc] ;scrolling vertical and ax,ax js PanUp ;négatif signifie scrolling vers le haut jz EndPan add [PanningStartOffset],LOGICAL_SCREEN_WIDTH jmp short EndPan PanUp: sub [PanningStartOffset],LOGICAL_SCREEN_WIDTH EndPan: ret ; ; Affiche une bordure autour de la zone de jeu qui commence à DI. ; DrawBorder proc near ; ; Affiche la bordure de gauche. ; push di mov cx,LOGICAL_SCREEN_HEIGHT / 16 DrawLeftBorderLoop: mov al,0ch ;sélectionne la couleur rouge pour ;le bloc call DrawBorderBlock add di,LOGICAL_SCREEN_WIDTH * 8 mov al,0eh ;sélectionne la couleur jaune pour ;le bloc call DrawBorderBlock add di,LOGICAL_SCREEN_WIDTH * 8 loop DrawLeftBorderLoop pop di ; ; Affiche la bordure de droite. ; push di add di,LOGICAL_SCREEN_WIDTH - 1 mov cx,LOGICAL_SCREEN_HEIGHT / 16 DrawRightBorderLoop: mov al,0eh ;sélectionne la couleur jaune pour l ;le bloc call DrawBorderBlock add di,LOGICAL_SCREEN_WIDTH * 8 mov al,0ch ;sélectionne la couleur rouge pour l le bloc call DrawBorderBlock add di,LOGICAL_SCREEN_WIDTH * 8 loop DrawRightBorderLoop pop di ; ; Affiche la bordure supérieure. ; push di mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2 DrawTopBorderLoop: inc di mov al,0eh ;sélectionne la couleur jaune pour ;le bloc call DrawBorderBlock inc di mov al,0ch ;sélectionne la couleur rouge pour ;le bloc call DrawBorderBlock loop DrawTopBorderLoop pop di ; ; Affiche la bordure inférieure. ; add di,(LOGICAL_SCREEN_HEIGHT - 8) * LOGICAL_SCREE ;N_WIDTH mov cx,(LOGICAL_SCREEN_WIDTH - 2) / 2 DrawBottomBorderLoop: inc di mov al,0ch ;sélectionne la couleur rouge pour ;le bloc call DrawBorderBlock inc di mov al,0eh ;sélectionne la couleur jaune pour ;le bloc call DrawBorderBlock loop DrawBottomBorderLoop ret DrawBorder endp ; ; Affiche un bloc de 8x8 de la bordure de couleur AL à l'emplacement DI. ; DI est préservé. ; DrawBorderBlock proc near push di SETREG SC_INDEX, MAP_MASK mov al,0ffh rept 8 stosb add di,LOGICAL_SCREEN_WIDTH - 1 endm pop di ret DrawBorderBlock endp AdjustPanning endp cseg ends end start