;
;	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   A S S O C I A T E S   **
;***************************************************************************
;*                                                                         *
;*                 Project Name : Westwood 32 bit Library                  *
;*                                                                         *
;*                    File Name : BITBLIT.ASM                              *
;*                                                                         *
;*                   Programmer : Phil W. Gorrow                           *
;*                                                                         *
;*                   Start Date : June 8, 1994                             *
;*                                                                         *
;*                  Last Update : December 13, 1994   [PWG]                *
;*                                                                         *
;*-------------------------------------------------------------------------*
;* Functions:                                                              *
;* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - *

IDEAL
P386
MODEL USE32 FLAT
LOCALS ??

INCLUDE "svgaprim.inc"
INCLUDE "gbuffer.inc"

TRANSP	equ  0 

POOLSIZE equ	8000

CODESEG

	PROC	Vesa_Blit_To_Vesa C near 
	USES	ebx,ecx,edx,esi,edi

	;*===================================================================
	;* define the arguements that our function takes.
	;*===================================================================
	ARG    	this        :DWORD		; this is a member function
	ARG	dest        :DWORD		; what are we blitting to
	ARG	x_pixel     :DWORD		; x pixel position in source
	ARG	y_pixel     :DWORD		; y pixel position in source
	ARG	dest_x0     :dword
	ARG	dest_y0     :dword
	ARG	pixel_width :DWORD		; width of rectangle to blit
	ARG	pixel_height:DWORD		; height of rectangle to blit
	ARG	trans       :DWORD			; do we deal with transparents?

	;*===================================================================
	; Define some locals so that we can handle things quickly
	;*===================================================================
	LOCAL 	x1_pixel :dword
	LOCAL	y1_pixel :dword
	LOCAL	dest_x1 : dword
	LOCAL	dest_y1 : dword
	LOCAL	scr_ajust_width:DWORD
	LOCAL	dest_ajust_width:DWORD
        LOCAL	source_area :  dword
        LOCAL	dest_area :  dword
	local	total_lines  : dword
	local	count_dy     : dword
	local	mem_page     : dword
	local   vesa_page    : dword
	local	mem_pool     : byte : POOLSIZE

; Clip Source Rectangle against source Window boundaries.
	mov  	esi , [ this ]	    ; get ptr to src
	xor 	ecx , ecx
	xor 	edx , edx
	mov	edi , [ (VideoViewPort esi) . VIVPWidth ]  ; get width into register
	mov	ebx , [ x_pixel ]
	mov	eax , [ x_pixel ]
	add	ebx , [ pixel_width ]
	shld	ecx , eax , 1
	mov	[ x1_pixel ] , ebx
	inc	edi
	shld	edx , ebx , 1
	sub	eax , edi
	sub	ebx , edi
	shld	ecx , eax , 1
	shld	edx , ebx , 1

	mov	edi,[ ( VideoViewPort esi) . VIVPHeight ] ; get height into register
	mov	ebx , [ y_pixel ]
	mov	eax , [ y_pixel ]
	add	ebx , [ pixel_height ]
	shld	ecx , eax , 1
	mov	[ y1_pixel ] , ebx
	inc	edi
	shld	edx , ebx , 1
	sub	eax , edi
	sub	ebx , edi
	shld	ecx , eax , 1
	shld	edx , ebx , 1

	xor	cl , 5
	xor	dl , 5
	mov	al , cl
	test	dl , cl
	jnz	??real_out
	or	al , dl
	jz	??clip_against_dest

	test	cl , 1000b
	jz	??scr_left_ok
	mov	[ x_pixel ] , 0

??scr_left_ok:
	test	cl , 0010b
	jz	??scr_bottom_ok
	mov	[ y_pixel ] , 0

??scr_bottom_ok:
	test	dl , 0100b
	jz	??scr_right_ok
	mov	eax , [ (VideoViewPort esi) . VIVPWidth ]  ; get width into register
	mov	[ x1_pixel ] , eax
??scr_right_ok:
	test	dl , 0001b
	jz	??clip_against_dest
	mov	eax , [ (VideoViewPort esi) . VIVPHeight ]  ; get width into register
	mov	[ y1_pixel ] , eax


; Clip Source Rectangle against destination Window boundaries.
??clip_against_dest:

	mov	eax , [ dest_x0 ]
	mov	ebx , [ dest_y0 ]
	sub	eax , [ x_pixel ]
	sub	ebx , [ y_pixel ]
	add	eax , [ x1_pixel ]
	add	ebx , [ y1_pixel ]
	mov	[ dest_x1 ] , eax
	mov	[ dest_y1 ] , ebx

	mov  	esi , [ dest ]	    ; get ptr to src
	xor 	ecx , ecx
	xor 	edx , edx
	mov	edi , [ (VideoViewPort esi) . VIVPWidth ]  ; get width into register
	mov	eax , [ dest_x0 ]
	mov	ebx , [ dest_x1 ]
	shld	ecx , eax , 1
	inc	edi
	shld	edx , ebx , 1
	sub	eax , edi
	sub	ebx , edi
	shld	ecx , eax , 1
	shld	edx , ebx , 1

	mov	edi,[ ( VideoViewPort esi) . VIVPHeight ] ; get height into register
	mov	eax , [ dest_y0 ]
	mov	ebx , [ dest_y1 ]
	shld	ecx , eax , 1
	inc	edi
	shld	edx , ebx , 1
	sub	eax , edi
	sub	ebx , edi
	shld	ecx , eax , 1
	shld	edx , ebx , 1

	xor	cl , 5
	xor	dl , 5
	mov	al , cl
	test	dl , cl
	jnz	??real_out
	or	al , dl
	jz	??do_blit

	test	cl , 1000b
	jz	??dest_left_ok
	mov	eax , [ dest_x0 ]
	mov	[ dest_x0 ] , 0
	sub	[ x_pixel ] , eax

??dest_left_ok:
	test	cl , 0010b
	jz	??dest_bottom_ok
	mov	eax , [ dest_y0 ]
	mov	[ dest_y0 ] , 0
	sub	[ y_pixel ] , eax


??dest_bottom_ok:
	test	dl , 0100b
	jz	??dest_right_ok
	mov	ebx , [ (VideoViewPort esi) . VIVPWidth ]  ; get width into register
	mov	eax , [ dest_x1 ]
	mov	[ dest_x1 ] , ebx
	sub	eax , ebx
	sub	[ x1_pixel ] , eax

??dest_right_ok:
	test	dl , 0001b
	jz	??do_blit
	mov	ebx , [ (VideoViewPort esi) . VIVPHeight ]  ; get width into register
	mov	eax , [ dest_y1 ]
	mov	[ dest_y1 ] , ebx
	sub	eax , ebx
	sub	[ y1_pixel ] , eax

??do_blit:

       cld	
       mov	ebx , [ this ]
       mov	esi , [ (VideoViewPort ebx) . VIVPOffset ]
       mov	eax , [ (VideoViewPort ebx) . VIVPXAdd ]
       add	eax , [ (VideoViewPort ebx) . VIVPWidth ]
       mov	ecx , eax
       mul	[ y_pixel ]
       add	esi , [ x_pixel ]
       mov	[ source_area ] , ecx
       add	esi , eax

       add	ecx , [ x_pixel ]
       sub	ecx , [ x1_pixel ]
       mov	[ scr_ajust_width ] , ecx

       mov	ebx , [ dest ]
       mov	edi , [ (VideoViewPort ebx) . VIVPOffset ]
       mov	eax , [ (VideoViewPort ebx) . VIVPXAdd ]
       add	eax , [ (VideoViewPort ebx) . VIVPWidth ]
       mov	ecx , eax
       mul	[ dest_y0 ]
       add	edi , [ dest_x0 ]
       mov	[ dest_area ] , ecx
       add	edi , eax

       mov	eax , [ dest_x1 ]
       sub	eax , [ dest_x0 ]
       jz	??real_out
       sub	ecx , eax
       mov	[ dest_ajust_width ] , ecx

       mov	edx , [ dest_y1 ]
       sub	edx , [ dest_y0 ]
       jz	??real_out

       push	eax
       mov	[ mem_page ] , 0
       mov	[ vesa_page ] , 0

       mov	[ total_lines ] , edx	
       mov	eax , POOLSIZE
       xor	edx , edx
       idiv	[ dword ptr esp ]
       mov	[ count_dy ] , eax
       pop	eax

; **************************************************************************
; check direction of motions
       cmp	esi , edi
       jl	??backupward_blit

       ret

;***********************************************************************
; Backupward blit

??back_mem_loop:
       push	edi
       lea	edi , [ mem_pool ]
       mov	edx , [ count_dy ]
       call	??vesa_to_memory
       pop	edi

       push	esi
       lea	esi , [ mem_pool ]
       mov	edx , [ count_dy ]
       call	??memory_to_vesa
       pop	esi

??backupward_blit:
       mov	edx , [ total_lines ]
       sub	edx , [ count_dy ]
       mov	[ total_lines ]	, edx
       jg	??back_mem_loop

       add	edx , [ count_dy ]
       push	edi
       push	edx
       lea	edi , [ mem_pool ]
       call	??vesa_to_memory
       pop	edx
       pop	edi

       push	esi
       lea	esi , [ mem_pool ]
       call	??memory_to_vesa
       pop	esi
       ret



??real_out:
       ret




; ********************************************************************       
; Move Vesa video page to memory buffer

??vesa_to_memory:

       xchg	edi , esi
       add	edi , [ mem_page ]
       call	Vesa_Asm_Set_Win  
       xchg	edi , esi

IF  TRANSP
       test	[ trans ] , 1
       jnz	??tomem_forward_Blit_trans
ENDIF


; the inner loop is so efficient that 
; the optimal consept no longer apply because
; the optimal byte have to by a number greather than 9 bytes
       cmp	eax , 10        
       jl	??tomem_forward_loop_bytes

??tomem_forward_loop_dword:

       lea	ebx , [ esi + eax ]
       add	ebx , [ cpu_video_page ]
       cmp	ebx , [ cpu_page_limit ]
       jl	??tomem_in_range

       xor	ecx , ecx
       mov	ebx , eax
       cmp	esi , 0b0000h
       jge	??tomem_no_trailing
       mov	ecx , 0b0000h
       sub	ecx , esi 
       sub	ebx , ecx
       rep	movsb
??tomem_no_trailing:  
       add	esi , [ cpu_video_page ]
       xchg	edi , esi
       Call	Vesa_Asm_Set_Win			; set the window
       xchg	edi , esi

       mov	ecx , ebx
       rep	movsb
       add	esi , [ scr_ajust_width ]
       dec	edx					; decrement the height
       jnz	??tomem_forward_loop_dword
       mov	edx , [ cpu_video_page ] 
       mov	[ mem_page ] , edx 			
       retn

??tomem_in_range:
       mov	ecx , edi
       mov	ebx , eax
       neg	ecx
       and	ecx , 3
       sub	ebx , ecx
       rep	movsb
       mov	ecx , ebx
       shr	ecx , 2
       rep	movsd
       mov	ecx , ebx
       and	ecx , 3
       rep	movsb
       add	esi , [ scr_ajust_width ]
       dec	edx 
       jnz	??tomem_forward_loop_dword
       mov	edx , [ cpu_video_page ] 
       mov	[ mem_page ] , edx 			
       retn

??tomem_forward_loop_bytes:
       lea	ebx , [ esi + eax ]
       add	ebx , [ cpu_video_page ]
       cmp	ebx , [ cpu_page_limit ]
       mov	ebx , eax
       jl	??tomem_in_range_bytes

       xor	ecx , ecx
       cmp	esi , 0b0000h
       jge	??tomem_no_trailing_bytes
       mov	ecx , 0b0000h
       sub	ecx , esi 
       sub	ebx , ecx
       rep	movsb
??tomem_no_trailing_bytes:  
       add	esi , [ cpu_video_page ]
       xchg	edi , esi
       Call	Vesa_Asm_Set_Win			; set the window
       xchg	edi , esi
??tomem_in_range_bytes:
       mov	ecx , ebx
       rep	movsb
       add	esi , [ scr_ajust_width ]
       dec	edx					; decrement the height
       jnz	??tomem_forward_loop_bytes
       mov	edx , [ cpu_video_page ] 
       mov	[ mem_page ] , edx 			
       retn

IF  TRANSP
??tomem_forward_Blit_trans:
       mov	ecx , eax
       and	ecx , 01fh
       lea	ecx , [ ecx + ecx * 4 ]	
       neg	ecx
       shr	eax , 5
       lea	ecx , [ ??tomem_transp_reference + ecx * 2 ]
       mov	[ y1_pixel ] , ecx

??tomem_forward_loop_trans:
       mov	ecx , eax 
       jmp	[ y1_pixel ]
??tomem_forward_trans_line:
       REPT	32	
       local	transp_pixel
       		mov	bl , [ esi ]
       		inc	esi
       		test	bl , bl
       		jz	transp_pixel
       		mov	[ edi ] , bl
    	    transp_pixel:
       		inc	edi
	ENDM
    ??tomem_transp_reference:
       dec	ecx 
       jge	??tomem_forward_trans_line
       add	esi , [ scr_ajust_width ]
       dec	edx 
       jnz	??tomem_forward_loop_trans
       mov	edx , [ cpu_video_page ] 
       mov	[ mem_page ] , edx 			
       retn
ENDIF





;*************************************************************************
; copy from memory to vesa page

??memory_to_vesa:
       add	edi , [ vesa_page ]
       Call	Vesa_Asm_Set_Win  

IF TRANSP
       test	[ trans ] , 1
       jnz	??tovesa_forward_Blit_trans
ENDIF


; the inner loop is so efficient that 
; the optimal consept no longer apply because
; the optimal byte have to by a number greather than 9 bytes
       cmp	eax , 10        
       jl	??tovesa_forward_loop_bytes

??tovesa_forward_loop_dword:

       lea	ebx , [ edi + eax ]
       add	ebx , [ cpu_video_page ]
       cmp	ebx , [ cpu_page_limit ]
       jl	??tovesa_in_range

       xor	ecx , ecx
       cmp	edi , 0b0000h
       mov	ebx , eax
       jge	??tovesa_no_trailing
       mov	ecx , 0b0000h
       sub	ecx , edi 
       sub	ebx , ecx
       rep	movsb
??tovesa_no_trailing:  
       add	edi , [ cpu_video_page ]
       Call	Vesa_Asm_Set_Win			; set the window

       mov	ecx , ebx
       rep	movsb
       add	edi , [ dest_ajust_width ]
       dec	edx					; decrement the height
       jnz	??tovesa_forward_loop_dword
       mov	edx , [ cpu_video_page ] 
       mov	[ vesa_page ] , edx 
       retn

??tovesa_in_range:

       mov	ecx , edi
       mov	ebx , eax
       neg	ecx
       and	ecx , 3
       sub	ebx , ecx
       rep	movsb
       mov	ecx , ebx
       shr	ecx , 2
       rep	movsd
       mov	ecx , ebx
       and	ecx , 3
       rep	movsb
       add	edi , [ dest_ajust_width ]
       dec	edx 
       jnz	??tovesa_forward_loop_dword
       mov	edx , [ cpu_video_page ] 
       mov	[ vesa_page ] , edx 
       retn

??tovesa_forward_loop_bytes:
       lea	ebx , [ edi + eax ]
       add	ebx , [ cpu_video_page ]
       cmp	ebx , [ cpu_page_limit ]
       mov	ebx , eax
       jl	??tovesa_in_range_bytes

       xor	ecx , ecx
       cmp	edi , 0b0000h
       jge	??tovesa_no_trailing_bytes
       mov	ecx , 0b0000h
       sub	ecx , edi 
       sub	ebx , ecx
       rep	movsb
??tovesa_no_trailing_bytes:  
       add	edi , [ cpu_video_page ]
       Call	Vesa_Asm_Set_Win			; set the window
??tovesa_in_range_bytes:
       mov	ecx , ebx
       rep	movsb
       add	edi , [ dest_ajust_width ]
       dec	edx					; decrement the height
       jnz	??tovesa_forward_loop_bytes
       mov	edx , [ cpu_video_page ] 
       mov	[ vesa_page ] , edx 
       retn

IF  TRANSP


??tovesa_forward_Blit_trans:

       mov	ecx , eax
       and	ecx , 01fh
       lea	ecx , [ ecx + ecx * 4 ]	
       neg	ecx
       shr	eax , 5
       lea	ecx , [ ??tovesa_transp_reference + ecx * 2 ]
       mov	[ y1_pixel ] , ecx

??tovesa_forward_loop_trans:
       mov	ecx , eax 
       jmp	[ y1_pixel ]
??tovesa_forward_trans_line:
       REPT	32	
       local	transp_pixel
       		mov	bl , [ esi ]
       		test	bl , bl
       		jz	transp_pixel
       		mov	[ edi ] , bl
    	    transp_pixel:
       		inc	esi
	    	inc	edi
	ENDM
    ??tovesa_transp_reference:
       dec	ecx 
       jge	??tovesa_forward_trans_line
       add	edi , [ dest_ajust_width ]
       dec	edx 
       jnz	??tovesa_forward_loop_trans
       mov	edx , [ cpu_video_page ] 
       mov	[ vesa_page ] , edx 
       retn
ENDIF


ENDP	Vesa_Blit_To_Vesa



END
