CnC_Red_Alert/WINVQ/VQA32/OLD/UNVQVESA.ASM

381 lines
10 KiB
NASM
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
;* VQAPlay32 library.
;*
;* FILE
;* unvqvesa.asm
;*
;* DESCRIPTION
;* VESA VQ decompress/draw routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Denzil E. Long, Jr.
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* UnVQ_4x2_VESA320_32K - Draw 4x2 VQ frame to VESA320 32k color.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "vga.i"
INCLUDE "vesavid.i"
INCLUDE "vqaplay.i"
CODESEG
SKIP_PTR EQU 8000h
IF VQAVESA_ON
IF VQABLOCK_4X2
;****************************************************************************
;*
;* NAME
;* UnVQ_4x2_VESA320_32K - Draw 4x2 VQ frame to VESA320 32k color.
;*
;* SYNOPSIS
;* UnVQ_4x2_VESA320_32K(Codebook, Pointers, Palette, GrainPerWin)
;*
;* void UnVQ_4x2_VESA320_32K(char *, char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Codebook - Pointer to codebook.
;* Pointers - Pointer to vector pointer data to unvq.
;* Palette - Pointer to 15-bit palette.
;* GrainPerWin - Granularity units for 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
;---------------------------------------------------------------------------
; SET_2_PIXELS:
; - Loads 2 bytes from codebook, expands them into words in eax
; - Sets them on the screen
; cb_index: offset into codebook of start of 2 bytes to load
; di_index: offset from current di to draw 2 pixels
; BX: offset into codebook of this block
; Uses: EAX, DX, SI!
;---------------------------------------------------------------------------
MACRO SET_2_PIXELS cb_index,edi_index
xor edx,edx
mov dl,[BYTE PTR ebx+1+cb_index]
shl edx,1
add edx,[palette]
mov esi,edx
mov ax,[WORD PTR esi]
shl eax,16
xor edx,edx
mov dl,[BYTE PTR ebx+cb_index]
shl edx,1
add edx,[palette]
mov esi,edx
mov ax,[WORD PTR esi]
IF PHARLAP_TNT
mov [DWORD PTR es:edi+edi_index],eax
ELSE
mov [DWORD PTR edi+edi_index],eax
ENDIF
ENDM
;---------------------------------------------------------------------------
; DRAW_BLOCK_ROWS macro:
; Draws 'numrows' rows of 'blocksperrow' blocks each
;---------------------------------------------------------------------------
MACRO DRAW_BLOCK_ROWS numrows,blocksperrow
LOCAL ??Start_row
LOCAL ??Not_finished_a_line
LOCAL ??One_color
LOCAL ??Draw_One_Color
LOCAL ??Next_row
LOCAL ??Done
mov [rowcount],numrows ; initialize row counter
;---------------------------------------- Start a new row:
??Start_row:
mov ecx,blocksperrow ; # blocks to fill a line
;---------------------------------------- Start a new block:
??Not_finished_a_line:
;........................................ Get next pointer word:
xor ebx,ebx
mov bx,[WORD PTR esi] ; BX = pointer word
add esi,2
;........................................ Check for a 1-color block:
or bx,bx ; see if high bit is set
js ??One_color
;---------------------------------------- Multi-color block:
mov [esi_save],esi ; save current SI
add ebx,[cb_offset] ; get codebook offset
SET_2_PIXELS 0,0
SET_2_PIXELS 2,4
SET_2_PIXELS 4,640
SET_2_PIXELS 6,644
add edi,8 ; next block position
mov esi,[esi_save] ; get current SI
;........................................ Check block count
dec ecx ; decrement block count
jnz ??Not_finished_a_line
;---------------------------------------- Next block row:
add edi,640
;
;............ see if we're past the end of the ptr data ............
;
dec [rowcount]
jnz ??Start_row
jmp ??Done
;---------------------------------------- 1-color block:
??One_color:
;................... skip ptr value SKIP_PTR .......................
cmp bx,SKIP_PTR
jne ??Draw_One_Color
add edi,8
dec ecx
jnz ??Not_finished_a_line
jmp ??Next_row
??Draw_One_Color:
not bx ; get palette index
shl bx,1 ; convert to WORD offset
add ebx,[palette]
mov ax,[WORD PTR ebx] ; get 15-bit palette value
mov dx,ax ; copy it into dx
shl eax,16
mov ax,dx ; eax = 2 pixels, same color
mov edx,eax ; edx = 2 pixels, same color
IF PHARLAP_TNT
mov [DWORD PTR es:edi],eax ; set 2 pixels
mov [DWORD PTR es:edi+4],edx ; set 2 pixels
mov [DWORD PTR es:edi+640],eax ; set 2 pixels
mov [DWORD PTR es:edi+644],edx ; set 2 pixels
ELSE
mov [DWORD PTR edi],eax ; set 2 pixels
mov [DWORD PTR edi+4],edx ; set 2 pixels
mov [DWORD PTR edi+640],eax ; set 2 pixels
mov [DWORD PTR edi+644],edx ; set 2 pixels
ENDIF
add edi,8 ; next block position
;........................................ Check block count
dec ecx ; decrement block count
jnz ??Not_finished_a_line
;---------------------------------------- Next block row:
??Next_row:
add edi,640
;
;............ see if we're past the end of the ptr data ............
;
dec [rowcount]
jnz ??Start_row
??Done:
ENDM
;---------------------------------------------------------------------------
; DRAW_BLOCK_PART_ROW macro:
; Draws top or bottom half of blocks on a row
; 'numblocks' = # blocks to draw
; 'cb_add' = amt to add to codebook (0=top half, 4=bottom half)
;---------------------------------------------------------------------------
MACRO DRAW_BLOCK_PART_ROW numblocks,cb_add
LOCAL ??Not_finished_a_line
LOCAL ??One_color
LOCAL ??Draw_One_Color
LOCAL ??Done
mov ecx,numblocks
;---------------------------------------- Start a new block:
??Not_finished_a_line:
;........................................ Get next pointer word:
xor ebx,ebx
mov bx,[WORD PTR esi] ; BX = pointer word
add esi,2
;........................................ Check for a 1-color block:
or bx,bx ; see if high bit is set
js short ??One_color
;---------------------------------------- Multi-color block:
mov [esi_save],esi ; save current SI
add ebx,[cb_offset] ; get codebook offset
SET_2_PIXELS cb_add,0
SET_2_PIXELS cb_add+2,4
add edi,8 ; next block position
mov esi,[esi_save] ; get current SI
;........................................ Check block count
dec ecx ; decrement block count
jnz short ??Not_finished_a_line
jmp ??Done
;---------------------------------------- 1-color block:
??One_color:
;................... skip ptr value SKIP_PTR .......................
cmp bx,SKIP_PTR
jne ??Draw_One_Color
add edi,8
dec ecx
jnz short ??Not_finished_a_line
jmp ??Done
??Draw_One_Color:
not bx ; get palette index
shl bx,1 ; convert to WORD offset
add ebx,[palette]
mov ax,[WORD PTR ebx] ; get 15-bit palette value
mov dx,ax ; copy it into dx
shl eax,16
mov ax,dx ; eax = 2 pixels, same color
mov edx,eax ; edx = 2 pixels, same color
IF PHARLAP_TNT
mov [DWORD PTR es:edi],eax ; set 2 pixels
mov [DWORD PTR es:edi+4],edx ; set 2 pixels
ELSE
mov [DWORD PTR edi],eax ; set 2 pixels
mov [DWORD PTR edi+4],edx ; set 2 pixels
ENDIF
add edi,8 ; next block position
;........................................ Check block count
dec ecx ; decrement block count
jnz ??Not_finished_a_line
??Done:
ENDM
;===========================================================================
; The actual procedure:
;===========================================================================
GLOBAL C UnVQ_4x2_VESA320_32K:NEAR
PROC UnVQ_4x2_VESA320_32K C NEAR
ARG codebook:NEAR PTR
ARG pointers:NEAR PTR
IF PHARLAP_TNT
ARG pal:QWORD ;KLUDGE - bcc32 pads FARPTR
ELSE
ARG palette:NEAR PTR
ENDIF
ARG grains_per_win:DWORD
ARG dummy1:DWORD
ARG dummy2:DWORD
LOCAL rowcount:DWORD ; # rows drawn
LOCAL esi_save:DWORD
LOCAL cb_offset:DWORD
IF PHARLAP_TNT
LOCAL palette:NEAR PTR
ENDIF
;-------------------------------------------------------------------
; Save registers
;-------------------------------------------------------------------
pushad
;-------------------------------------------------------------------
; Set GS:[cb_offset] to codebook
;-------------------------------------------------------------------
mov eax,[codebook]
sub eax,4
mov [cb_offset],eax
mov esi,[pointers]
;-------------------------------------------------------------------
; Set ES:DI to screen
;-------------------------------------------------------------------
IF PHARLAP_TNT
push es
les edi,[FWORD pal]
mov [palette],edi
mov eax,01Ch
mov es,ax
mov edi,0
ELSE
mov edi,0A0000h
ENDIF
;-------------------------------------------------------------------
; Do Bank 0:
; - 102 full scanlines (51 rows of blocks)
; - 128 pixels of the top half of blocks (32 top-half blocks)
;-------------------------------------------------------------------
SET_WINDOW 0
DRAW_BLOCK_ROWS 51,80
DRAW_BLOCK_PART_ROW 32,0 ; do top half
;-------------------------------------------------------------------
; Do Bank 1:
; - 128 pixels of the bottom half of the previous 32 blocks
; - 192 pixels of full blocks (1 row of 48 blocks)
; - 96 full scanlines (48 rows of blocks)
;-------------------------------------------------------------------
SET_WINDOW [grains_per_win]
sub esi,64 ; subtract word size of last 32 blks
mov edi,384
DRAW_BLOCK_PART_ROW 32,4 ; do bottom half
mov edi,0
DRAW_BLOCK_ROWS 1,48 ; draw one row of 48 full blocks
DRAW_BLOCK_ROWS 48,80 ; draw 48 full block rows
??End_of_data:
IF PHARLAP_TNT
pop es
ENDIF
popad
ret
ENDP UnVQ_4x2_VESA320_32K
ENDIF ;VQABLOCK_4X2
ENDIF ;VQAVESA_ON
END