CnC_Red_Alert/VQ/VQA32/UNVQXMDE.ASM.BAK

1222 lines
38 KiB
Plaintext
Raw Permalink Normal View History

;
; 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 <http://www.gnu.org/licenses/>.
;
;****************************************************************************
;*
;* 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