CnC_Red_Alert/WINVQ/VQM32/XMODE.ASM

749 lines
15 KiB
NASM
Raw Permalink Normal View History

;
; 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
;* xmode.asm
;*
;* DESCRIPTION
;* Xmode graphics display routines. (32-Bit protected mode)
;*
;* PROGRAMMER
;* Bill Randolph
;* Denzil E. Long, Jr.
;*
;* DATE
;* Febuary 3, 1995
;*
;*---------------------------------------------------------------------------
;*
;* PUBLIC
;* SetXMode - Set the specified Xmode video mode.
;* ClearXMode - Clear the XMode VRAM.
;* ShowXPage - Set a specific page for XMode display.
;* Xmode_BufferCopy_320x200 - Copy 320x200 buffer to Xmode VRAM.
;* Xmode_Blit - Bit blit a block to the XMode display.
;*
;****************************************************************************
IDEAL
P386
MODEL USE32 FLAT
LOCALS ??
INCLUDE "vga.i"
INCLUDE "video.i"
CODESEG
;****************************************************************************
;*
;* NAME
;* SetXMode - Set the specified Xmode video mode.
;*
;* SYNOPSIS
;* Error = SetXMode(Mode)
;*
;* long SetXMode(long);
;*
;* FUNCTION
;* This routines set the current display adapter to the specified Xmode.
;* Portions of this routine were take from Dr. Dobb's, written in C, and
;* portions were taken from Dominic's 320x200 code.
;*
;* INPUTS
;* Mode - Xmode mode to set display to.
;*
;* RESULT
;* Error - 0 if successful, or -1 if error.
;*
;****************************************************************************
GLOBAL C SetXMode:NEAR
PROC SetXMode C NEAR USES edx
ARG mode:DWORD
??Set320x200:
cmp [mode],XMODE_320X200 ;320x200?
jne ??Set320x240
IF 0
mov eax,MCGA
int 10h
; Memory Mode:
; bit3 (chain) = 0 (planes are accessed via Map Mask)
; bit2 (odd/even) = 1 (use sequential addressing mode)
INPORT R_SEQUENCER,SEQ_MEMORY_MODE
and al,not 08h ;Turn off chain 4
or al,04h ;Turn off odd/even
out dx,al
INPORT R_GRAPHICS_CONTROLLER,GC_MODE
and al,not 10h ;Turn off odd/even
out dx,al
INPORT R_GRAPHICS_CONTROLLER,GC_MISC
and al,not 02h ;Turn off chain
out dx,al
OUTPORT R_SEQUENCER,SEQ_MAP_MASK,0Fh
INPORT R_CRT_CONTROLLER, CRT_MAX_SCANLINE
and al,not 1fh ;Clear low 5 bits
or al,1 ;Mode = 0 => 400 lines
out dx,al ;Mode =1 => 200
INPORT R_CRT_CONTROLLER,CRT_UNDERLINE
and al,not 40h ;Turn off doubleword
out dx,al
INPORT R_CRT_CONTROLLER,CRT_MODE_CONTROL
or al,40h ;Turn on byte mode bit,
out dx,al ; so mem scanned linearly
ENDIF
; The following section of code is from Roger Stevens' XMode
; example code; it's the same as 320x400, except the value sent
; to CRT_MAX_SCANLINE is 41, not 40.
mov eax,MCGA
int 10h
OUTPORT R_SEQUENCER,SEQ_MEMORY_MODE,06h
INPORT R_CRT_CONTROLLER,CRT_VERTRET_END
and al,07Fh
out dx,al
OUTPORT R_CRT_CONTROLLER,CRT_MAX_SCANLINE,41h
OUTPORT R_CRT_CONTROLLER,CRT_UNDERLINE,00h
OUTPORT R_CRT_CONTROLLER,CRT_MODE_CONTROL,0E3h
mov eax,0
jmp ??Done
??Set320x240:
cmp [mode],XMODE_320X240 ;320x240?
jne ??Set320x400
; Start by setting MCGA to let the BIOS program the registers;
; then, reprogram the registers that need it.
mov eax,MCGA
int 10h
; Memory Mode:
; bit3 (chain) = 0 (planes are accessed via Map Mask)
; bit2 (odd/even) = 1 (use sequential addressing mode)
; bit1 (extended mem) = 1 (>64K video RAM)
; bit0 (alpha/graph) = 0 (graphics mode)
OUTPORT R_SEQUENCER,SEQ_MEMORY_MODE,06h
; Issue a Sequencer Reset
OUTPORT R_SEQUENCER,SEQ_RESET,01h
; Misc Output: (set to 1100 0011)
; Bit 7: VSync polarity (1=negative)
; Bit 6: HSync polarity (1=negative)
; Bit 5: page bit for odd/even (0=low 64K)
; Bit 4: Video drivers (0=enable)
; Bit 3,2: clock select (0=25-MHz clock)
; Bit 1: VRAM access (1 = enable CPU to access)
; Bit 0: I/O Address (1=color emulation)
mov edx,R_MISC_OUTPUT
mov al,0C3h
out dx,al
; Clear Sequencer Reset
OUTPORT R_SEQUENCER,SEQ_RESET,03h
; Read Vertical Retrace End, and with 07f to clear high bit
; (clearing bit 7 enables writing to registers 0-7)
INPORT R_CRT_CONTROLLER,CRT_VERTRET_END
and al,07Fh
out dx,al
; Program the CRT Controller to display 480 scanlines, but to
; double each scanline so only 240 are displayed:
OUTPORT R_CRT_CONTROLLER,CRT_UNDERLINE,00h
OUTPORT R_CRT_CONTROLLER,CRT_MODE_CONTROL,0E3h
OUTPORT R_CRT_CONTROLLER,CRT_VERT_TOTAL,0Dh
OUTPORT R_CRT_CONTROLLER,CRT_OVERFLOW,03Eh
OUTPORT R_CRT_CONTROLLER,CRT_VERTRET_START,0EAh
OUTPORT R_CRT_CONTROLLER,CRT_VERTRET_END,0ACh
OUTPORT R_CRT_CONTROLLER,CRT_VERTDISP_END,0DFh
OUTPORT R_CRT_CONTROLLER,CRT_START_VB,0E7h
OUTPORT R_CRT_CONTROLLER,CRT_END_VB,06h
OUTPORT R_CRT_CONTROLLER,CRT_MAX_SCANLINE,041h
xor eax,eax
jmp ??Done
??Set320x400:
cmp [mode],XMODE_320X400 ;320x400
jne ??Set320x480
mov eax,MCGA
int 10h
OUTPORT R_SEQUENCER,04h,06h
INPORT R_CRT_CONTROLLER,011h
and al,07Fh
out dx,al
OUTPORT R_CRT_CONTROLLER,09h,40h
OUTPORT R_CRT_CONTROLLER,014h,00h
OUTPORT R_CRT_CONTROLLER,017h,0E3h
xor eax,eax
jmp ??Done
??Set320x480:
cmp [mode],XMODE_320X480 ;320x480?
jne ??Set360x400
mov eax,MCGA
int 10h
mov edx,R_SEQUENCER
mov eax,0604h
out dx,ax
mov eax,0100h
out dx,ax
mov edx,R_MISC_OUTPUT
mov al,0C3h
out dx,al
mov edx,R_SEQUENCER
mov eax,0300h
out dx,ax
mov edx,R_CRT_CONTROLLER
mov al,011h
out dx,al
mov edx,03D5h
in al,dx
and al,07Fh
out dx,al
mov edx,R_CRT_CONTROLLER
mov eax,04009h
out dx,ax
mov eax,00014h
out dx,ax
mov eax,0E317h
out dx,ax
mov eax,00D06h
out dx,ax
mov eax,03E07h
out dx,ax
mov eax,0EA10h
out dx,ax
mov eax,0AC11h
out dx,ax
mov eax,0DF12h
out dx,ax
mov eax,0E715h
out dx,ax
mov eax,00616h
out dx,ax
mov eax,04009h
out dx,ax
xor eax,eax
jmp ??Done
??Set360x400:
cmp [mode],XMODE_360X400 ;360x400
jne ??Set360x480
mov eax,MCGA
int 10h
mov edx,R_SEQUENCER
mov eax,0604h
out dx,ax
mov eax,0100h
out dx,ax
mov edx,R_MISC_OUTPUT
mov al,067h
out dx,al
mov edx,R_SEQUENCER
mov eax,0300h
out dx,ax
mov edx,R_CRT_CONTROLLER
mov al,011h
out dx,al
mov edx,03D5h
in al,dx
and al,07Fh
out dx,al
mov edx,R_CRT_CONTROLLER
mov eax,06B00h
out dx,ax
mov eax,05901h
out dx,ax
mov eax,05A02h
out dx,ax
mov eax,08E03h
out dx,ax
mov eax,05E04h
out dx,ax
mov eax,08A05h
out dx,ax
mov eax,04009
out dx,ax
mov eax,00014h
out dx,ax
mov eax,0E317h
out dx,ax
mov eax,02D13h
out dx,ax
xor eax,eax
jmp ??Done
??Set360x480:
cmp [mode],XMODE_360X480 ;360x480?
jne ??Unknown_mode
mov eax,MCGA
int 10h
mov edx,R_SEQUENCER
mov eax,0604h
out dx,ax
mov eax,0100h
out dx,ax
mov edx,R_MISC_OUTPUT
mov al,0E7h
out dx,al
mov edx,R_SEQUENCER
mov eax,0300h
out dx,ax
mov edx,R_CRT_CONTROLLER
mov al,011h
out dx,al
mov edx,03D5h
in al,dx
and al,07Fh
out dx,al
mov edx,R_CRT_CONTROLLER
mov eax,06B00h
out dx,ax
mov eax,05901h
out dx,ax
mov eax,05A02h
out dx,ax
mov eax,08E03h
out dx,ax
mov eax,05E04h
out dx,ax
mov eax,08A05h
out dx,ax
mov eax,04009h
out dx,ax
mov eax,00014h
out dx,ax
mov eax,0E317h
out dx,ax
mov eax,00D06h
out dx,ax
mov eax,03E07h
out dx,ax
mov eax,0EA10h
out dx,ax
mov eax,0AC11h
out dx,ax
mov eax,0DF12h
out dx,ax
mov eax,0E715h
out dx,ax
mov eax,00616h
out dx,ax
mov eax,02D13h
out dx,ax
xor eax,eax
jmp ??Done
??Unknown_mode:
mov eax,0FFFFFFFFh ;Unknown mode
??Done:
ret
ENDP SetXMode
;****************************************************************************
;*
;* NAME
;* ClearXMode - Clear the XMode VRAM.
;*
;* SYNOPSIS
;* ClearXMode()
;*
;* void ClearXMode(void);
;*
;* FUNCTION
;*
;* INPUTS
;* NONE
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C ClearXMode:NEAR
PROC ClearXMode C NEAR USES eax ecx edi es
IF PHARLAP_TNT
mov eax,01Ch
mov es,ax ;Set ES selector to VRAM
mov edi,0
ELSE
mov edi,0A0000h
ENDIF
SET_PLANE 0Fh
mov ecx,((320*240*2)/4/4)
xor eax,eax
rep stosd
ret
ENDP ClearXMode
;****************************************************************************
;*
;* NAME
;* ShowXPage - Set a specific page for XMode display.
;*
;* SYNOPSIS
;* ShowXPage(Offset)
;*
;* void ShowXPage();
;*
;* FUNCTION
;* Show the page at the specified offset in the bitmap. Page-flip takes
;* effect on the next active scan cycle.
;*
;* INPUTS
;* Offset - Offset to set page to.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C ShowXPage:NEAR
PROC ShowXPage C NEAR USES eax ebx ecx edx
ARG StartOffset:DWORD
mov edx,R_CRT_CONTROLLER
mov bl,CRT_STARTADDR_LOW
mov bh,[byte ptr StartOffset]
mov cl,CRT_STARTADDR_HIGH
mov ch,[byte ptr StartOffset+1]
mov eax,ebx
out dx,ax
mov eax,ecx
out dx,ax
ret
ENDP ShowXPage
;****************************************************************************
;*
;* NAME
;* Xmode_BufferCopy_320x200 - Copy 320x200 buffer to Xmode VRAM.
;*
;* SYNOPSIS
;* Xmode_BufferCopy_320x200(Buffer, Screen)
;*
;* void Xmode_BufferCopy_320x200(char *, char *);
;*
;* FUNCTION
;* BitBlt copy to VRAM.
;*
;* INPUTS
;* Buffer - Pointer to buffer to copy to XMode VRAM.
;* Screen - XMode VRAM screen address to copy buffer to.
;*
;* RESULT
;* NONE
;*
;****************************************************************************
GLOBAL C Xmode_BufferCopy_320x200:NEAR
PROC Xmode_BufferCopy_320x200 C NEAR USES eax ecx edx edi esi es
ARG buffer:NEAR PTR
ARG screen:NEAR PTR
LOCAL save_esi:DWORD
LOCAL save_edi:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
mov eax,01Ch ;Set ES selector to VRAM.
mov es,ax
ENDIF
mov esi,[buffer] ;Set pointers
mov edi,[screen]
mov [save_esi],esi
mov [save_edi],edi
;----------------------------------------------------------------------------
; Copy plane 1
;----------------------------------------------------------------------------
SET_PLANE XPLANE_1
mov ecx,4000
x_loop_1:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 1 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next VRAM position
dec ecx
jnz short x_loop_1
;----------------------------------------------------------------------------
; Copy plane 2
;----------------------------------------------------------------------------
mov esi,[save_esi] ;Restore pointers
mov edi,[save_edi]
inc esi ;Adjust source pointer to plane 2
SET_PLANE XPLANE_2
mov ecx,4000
x_loop_2:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 2 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next VRAM position
dec ecx
jnz short x_loop_2
;----------------------------------------------------------------------------
; Copy plane 3
;----------------------------------------------------------------------------
mov esi,[save_esi] ;Restore pointers
mov edi,[save_edi]
add esi,2 ;Adjust source pointer to plane 3
SET_PLANE XPLANE_3
mov ecx,4000
x_loop_3:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 3 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next VRAM position
dec ecx
jnz short x_loop_3
;----------------------------------------------------------------------------
; Copy plane 4
;----------------------------------------------------------------------------
mov esi,[save_esi] ;Restore pointers
mov edi,[save_edi]
add esi,3 ;Adjust source pointer to plane 4
SET_PLANE XPLANE_4
mov ecx,4000
x_loop_4:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write plane 4 pixels to VRAM
add esi,16 ;Next source pixel position
add edi,4 ;Next screen position
dec ecx
jnz short x_loop_4
ret
ENDP Xmode_BufferCopy_320x200
;****************************************************************************
;*
;* NAME
;* Xmode_Blit - Bit blit a block to the XMode display.
;*
;* SYNOPSIS
;* XMode_Blit(Buffer, Screen, Width, Height)
;*
;* void XMode_Blit(char *, char *, long, long);
;*
;* FUNCTION
;*
;* INPUTS
;* Buffer - Pointer buffer to blit to screen.
;* Screen - Screen address to blit buffer to.
;* Width - Width of buffer.
;* Height - Height of buffer.
;*
;* RESULT
;* NONE
;*
;* WARNINGS
;* Assumes the screen to be 320 pixels wide and the source buffer width
;* to be divisible by 16.
;*
;****************************************************************************
GLOBAL C Xmode_Blit:NEAR
PROC Xmode_Blit C NEAR USES ecx edx esi edi es
ARG buffer:NEAR PTR
ARG screen:NEAR PTR
ARG imgwidth:DWORD
ARG imgheight:DWORD
LOCAL rowcount:DWORD
LOCAL xplane:DWORD
LOCAL edi_startval:DWORD
LOCAL esi_startval:DWORD
LOCAL xadd:DWORD
;----------------------------------------------------------------------------
; Initialize
;----------------------------------------------------------------------------
IF PHARLAP_TNT
mov eax,01Ch ;Set ES selector to VRAM
mov es,ax
ENDIF
mov esi,[buffer]
mov edi,[screen]
mov [esi_startval],esi
mov [edi_startval],edi
mov edx,320 ;Compute modulo
sub edx,[imgwidth]
shr edx,2
mov [xadd],edx
;----------------------------------------------------------------------------
; Transfer the data on plane at a time.
;----------------------------------------------------------------------------
mov [xplane],1
??Do_plane:
SET_PLANE [xplane] ;Set plane to transfer to
mov eax,[imgheight]
mov [rowcount],eax
mov edx,[xadd]
??Do_row:
mov ecx,[imgwidth] ;Length of row to copy in DWORDS
shr ecx,4
; Transfer a row of pixels
??Not_done:
mov al,[esi + 8] ;Get pixel
mov ah,[esi + 12] ;Get pixel
ror eax,16
mov al,[esi] ;Get pixel
mov ah,[esi + 4] ;Get pixel
mov [es:edi],eax ;Write pixels to VRAM plane
add esi,16 ;Next source position
add edi,4 ;Next VRAM position
dec ecx
jnz ??Not_done
add edi,edx ;Next VRAM row
dec [rowcount] ;Decrement the row count
jnz ??Do_row
; Go to next X-Plane
inc [esi_startval]
mov eax,[esi_startval]
mov esi,eax
mov eax,[edi_startval]
mov edi,eax
shl [xplane],1
cmp [xplane],16
jnz ??Do_plane
ret
ENDP Xmode_Blit
END