CnC_Red_Alert/WWFLAT32/SVGAPRIM/VVBLIT.ASM

598 lines
14 KiB
NASM

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