; ; Command & Conquer Red Alert(tm) ; Copyright 2025 Electronic Arts Inc. ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ;**************************************************************************** ;* ;* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S ;* ;*--------------------------------------------------------------------------- ;* ;* PROJECT ;* VQA player library. ;* ;* FILE ;* UnVQ4x2.asm ;* ;* DESCRIPTION ;* 4x2 VQ decompress/draw routines. ;* ;* PROGRAMMER ;* Denzil E. Long, Jr. ;* ;*--------------------------------------------------------------------------- ;* ;* PUBLIC ;* UnVQ_4x2_Xmode - Draw 4x2 VQ frame directly to Xmode. ;* UnVQ_4x2_XmodeCB - Draw 4x2 VQ frame to Xmode from VRAM codebook. ;* Upload_4x2CB - Upload 4x2 codebook into XMode VRAM. ;* UnVQ_4x2_VESA320_32K - Draw 4x2 VQ frame to VESA320 32k color. ;* XlatePointers - Translate pointer to optimal XMode format. ;* ;**************************************************************************** IDEAL MODEL LARGE P386N LOCALS ?? INCLUDE "vga.i" INCLUDE "vesavid.i" INCLUDE "vqaplay.i" CODESEG IF VQAXMODE_ON SKIP_PTR EQU 8000h CBOOK_SEG EQU (0B000h - 270h) IF VQABLOCK_4X2 ;**************************************************************************** ;* ;* NAME ;* UnVQ_4x2_Xmode - Draw 4x2 VQ frame directly to Xmode. ;* ;* SYNOPSIS ;* UnVQ_4x2_Xmode(Codebook, Pointers, Buffer, BPR, Rows, Dummy) ;* ;* void UnVQ_4x2_Xmode(unsigned char *, unsigned char *, unsigned char *, ;* unsigned short, unsigned short, unsigned short); ;* ;* FUNCTION ;* This function draws an image to the Xmode display from the pointers ;* and codebook provided. This routine has been optimized for a 320x200 ;* image. ;* ;* INPUTS ;* Codebook - Pointer to codebook used to draw image. ;* Pointers - Pointer to vector pointer data. ;* Buffer - Pointer to buffer to draw image into. ;* BPR - Number of blocks per row. ;* Rows - Number of rows. ;* Dummy - Not used (prototype placeholder) ;* ;* RESULT ;* NONE ;* ;**************************************************************************** PUBLIC C UnVQ_4x2_Xmode PROC C UnVQ_4x2_Xmode FAR USES ARG codebook:FAR PTR ARG pointers:FAR PTR ARG buffer:FAR PTR ARG blocksperrow:WORD ARG numrows:WORD ARG dummy:WORD ;------------------------------------------------------------------- ; Local variables: ;------------------------------------------------------------------- LOCAL data_end:WORD ; end of pointer data LOCAL si_startval:WORD ; init value for SI, for new plane LOCAL es_startval:WORD ; init value for ES, for new plane LOCAL di_startval:WORD ; init value for DI, for new row LOCAL cb_offset:WORD ; codebook offset ;=================================================================== ; Initialization ;=================================================================== ;------------------------------------------------------------------- ; Save our registers ;------------------------------------------------------------------- push ds push es push fs pushad ;------------------------------------------------------------------- ; Save codebook's address in FS:[cb_offset]: ; - load it into DS:SI, and normalize it ; - save it into FS:[cb_offset], and subtract 4 from it, so the ; pointer offsets will point directly at the correct codeword ;------------------------------------------------------------------- lds si,[codebook] ; DS:SI = codebook cmp si, 16 ; SI < 16 ? jb short ??Decrement_codebook ; yes - don't normalize it mov ax, si ; AX = SI shr ax, 4 ; AX = SI / 16 mov bx, ds ; BX = DS add ax, bx ; AX = (SI / 16) + DS mov ds, ax ; adjust DS upward and si, 000Fh ; save only low nybble ??Decrement_codebook: mov ax,ds ; AX = cb segment sub ax,1 ; subtract 16 bytes mov fs,ax ; save in FS mov [cb_offset],si add [cb_offset],12 ;------------------------------------------------------------------- ; Load pointers into DS:SI, then normalize DS:SI to minimize offset ;------------------------------------------------------------------- ??Normalize_pointers: lds si, [pointers] ; DS:SI = pointers cmp si, 16 ; SI < 16 ? jb short ??Set_Data_End ; yes - don't normalize it mov ax, si ; AX = SI shr ax, 4 ; AX = SI / 16 mov bx, ds ; BX = DS add ax, bx ; AX = (SI / 16) + DS mov ds, ax ; adjust DS upward and si, 000Fh ; save only low nybble ;------------------------------------------------------------------- ; Set [data_end] to [pointers] + size of ptr data ;------------------------------------------------------------------- ??Set_Data_End: mov ax,[numrows] mul [blocksperrow] ; AX = total # blocks shl ax,1 ; mult by 2 for word size add ax,si ; compute end of data mov [data_end],ax ; store it mov [si_startval],si ; save SI ;------------------------------------------------------------------- ; Load buffer into ES:DI, then normalize ES:DI to minimize offset ;------------------------------------------------------------------- les di, [buffer] ; point ES:DI to dest mov [es_startval],es ; save ES's start value mov [di_startval],di ; store it cmp di, 16 ; DI < 16 ? jb short ??Set_XPlane1 ; yes - don't normalize it mov ax, di ; AX = DI shr ax, 4 ; AX = DI / 16 mov bx, es ; BX = ES add ax, bx ; AX = (DI / 16) + ES mov es, ax ; adjust ES upward and di, 000Fh ; save only low nybble mov [es_startval],es ; save ES's start value mov [di_startval],di ; save DI's start value ;=================================================================== ; The drawing loop: ; DS:SI = pointer data ; ES:DI = drawing buffer ; FS:[cb_offset] = codebook ;=================================================================== ;=================================================================== ; Set X-Mode Plane 1 ; Plane 1 is the left half of even-numbered blocks on a row. ; (left pixel = low byte of codebook word) ;=================================================================== ??Set_XPlane1: SET_PLANE XPLANE_1 ;------------------------------------------------------------------- ; Start a new row of drawing ;------------------------------------------------------------------- ??Start_row_1: mov cx,[blocksperrow] ; # blocks to fill a line ;------------------------------------------------------------------- ; Start a new block ;------------------------------------------------------------------- ??Not_finished_a_line_1: ; ;..................... get next pointer word ....................... ; mov bx,[WORD PTR DS:SI] ; AX = pointer word add si,2 ; SI = next pointer ; ;.................... check for a 1-color block .................... ; or bx,bx ; check to see if high bit set js short ??One_color_1 ;------------------------------------------------------------------- ; Draw a multi-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- add bx,[cb_offset] ; get codebook offset ; ;................ transfer bytes from FS:BX to ES:DI ............... ; mov ax,[fs:bx] ; get 1st codeword mov dx,[fs:bx+4] ; get 2nd codeword mov [es:di],al ; draw 1st mov [es:di+80],dl ; draw 2nd inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_1 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_1 ; no - goto end jmp ??Start_row_1 ; start new block row ;------------------------------------------------------------------- ; Draw 1-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- ??One_color_1: ; ;................... skip ptr value SKIP_PTR ....................... ; cmp bx,SKIP_PTR jne ??Draw_One_Color_1 inc di dec cx jnz short ??Not_finished_a_line_1 jmp ??Next_row_1 ; ;................. transfer bytes from AX to DS:SI ................. ; ??Draw_One_Color_1: not bx mov bh,bl ; dup al in al&ah mov [es:di],bl ; set pixel mov [es:di+80],bl ; set pixel inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_1 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; ??Next_row_1: mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_1 ; no - goto end jmp ??Start_row_1 ; start new block row ??End_of_data_1: ;------------------------------------------------------------------- ; Restore DS:SI to start of pointer data, and ES:DI to Xmode page ;------------------------------------------------------------------- mov si,[si_startval] mov es,[es_startval] mov di,[di_startval] ;=================================================================== ; Set X-Mode Plane 2 ; Plane 2 is the right half of even-numbered blocks on a row. ; (right pixel = high byte of codebook word) ;=================================================================== SET_PLANE XPLANE_2 ;------------------------------------------------------------------- ; Start a new row of drawing ;------------------------------------------------------------------- ??Start_row_2: mov cx,[blocksperrow] ; # blocks to fill a line ;------------------------------------------------------------------- ; Start a new block ;------------------------------------------------------------------- ??Not_finished_a_line_2: ; ;..................... get next pointer word ....................... ; mov bx,[WORD PTR DS:SI] ; AX = pointer word add si,2 ; SI = next pointer ; ;.................... check for a 1-color block .................... ; or bx,bx ; check to see if high bit set js short ??One_color_2 ;------------------------------------------------------------------- ; Draw a multi-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- add bx,[cb_offset] ; get codebook offset ; ;................ transfer bytes from FS:BX to ES:DI ............... ; mov ax,[fs:bx] ; get 1st codeword mov dx,[fs:bx+4] ; get 2nd codeword mov [es:di],ah ; draw 1st mov [es:di+80],dh ; draw 2nd inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_2 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_2 ; no - goto end jmp ??Start_row_2 ; start new block row ;------------------------------------------------------------------- ; Draw 1-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- ??One_color_2: ; ;................... skip ptr value SKIP_PTR ....................... ; cmp bx,SKIP_PTR jne ??Draw_One_Color_2 inc di dec cx jnz short ??Not_finished_a_line_2 jmp ??Next_row_2 ; ;................. transfer bytes from AX to DS:SI ................. ; ??Draw_One_Color_2: not bx mov bh,bl ; dup al in al&ah mov [es:di],bh ; store 2 colors mov [es:di+80],bh ; store 2 colors inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_2 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; ??Next_row_2: mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_2 ; no - goto end jmp ??Start_row_2 ; start new block row ??End_of_data_2: ;------------------------------------------------------------------- ; Restore DS:SI to start of pointer data, and ES:DI to Xmode page ;------------------------------------------------------------------- mov si,[si_startval] mov es,[es_startval] mov di,[di_startval] ;=================================================================== ; Set X-Mode Plane 3 ; Plane 3 is the left half of odd-numbered blocks on a row. ; (left pixel = low byte of codebook word) ;=================================================================== SET_PLANE XPLANE_3 ;------------------------------------------------------------------- ; Start a new row of drawing ;------------------------------------------------------------------- ??Start_row_3: mov cx,[blocksperrow] ; # blocks to fill a line ;------------------------------------------------------------------- ; Start a new block ;------------------------------------------------------------------- ??Not_finished_a_line_3: ; ;..................... get next pointer word ....................... ; mov bx,[WORD PTR DS:SI] ; AX = pointer word add si,2 ; SI = next pointer ; ;.................... check for a 1-color block .................... ; or bx,bx ; check to see if high bit set js short ??One_color_3 ;------------------------------------------------------------------- ; Draw a multi-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- add bx,[cb_offset] ; get codebook offset ; ;................ transfer bytes from FS:BX to ES:DI ............... ; mov ax,[fs:bx+2] ; get 1st codeword mov dx,[fs:bx+6] ; get 2nd codeword mov [es:di],al ; draw 1st mov [es:di+80],dl ; draw 2nd inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_3 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_3 ; no - goto end jmp ??Start_row_3 ; start new block row ;------------------------------------------------------------------- ; Draw 1-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- ??One_color_3: ; ;................... skip ptr value SKIP_PTR ....................... ; cmp bx,SKIP_PTR jne ??Draw_One_Color_3 inc di dec cx jnz short ??Not_finished_a_line_3 jmp ??Next_row_3 ; ;................. transfer bytes from AX to DS:SI ................. ; ??Draw_One_Color_3: not bx mov bh,bl ; dup al in al&ah mov [es:di],bl ; store 2 colors mov [es:di+80],bl ; store 2 colors inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_3 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; ??Next_row_3: mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_3 ; no - goto end jmp ??Start_row_3 ; start new block row ??End_of_data_3: ;------------------------------------------------------------------- ; Restore DS:SI to start of pointer data, and ES:DI to Xmode page ;------------------------------------------------------------------- mov si,[si_startval] mov es,[es_startval] mov di,[di_startval] ;=================================================================== ; Set X-Mode Plane 4 ; Plane 4 is the right half of odd-numbered blocks on a row. ; (right pixel = high byte of codebook word) ;=================================================================== SET_PLANE XPLANE_4 ;------------------------------------------------------------------- ; Start a new row of drawing ;------------------------------------------------------------------- ??Start_row_4: mov cx,[blocksperrow] ; # blocks to fill a line ;------------------------------------------------------------------- ; Start a new block ;------------------------------------------------------------------- ??Not_finished_a_line_4: ; ;..................... get next pointer word ....................... ; mov bx,[WORD PTR DS:SI] ; AX = pointer word add si,2 ; SI = next pointer ; ;.................... check for a 1-color block .................... ; or bx,bx ; check to see if high bit set js short ??One_color_4 ;------------------------------------------------------------------- ; Draw a multi-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- add bx,[cb_offset] ; get codebook offset ; ;................ transfer bytes from FS:BX to ES:DI ............... ; mov ax,[fs:bx+2] ; get 1st codeword mov dx,[fs:bx+6] ; get 2nd codeword mov [es:di],ah ; draw 1st mov [es:di+80],dh ; draw 2nd inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_4 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_4 ; no - goto end jmp ??Start_row_4 ; start new block row ;------------------------------------------------------------------- ; Draw 1-color block ; (AX = pointer byte) ; (ES:DI = buffer position to draw at) ; (FS:[cb_offset] = codebook address) ;------------------------------------------------------------------- ??One_color_4: ; ;................... skip ptr value SKIP_PTR ....................... ; cmp bx,SKIP_PTR jne ??Draw_One_Color_4 inc di dec cx jnz short ??Not_finished_a_line_4 jmp ??Next_row_4 ; ;................. transfer bytes from AX to DS:SI ................. ; ??Draw_One_Color_4: not bx mov bh,bl ; dup al in al&ah mov [es:di],bh ; store 2 colors mov [es:di+80],bh ; store 2 colors inc di ; next pixel ; ;..................... check block count ........................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line_4 ;------------------------------------------------------------------- ; Go to the next block row: ; - Add new offset to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ; (Divide by 4 because there's 1/4 as many addresses per line ; in XMODE) ;------------------------------------------------------------------- ; ;....................... Add 80*2/16 to ES ......................... ; ??Next_row_4: mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; cmp si,[data_end] jnb short ??End_of_data_4 ; no - goto end jmp ??Start_row_4 ; start new block row ??End_of_data_4: popad pop fs pop es pop ds ret ENDP UnVQ_4x2_Xmode ;**************************************************************************** ;* ;* NAME ;* UnVQ_4x2_XmodeCB - Draw 4x2 VQ frame to Xmode from VRAM codebook. ;* ;* SYNOPSIS ;* UnVQ_4x2_XmodeCB(Dummy, Pointers, Buffer, BPR, Rows) ;* ;* void UnVQ_4x2_XmodeCB(unsigned char *, unsigned char *, ;* unsigned char *, unsigned short, ;* unsigned short); ;* ;* FUNCTION ;* This routine copies codebook entries from video RAM to video RAM. ;* The procedure for Write Mode 1 is: ;* ;* - Perform a CPU read at the address of the 4-byte codebook entry; ;* this will load each byte at that address from all 4 bitplanes ;* into the VGA's internal latches. ;* ;* - Perform a CPU write at the destination address, with the BitMask ;* register set to 0 (this tells the VGA hardware to only use the ;* data stored in the latches to write with), and the Map Mask ;* register set to 0Fh (all bitplanes enabled). ;* ;* Optimized for 320x200. ;* The codebook must have been downloaded to video RAM before this ;* routine is called. This routine assumes the multicolor block pointers ;* have been pre-divided by 4, and have a total of 512 added to them, so ;* the pointer is an exact offset into the codebook. ;* ;* INPUTS ;* Dummy - Not used (prototype placeholder) ;* Pointers - Pointer to vector pointer data. ;* Buffer - Pointer to Xmode buffer. ;* BPR - Number of blocks per row. ;* Rows - Number of rows. ;* ;* RESULT ;* NONE ;* ;**************************************************************************** PUBLIC C UnVQ_4x2_XmodeCB PROC C UnVQ_4x2_XmodeCB FAR USES ARG cbdummy:FAR PTR ARG pointers:FAR PTR ARG buffer:FAR PTR ARG blocksperrow:WORD ARG numrows:WORD ;------------------------------------------------------------------- ; Local variables: ;------------------------------------------------------------------- LOCAL di_startval:WORD ; init value for DI, for new row ;=================================================================== ; Initialization ;=================================================================== ;------------------------------------------------------------------- ; Save our registers ;------------------------------------------------------------------- push ds push es push fs pushad ;------------------------------------------------------------------- ; Save codebook's segment in DS ;------------------------------------------------------------------- mov ax,CBOOK_SEG mov ds,ax ;------------------------------------------------------------------- ; Load pointers into FS:BX ;------------------------------------------------------------------- les di,[pointers] mov ax,es mov fs,ax mov bx,di ;------------------------------------------------------------------- ; Load screen address into ES:DI ;------------------------------------------------------------------- les di, [buffer] ; point ES:DI to dest mov [di_startval],di ; store it ;------------------------------------------------------------------- ; Initialize VGA registers: ; - Enable all bitplanes for writing ; - Set the BitMask register to 0, so only the data from the ; VGA latches is written into the bitplanes ;------------------------------------------------------------------- SET_PLANE 0fh ; enable all planes for write SET_WRITEMODE 1 ;=================================================================== ; The drawing loop: ; DS:SI = codebook ; ES:DI = drawing buffer ; FS:BX = pointers ;=================================================================== ;------------------------------------------------------------------- ; Start a new row of drawing ;------------------------------------------------------------------- ??Start_row: mov cx,[blocksperrow] ; # blocks to fill a line ;------------------------------------------------------------------- ; Start a new block ;------------------------------------------------------------------- ??Not_finished_a_line: ; ;..................... get next pointer word ....................... ; mov si,[WORD PTR fs:bx] ; SI = ptr word (cbook offset) add bx,2 ; next ptr word ; ;................... skip ptr value SKIP_PTR ....................... ; cmp si,SKIP_PTR jne ??Draw_Block inc di dec cx jnz short ??Not_finished_a_line jmp ??Next_row ;------------------------------------------------------------------- ; Draw a block via the VGA internal latches: ; DS:SI = codebook address ; ES:DI = buffer position to draw at ; - Load the VGA latches from the 1st 4 codebook bytes ; - write 4 pixels with one CPU write ; - If this is a one-color block, skip the next codebook read ; (Video RAM reads are very slow); otherwise, latch the next 4 ; codebook bytes ; - write the next 4 pixels ;------------------------------------------------------------------- ; ;..................... draw 1st 4 pixels ........................... ; ??Draw_Block: mov al,[ds:si] ; latch 1st 4 cbook bytes mov [es:di],al ; write 4 pixels ; ;.................. check for 1-color block ........................ ; cmp si,512 ; if 1color blk, don't read jb ??One_Color ; ;..................... draw next 4 pixels .......................... ; mov al,[ds:si+1] ; latch next 4 cbook bytes ??One_Color: mov [es:di+80],al ; write next 4 pixels inc di ; next block position ; ;...................... check block count .......................... ; dec cx ; decrement block count jnz short ??Not_finished_a_line ;------------------------------------------------------------------- ; Go to the next block row: ; - Add (80*2/16) to ES, and set DI to its start-row value ; (Incrementing the segment allows us to unpack up to 1MB of data) ;------------------------------------------------------------------- ; ;...................... add (320*2/16) to ES ....................... ; ??Next_row: mov ax,es add ax,10 ; add 80*2/16 mov es,ax ; ;.................. set DI to its start-row value .................. ; mov di,[di_startval] ; ;............ see if we're past the end of the ptr data ............ ; dec [numrows] jg ??Start_row ??End_of_data: ;------------------------------------------------------------------- ; Restore VGA Write Mode to 0 ;------------------------------------------------------------------- SET_WRITEMODE 0 popad pop fs pop es pop ds ret ENDP UnVQ_4x2_XmodeCB ;**************************************************************************** ;* ;* NAME ;* Upload_4x2CB - Upload 4x2 codebook into XMode VRAM. ;* ;* SYNOPSIS ;* Upload_4x2CB(Codebook, Entries) ;* ;* void Upload_4x2CB(unsigned char *, unsigned short); ;* ;* FUNCTION ;* This routine copies the given codebook into Xmode VRAM, so that it ;* can be used later for direct video-to-video copies. The address used ;* is the end of video memory minus 02700h (10K). This should be plenty ;* for a 3000-entry codebook; each 4x2 codebook entry will take up 8 ;* 8 bytes, or 2 addresses in XMode (6000 addresses). ;* ;* The routine also creates a 1-color-block table in VRAM, so the 1-color ;* blocks can be generated the same way as the multicolor blocks. ;* ;* XMode 320x200 uses 320x200/4 addresses per page, for a total of 32000 ;* addresses. XMode 320x240 uses 320x240/4 addresses per page, for a ;* total of 38400 addresses. This leaves 27136 addresses unused. ;* ;* INPUTS ;* Codebook - Pointer to codebook to copy. ;* Entries - Number of codebook entries to copy. ;* ;* RESULT ;* NONE ;* ;**************************************************************************** PUBLIC C Upload_4x2CB PROC C Upload_4x2CB FAR USES ds si es di cx dx ARG codebook:FAR PTR ARG numentries:WORD ;=================================================================== ; Generate the 1-color block table by writing each color value from ; 0-255 into all 4 bitplanes, at 256 consecutive addresses: ;=================================================================== SET_PLANE 0fh ; enable all bitplanes for writing ;................................................................... ; Set ES:DI to destination address, set up CX for the loop ;................................................................... mov ax,CBOOK_SEG mov es,ax mov di,0 mov cx,256 mov ax,0 ??1_Color_Loop: mov [es:di],al ; write 4 bytes inc di ; next 4-byte position mov [es:di],al ; write 4 bytes inc di ; next 4-byte position inc ax ; next color # dec cx ; decrement loop counter jnz ??1_Color_Loop ;=================================================================== ; Copy the codebook into video RAM, one plane at a time: ;=================================================================== ;------------------------------------------------------------------- ; Copy codebook byte 0 into Plane 1 ;------------------------------------------------------------------- ;................................................................... ; Set DS:SI to codebook address, ES:DI to screen address ; (Codebook is stored at offset 1, so the pointers will point at ; exactly the right offset.) ;................................................................... lds si, [codebook] ; DS:SI = codebook mov ax,CBOOK_SEG mov es,ax mov di,512 ;................................................................... ; Set up the loop ;................................................................... SET_PLANE XPLANE_1 mov cx,[numentries] ; set loop counter shl cx,1 ; do 2 DWORDS per cbook entry ;................................................................... ; Loop through codebook entries ;................................................................... ??CB_Loop_1: mov al,[ds:si] mov [es:di],al add si,4 inc di dec cx jnz ??CB_Loop_1 ;------------------------------------------------------------------- ; Copy codebook byte 1 Plane 2 ;------------------------------------------------------------------- ;................................................................... ; Set DS:SI to codebook address, ES:DI to screen address ; (Codebook is stored at offset 1, so the pointers will point at ; exactly the right offset.) ;................................................................... lds si, [codebook] ; DS:SI = codebook mov ax,CBOOK_SEG mov es,ax mov di,512 add si,1 ; use 2nd byte value ;................................................................... ; Set up the loop ;................................................................... SET_PLANE XPLANE_2 mov cx,[numentries] ; set loop counter shl cx,1 ; do 2 DWORDS per cbook entry ;................................................................... ; Loop through codebook entries ;................................................................... ??CB_Loop_2: mov al,[ds:si] mov [es:di],al add si,4 inc di dec cx jnz ??CB_Loop_2 ;------------------------------------------------------------------- ; Copy codebook byte 2 Plane 3 ;------------------------------------------------------------------- ;................................................................... ; Set DS:SI to codebook address, ES:DI to screen address ; (Codebook is stored at offset 1, so the pointers will point at ; exactly the right offset.) ;................................................................... lds si, [codebook] ; DS:SI = codebook mov ax,CBOOK_SEG mov es,ax mov di,512 add si,2 ; use 3rd byte value ;................................................................... ; Set up the loop ;................................................................... SET_PLANE XPLANE_3 mov cx,[numentries] ; set loop counter shl cx,1 ; do 2 DWORDS per cbook entry ;................................................................... ; Loop through codebook entries ;................................................................... ??CB_Loop_3: mov al,[ds:si] mov [es:di],al add si,4 inc di dec cx jnz ??CB_Loop_3 ;------------------------------------------------------------------- ; Copy codebook byte 3 Plane 4 ;------------------------------------------------------------------- ;................................................................... ; Set DS:SI to codebook address, ES:DI to screen address ; (Codebook is stored at offset 1, so the pointers will point at ; exactly the right offset.) ;................................................................... lds si, [codebook] ; DS:SI = codebook mov ax,CBOOK_SEG mov es,ax mov di,512 add si,3 ; use 4th byte value ;................................................................... ; Set up the loop ;................................................................... SET_PLANE XPLANE_4 mov cx,[numentries] ; set loop counter shl cx,1 ; do 2 DWORDS per cbook entry ;................................................................... ; Loop through codebook entries ;................................................................... ??CB_Loop_4: mov al,[ds:si] mov [es:di],al add si,4 inc di dec cx jnz ??CB_Loop_4 ret ENDP Upload_4x2CB ENDIF ;VQABLOCK_4X2 ;**************************************************************************** ;* ;* NAME ;* XlatePointers - Translate pointer to optimal XMode format. ;* ;* SYNOPSIS ;* XlatePointers(Pointers, Entries) ;* ;* void XlatePointers(unsigned char *, unsigned short); ;* ;* FUNCTION ;* ;* INPUTS ;* Pointers - Pointer to vector pointers to translate. ;* Entries - Number of pointer entries. ;* ;* RESULT ;* NONE ;* ;**************************************************************************** PUBLIC C XlatePointers PROC C XlatePointers FAR USES ds si cx ARG pointers:FAR PTR ARG numpointers:WORD ;------------------------------------------------------------------- ; Load pointers into DS:SI ;------------------------------------------------------------------- lds si,[pointers] mov cx,[numpointers] ; init to # pointers on scrn ??Process_pointer: ; ;..................... get next pointer word ....................... ; mov ax,[WORD PTR ds:si] ; SI = ptr word (cbook offset) ; ;.................... check for a 1-color block .................... ; or ax,ax ; check to see if high bit set js short ??One_color ; ;....................... multi-color pointer ....................... ; sub ax,4 ; subtract 4 shr ax,2 ; divide by 4 add ax,512 ; add 512 mov [WORD PTR ds:si],ax ; save new value add si,2 ; next ptr word ; ;....................... see if we're done ......................... ; dec cx jnz ??Process_pointer jmp ??Done ??One_color: ; ;......................... 1-color pointer ......................... ; not ax ; get actual color value shl ax,1 ; multiply by 2 mov [WORD PTR ds:si],ax ; save new value add si,2 ; next ptr word ; ;....................... see if we're done ......................... ; dec cx jnz ??Process_pointer ??Done: ret ENDP XlatePointers ENDIF ;VQAXMODE_ON END