Outils pour utilisateurs

Outils du site


back2root:tutoriaux:vga-avance-dac-part-3

Différences

Ci-dessous, les différences entre deux révisions de la page.


Révision précédente
back2root:tutoriaux:vga-avance-dac-part-3 [2024/08/08 10:54] (Version actuelle) – [Le Code] frater
Ligne 1: Ligne 1:
 +====== VGA Avancée - DAC - Part 3 ======
 +
 +===== CopperList avancée =====
 +
 +Dans nos deux derniers articles, nous avons appris à faire des dégradés et ensuite à programmer un changement de couleur suivant l'index de la ligne en cours. Maintenant il faut mixer les deux.
 +
 +Comme je l'ai dit dans un article précédent, la carte VGA n'est pas aussi performante que un processeur dédié comme en disposait l'amiga (voir même le C64 dans une moindre mesure).
 +
 +Nous allons donc re-définir nos instructions et en ajouter une nouvelle.
 +
 +==== Instruction CopperList ====
 +
 +Nous allons corrigé un problème qui peut se présenter avec certains chipset VGA, la limite des intensités qui varie de 0 à 63. Pour éviter les ennuis, nous allons tout simplement ramener les intensité de notre copperlist à 6 bits (via un shr).
 +
 +=== Wait: 0x10 ===
 +
 +Aucune modification n'est apportée a cette instruction.
 +
 +=== SetColor: 0x20 ===
 +
 +Cette instruction est modifiée dans son comportement, les intensités de rouge, vert et bleu sont divisées par 4 avant d'être envoyées au DAC.
 +
 +=== GradiantTo: 0x30 ===
 +
 +Cette instruction prends les valeurs du dernier "SetColor" (y compris la couleur) pour faire varier les intensités jusqu'aux nouvelles valeurs paramètres, et ce depuis la ligne courant jusqu'à la ligne cible.
 +
 +^  Byte 0  ^  Byte 1  ^  Byte 2  ^  Byte 3  ^  Byte 4  ^  Byte 5  ^
 +|  0x30  |  LineH  |  LineL  |  Red  |  Green  |  Blue  |
 +
 +Les bytes "LineH" et "LineL" sont les octets de poids fort et faible du mot qui défini la ligne "cible", celle-ci DOIT être inférieur à copper_maxrow, sans quoi l’exécution des copper s’arrêtent avec un code d'erreur.
 +
 +=== EOC: 0xFF ===
 +
 +Cette instruction n'est pas modifiée.
 +
 +==== Le Code ====
 +
 +<code c>
 +#include "dos.h"
 +#include "conio.h"
 +
 +typedef unsigned char BYTE;
 +typedef unsigned int  WORD;
 +
 +// copper_maxrow is a parameter to avoid copper/raster to turn forever
 +// copper_error must be set to 0 to run
 +
 +int    copper_maxrow    = 400;
 +BYTE   copper_error      = 0;
 +
 +#define PRECIS             8
 +
 +BYTE copperlistv2[] =
 +  {
 +    0x20,       0x00, 0x00, 0x00, 0x00,         // setColor   0x00 0x00,0x00,0x00  : Black
 +    0x30, 0x00, 0x32, 0xFF, 0xFF, 0x00,         // GradiantTo 0x32 0xFF,0xFF,0x00  : Yellow
 +    0x30, 0x00, 0x64, 0xFF, 0x00, 0x00,         // GradiantTo 0x64 0x09,0x0f,0x34  : Red
 +    0x30, 0x00, 0x96, 0x00, 0x00, 0x00,         // GradiantTo 0x96 0x00,0x00,0x00  : Black
 +    0x30, 0x00, 0xC8, 0xFF, 0xFF, 0x00,         // GradiantTo 0x32 0xFF,0xFF,0x00  : Yellow
 +    0x30, 0x00, 0xFA, 0xFF, 0x00, 0x00,         // GradiantTo 0x64 0x09,0x0f,0x34  : Red
 +    0x30, 0x01, 0x2C, 0x00, 0x00, 0x00,         // GradiantTo 0x96 0x00,0x00,0x00  : Black
 +    0xFF                                        // EOC
 +
 +  };
 +
 +void DrawCopperListv2(char *copperlist)
 +{
 +  BYTE  color=0;
 +  BYTE  red_prec=0, green_prec=0, blue_prec=0;    // color set or starting of gradient
 +  BYTE  red_step=0, green_step=0, blue_step=0;    // steps (end color - start color)
 +  BYTE  red_end=0, green_end=0, blue_end=0;       // end color
 +  WORD  line_end=0, line_start=0;                 // line end line start
 +  WORD  line_delta=0;                             // delta between end and start
 +
 +  if (copper_error!=0)
 +    return;
 +
 +    asm {
 +        push  ds
 +        push  si
 +        lds   si,copperlist
 +        xor    cx,cx                  // reset cx : line counter
 +        xor    bx,bx
 +        mov   dx,0x3DA }              // wait for stable know pos (0)
 +w1: asm {
 +        in    al,dx
 +        test  al,0x08
 +        jne   w1 }
 +w2: asm {
 +        in    al,dx
 +        test  al,0x08
 +        je    w2 }
 +
 +start:asm {                           // protection
 +        mov   al,0x05                 // error 1
 +        cmp   cx,copper_maxrow        // line counter copper> max ?
 +        jb    start2                  // go
 +        jmp    eocl }                 // exit
 +
 +start2: asm {
 +        lodsb                         // load copper list operand
 +        cmp   al,0xFF                 // eocl ?
 +        jne   start3
 +        xor    al,al
 +        jmp    eocl }
 +
 +start3: asm {
 +        cmp   al,0x10                 // wait ?
 +        jne    start4
 +        jmp    wait_line }
 +
 +start4:asm {
 +        cmp   al,0x20                 // setcolor ?
 +        jne    start5
 +        jmp    set_color }
 +
 +start5:asm {
 +        cmp   al,0x30                 // gradient ?
 +        je    gradient
 +
 +        mov   al,0xFF                 // unknown command
 +        jmp   eocl }
 +
 +// ------------------------------------- GRADIENT
 +gradient: asm {
 +        mov    line_start,cx          // preserve line start
 +        lodsw
 +        mov    bh,al                  // reverse endian
 +        mov   bl,ah
 +        mov   line_end,bx             // preserve line end
 +
 +        // calculate the number of line between line_start and line_end
 +        sub    bx,cx
 +        mov    line_delta,bx          // pct_max = line count between line_start and end
 +
 +        lodsb                         // load red_end
 +        shr    al,2                   // reduce to 6 bits only
 +        mov    red_end,al             // preserve red target
 +        mov    ah,al
 +
 +        mov    bl,red_prec            // bl = red start
 +        sub    al,bl                  // end - start
 +        mov   red_step,al             // calculate Red Stepping
 +        mov    red_prec,ah            //
 +
 +        lodsb                         // load green_end
 +        shr    al,2
 +        mov    green_end,al
 +        mov    ah,al
 +        mov    bl,green_prec          // get green start
 +        sub    al,bl
 +        mov   green_step,al           // calculate green stepping
 +        mov    green_prec,ah
 +
 +        lodsb                         // load blue_end
 +        shr    al,2
 +        mov    blue_end,al
 +        mov    ah,al
 +        mov   bl,blue_prec
 +        sub    al,bl
 +        mov   blue_step,al
 +        mov    blue_prec,ah }         // calculate Blue Stepping
 +
 +gr_start: asm {
 +        inc    cx                     // cx = cx+1
 +        cmp   cx,line_end             // gradient complet ?
 +        jb    gradient_hbl
 +        jmp    start  }               // next operant
 +
 +gradient_hbl:asm {
 +        mov    dx,0x3da }             // read input state
 +gr_in_retrace:asm  {
 +        in    al,dx                   // test if we are redrawing
 +        test  al,1
 +        jne    gr_in_retrace }
 +
 +gr_in_display:asm  {
 +        in    al,dx
 +        test  al,1                    // wait for hbl (horizontal return)
 +        je    gr_in_display
 +
 +        mov    ax,cx
 +        sub    ax,line_start          // pct_current(ax) = currentline(cx) - line_start
 +        mov    bx,line_delta          // bx = line_start - line_end
 +
 +        xor   dx,dx
 +        shl   ax,PRECIS               // increase precision
 +        div   bx                      // pct_current / pct_max
 +        mov    bx,ax                  // bx = percentage 0..100
 +
 +        cli
 +        mov   al,color
 +        mov    dx,0x3c8
 +        out   dx,al                   // select color index
 +        inc   dx
 +
 +        xor   ax,ax
 +        mov   al,red_step
 +        imul  bl                      // must be signed multiplication
 +        shr   ax,PRECIS
 +        add   al,red_prec
 +        out    dx,al                  // set RED to dac
 +        mov    red_end,al
 +
 +        xor   ax,ax
 +        mov   al,green_step
 +        imul  bl                      // must be signed multiplication
 +        shr   ax,PRECIS
 +        add   al,green_prec
 +        out    dx,al                  // set GREEN to dac
 +        mov    green_end,al
 +
 +        xor   ax,ax
 +        mov   al,blue_step
 +        imul  bl                      // must be signed multiplication
 +        shr   ax,PRECIS
 +        add   al,blue_prec
 +        out    dx,al                  // set BLUE to dac
 +        mov    blue_end,al
 +        sti
 +
 +        jmp   gr_start }              // new line
 +
 +// ------------------------------------- WAIT
 +wait_line:asm  {
 +        lodsw
 +        mov    bh,al                  // swap byte endian encoding craps
 +        mov   bl,ah                   // bx = line word
 +        mov    dx,0x3da }             // input state
 +
 +wait_next: asm {
 +        inc    cx                     // cx = cx+1
 +        cmp   cx,bx                   // current line>= wait_line ?
 +        jae   wait_end }              // YES : next operand please
 +
 +in_retrace:asm  {
 +        in    al,dx                   // read input state, test if we are redrawing
 +        test  al,1
 +        jne    in_retrace }
 +in_display:asm  {
 +        in    al,dx
 +        test  al,1                    // wait for hbl (horizontal return)
 +        je    in_display
 +        jmp   wait_next }             // new line
 +
 +wait_end:asm {
 +        jmp    start }
 +
 +// ------------------------------------- SETCOLOR
 +set_color: asm {
 +        cli
 +        lodsb                         // get color index
 +        mov   color,al
 +        mov    dx,0x3c8
 +        out   dx,al                   // select color index
 +        inc   dx                      // mov   dx,0x3c9
 +
 +        lodsb                         // get RED level
 +        shr    al,2
 +        mov   red_prec,al
 +        out    dx,al                  // set RED to dac
 +
 +        lodsb                         // get GREEN level
 +        shr    al,2
 +        mov   green_prec,al
 +        out    dx,al                  // set GREEN to dac
 +
 +        lodsb                         // get BLUE level
 +        shr    al,2
 +        mov   blue_prec,al
 +        out    dx,al                  // set BLUE to dac
 +        sti
 +        jmp   start }                 // get next operand
 +
 +eocl:asm {
 +        sti
 +        pop    si
 +        pop    ds
 +        mov   copper_error, al        // set error (if any)
 +
 +        xor    al,al                  // normally we should restore whole DAC's status
 +        mov    dx,0x3c8               // but we only reset color 0 to black
 +        out    dx,al
 +        inc    dx
 +        out    dx,al                  // turn to RGB 0,0,0
 +        out    dx,al
 +        out    dx,al  }
 +}
 +
 +void main()
 +{
 +  unsigned char running=1;
 +
 +  textmode(3);
 +  clrscr();
 +
 +  while (running)
 +  {
 +    running=(copper_error?0:1);
 +    if (kbhit())
 +    {
 +      running=0;
 +    }
 +    // do some stuffs
 +
 +    printf("T h i s  I s  T h e  T e s t\n");
 +    DrawCopperListv2(copperlistv2);
 +  }
 +
 +  printf("\n error: %i\n",copper_error);
 +}
 +
 +
 +</code>
 +
 +== Commentaire sur les sources ==
 +
 +<WRAP center round info 95%>
 +A cause des limitations du x86 concernant les jump conditionnels (near), il a fallut mettre en place un structure de type switch case; car l'oppérande n'est que de 2 octets et n'est pas capable de faire de sauts conditionnel au delà d'un delta de -126 +127.
 +
 +Le build-in assembler de borland C++ utilise des instruction 'near' pour son assemblage, ce qui fait que certains sauts sont hors limite; pour contourner ce problème il aurait fallut écrire le code assembleur ''.386'' dans un fichier //.asm// et ensuite le linker au code C, ce qui aurait permis de réduire la "boucle" comme ci-dessous.
 +</WRAP>
 +
 +<code asm>
 +        mov   al,0x05                 // error 1
 +        cmp   cx,copper_maxrow        // line counter copper> max ?
 +        jae   eocl                    // exit
 +
 +        lodsb                         // load copper list operand
 +        cmp   al,0xFF                 // eocl ?
 +        je    eocl
 +        cmp   al,0x10                 // wait ?
 +        je    wait_line
 +        cmp   al,0x20                 // setcolor ?
 +        je    set_color
 +        cmp   al,0x30                 // gradient ?
 +        je    gradient
 +        jmp   eocl                    // unknown command
 +
 +
 +</code>
 +
 +Ce qui se révèle plus simple et plus rapide (pas de re-fetch), mais dans le cadre de ce tuto cela n'a pas grande importance.
 +
 +=== Source Code asm ===
 +
 +<code asm>
 +          .model   TCHUGE
 +          jumps
 +          locals
 +          .386
 +
 +PRECIS              EQU       8
 +
 +CODESEG
 +
 +; public variables
 +
 +_copper_error        db        0                       ; error reporting
 +_copper_maxrow      dw        400                      ; max linescan
 +
 +public _copper_error
 +public _copper_maxrow
 +
 +; private variables
 +
 +;color               db        0                   ; color set or starting of gradient
 +;red_prec            db        0
 +;green_prec          db        0
 +;blue_prec           db        0
 +
 +;red_step            db        0                   ; steps (end color - start color)
 +;green_step          db        0
 +;blue_step           db        0
 +
 +;red_end             db        0                   ; end color
 +;green_end           db        0
 +;blue_end            db        0
 +
 +;line_end            dw        0                   ; line end line start
 +;line_start          dw        0
 +;line_delta          dw        0                   ; delta between end and start
 +
 +public    _DrawCopperList
 +
 +_DrawCopperList PROC C FAR
 +        ARG      CopperList:DWORD
 +local   color:byte
 +local   red_prec:byte, green_prec:byte, blue_prec:byte
 +local   red_step:byte, green_step:byte, blue_step:byte
 +local   red_end:byte , green_end:byte , blue_end:byte
 +local   line_end: word, line_start: word, line_delta: word
 +
 +        push  ds
 +        push  si
 +
 +        lds   si,copperlist
 +
 +        cmp    cs:_copper_error,0
 +        jne    clean_eocl
 +
 +        xor    ecx,ecx                 ; reset cx : line counter
 +        xor    ebx,ebx
 +
 +        mov   dx,03DAh                 ; wait for stable know pos (0)
 +w1:     in    al,dx
 +        test  al,08h
 +        jne   w1
 +w2:     in    al,dx
 +        test  al,08h
 +        je    w2
 +
 +start:  mov   al,01h                  ; error 1
 +        cmp   cx,CS:_copper_maxrow    ; line counter copper> max ?
 +        jae   eocl                    ; exit
 +
 +        lodsb                         ; load copper list operand
 +        cmp   al,0FFh                 ; eocl ?
 +        je    clean_eocl
 +
 +        cmp   al,010h                 ; wait ?
 +        je    wait_line
 +
 +        cmp   al,020h                 ; setcolor ?
 +        je    set_color
 +
 +        cmp   al,030h                 ; gradient ?
 +        je    gradient
 +
 +        mov   al,002h                 ; unknown command
 +        jmp   eocl
 +
 +; ------------------------------------- GRADIENT
 +gradient:
 +        mov    line_start,cx          ; preserve line start
 +        lodsw
 +        mov    bh,al                  ; reverse endian
 +        mov    bl,ah
 +        mov    line_end,bx            ; preserve line end
 +
 +        ; calculate the number of line between line_start and line_end
 +        sub    bx,cx
 +        mov    line_delta,bx          ; pct_max = line count between line_start and end
 +
 +        lodsb                         ; load red_end
 +        shr    al,2                   ; reduce to 6 bits only
 +        mov    red_end,al             ; preserve red target
 +        mov    ah,al
 +
 +        mov    bl,red_prec            ; bl = red start
 +        sub    al,bl                  ; end - start
 +        mov    red_step,al            ; calculate Red Stepping
 +        mov    red_prec,ah
 +
 +        lodsb                         ; load green_end
 +        shr    al,2
 +        mov    green_end,al
 +        mov    ah,al
 +        mov    bl,green_prec          ; get green start
 +        sub    al,bl
 +        mov    green_step,al          ; calculate green stepping
 +        mov    green_prec,ah
 +
 +        lodsb                         ; load blue_end
 +        shr    al,2
 +        mov    blue_end,al
 +        mov    ah,al
 +        mov    bl,blue_prec
 +        sub    al,bl
 +        mov    blue_step,al
 +        mov    blue_prec,ah           ; calculate Blue Stepping
 +
 +gr_start:
 +        inc    cx                     ; cx = cx+1
 +        cmp    cx,line_end            ; gradient complet ?
 +        jb     gradient_hbl
 +        jmp    start                  ; next operant
 +
 +gradient_hbl:
 +        mov    dx,03DAh               ; read input state
 +
 +gr_in_retrace:
 +        in     al,dx                  ; test if we are redrawing
 +        test   al,1
 +        jne    gr_in_retrace
 +
 +gr_in_display:
 +        in     al,dx
 +        test   al,                  ; wait for hbl (horizontal return)
 +        je     gr_in_display
 +
 +        xor    eax,eax
 +        mov    ax,cx
 +        sub    ax,line_start          ; pct_current(ax) = currentline(cx) - line_start
 +        mov    bx,line_delta          ; bx = line_start - line_end
 +
 +        xor    dx,dx
 +        shl    eax,PRECIS             ; increase precision
 +        div    bx                     ; pct_current / pct_max
 +        mov    bx,ax                  ; bx = percentage 0..100
 +
 +        cli
 +        mov    al,color
 +        mov    dx,03C8h
 +        out    dx,al                   ; select color index
 +        inc    dx
 +
 +        xor    eax,eax
 +        mov    al,red_step
 +        imul   bl                     ; must be signed multiplication
 +        shr    ax,PRECIS
 +        add    al,red_prec
 +        out    dx,al                  ; set RED to dac
 +        mov    red_end,al
 +
 +        xor    ax,ax
 +        mov    al,green_step
 +        imul   bl                     ; must be signed multiplication
 +        shr    ax,PRECIS
 +        add    al,green_prec
 +        out    dx,al                  ; set GREEN to dac
 +        mov    green_end,al
 +
 +        xor    ax,ax
 +        mov    al,blue_step
 +        imul   bl                     ; must be signed multiplication
 +        shr    ax,PRECIS
 +        add    al,blue_prec
 +        out    dx,al                  ; set BLUE to dac
 +        mov    blue_end,al
 +        sti
 +
 +        jmp    gr_start               ; new line
 +
 +; ------------------------------------- WAIT
 +wait_line:
 +        lodsw
 +        mov    bh,al                   ; swap byte endian encoding craps
 +        mov    bl,ah                   ; bx = line word
 +        mov    dx,03DAh                ; input state
 +
 +wait_next:
 +        inc    cx                      ; cx = cx+1
 +        cmp    cx,bx                   ; current line>= wait_line ?
 +        jae    wait_end                ; YES : next operand please
 +
 +in_retrace:
 +        in     al,dx                   ; read input state, test if we are redrawing
 +        test   al,1
 +        jne    in_retrace
 +in_display:
 +        in     al,dx
 +        test   al,                   ; wait for hbl (horizontal return)
 +        je     in_display
 +        jmp    wait_next               ; new line
 +
 +wait_end:
 +        jmp    start
 +
 +; ------------------------------------- SETCOLOR
 +set_color:
 +        cli
 +        lodsb                          ; get color index
 +        mov    color,al
 +        mov    dx,03C8h
 +        out    dx,al                   ; select color index
 +        inc    dx                      ; mov   dx,0x3c9
 +
 +        lodsb                          ; get RED level
 +        shr    al,2
 +        mov    red_prec,al
 +        out    dx,al                   ; set RED to dac
 +
 +        lodsb                          ; get GREEN level
 +        shr    al,2
 +        mov    green_prec,al
 +        out    dx,al                   ; set GREEN to dac
 +
 +        lodsb                          ; get BLUE level
 +        shr    al,2
 +        mov    blue_prec,al
 +        out    dx,al                   ; set BLUE to dac
 +        sti
 +        jmp    start                   ; get next operand
 +
 +clean_eocl:
 +        xor    al,al
 +eocl:
 +        mov   _copper_error, al        ; set error (if any)
 +        pop    si
 +        pop    ds
 +
 +        xor    al,al                   ; normally we should restore whole DAC's status
 +        mov    dx,03C8h                ; but we only reset color 0 to black
 +        out    dx,al
 +        inc    dx
 +        out    dx,al                   ; turn to RGB 0,0,0
 +        out    dx,al
 +        out    dx,al
 +        ret
 +_DrawCopperList endp
 +
 +      END
 +
 +
 +</code>
 +
 +=== le header .h ===
 +
 +<code c>
 +#ifndef __COPPERL_H__
 +#define __COPPERL_H__
 +
 +extern unsigned char copper_error;                    // error reporting
 +extern unsigned int  copper_maxrow;                   // max linescan
 +
 +extern void DrawCopperList(unsigned char *CopperList);
 +
 +#endif
 +</code>
 +
 +<nspages back2root/tutoriaux -simpleList -h1 -exclude:start -textPages="Tutoriaux disponible">
 +