CnC_Red_Alert/WINVQ/VQM32/VESABUF.ASM

723 lines
16 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 S T U D I O S
;*
;*---------------------------------------------------------------------------
;*
;* FILE
;* vesabuf.asm
;*
;* DESCRIPTION
;* VESA buffered blit routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Bill Randolph
;* Denzil E. Long, Jr.
;*
;* DATE
;* Febuary 3, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* Buf_320x200_To_VESA_320x200 - Buffer copy, unscaled
;* Buf_320x200_To_VESA_640x400 - Scales and copies 320x200 to 640x400
;* Buf_320x200_To_VESA_32K - Copies 320x200 buffer to VESA 32K
;* colors
;* Copy_Row - Copy a row of pixels to VRAM.
;* Copy_Word_Row - Copy a row of 15-bit pixels to VRAM
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "video.i"
CODESEG
;---------------------------------------------------------------------------
; DRAW_BLOCK_ROWS: draws 'numrows' rows of 2x2 blocks
; Set ES:DI to current screen location
; Set DS:SI to current source location
; Uses: ax, cx, dx
;---------------------------------------------------------------------------
MACRO DRAW_BLOCK_ROWS numrows
LOCAL ??Start_row
LOCAL ??Not_finished_a_line
LOCAL ??Done
mov edx,numrows
??Start_row:
mov ecx,320
??Not_finished_a_line:
mov al,[BYTE PTR esi]
mov ah,al
inc esi
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
mov [WORD PTR es:edi+640],ax
ELSE
mov [WORD PTR edi],ax
mov [WORD PTR edi+640],ax
ENDIF
add edi,2
dec ecx
jnz ??Not_finished_a_line
add edi,640
dec edx
jz ??Done
jmp ??Start_row
??Done:
ENDM
;---------------------------------------------------------------------------
; DRAW_BLOCK_ROW: draws one row of 'numblks' 2x2 blocks
; Set ES:DI to current screen location
; Set DS:SI to current source location
; Uses: ax, cx
;---------------------------------------------------------------------------
MACRO DRAW_BLOCK_ROW numblks
LOCAL ??Not_done
mov ecx,numblks
??Not_done:
mov al,[BYTE PTR esi]
mov ah,al
inc esi
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
mov [WORD PTR es:edi+640],ax
ELSE
mov [WORD PTR edi],ax
mov [WORD PTR edi+640],ax
ENDIF
add edi,2
dec ecx
jnz ??Not_done
ENDM
;---------------------------------------------------------------------------
; DRAW_PIXEL_ROW: draws 'numblks' 2x1 blocks
; Set ES:DI to current screen location
; Set DS:SI to current source location
; Uses: ax, cx
;---------------------------------------------------------------------------
MACRO DRAW_PIXEL_ROW numblks
LOCAL ??Not_done
mov ecx,numblks
??Not_done:
mov al,[BYTE PTR esi]
mov ah,al
inc esi
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
ELSE
mov [WORD PTR edi],ax
ENDIF
add edi,2
dec ecx
jnz ??Not_done
ENDM
;****************************************************************************
;*
;* NAME
;* Blit_VESA640x480 - Blit to 640x480 256 color VESA mode.
;*
;* SYNOPSIS
;* Blit_VESA640x480(DisplayInfo, Buffer, X, Y, Width, Height)
;*
;* void Blit_VESA640x480(DisplayInfo *, char *, long, long, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* DisplayInfo - Pointer to display information structure.
;* Buffer - Pointer to buffer to blit to VRAM.
;* X - Destination X coordinate of blit (upper left).
;* Y - Destination Y coordinate of blit (upper left).
;* Width - Width of blit.
;* Height - Height of blit.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
; GLOBAL C Blit_VESA640x480:NEAR
; PROC Blit_VESA640x480 C NEAR USES
;
; ARG disp:NEAR PTR DisplayInfo
; ARG buffer:NEAR PTR
; ARG x:DWORD
; ARG y:DWORD
; ARG width:DWORD
; ARG height:DWORD
;
; LOCAL grain:DWORD
; LOCAL scrn_offset:DWORD
; LOCAL bank_offset:DWORD
; LOCAL bank:DWORD
; LOCAL xres:DWORD
;
;;----------------------------------------------------------------------------
;; INITIALIZE
;;----------------------------------------------------------------------------
;
; pushad
;
;; Calculate granularity units per window
;
; mov esi,[disp]
; xor eax,eax
; mov edi,[(DisplayInfo esi).Extended]
; xor ebx,ebx
; mov ax,[(VESAModeInfo edi).WinSize]
; xor edx,edx
; mov bx,[(VESAModeInfo edi).WinGranularity]
; idiv ebx
; mov [grain],eax
;
;; Calculate screen offset
;
; mov eax,[(DisplayInfo esi).XRes]
; mov [xres],eax
; imul [y]
; add eax,[x]
; mov [scrn_offset],eax
;
;; Calculate bank offset
;
; mov ebx,65536
; idiv ebx
; mov [bank_offset],edx
; mov [bank],eax
;
; popad
; ret
;
; ENDP Blit_VESA640x480
;****************************************************************************
;*
;* NAME
;* Buf_320x200_To_VESA_320x200 - Buffer copy, unscaled
;*
;* SYNOPSIS
;* Buf_320x200_To_VESA_320x200(Buffer, GrainPerWin)
;*
;* void Buf_320x200_To_VESA_320x200(char *, long);
;*
;* FUNCTION
;* To center the buffer on the screen, it's upper-left corner goes at
;* (160,140). This means the buffer spans VESA banks 1,2 & 3, so it must
;* be copied in 3 parts:
;*
;* Bank 1: starting offset 24224, 65 lines
;* Bank 2: starting offset 288, 102 lines
;* Bank 3: starting offset 32, 33 lines
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer to VRAM
;* GrainPerWin - Granularity units per 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Buf_320x200_To_VESA_320x200:NEAR
PROC Buf_320x200_To_VESA_320x200 C NEAR USES ebx ecx edx esi edi
ARG buffer:NEAR PTR
ARG grains_per_win:DWORD
LOCAL grain_num:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
push es
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov eax,[grains_per_win]
mov esi,[buffer]
mov [grain_num],eax
;----------------------------------------------------------------------------
; Copy Bank 1
;----------------------------------------------------------------------------
SET_WINDOW [grain_num]
mov edi,24224 ;Starting screen address
mov edx,65 ;Lines to copy
??SetBank1:
mov ecx,80 ;DWORDS to copy
rep movsd ;Move the pixels
add edi,320 ;Wrap to start of next line
dec edx ;Decrement our line counter
jnz ??SetBank1 ;Draw more lines
;----------------------------------------------------------------------------
; Copy Bank 2
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
mov edi,288 ;Starting screen address
mov edx,102 ;Lines to copy
??SetBank2:
mov ecx,80 ;DWORDS to copy
rep movsd ;Move the pixels
add edi,320 ;Wrap to start of next line
dec edx ;Decrement our line counter
jnz ??SetBank2 ;Draw more lines
;----------------------------------------------------------------------------
; Copy Bank 3
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
mov edi,32 ;Starting screen address
mov edx,33 ;Lines to copy
??SetBank3:
mov ecx,80 ;DWORDS to copy
rep movsd ;Move the pixels
add edi,320 ;Wrap to start of next line
dec edx ;Decrement our line counter
jnz ??SetBank3 ;Draw more lines
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Buf_320x200_To_VESA_320x200
;****************************************************************************
;*
;* NAME
;* Buf_320x200_To_VESA_640x400 - Scales and copies 320x200 to 640x400
;*
;* SYNOPSIS
;* Buf_320x200_To_VESA_640x400(Buffer, GrainPerWin)
;*
;* void Buf_320x200_To_VESA_640x400(char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer to VRAM
;* GrainPerWin - Granularity units per 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Buf_320x200_To_VESA_640x400:NEAR
PROC Buf_320x200_To_VESA_640x400 C NEAR USES ebx ecx edx esi edi
ARG buffer:NEAR PTR
ARG grains_per_win:DWORD
LOCAL grain_num:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
push es
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
mov [grain_num],0
;----------------------------------------------------------------------------
; Copy Bank 0
; - Skip down 40 scanlines (to center the image)
; - Draw 62 scanlines (31 rows of blocks)
; - Draw top half of 128 blocks
;----------------------------------------------------------------------------
SET_WINDOW [grain_num]
mov edi,25600 ;Starting screen address
DRAW_BLOCK_ROWS 62/2 ;Draw 31 rows of blocks
DRAW_PIXEL_ROW 256/2 ;Draw top half of next 128 blocks
;----------------------------------------------------------------------------
; Copy Bank 1
; - Draw bottom half of previous 128 blocks
; - Finish the scan line with full blocks
; - Draw 100 scanlines of blocks
; - last line: top half of 256 blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,256/2 ;Draw bottom half of prev 128 blks
mov edi,384
DRAW_PIXEL_ROW 256/2
mov edi,0
DRAW_BLOCK_ROW 384/2 ;Fill rest of this block row
add edi,640
DRAW_BLOCK_ROWS 100/2 ;Draw the block rows
DRAW_PIXEL_ROW 512/2 ;Draw top half of next 512 blocks
;----------------------------------------------------------------------------
; Copy Bank 2
; - Draw bottom half of previous 256 blocks
; - Finish the scan line with full blocks
; - Draw 101 scanlines of blocks
; - last line: 64 full blocks plus top half of 256 blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,512/2 ;Draw bottom half of prev 256 blks
mov edi,128
DRAW_PIXEL_ROW 512/2
mov edi,0
DRAW_BLOCK_ROW 128/2 ;Fill rest of this block row
add edi,640
DRAW_BLOCK_ROWS 101/2 ;Draw the block rows
DRAW_BLOCK_ROW 128/2 ;Draw next 64 blocks
DRAW_PIXEL_ROW 512/2 ;Top half of 256 blocks
;----------------------------------------------------------------------------
; Copy Bank 3
; - Draw bottom half of previous 256 blocks
; - Finish the scan line with full blocks
; - Draw 101 scanlines of blocks
; - last line: 192 full blocks, top half of 128 blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,512/2 ;Draw bottom half of prev 256 blks
mov edi,0
DRAW_PIXEL_ROW 512/2
DRAW_BLOCK_ROWS 101/2 ;Draw the block rows
DRAW_BLOCK_ROW 384/2 ;Last row of full blocks
DRAW_PIXEL_ROW 256/2 ;Top half of 128 blocks
;----------------------------------------------------------------------------
; Copy Bank 4
; - Draw bottom half of previous 128 blocks
; - Draw 30 scanlines of blocks
;----------------------------------------------------------------------------
mov eax,[grains_per_win]
add [grain_num],eax
SET_WINDOW [grain_num]
sub esi,256/2 ;Draw bottom half of prev 256 blks
mov edi,0
DRAW_PIXEL_ROW 256/2
DRAW_BLOCK_ROWS 30/2 ;Draw the block rows
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Buf_320x200_To_VESA_640x400
;****************************************************************************
;*
;* NAME
;* Buf_320x200_To_VESA_32K - Copies 320x200 buffer to VESA 32K colors
;*
;* SYNOPSIS
;* Buf_320x200_To_VESA_32K(Buffer, Palette, GrainPerWin)
;*
;* void Buf_320x200_To_VESA_32K(char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer to buffer to transfer to VRAM
;* Palette - Pointer to 15-bit palette to use.
;* GrainPerWin - Granularity units per 64k window.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Buf_320x200_To_VESA_32K:NEAR
PROC Buf_320x200_To_VESA_32K C NEAR USES ebx ecx edx esi edi
ARG buffer:NEAR PTR
ARG palette:NEAR PTR
ARG grains_per_win:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
push es
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
;----------------------------------------------------------------------------
; Copy Bank 0
;----------------------------------------------------------------------------
SET_WINDOW 0
mov edi,0 ;Start at Bank 0, offset 0
mov ecx,32768 ;# words we'll be setting
; Get the pixel's offset into the palette
??Buf0Loop:
xor eax,eax
mov ebx,[palette]
mov al,[BYTE PTR esi]
add ebx,eax
inc esi
add ebx,eax
; store the 15-bit palette value
mov ax,[WORD PTR ebx]
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
ELSE
mov [WORD PTR edi],ax
ENDIF
add edi,2
dec ecx
jnz ??Buf0Loop
;----------------------------------------------------------------------------
; Copy Bank 1
;----------------------------------------------------------------------------
SET_WINDOW [grains_per_win]
mov edi,0 ;Start at Bank 1, offset 0
mov ecx,31232 ;# words we'll be setting
; Get the pixel's offset into the palette
??Buf1Loop:
xor eax,eax
mov ebx,[palette]
mov al,[BYTE PTR esi]
add ebx,eax
inc esi
add ebx,eax
; Store the 15-bit palette value
mov ax,[WORD PTR ebx]
IF PHARLAP_TNT
mov [WORD PTR es:edi],ax
ELSE
mov [WORD PTR edi],ax
ENDIF
add edi,2
dec ecx
jnz ??Buf1Loop
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Buf_320x200_To_VESA_32K
;****************************************************************************
;*
;* NAME
;* Copy_Row - Copy a row of pixels to VRAM.
;*
;* SYNOPSIS
;* Copy_Row(Source, Dest, Length)
;*
;* void Copy_Row(char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Source - Pointer to data to copy to VRAM
;* Dest - Destination VRAM address.
;* Length - Number of bytes to copy.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Copy_Row:NEAR
PROC Copy_Row C NEAR USES ecx esi edi
ARG source:NEAR PTR
ARG dest:NEAR PTR
ARG numbytes:DWORD
IF PHARLAP_TNT
push es
mov eax,01Ch
mov es,ax
ENDIF
cld
mov esi,[source]
mov edi,[dest]
mov ecx,[numbytes]
rep movsb
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Copy_Row
;****************************************************************************
;*
;* NAME
;* Copy_Word_Row - Copy a row of 15-bit pixels to VRAM
;*
;* SYNOPSIS
;* Copy_Word_Row(Source, Dest, Palette, Length)
;*
;* void Copy_Word_Row(char *, char *, char *, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Source - Pointer to data to transfer.
;* Dest - Destination screen address.
;* Palette - 15bit palette to use.
;* Length - Bytes to transfer.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Copy_Word_Row:NEAR
PROC Copy_Word_Row C NEAR USES ebx ecx esi edi
ARG source:NEAR PTR
ARG dest:NEAR PTR
ARG palette:NEAR PTR
ARG numbytes:DWORD
IF PHARLAP_TNT
push es
mov eax,01Ch
mov es,ax
ENDIF
mov esi,[source]
mov edi,[dest]
mov ecx,[numbytes]
??loop:
mov ebx,[palette]
xor eax,eax
mov al,[esi] ;Get pixel value
shl eax,1 ;Adjust for word entry
add ebx,eax ;Compute color address
mov ax,[ebx] ;Get color
IF PHARLAP_TNT
mov [es:edi],ax ;Set 16bit pixel
ELSE
mov [edi],ax ;Set 16bit pixel
ENDIF
inc esi ;Next source pixel
add edi,2 ;Next dest pixel
dec ecx ;Decrement pixel count
jnz ??loop
IF PHARLAP_TNT
pop es
ENDIF
ret
ENDP Copy_Word_Row
END