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/ | ||
+ | |||