;Affiche tous les pixels de la ligne d'affichage spécifiée, avec les couleurs ;de pixels prises dans le plaquage de texture spécifié.Emploie l'approche de pré-;avancée d'1/2 pixel dans l'image source et arrondit le pixel source le plus proche ;à chaque avancée, si bien que le plaquage de texture semblera relativement ; identique sous tous les angles. Cette routine est spécifique aux modes de plan ;(non chain4) de 320 pixels de large et en 256 couleurs comme le mode X qui est un ;mode 320x240(non chain4)en 256 couleurs. ;Appelable en C near comme suit: ; void ScanOutLine(EdgeScan*LeftEdge, EdgeScan * RightEdge); ;Testé avec TASM 3.0. SC-INDEX equ 03c4h ;Index Sequence Controller MAP-MASK equ 02h ;index dans SC du registre Map Mask SCREEN-SEG equ OaOOOh ;segment de la mémoire vidéo en mode X SCREEN-WIOTH equ 80 :largeur de l'écran en octets d'une ligne d'affichage ;à la suivante .model small .data extrn_TexMapBits:word, _TexMapWidth:word, _DestY:word extrn_CurrentPageBase:word, _ClipMinX:word extrn_ClipMinY:word, _ClipMaxX:word, _ClipMaxY:word ;Décrit l'emplacement courant et l'avancée d'un coté dans la source et la ;destination. EdgeScan struc Direction dw ? ;via la liste des cotés; 1 pour le coté droit ;(avance dans la liste des points),-1 pour le coté ;gauche (recule dans la liste des points) RemainingScans dw ? :hauteur restant à parcourir dans destination CurrentEnd dw ? ;numéro du point final du coté courant SourceX dd ? ; emplacement X dans la source pour ce coté SourceY dd ? ;emplacement Y dans la source pour ce coté SourceStepX dd ? ;avancée X dans la source par avancée Y de 1 dans ;destination SourceStepY dd ? ;avancée Y dans la source par avancée Y de 1 dans ;destination ;variables sont utilisées pour l'avancée X en entier ; de type Bresenham dans la destination, ce qui est ;indispensable pour placer avec précision les pixels ;et éviter les trous. Destx dw ? ;emplacement X courant dans destination pour ce coté DestXIntStep dw ? ;toute la partie de l'avancée X de destination par ;avancée Y d'une ligne d'affichage DestXDirection dw ? ;-l or 1 pour indiquer le sens de l'avancée X ;(gauche/droite) DestXErrTerm dw ? ;terme d'erreur courant pour l'avancée X courante DestXAdjUp dw ? ;somme à ajouter au terme d'erreur par déplacement de ;ligne d'affichage DestXAdjDown dw ? ;somme à soustraire du terme d'erreur quand ce ;dernier déborde EdgeScan ends Parms struc dw 2 dup(?) ;adresse de retour et BP empilé LeftEdge dw ? ;pointeur sur la structure EdgeScan pour le coté ; gauche RightEdge dw ? ;pointeur sur la structure EdgeScan pour le coté ;droit Parms ends ;Offsets depuis BP dans la stack frame des variables locales. 1SourceX equ -4 ;coordonnée X courante dans l'image source 1SourceY equ -8 ;coordonnée Y courante dans l'image 1SourceStepX equ -12 ;avancée X dans l'image source pour une avancée X de 1 ;dans destination lSourceStepY equ -16 ;avancée Y dans l'image source pour une avancée X de 1 ;dans destination 1XAdvanceByOne equ -18 ;Utilisé pour avancer en incrémentant de 1 pixel le ; pointeur source dans X 1XBaseAdvance equ -20 ;utilisé pour avancer en incrémentant d'un minimum de ;pixels le pointeur source dans X source pointer 1YAdvanceByOne equ -22 ;utilisé pour avancer en incrémentant de 1 pixel le ;pointeur source dans Y 1YBaseAdvance equ -24 ;utilisé pour avancer en incrémentant d'un minimum de ;pixels le pointeur source dans Y LOCAL_SIZE equ 24 ;taille totale des variables locales .code extrn _FixedMul:near, _FixedDiv:near align 2 ToScanDone: jmp ScanDone public _ScanOutLine align 2 _ScanOutLine proc near push bp ; préserve la stack frame de l'appelant mov bp,sp ;pointe sur notre stack frame sub sp,LOCAL_SIZE ; alloue de l'espace aux variables locales push si ; préserve les variables registre de l'appelant push di ; Il n'y a rien à faire si la destination est entièrement clippée en X mov di.[bp].RightEdge mov si.[di].DestX cmp si.[_ClipMinX] jle ToScanDone ;le coté droit est à gauche du rectangle de clipping, ; donc terminé mov bx,[bp].LeftEdge mov dx,[bx].DestX cmp dx,[-ClipMaxX] jle ToScanDone ;le coté gauche est à droite du rectangle de clipping, ; donc terminé sub si,dx :largeur de remplissage de destination jle ToScanDone ;largeur de remplissage nulle ou négative, donc ;terminé mov ax.word ptr [bx].SourceX ;coordonnée X source initiale mov word ptr [bp].lSourceX,ax mov ax,word ptr [bx].SourceX+2 mov word ptr [bp] 1SourceX+2,ax mov ax,word ptr [bx].SourceY ;coordonnée Y de source initiale mov word ptr [bp].lSourceY,ax mov ax.word ptr [bx].SourceY+2 mov word ptr [bp]1SourceY+2,ax ;Calcule l'avancé dans source qui correspond à chaque avancée X d'1pixel dans ;destination (dans la ligne d'affichage destination). push si ;largeur X de destination en virgule fixe sub ax,ax push ax ; empile 0 partie fractionnaire de la largeur X ; destination mov ax.word ptr [di].SourceX sub ax.word ptr [bp].lSourceX ; mot inférieur de la largeur X source mov dx,word ptr [di].SourceX+2 sbb dx,word ptr [bp].lSourceX+2 ;mot supérieur de la largeur X source push dx ;largeur X source en virgule fixe push ax call _FixedDiv ; largeur X source à correspond largeur X destination add sp,8 ;efface les paramètres dans la pile mov word ptr [bp].lSourceStepX.ax ; mémorise l'avancée X source par mov word ptr [bp].1SourceStepX+2.dx ; avancée X d'1 pixel dans ; destination mov cx,l ;suppose que X source avance de manière non négative and dx,dx ; dans quel sens avance X source ? jns SourceXNonNeg ;non négatif neg cx ;négatif cmp ax,0 ;l'avancée entière est-elle en un entier ? iz SourceXNonNeg ;oui inc dx ;non, tronque en entier vers 0, sinon nous obtiendrons ;une avancée plus grande de 1 SourceXNonNeg: mov [bp].lXAdvanceByOne.cx ;somme à ajouter au pointeur source pour un ;déplacement de 1 dans X mov [bp].1XBaseAdvance,dx ;minimum à ajouter au pointeur source chaque ; fois que la destination avance de 0 dans X push si ;hauteur Y destination en virgule fixe sub ax,ax push ax ; empile 0 partie fractionnaire de hauteur Y ;destination mov ax,word ptr [di].SourceY sub ax,word ptr [bp].lSourceY ;mot inférieur de hauteur Y source mov dx.word ptr [di].SourceY+2 sbb dx,word ptr [bp].lSourceY+2 ;mot supérieur de hauteur Y source push dx ; hauteur Y source en virgule fixe push ax call _FixedDiv ; hauteur Y source correspond à largeur X destination add sp,8 ;efface les paramètres dans la pile mov word ptr [bp].lSourceStepY.ax :mémorise l'avancée Y source par mov word ptr [bp].lSourceStepY+2,dx ;avancée X d'1 pixel dans ; destination mov cx,[_TexMapWidth] ;suppose que Y source avance dans un sens non ; négatif and dx,dx ;dans quel sens avance Y source? jns SourceYNonNeg ;non négatif neg cx ;négatif cmp ax,0 ; l'avancée est-elle en entier ? jz SourceYNonNeg ;oui inc dx ;non, tronque en entier vers 0, sinon nous ; obtiendrons une avancée trop grande de 1 SourceYNonNeg: mov [bp].lYAdvanceByOne.cx ;somme à ajouter au pointeur source pour un ; déplacement de 1 dans Y mov ax,[-TexMapWidth] ; distance minimale sautée dans source imul dx ; bitmap quand Y avance (ignorant la retenue mov [bp].1YBaseAdvance,ax ; de la partie fractionnaire) ;Progresse d'1/2 avancée dans le sens de l'avancée, pour espacer les pixels ;parcourus entre les cotés droit et gauche. (Il y a une légère imprécision dans la division de nombres négatifs par 2 en décalant au lieu de diviser, mais l'imprécision est le bit e moins significatif, et nous ferons avec). mov ax.word ptr [bp].lSourceStepX mov dx,word ptr [bp].1SourceStepX+2 sar dx,l rcr ax,l adc word ptr [bp].lSourceX+2,dx mov ax,word ptr [bp].TSourceStepY mov dx,word ptr [bp].lSourceStepY+2 sar dx,l rcr ax.1 add word ptr [bp].1SourceY,ax adc word ptr [bp].lSourceY+2.,dx Clippe le coté droit si nécessaire mov si,[di].DestX cmp si,[_ClipMaxX] jl RightEdgeClipped mov si,[-ClipMaxX] RightEdgeClipped: ; clippe le coté gauche si nécessaire mov bx,Ebp].LeftEdge mov di,[bx].DestX cmp di,[-ClipMinX] jge LeftEdgeClipped ; Clipping gauche est nécessaire; avançons donc la source neg di ;ClipMinX - DestX add di,[-ClipMinX] ; avance en premier lieu la source dans X push di ; ClipMinX-DestX en virgule fixe sub ax,ax push ax ; empile 0 partie fractionnaire de ClipMinX-DestX push word ptr [bp].1SourceStepX+2 push word ptr [bp].lSourceStepX call _FixedMul ;avancée complète de X source dans la partie clippée add sp,8 ;efface les paramètres dans la pile add word ptr [bp].lSourceX,ax ;avance X source après clipping adc word ptr [bp].lSourceX+2,dx ; push di ; ClipMinX-DestX en virgule fixe sub ax,ax push ax ; empile 0 partie fractionnaire de ClipMinX-DestX push word ptr [bp].lSourceStepY+2 push word ptr [bp].lSourceStepY call _FixedMul ; avancée complète de Y source dans partie clippée add sp,8 ;efface les paramètres de la pile add word ptr [bp].1SourceY,ax ; avance Y source après clipping adc word ptr [bp].lSourceY+2.dx mov di.[_ClipMinX] ; coordonnée X de départ destination après clipping LeftEdgeClipped: ;Calcule la largeur d'affichage de la destination clippée courante. sub si,di ;Parcourt la ligne d'affichage destination, en mettant à jour l'emplacement de ;l'image source. ;Pointe sur le pixel initial de l'image source, en ajoutant 0 et 5 à X et Y afin ;que nous puissions dès à présent tronquer en entier sans arrondir vraiment. mov ax,word ptr [bp].lSourceY+2 adc ax,0 mul [_TexMapWidth] ; ligne d'affichage initiale dans l'image source mov bx,word ptr [bp].lSourceX+2 ; offset dans la ligne d'affichage adc bx,ax ; offset source dans l'image source add bx.[_TexMapBits] ;DS:BX pointe sur le pixel initial de l'image ;Pointe sur le pixel destination initial. mov ax,SCREEN_SEG mov es.ax mov ax,SCREEN_WIDTH mul [_DestY] ;offset de la ligne d'affichage destination initiale mov cx,di :X initial de destination shr di,l shr di,1 ;X/4 = offset du pixel dans la ligne d'affichage add di,ax ;offset du pixel dans la page add di,[_CurrentPageBase] ;offset du pixel dans la mémoire vidéo ;ES:DI pointe sur le premier pixel de destination and cl,011lb ;CL = plan du pixel mov al,MAP_MASK mov dx.SC_INDEX out dx.al ;registre Index SC Index sur Map Mask mov al,llh ;un bit de plan dans les quatre bits, nous ;récupérerons alors la retenue automatiquement ; du plan 3 au plan 0 shl al,cl ; paramètre le bit pour le premier pixel du plan à 1 ;Si l'avancée X source est négative, changer pour travailler avec des valeurs qui ;ne sont pas négatives. cmp word ptr [bp].1XAdvanceByOne,0 jge SXStepSet neg word ptr [bp].lSourceStepX not word ptr [bp].lSourceX SXStepSet: ;Si l'avancée Y source est négative, changer pour travailler avec des valeurs qui ;ne sont pas négatives. cmp word ptr [bp].1YAdvanceByOne,0 jge SYStepSet neg word ptr [bp].lSourceStepY not word ptr [bp].lSourceY SYStepSet: ;A ce stade: AL = masque de plan de pixel initial BX = pointeur sur le pixel initial de l'image SI = nombre de pixels à remplir DI = pointeur sur le pixel initial de destination mov dx,SC_INDEX+1 ;point sur SC Data; Index pointe sur Map Mask ;Positionne Map Mask pour le plan de ce pixel, puis affiche le pixel. out dx,al mov ah,[bxl ;récupère le pixel de l'image mov es:[di],ah ;paramètre le pixel de l'image mov dx,SC_INDEX+l TexScanLoop: ;Pointe sur le prochain pixel source, add bx.[bp].1XBaseAdvance ; avance d'un minimum de pixels dans X mov cx,word ptr [bp].lSourceStepX add word ptr [bp].ISourceX,cx ;avance la partie fractionnaire X source jnc NoExtraXAdvance n'a pas permuté add bx,[bp].lXAdvanceByOne ; a permuté, avance X de un NoExtraXAdvance: add bx,[bp].1YBaseAdvance ;avance d'un minimum de pixels dans Y mov cx.word ptr [bp].lSourceStepY add word ptr [bp].1SourceY.cx ; avance la partie fractionnaire Y ;source jnc NoExtraYAdvance ; n'a pas permuté add bx,[bp].1YAdvanceByOne ; a permuté, avance Y de un NoExtraYAdvance: ;Pointe sur e prochain pixel destination, en allant au prochain plan et avançant à ;la prochaine adresse, si le plan passe de 3 à 0. rol al,l adc di,0 ;Continue s'il reste des pixels à afficher dec si jnz TextScanLoop ScanDone: pop di ;restaure les variables registre de l'appelant pop si mov sp,bp ;désalloue les variables locales pop bp ;restaure la stack frame de l'appelant ret ScanOutLine endp end