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