;
;	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