Outils pour utilisateurs

Outils du site


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

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

#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);
}
Commentaire sur les sources

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.

back2root/tutoriaux/vga-avance-dac-part-3.txt · Dernière modification : de frater