;
;	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
;*     VQAPlay library.
;*
;* FILE
;*     UnVQBuff.asm
;*
;* DESCRIPTION
;*     Buffered VQ decompress/draw routines.
;*
;* PROGRAMMER
;*     Denzil E. Long, Jr.
;*
;* DATE
;*     Feburary 8, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;*     UnVQ_2x2 - Draw 2x2 block VQ frame to a buffer.
;*     UnVQ_2x3 - Draw 2x3 block VQ frame to a buffer.
;*     UnVQ_4x2 - Draw 4x2 block VQ frame to a buffer.
;*     UnVQ_4x4 - Draw 4x4 block VQ frame to a buffer.
;*
;****************************************************************************

	IDEAL
	P386
	MODEL	USE32 FLAT
	LOCALS	??
	INCLUDE	"vga.i"
	INCLUDE	"vesavid.i"
	INCLUDE	"vqaplay.i"
	CODESEG

SKIP_PTR	EQU	8000h


	IF	VQABLOCK_2X2
;****************************************************************************
;*
;* NAME
;*     UnVQ_2x2 - Draw 2x2 block VQ frame to a buffer.
;*
;* SYNOPSIS
;*     UnVQ_2x2(Codebook, Pointers, Buffer, BPR, Rows, BufWidth)
;*
;*     void UnVQ_2x2(unsigned char *, unsigned char *, unsigned char *,
;*                        unsigned short, unsigned short, unsigned short);
;*
;* FUNCTION
;*     This function draws an image into the specified buffer 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.
;*     BufWidth - Width of destination buffer in pixels.
;*
;* RESULT
;*     NONE
;*
;****************************************************************************

	GLOBAL	C UnVQ_2x2:NEAR
	PROC	UnVQ_2x2 C NEAR USES ebx ecx edx esi edi

	ARG	codebook:NEAR PTR
	ARG	pointers:NEAR PTR

	IF	PHARLAP_TNT
	ARG	buffer:QWORD	;KLUDGE - bcc32 pads FARPTR
	ELSE
	ARG	buffer:NEAR PTR
	ENDIF

	ARG	blocksperrow:DWORD
	ARG	numrows:DWORD
	ARG	bufwidth:DWORD

	LOCAL	data_end:DWORD
	LOCAL	cb_offset:DWORD
	LOCAL	edi_startval:DWORD
	LOCAL	rowoffset:DWORD

;----------------------------------------------------------------------------
;	Initialize
;----------------------------------------------------------------------------

	mov	eax,[codebook]		;Adjust the codebook address so
	sub	eax,4		; that the pointer offsets will
	mov	[cb_offset],eax	; point directly at the codeword.

	mov	eax,[bufwidth]		;Compute the offset to the next
	shl	eax,1		; row of blocks.
	mov	[rowoffset],eax

	mov	esi,[pointers]
	mov	eax,[numrows]		;Compute the end address of the
	mul	[blocksperrow]		; pointer data.
	shl	eax,1
	add	eax,esi
	mov	[data_end],eax

	IF	PHARLAP_TNT
	push	es
	les	edi,[FWORD buffer]	;KLUDGE - bcc32 pads FARPTR
	ELSE
	mov	edi,[buffer]
	ENDIF

	mov	[edi_startval],edi

;----------------------------------------------------------------------------
;	Drawing loop
;----------------------------------------------------------------------------

??Start_row:
	mov	ecx,[blocksperrow]	;Number of blocks in a line

??Not_finished_a_line:
	sub	ebx,ebx
	mov	bx,[WORD PTR esi]	;Get the codebook pointer value
	add	esi,2		; then advance to the next one.

	or	bx,bx		;Is it a one color block?
	js	short ??One_color

;	Draw multi-color block

	add	ebx,[cb_offset]	;Codeword address
	mov	eax,[ebx]		;Read codeword
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],ax		;Write 1st row to dest
	ELSE
	mov	[edi],ax		;Write 1st row to dest
	ENDIF

	shr	eax,16

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],ax	;Write 2nd row to dest
	ELSE
	mov	[edi+ebx],ax		;Write 2nd row to dest
	ENDIF


	add	edi,2		;Next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

;	Draw 1-color block

??One_color:
	cmp	bx,SKIP_PTR		;Is this a skip block?
	jne	??Draw_One_Color

	add	edi,2		;Move to next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line
	jmp	??Next_row

??Draw_One_Color:
	not	bx		;NOT pointer value to get color
	mov	bh,bl		;Duplicate color through the
	mov	ax,bx		; entire dword register.
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],ax		;Write 1st row to dest
	mov	[es:edi+ebx],ax	;Write 2nd row to dest
	ELSE
	mov	[edi],ax		;Write 1st row to dest
	mov	[edi+ebx],ax		;Write 2nd row to dest
	ENDIF

	add	edi,2		;Next dest block positionw
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

??Next_row:
	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

??End_of_data:
	IF	PHARLAP_TNT
	pop	es
	ENDIF

	ret

	ENDP	UnVQ_2x2
	ENDIF	;VQABLOCK_2X2


	IF	VQABLOCK_2X3
;****************************************************************************
;*
;* NAME
;*     UnVQ_2x3 - Draw 2x3 block VQ frame to a buffer.
;*
;* SYNOPSIS
;*     UnVQ_2x3(Codebook, Pointers, Buffer, BPR, Rows, BufWidth)
;*
;*     void UnVQ_2x3(unsigned char *, unsigned char *, unsigned char *,
;*                        unsigned short, unsigned short, unsigned short);
;*
;* FUNCTION
;*     This function draws an image into the specified buffer 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.
;*     BufWidth - Width of destination buffer in pixels.
;*
;* RESULT
;*     NONE
;*
;****************************************************************************

	GLOBAL	C UnVQ_2x3:NEAR
	PROC	UnVQ_2x3 C NEAR USES ebx ecx edx esi edi

	ARG	codebook:NEAR PTR
	ARG	pointers:NEAR PTR

	IF	PHARLAP_TNT
	ARG	buffer:QWORD	;KLUDGE - bcc32 pads FARPTR
	ELSE
	ARG	buffer:NEAR PTR
	ENDIF

	ARG	blocksperrow:DWORD
	ARG	numrows:DWORD
	ARG	bufwidth:DWORD

	LOCAL	data_end:DWORD
	LOCAL	cb_offset:DWORD
	LOCAL	edi_startval:DWORD
	LOCAL	rowoffset:DWORD

;----------------------------------------------------------------------------
;	Initialize
;----------------------------------------------------------------------------

	mov	eax,[codebook]		;Adjust the codebook address so
	sub	eax,4		; that the pointer offsets will
	mov	[cb_offset],eax	; point directly at the codeword.

	mov	eax,[bufwidth]		;Compute the offset to the next
	shl	eax,1		; row of blocks.
	add	eax,[bufwidth]
	mov	[rowoffset],eax

	mov	esi,[pointers]
	mov	eax,[numrows]		;Compute the end address of the
	mul	[blocksperrow]		; pointer data.
	shl	eax,1
	add	eax,esi
	mov	[data_end],eax

	IF	PHARLAP_TNT
	push	es
	les	edi,[FWORD buffer]	;KLUDGE - bcc32 pads FARPTR
	ELSE
	mov	edi,[buffer]
	ENDIF

	mov	[edi_startval],edi

;----------------------------------------------------------------------------
;	Drawing loop
;----------------------------------------------------------------------------

??Start_row:
	mov	ecx,[blocksperrow]	;Number of blocks in a line

??Not_finished_a_line:
	sub	ebx,ebx
	mov	bx,[WORD PTR esi]	;Get the codebook pointer value
	add	esi,2		; then advance to the next one.

	or	bx,bx		;Is it a one color block?
	js	short ??One_color

;	Draw multi-color block

	add	ebx,[cb_offset]	;Codeword address
	mov	eax,[ebx]		;Read 1st row of codeword
	mov	dx,[ebx+4]		;Read 2nd row of codeword
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],ax		;Write 1st row to dest
	ELSE
	mov	[edi],ax		;Write 1st row to dest
	ENDIF

	shr	eax,16

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],ax	;Write 2nd row to dest
	ELSE
	mov	[edi+ebx],ax		;Write 2nd row to dest
	ENDIF

	add	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],dx
	ELSE
	mov	[edi+ebx],dx
	ENDIF

	add	edi,2		;Next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

;	Draw 1-color block

??One_color:
	cmp	bx,SKIP_PTR		;Is this a skip block?
	jne	??Draw_One_Color

	add	edi,2		;Move to next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line
	jmp	??Next_row

??Draw_One_Color:
	not	bx		;NOT pointer value to get color
	mov	bh,bl		;Duplicate color through the
	mov	ax,bx		; entire dword register.
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],ax		;Write 1st row to dest
	mov	[es:edi+ebx],ax	;Write 2nd row to dest
	ELSE
	mov	[edi],ax		;Write 1st row to dest
	mov	[edi+ebx],ax		;Write 2nd row to dest
	ENDIF

	add	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],ax	;Write 2rd row to dest
	ELSE
	mov	[edi+ebx],ax		;Write 2rd row to dest
	ENDIF

	add	edi,2		;Next dest block positionw
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

??Next_row:
	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

??End_of_data:
	IF	PHARLAP_TNT
	pop	es
	ENDIF

	ret

	ENDP	UnVQ_2x3
	ENDIF	;VQABLOCK_2X3


	IF	VQABLOCK_4X2
;****************************************************************************
;*
;* NAME
;*     UnVQ_4x2 - Draw 4x2 block VQ frame to a buffer.
;*
;* SYNOPSIS
;*     UnVQ_4x2(Codebook, Pointers, Buffer, BPR, Rows, BufWidth)
;*
;*     void UnVQ_4x2(unsigned char *, unsigned char *, unsigned char *,
;*                        long, long, long);
;*
;* FUNCTION
;*     This function draws an image into the specified buffer 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.
;*     BufWidth - Width of destination buffer in pixels.
;*
;* RESULT
;*     NONE
;*
;****************************************************************************

;;;	GLOBAL	C UnVQ_4x2:NEAR
;;;	PROC	UnVQ_4x2 C NEAR USES ebx ecx edx esi edi
;;;
;;;	ARG	codebook:NEAR PTR
;;;	ARG	pointers:NEAR PTR
;;;
;;;	IF	PHARLAP_TNT
;;;	ARG	buffer:QWORD	;KLUDGE - bcc32 pads FARPTR
;;;	ELSE
;;;	ARG	buffer:NEAR PTR
;;;	ENDIF
;;;
;;;	ARG	blocksperrow:DWORD
;;;	ARG	numrows:DWORD
;;;	ARG	bufwidth:DWORD
;;;
;;;	LOCAL	data_end:DWORD
;;;	LOCAL	cb_offset:DWORD
;;;	LOCAL	edi_startval:DWORD
;;;	LOCAL	rowoffset:DWORD
;;;
;;;;----------------------------------------------------------------------------
;;;;	Initialize
;;;;----------------------------------------------------------------------------
;;;
;;;	mov	eax,[codebook]		;Adjust the codebook address so
;;;	sub	eax,4		; that the pointer offsets will
;;;	mov	[cb_offset],eax	; point directly at the codeword.
;;;
;;;	mov	eax,[bufwidth]		;Compute the offset to the next
;;;	shl	eax,1		; row of blocks.
;;;	mov	[rowoffset],eax
;;;
;;;	mov	esi,[pointers]
;;;	mov	eax,[numrows]		;Compute the end address of the
;;;	mul	[blocksperrow]		; pointer data.
;;;	shl	eax,1
;;;	add	eax,esi
;;;	mov	[data_end],eax
;;;
;;;	IF	PHARLAP_TNT
;;;	push	es
;;;	les	edi,[FWORD buffer]	;KLUDGE - bcc32 pads FARPTR
;;;	ELSE
;;;	mov	edi,[buffer]
;;;	ENDIF
;;;
;;;	mov	[edi_startval],edi
;;;
;;;;----------------------------------------------------------------------------
;;;;	Drawing loop
;;;;----------------------------------------------------------------------------
;;;
;;;??Start_row:
;;;	mov	ecx,[blocksperrow]	;Number of blocks in a line
;;;
;;;??Not_finished_a_line:
;;;	sub	ebx,ebx
;;;	mov	bx,[WORD PTR esi]	;Get the codebook pointer value
;;;	add	esi,2		; then advance to the next one.
;;;
;;;	or	bx,bx		;Is it a one color block?
;;;	js	short ??One_color
;;;
;;;;	Draw multi-color block
;;;
;;;	add	ebx,[cb_offset]	;Codeword address
;;;	mov	eax,[ebx]		;Read 1st row of codeword
;;;	mov	edx,[ebx+4]		;Read 2nd row of codeword
;;;	mov	ebx,[bufwidth]
;;;
;;;	IF	PHARLAP_TNT
;;;	mov	[es:edi],eax		;Write 1st row to dest
;;;	mov	[es:edi+ebx],edx	;Write 2nd row to dest
;;;	ELSE
;;;	mov	[edi],eax		;Write 1st row to dest
;;;	mov	[edi+ebx],edx		;Write 2nd row to dest
;;;	ENDIF
;;;
;;;	add	edi,4		;Next dest block position
;;;	dec	ecx		;More blocks for this row?
;;;	jnz	short ??Not_finished_a_line
;;;
;;;;	Advance to the next destination row of blocks.
;;;
;;;	mov	edi,[edi_startval]
;;;	add	edi,[rowoffset]
;;;	mov	[edi_startval],edi
;;;
;;;	cmp	esi,[data_end]		;Have we reached the end of the
;;;	jnb	short ??End_of_data	; pointers buffer?
;;;	jmp	??Start_row
;;;
;;;;	Draw 1-color block
;;;
;;;??One_color:
;;;	cmp	bx,SKIP_PTR		;Is this a skip block?
;;;	jne	??Draw_One_Color
;;;
;;;	add	edi,4		;Move to next dest block position
;;;	dec	ecx		;More blocks for this row?
;;;	jnz	short ??Not_finished_a_line
;;;	jmp	??Next_row
;;;
;;;??Draw_One_Color:
;;;	not	bx		;NOT pointer value to get color
;;;	mov	bh,bl		;Duplicate color through the
;;;	mov	ax,bx		; entire dword register.
;;;	rol	eax,16
;;;	mov	ax,bx
;;;	mov	ebx,[bufwidth]
;;;
;;;	IF	PHARLAP_TNT
;;;	mov	[es:edi],eax		;Write 1st row to dest
;;;	mov	[es:edi+ebx],eax	;Write 2nd row to dest
;;;	ELSE
;;;	mov	[edi],eax		;Write 1st row to dest
;;;	mov	[edi+ebx],eax		;Write 2nd row to dest
;;;	ENDIF
;;;
;;;	add	edi,4		;Next dest block positionw
;;;	dec	ecx		;More blocks for this row?
;;;	jnz	short ??Not_finished_a_line
;;;
;;;;	Advance to the next destination row of blocks.
;;;
;;;??Next_row:
;;;	mov	edi,[edi_startval]
;;;	add	edi,[rowoffset]
;;;	mov	[edi_startval],edi
;;;
;;;	cmp	esi,[data_end]		;Have we reached the end of the
;;;	jnb	short ??End_of_data	; pointers buffer?
;;;	jmp	??Start_row
;;;
;;;??End_of_data:
;;;	IF	PHARLAP_TNT
;;;	pop	es
;;;	ENDIF
;;;
;;;	ret
;;;
;;;	ENDP	UnVQ_4x2
;;;	ENDIF	;VQABLOCK_4X2

	GLOBAL	C UnVQ_4x2:NEAR
	PROC	UnVQ_4x2 C NEAR USES ebx ecx edx esi edi

	ARG	codebook:NEAR PTR
	ARG	pointers:NEAR PTR
	ARG	buffer:NEAR PTR
	ARG	blocksperrow:DWORD
	ARG	numrows:DWORD
	ARG	bufwidth:DWORD

	LOCAL	data_end:DWORD
	LOCAL	cb_offset:DWORD
	LOCAL	edi_startval:DWORD
	LOCAL	rowoffset:DWORD
	LOCAL	entries:DWORD

;----------------------------------------------------------------------------
;	Initialize
;----------------------------------------------------------------------------

	mov	eax,[codebook]		;Adjust the codebook address so
;	sub	eax,4		; that the pointer offsets will
	mov	[cb_offset],eax	; point directly at the codeword.

	mov	eax,[bufwidth]		;Compute the offset to the next
	shl	eax,1		; row of blocks.
	mov	[rowoffset],eax

	mov	esi,[pointers]
	mov	eax,[numrows]		;Compute the end address of the
	mul	[blocksperrow]		; pointer data.
	mov	[entries],eax
	add	eax,esi
	mov	[data_end],eax
	
	mov	edi,[buffer]
	mov	[edi_startval],edi

;----------------------------------------------------------------------------
;	Drawing loop
;----------------------------------------------------------------------------

??Start_row:
	mov	ecx,[blocksperrow]	;Number of blocks in a line

??Not_finished_a_line:
	mov	eax,[entries]
	xor	ebx,ebx
	mov	bl,[esi]
	mov	bh,[esi + eax]	;Get the codebook pointer value
	inc	esi		; then advance to the next one.

	cmp	bh,00Fh		;Is it a one color block?
	je	short ??One_color

;	Draw multi-color block

	shl	ebx,3
	add	ebx,[cb_offset]	;Codeword address
	mov	eax,[ebx]		;Read 1st row of codeword
	mov	edx,[ebx+4]		;Read 2nd row of codeword
	mov	ebx,[bufwidth]
	mov	[edi],eax		;Write 1st row to dest
	mov	[edi+ebx],edx		;Write 2nd row to dest

	add	edi,4		;Next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

;	Draw 1-color block

??One_color:
;	cmp	bx,SKIP_PTR		;Is this a skip block?
;	jne	??Draw_One_Color
;
;	add	edi,4		;Move to next dest block position
;	dec	ecx		;More blocks for this row?
;	jnz	short ??Not_finished_a_line
;	jmp	??Next_row

??Draw_One_Color:
;	not	bx		;NOT pointer value to get color
	mov	bh,bl		;Duplicate color through the
	mov	ax,bx		; entire dword register.
	rol	eax,16
	mov	ax,bx
	mov	ebx,[bufwidth]
	mov	[edi],eax		;Write 1st row to dest
	mov	[edi+ebx],eax		;Write 2nd row to dest

	add	edi,4		;Next dest block positionw
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

??Next_row:
	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

??End_of_data:
	ret

	ENDP	UnVQ_4x2
	ENDIF	;VQABLOCK_4X2


	IF	VQABLOCK_4X4
;****************************************************************************
;*
;* NAME
;*     UnVQ_4x4 - Draw 4x4 block VQ frame to a buffer.
;*
;* SYNOPSIS
;*     UnVQ_4x4(Codebook, Pointers, Buffer, BPR, Rows, BufWidth)
;*
;*     void UnVQ_4x4(unsigned char *, unsigned char *, unsigned char *,
;*                        unsigned short, unsigned short, unsigned short);
;*
;* FUNCTION
;*     This function draws an image into the specified buffer 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.
;*     BufWidth - Width of destination buffer in pixels.
;*
;* RESULT
;*     NONE
;*
;****************************************************************************

	GLOBAL	C UnVQ_4x4:NEAR
	PROC	UnVQ_4x4 C NEAR USES ebx ecx edx esi edi

	ARG	codebook:NEAR PTR
	ARG	pointers:NEAR PTR

	IF	PHARLAP_TNT
	ARG	buffer:QWORD	;KLUDGE - bcc32 pads FARPTR
	ELSE
	ARG	buffer:NEAR PTR
	ENDIF

	ARG	blocksperrow:DWORD
	ARG	numrows:DWORD
	ARG	bufwidth:DWORD

	LOCAL	data_end:DWORD
	LOCAL	cb_offset:DWORD
	LOCAL	edi_startval:DWORD
	LOCAL	rowoffset:DWORD

;----------------------------------------------------------------------------
;	Initialize
;----------------------------------------------------------------------------

	mov	eax,[codebook]		;Adjust the codebook address so
	sub	eax,4		; that the pointer offsets will
	mov	[cb_offset],eax	; point directly at the codeword.

	mov	eax,[bufwidth]		;Compute the offset to the next
	shl	eax,2		; row of blocks
	mov	[rowoffset],eax 

	mov	esi,[pointers]
	mov	eax,[numrows]		;Compute the end address of the
	mul	[blocksperrow]		; pointer data.
	shl	eax,1
	add	eax,esi
	mov	[data_end],eax

	IF	PHARLAP_TNT
	push	es
	les	edi,[FWORD buffer]	;KLUDGE - bcc32 pads FARPTR
	ELSE
	mov	edi,[buffer]
	ENDIF

	mov	[edi_startval],edi

;----------------------------------------------------------------------------
;	Drawing loop
;----------------------------------------------------------------------------

??Start_row:
	mov	ecx,[blocksperrow]	;Number of blocks in a line

??Not_finished_a_line:
	sub	ebx,ebx
	mov	bx,[WORD PTR esi]	;Get the codebook pointer value
	add	esi,2		; then advance to the next one.

	or	bx,bx		;Is it a one color block?
	js	short ??One_color

;	Draw multi-color block

	add	ebx,[cb_offset]	;Codeword address
	mov	eax,[ebx]		;Read 1st row of codeword
	mov	edx,[ebx+4]		;Read 2nd row of codeword

	IF	PHARLAP_TNT
	mov	[es:edi],eax		;Write 1st row to dest
	ELSE
	mov	[edi],eax		;Write 1st row to dest
	ENDIF

	mov	eax,ebx
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],edx	;Write 2nd row to dest
	ELSE
	mov	[edi+ebx],edx		;Write 2nd row to dest
	ENDIF

	mov	ebx,eax
	mov	eax,[ebx+8]
	mov	edx,[ebx+12]
	mov	ebx,[bufwidth]
	shl	ebx,1

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],eax	;Write 2nd row to dest
	ELSE
	mov	[edi+ebx],eax		;Write 2nd row to dest
	ENDIF

	add	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],edx	;Write 2nd row to dest
	ELSE
	mov	[edi+ebx],edx		;Write 2nd row to dest
	ENDIF

	add	edi,4		;Next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

;	Draw 1-color block

??One_color:
	cmp	bx,SKIP_PTR		;Is this a skip block?
	jne	??Draw_One_Color

	add	edi,4		;Move to next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line
	jmp	??Next_row

??Draw_One_Color:
	not	bx		;NOT pointer value to get color
	mov	bh,bl		;Duplicate color through the
	mov	ax,bx		; entire dword register.
	rol	eax,16
	mov	ax,bx
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],eax		;Write 1st row to dest
	mov	[es:edi+ebx],eax	;Write 2nd row to dest
	ELSE
	mov	[edi],eax		;Write 1st row to dest
	mov	[edi+ebx],eax		;Write 2nd row to dest
	ENDIF

	add	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],eax	;Write 3rd row to dest
	ELSE
	mov	[edi+ebx],eax		;Write 3rd row to dest
	ENDIF

	add	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi+ebx],eax	;Write 4th row to dest
	ELSE
	mov	[edi+ebx],eax		;Write 4th row to dest
	ENDIF

	add	edi,4		;Next dest block positionw
	dec	ecx		;More blocks for this row?
	jnz	??Not_finished_a_line

;	Advance to the next destination row of blocks.

??Next_row:
	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

??End_of_data:
	IF	PHARLAP_TNT
	pop	es
	ENDIF

	ret

	ENDP	UnVQ_4x4
	ENDIF	;VQABLOCK_4X4


	IF	VQABLOCK_WOOFER
	IF	VQABLOCK_4X2
;****************************************************************************
;*
;* NAME
;*     UnVQ_4x2_Woofer - Draw 4x2 block VQ frame to a buffer.
;*
;* SYNOPSIS
;*     UnVQ_4x2_Woofer(Codebook, Pointers, Buffer, BPR, Rows, BufWidth)
;*
;*     void UnVQ_4x2_Woofer(unsigned char *, unsigned char *,
;*                          unsigned char *, long, long, long);
;*
;* FUNCTION
;*     This function draws an image into the specified buffer 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.
;*     BufWidth - Width of destination buffer in pixels.
;*
;* RESULT
;*     NONE
;*
;****************************************************************************

	GLOBAL	C UnVQ_4x2_Woofer:NEAR
	PROC	UnVQ_4x2_Woofer C NEAR USES ebx ecx edx esi edi

	ARG	codebook:NEAR PTR
	ARG	pointers:NEAR PTR

	IF	PHARLAP_TNT
	ARG	buffer:QWORD	;KLUDGE - bcc32 pads FARPTR
	ELSE
	ARG	buffer:NEAR PTR
	ENDIF

	ARG	blocksperrow:DWORD
	ARG	numrows:DWORD
	ARG	bufwidth:DWORD

	LOCAL	data_end:DWORD
	LOCAL	cb_offset:DWORD
	LOCAL	edi_startval:DWORD
	LOCAL	rowoffset:DWORD
	LOCAL	entries:DWORD

;----------------------------------------------------------------------------
;	Initialize
;----------------------------------------------------------------------------

	mov	eax,[codebook]		;Adjust the codebook address so
;	sub	eax,4		; that the pointer offsets will
	mov	[cb_offset],eax	; point directly at the codeword.

	mov	eax,[bufwidth]		;Compute the offset to the next
	shl	eax,1		; row of blocks.
	mov	[rowoffset],eax

	mov	esi,[pointers]
	mov	eax,[numrows]		;Compute the end address of the
	mul	[blocksperrow]		; pointer data.
	mov	[entries],eax
;	shl	eax,1
	add	eax,esi
	mov	[data_end],eax

	IF	PHARLAP_TNT
	push	es
	les	edi,[FWORD buffer]	;KLUDGE - bcc32 pads FARPTR
	ELSE
	mov	edi,[buffer]
	ENDIF

	mov	[edi_startval],edi

;----------------------------------------------------------------------------
;	Drawing loop
;----------------------------------------------------------------------------

??Start_row:
	mov	ecx,[blocksperrow]	;Number of blocks in a line

??Not_finished_a_line:
	mov	eax,[entries]
	xor	ebx,ebx
;	mov	bx,[WORD PTR esi]	;Get the codebook pointer value
;	add	esi,2		; then advance to the next one.
	mov	bl,[esi]
	mov	bh,[esi + eax]
	inc	esi

;	or	bx,bx		;Is it a one color block?
;	js	short ??One_color

	cmp	bh,00Fh
	je	short ??One_color

;	Draw multi-color block

	shl	ebx,3

	add	ebx,[cb_offset]	;Codeword address
	mov	eax,[ebx]		;Read 1st row of codeword
	mov	edx,[ebx+4]		;Read 2nd row of codeword
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],al		;Write 1st row to dest
	shr	eax,16
	mov	[es:edi+2],al
	mov	[es:edi+ebx+1],dh		;Write 1st row to dest
	shr	edx,16
	mov	[es:edi+ebx+3],dh
	ELSE
	mov	[edi],al		;Write 1st row to dest
	shr	eax,16
	mov	[edi+2],al
	mov	[edi+ebx+1],dh		;Write 1st row to dest
	shr	edx,16
	mov	[edi+ebx+3],dh
	ENDIF

	add	edi,4		;Next dest block position
	dec	ecx		;More blocks for this row?
	jnz	short ??Not_finished_a_line

;	Advance to the next destination row of blocks.

	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

;	Draw 1-color block

??One_color:
;	cmp	bx,SKIP_PTR		;Is this a skip block?
;	jne	??Draw_One_Color

;	add	edi,4		;Move to next dest block position
;	dec	ecx		;More blocks for this row?
;	jnz	short ??Not_finished_a_line
;	jmp	??Next_row

??Draw_One_Color:
;	not	bx		;NOT pointer value to get color
	mov	al,bl
	mov	ebx,[bufwidth]

	IF	PHARLAP_TNT
	mov	[es:edi],al
	mov	[es:edi+2],al
	mov	[es:edi+ebx+1],al	;Write 2nd row to dest
	mov	[es:edi+ebx+3],al	;Write 2nd row to dest
	ELSE
	mov	[edi],al
	mov	[edi+2],al
	mov	[edi+ebx+1],al		;Write 2nd row to dest
	mov	[edi+ebx+3],al		;Write 2nd row to dest
	ENDIF

	add	edi,4		;Next dest block positionw
	dec	ecx		;More blocks for this row?
	jnz	??Not_finished_a_line

;	Advance to the next destination row of blocks.

??Next_row:
	mov	edi,[edi_startval]
	add	edi,[rowoffset]
	mov	[edi_startval],edi

	cmp	esi,[data_end]		;Have we reached the end of the
	jnb	short ??End_of_data	; pointers buffer?
	jmp	??Start_row

??End_of_data:
	IF	PHARLAP_TNT
	pop	es
	ENDIF

	ret

	ENDP	UnVQ_4x2_Woofer
	ENDIF	;VQABLOCK_4X2
	ENDIF	;VQABLOCK_WOOFER

	END

