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

; $Header: g:/library/source/rcs/./shadow.asm 1.9 1994/05/20 15:30:49 joe_bostic Exp $
;***************************************************************************
;**   C O N F I D E N T I A L --- W E S T W O O D   A S S O C I A T E S   **
;***************************************************************************
;*                                                                         *
;*                 Project Name : LIBRARY                                  *
;*                                                                         *
;*                    File Name : SHADOW.ASM                               *
;*                                                                         *
;*                   Programmer : Christopher Yates                        *
;*                                                                         *
;*                  Last Update : February 28, 1995   [BG]                 *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;*                                                                         *
;* void Shadow_Blit(int xpix, int ypix, int width, int height, GVPC src, GVPC dst, void *shadowbuff);
;*                                                                         *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *

IDEAL
P386
MODEL USE32 FLAT

INCLUDE "mcgaprim.inc"
INCLUDE ".\gbuffer.inc"
INCLUDE ".\keystruc.inc"

GLOBAL	Shadow_Blit	: NEAR

GLOBAL	RealModePtr : DWORD
GLOBAL	Hide_Mouse  : NEAR
GLOBAL	Show_Mouse  : NEAR

	CODESEG

; void Shadow_Blit(int xpix, int ypix, int width, int height, GVPC src, VBC dst, void *shadowbuff);
; Warning: Shadow_Blit appears to be relatively stupid, in that while it is
;	   optimized to perform word or dword blits, it only does so if the
;	   entire region is word or dword-sized.  In other words, if you blit
;	   a region that is 200 pixels wide (clearly dword-sized), then it
;	   will use the dword loop.  However, if you blit a region that is
;	   201 pixels wide, the dumb thing will use the byte loop for the
;	   entire blit.
	PROC    Shadow_Blit C near
	USES	eax,ebx,ecx,edx,esi,edi

	ARG	x:DWORD
	ARG	y:DWORD
	ARG	width:DWORD
	ARG	height:DWORD
	ARG     srcpage:DWORD
	ARG     dstpage:DWORD
	ARG     shadow:DWORD

	LOCAL	modulo:DWORD		; Row modulo
	LOCAL	hidemouse:DWORD		; Was the mouse hidden?
	LOCAL	dwordwidth:DWORD
	LOCAL	bytewidth:DWORD

	cld                             ; Always move forward.
	mov	[hidemouse],0		; Presume mouse hasn't been hidden.

; Fetch the segment of the seenpage.
	mov	ebx,[dstpage]
	mov	ebx,[(GraphicViewPort ebx).GVPOffset]

	; Determine if the mouse needs to be hidden at all.  If this happens to be
	; a shadow blit to non visible page (who knows why!?) then don't bother to
	; hide the mouse since it isn't necessary.
;	cmp	ebx,0A0000h
;	setne	[BYTE PTR hidemouse]	; Flag that mouse need not be hidden.
;	jne	short ??itsok
	mov	esi,[RealModePtr]
	cmp	[(KeyboardType esi).MState],0
	je	short ??itsok
	mov	[hidemouse],1
	call	Hide_Mouse C		; Hides mouse again (just to be sure).
??itsok:
	mov	edi,[srcpage]
	mov	esi,[(GraphicViewPort edi).GVPOffset]

	mov	eax,[(GraphicViewPort edi).GVPWidth]
	add	eax,[(GraphicViewPort edi).GVPXAdd]
	push	eax			; save width+xadd for later calc
	mov	edx,[y]
	mul	edx
	add	eax,[x]
	add	esi,eax
; At this point, esi points to the source page and ebx points to the dest page
	sub	ebx,esi			; esi+ebx == dest page pointer

	mov	edi,[shadow]             ; EDI points to shadow buffer.

	mov     ecx,[height]		; get the height of the window in cx

	mov	edx,[RealModePtr]

	; Calculate the row add module.
	pop	eax			; restore width+xadd
	sub	eax,[width]
	mov	[modulo],eax

	mov	eax,[width]
	shr	eax,2
	mov	[dwordwidth],eax
	mov	eax,[width]
	and	eax,3
	mov	[bytewidth],eax

;---------------------------------------
; DOUBLE WORD shadow blit if possible.
;---------------------------------------
??dloop_top:
	push	ecx
	mov	ecx,[dwordwidth]

??lcontinue:
	repe    cmpsd                   ; check the entire row for changed longs
	je      short ??loop_top

	; If this row would interfere with the mouse image, then hide it.
	cmp	[hidemouse],0
	jnz	short ??dok
	mov	eax,[(KeyboardType edx).MouseY]
	sub	eax,[(KeyboardType edx).MouseYHot]
	cmp	eax,[y]
	jg	short ??dok
	add	eax,[(KeyboardType edx).MouseHeight]
	cmp	eax,[y]
	jb	short ??dok
	mov	[hidemouse],1		; Manual hide of the mouse.
	call	Hide_Mouse C
??dok:

	mov     eax,[esi-4]
	mov     [ebx+esi-4],eax		; Update destination page.
	mov     [edi-4],eax		; Update shadow buffer.
	or	ecx,ecx
	jne     short ??lcontinue

;---------------------------------------
; Row loop start for BYTES.
;---------------------------------------
??loop_top:
	mov	ecx,[bytewidth]

; Column loop start -- by bytes.
??continue:
	repe    cmpsb                   ; check the entire row for changed longs
	je      short ??done_x

	; If this row would interfere with the mouse image, then hide it.
	cmp	[hidemouse],0
	jnz	short ??bok
	mov	eax,[(KeyboardType edx).MouseY]
	sub	eax,[(KeyboardType edx).MouseYHot]
	cmp	eax,[y]
	jg	short ??bok
	add	eax,[(KeyboardType edx).MouseHeight]
	cmp	eax,[y]
	jl	short ??bok
	mov	[hidemouse],1		; Manual hide of the mouse.
	call	Hide_Mouse C
??bok:

	mov     al,[esi-1]
	mov     [ebx+esi-1],al		; Update destination page.
	mov     [edi-1],al		; Update shadow buffer.

	or	ecx,ecx
	jne     short ??continue

??done_x:
	inc	[y]
	add     esi,[modulo]
	pop     ecx
	loop    ??dloop_top

??fini:
	; Re show the mouse if it was hidden by this routine.
	cmp	[hidemouse],0
	je	short ??reallyfini
	call	Show_Mouse C
??reallyfini:
	ret

	ENDP    Shadow_Blit

	END


