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' | ||
| + | |||
| + | Comme je l'ai dit dans un article précédent, | ||
| + | |||
| + | 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, | ||
| + | |||
| + | === GradiantTo: 0x30 === | ||
| + | |||
| + | Cette instruction prends les valeurs du dernier " | ||
| + | |||
| + | ^ Byte 0 ^ Byte 1 ^ Byte 2 ^ Byte 3 ^ Byte 4 ^ Byte 5 ^ | ||
| + | | 0x30 | LineH | LineL | Red | Green | Blue | | ||
| + | |||
| + | Les bytes " | ||
| + | |||
| + | === EOC: 0xFF === | ||
| + | |||
| + | Cette instruction n'est pas modifiée. | ||
| + | |||
| + | ==== Le Code ==== | ||
| + | |||
| + | <code c> | ||
| + | #include " | ||
| + | #include " | ||
| + | |||
| + | typedef unsigned char BYTE; | ||
| + | typedef unsigned int WORD; | ||
| + | |||
| + | // copper_maxrow is a parameter to avoid copper/ | ||
| + | // copper_error must be set to 0 to run | ||
| + | |||
| + | int copper_maxrow | ||
| + | BYTE | ||
| + | |||
| + | #define PRECIS | ||
| + | |||
| + | BYTE copperlistv2[] = | ||
| + | { | ||
| + | 0x20, 0x00, 0x00, 0x00, 0x00, // setColor | ||
| + | 0x30, 0x00, 0x32, 0xFF, 0xFF, 0x00, // GradiantTo 0x32 0xFF, | ||
| + | 0x30, 0x00, 0x64, 0xFF, 0x00, 0x00, // GradiantTo 0x64 0x09, | ||
| + | 0x30, 0x00, 0x96, 0x00, 0x00, 0x00, // GradiantTo 0x96 0x00, | ||
| + | 0x30, 0x00, 0xC8, 0xFF, 0xFF, 0x00, // GradiantTo 0x32 0xFF, | ||
| + | 0x30, 0x00, 0xFA, 0xFF, 0x00, 0x00, // GradiantTo 0x64 0x09, | ||
| + | 0x30, 0x01, 0x2C, 0x00, 0x00, 0x00, // GradiantTo 0x96 0x00, | ||
| + | 0xFF // EOC | ||
| + | |||
| + | }; | ||
| + | |||
| + | void DrawCopperListv2(char *copperlist) | ||
| + | { | ||
| + | BYTE color=0; | ||
| + | BYTE red_prec=0, green_prec=0, | ||
| + | BYTE red_step=0, green_step=0, | ||
| + | BYTE red_end=0, green_end=0, | ||
| + | WORD line_end=0, line_start=0; | ||
| + | WORD line_delta=0; | ||
| + | |||
| + | if (copper_error!=0) | ||
| + | return; | ||
| + | |||
| + | asm { | ||
| + | push ds | ||
| + | push si | ||
| + | lds | ||
| + | xor cx,cx // reset cx : line counter | ||
| + | xor bx,bx | ||
| + | mov | ||
| + | w1: asm { | ||
| + | in al,dx | ||
| + | test al,0x08 | ||
| + | jne w1 } | ||
| + | w2: asm { | ||
| + | in al,dx | ||
| + | test al,0x08 | ||
| + | je w2 } | ||
| + | |||
| + | start:asm { // protection | ||
| + | mov | ||
| + | cmp | ||
| + | jb start2 | ||
| + | jmp eocl } // exit | ||
| + | |||
| + | start2: asm { | ||
| + | lodsb // load copper list operand | ||
| + | cmp | ||
| + | jne | ||
| + | xor al,al | ||
| + | jmp eocl } | ||
| + | |||
| + | start3: asm { | ||
| + | cmp | ||
| + | jne start4 | ||
| + | jmp wait_line } | ||
| + | |||
| + | start4:asm { | ||
| + | cmp | ||
| + | jne start5 | ||
| + | jmp set_color } | ||
| + | |||
| + | start5:asm { | ||
| + | cmp | ||
| + | je gradient | ||
| + | |||
| + | mov | ||
| + | jmp eocl } | ||
| + | |||
| + | // ------------------------------------- GRADIENT | ||
| + | gradient: asm { | ||
| + | mov line_start, | ||
| + | lodsw | ||
| + | mov bh,al // reverse endian | ||
| + | mov bl,ah | ||
| + | mov | ||
| + | |||
| + | // calculate the number of line between line_start and line_end | ||
| + | sub bx,cx | ||
| + | mov line_delta, | ||
| + | |||
| + | lodsb // load red_end | ||
| + | shr al,2 // reduce to 6 bits only | ||
| + | mov red_end, | ||
| + | mov ah,al | ||
| + | |||
| + | mov bl, | ||
| + | sub al,bl // end - start | ||
| + | mov | ||
| + | mov red_prec, | ||
| + | |||
| + | lodsb // load green_end | ||
| + | shr al,2 | ||
| + | mov green_end, | ||
| + | mov ah,al | ||
| + | mov bl, | ||
| + | sub al,bl | ||
| + | mov | ||
| + | mov green_prec, | ||
| + | |||
| + | lodsb // load blue_end | ||
| + | shr al,2 | ||
| + | mov blue_end,al | ||
| + | mov ah,al | ||
| + | mov | ||
| + | sub al,bl | ||
| + | mov | ||
| + | mov blue_prec, | ||
| + | |||
| + | gr_start: asm { | ||
| + | inc cx // cx = cx+1 | ||
| + | cmp | ||
| + | jb gradient_hbl | ||
| + | jmp start } // next operant | ||
| + | |||
| + | gradient_hbl: | ||
| + | mov dx,0x3da } // 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,1 // wait for hbl (horizontal return) | ||
| + | je gr_in_display | ||
| + | |||
| + | mov ax,cx | ||
| + | sub ax, | ||
| + | mov bx, | ||
| + | |||
| + | xor dx,dx | ||
| + | shl | ||
| + | div | ||
| + | mov bx,ax // bx = percentage 0..100 | ||
| + | |||
| + | cli | ||
| + | mov | ||
| + | mov dx,0x3c8 | ||
| + | out | ||
| + | inc dx | ||
| + | |||
| + | xor ax,ax | ||
| + | mov | ||
| + | imul bl // must be signed multiplication | ||
| + | shr | ||
| + | add | ||
| + | out dx,al // set RED to dac | ||
| + | mov red_end,al | ||
| + | |||
| + | xor ax,ax | ||
| + | mov | ||
| + | imul bl // must be signed multiplication | ||
| + | shr | ||
| + | add | ||
| + | out dx,al // set GREEN to dac | ||
| + | mov green_end, | ||
| + | |||
| + | xor ax,ax | ||
| + | mov | ||
| + | imul bl // must be signed multiplication | ||
| + | shr | ||
| + | add | ||
| + | out dx,al // set BLUE to dac | ||
| + | mov blue_end,al | ||
| + | sti | ||
| + | |||
| + | jmp | ||
| + | |||
| + | // ------------------------------------- WAIT | ||
| + | wait_line: | ||
| + | lodsw | ||
| + | mov bh,al // swap byte endian encoding craps | ||
| + | mov | ||
| + | mov dx,0x3da } // input state | ||
| + | |||
| + | wait_next: asm { | ||
| + | inc cx // cx = cx+1 | ||
| + | cmp | ||
| + | jae | ||
| + | |||
| + | 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,1 // wait for hbl (horizontal return) | ||
| + | je in_display | ||
| + | jmp | ||
| + | |||
| + | wait_end: | ||
| + | jmp start } | ||
| + | |||
| + | // ------------------------------------- SETCOLOR | ||
| + | set_color: asm { | ||
| + | cli | ||
| + | lodsb // get color index | ||
| + | mov | ||
| + | mov dx,0x3c8 | ||
| + | out | ||
| + | inc | ||
| + | |||
| + | lodsb // get RED level | ||
| + | shr al,2 | ||
| + | mov | ||
| + | out dx,al // set RED to dac | ||
| + | |||
| + | lodsb // get GREEN level | ||
| + | shr al,2 | ||
| + | mov | ||
| + | out dx,al // set GREEN to dac | ||
| + | |||
| + | lodsb // get BLUE level | ||
| + | shr al,2 | ||
| + | mov | ||
| + | out dx,al // set BLUE to dac | ||
| + | sti | ||
| + | jmp start } // get next operand | ||
| + | |||
| + | eocl:asm { | ||
| + | sti | ||
| + | pop si | ||
| + | pop ds | ||
| + | mov | ||
| + | |||
| + | xor al,al // normally we should restore whole DAC's status | ||
| + | mov dx, | ||
| + | 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? | ||
| + | if (kbhit()) | ||
| + | { | ||
| + | running=0; | ||
| + | } | ||
| + | // do some stuffs | ||
| + | |||
| + | printf(" | ||
| + | DrawCopperListv2(copperlistv2); | ||
| + | } | ||
| + | |||
| + | printf(" | ||
| + | } | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | == 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' | ||
| + | |||
| + | Le build-in assembler de borland C++ utilise des instruction ' | ||
| + | </ | ||
| + | |||
| + | <code asm> | ||
| + | mov | ||
| + | cmp | ||
| + | jae | ||
| + | |||
| + | lodsb // load copper list operand | ||
| + | cmp | ||
| + | je eocl | ||
| + | cmp | ||
| + | je wait_line | ||
| + | cmp | ||
| + | je set_color | ||
| + | cmp | ||
| + | je gradient | ||
| + | jmp | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | 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 | ||
| + | jumps | ||
| + | locals | ||
| + | .386 | ||
| + | |||
| + | PRECIS | ||
| + | |||
| + | CODESEG | ||
| + | |||
| + | ; public variables | ||
| + | |||
| + | _copper_error | ||
| + | _copper_maxrow | ||
| + | |||
| + | public _copper_error | ||
| + | public _copper_maxrow | ||
| + | |||
| + | ; private variables | ||
| + | |||
| + | ; | ||
| + | ; | ||
| + | ; | ||
| + | ; | ||
| + | |||
| + | ; | ||
| + | ; | ||
| + | ; | ||
| + | |||
| + | ; | ||
| + | ; | ||
| + | ; | ||
| + | |||
| + | ; | ||
| + | ; | ||
| + | ; | ||
| + | |||
| + | public | ||
| + | |||
| + | _DrawCopperList PROC C FAR | ||
| + | ARG CopperList: | ||
| + | local | ||
| + | local | ||
| + | local | ||
| + | local | ||
| + | local | ||
| + | |||
| + | push ds | ||
| + | push si | ||
| + | |||
| + | lds | ||
| + | |||
| + | cmp cs: | ||
| + | jne clean_eocl | ||
| + | |||
| + | xor ecx, | ||
| + | xor ebx,ebx | ||
| + | |||
| + | mov | ||
| + | w1: | ||
| + | test al,08h | ||
| + | jne w1 | ||
| + | w2: | ||
| + | test al,08h | ||
| + | je w2 | ||
| + | |||
| + | start: | ||
| + | cmp | ||
| + | jae | ||
| + | |||
| + | lodsb ; load copper list operand | ||
| + | cmp | ||
| + | je clean_eocl | ||
| + | |||
| + | cmp | ||
| + | je wait_line | ||
| + | |||
| + | cmp | ||
| + | je set_color | ||
| + | |||
| + | cmp | ||
| + | je gradient | ||
| + | |||
| + | mov | ||
| + | jmp eocl | ||
| + | |||
| + | ; ------------------------------------- GRADIENT | ||
| + | gradient: | ||
| + | mov line_start, | ||
| + | lodsw | ||
| + | mov bh,al ; reverse endian | ||
| + | mov bl,ah | ||
| + | mov line_end, | ||
| + | |||
| + | ; calculate the number of line between line_start and line_end | ||
| + | sub bx,cx | ||
| + | mov line_delta, | ||
| + | |||
| + | lodsb ; load red_end | ||
| + | shr al,2 ; reduce to 6 bits only | ||
| + | mov red_end, | ||
| + | mov ah,al | ||
| + | |||
| + | mov bl, | ||
| + | sub al,bl ; end - start | ||
| + | mov red_step, | ||
| + | mov red_prec,ah | ||
| + | |||
| + | lodsb ; load green_end | ||
| + | shr al,2 | ||
| + | mov green_end, | ||
| + | mov ah,al | ||
| + | mov bl, | ||
| + | sub al,bl | ||
| + | mov green_step, | ||
| + | mov green_prec, | ||
| + | |||
| + | lodsb ; load blue_end | ||
| + | shr al,2 | ||
| + | mov blue_end,al | ||
| + | mov ah,al | ||
| + | mov bl, | ||
| + | sub al,bl | ||
| + | mov blue_step, | ||
| + | mov blue_prec, | ||
| + | |||
| + | gr_start: | ||
| + | inc cx ; cx = cx+1 | ||
| + | cmp cx, | ||
| + | jb | ||
| + | jmp start ; next operant | ||
| + | |||
| + | gradient_hbl: | ||
| + | mov dx, | ||
| + | |||
| + | gr_in_retrace: | ||
| + | in | ||
| + | test al,1 | ||
| + | jne gr_in_retrace | ||
| + | |||
| + | gr_in_display: | ||
| + | in al,dx | ||
| + | test | ||
| + | je | ||
| + | |||
| + | xor eax,eax | ||
| + | mov ax,cx | ||
| + | sub ax, | ||
| + | mov bx, | ||
| + | |||
| + | xor dx,dx | ||
| + | shl eax, | ||
| + | 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 | ||
| + | shr ax,PRECIS | ||
| + | add al,red_prec | ||
| + | out dx,al ; set RED to dac | ||
| + | mov red_end,al | ||
| + | |||
| + | xor ax,ax | ||
| + | mov al, | ||
| + | imul | ||
| + | shr ax,PRECIS | ||
| + | add al, | ||
| + | out dx,al ; set GREEN to dac | ||
| + | mov green_end, | ||
| + | |||
| + | xor ax,ax | ||
| + | mov al, | ||
| + | imul | ||
| + | shr ax,PRECIS | ||
| + | add al, | ||
| + | out dx,al ; set BLUE to dac | ||
| + | mov blue_end,al | ||
| + | sti | ||
| + | |||
| + | jmp gr_start | ||
| + | |||
| + | ; ------------------------------------- WAIT | ||
| + | wait_line: | ||
| + | lodsw | ||
| + | mov bh,al ; swap byte endian encoding craps | ||
| + | mov bl,ah ; bx = line word | ||
| + | mov dx, | ||
| + | |||
| + | wait_next: | ||
| + | inc cx ; cx = cx+1 | ||
| + | cmp cx,bx ; current line>= wait_line ? | ||
| + | jae wait_end | ||
| + | |||
| + | in_retrace: | ||
| + | in | ||
| + | test al,1 | ||
| + | jne in_retrace | ||
| + | in_display: | ||
| + | in al,dx | ||
| + | test | ||
| + | je | ||
| + | jmp wait_next | ||
| + | |||
| + | 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 | ||
| + | |||
| + | 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, | ||
| + | out dx,al ; set GREEN to dac | ||
| + | |||
| + | lodsb ; get BLUE level | ||
| + | shr al,2 | ||
| + | mov blue_prec, | ||
| + | out dx,al ; set BLUE to dac | ||
| + | sti | ||
| + | jmp start ; get next operand | ||
| + | |||
| + | clean_eocl: | ||
| + | xor al,al | ||
| + | eocl: | ||
| + | mov | ||
| + | pop si | ||
| + | pop ds | ||
| + | |||
| + | xor al,al ; normally we should restore whole DAC's status | ||
| + | mov dx, | ||
| + | out dx,al | ||
| + | inc dx | ||
| + | out dx,al ; turn to RGB 0,0,0 | ||
| + | out dx,al | ||
| + | out dx,al | ||
| + | ret | ||
| + | _DrawCopperList endp | ||
| + | |||
| + | END | ||
| + | |||
| + | |||
| + | </ | ||
| + | |||
| + | === le header .h === | ||
| + | |||
| + | <code c> | ||
| + | #ifndef __COPPERL_H__ | ||
| + | #define __COPPERL_H__ | ||
| + | |||
| + | extern unsigned char copper_error; | ||
| + | extern unsigned int copper_maxrow; | ||
| + | |||
| + | extern void DrawCopperList(unsigned char *CopperList); | ||
| + | |||
| + | #endif | ||
| + | </ | ||
| + | |||
| + | <nspages back2root/ | ||
| + | |||