Files
Catacomb3D/ID_RF_A.ASM
2026-03-12 19:22:23 +01:00

691 lines
14 KiB
NASM

; Catacomb 3-D Source Code
; Copyright (C) 1993-2014 Flat Rock Software
;
; 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 2 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, write to the Free Software Foundation, Inc.,
; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
; ID_RF_A.ASM
IDEAL
MODEL MEDIUM,C
INCLUDE "ID_ASM.EQU"
;============================================================================
TILESWIDE = 21
TILESHIGH = 14
UPDATESIZE = (TILESWIDE+1)*TILESHIGH+1
DATASEG
EXTRN screenseg:WORD
EXTRN updateptr:WORD
EXTRN updatestart:WORD
EXTRN masterofs:WORD ;start of master tile port
EXTRN bufferofs:WORD ;start of current buffer port
EXTRN screenstart:WORD ;starts of three screens (0/1/master) in EGA mem
EXTRN grsegs:WORD
EXTRN mapsegs:WORD
EXTRN originmap:WORD
EXTRN updatemapofs:WORD
EXTRN tinf:WORD ;seg pointer to map header and tile info
EXTRN blockstarts:WORD ;offsets from bufferofs for each update block
planemask db ?
planenum db ?
CODESEG
screenstartcs dw ? ;in code segment for accesability
IFE GRMODE-CGAGR
;============================================================================
;
; CGA refresh routines
;
;============================================================================
TILEWIDTH = 4
;=================
;
; RFL_NewTile
;
; Draws a composit two plane tile to the master screen and sets the update
; spot to 1 in both update pages, forcing the tile to be copied to the
; view pages the next two refreshes
;
; Called to draw newlly scrolled on strips and animating tiles
;
;=================
PROC RFL_NewTile updateoffset:WORD
PUBLIC RFL_NewTile
USES SI,DI
;
; mark both update lists at this spot
;
mov di,[updateoffset]
mov bx,[updateptr] ;start of update matrix
mov [BYTE bx+di],1
mov dx,SCREENWIDTH-TILEWIDTH ;add to get to start of next line
;
; set di to the location in screenseg to draw the tile
;
shl di,1
mov si,[updatemapofs+di] ;offset in map from origin
add si,[originmap]
mov di,[blockstarts+di] ;screen location for tile
add di,[masterofs]
;
; set BX to the foreground tile number and SI to the background number
; If either BX or SI = 0xFFFF, the tile does not need to be masked together
; as one of the planes totally eclipses the other
;
mov es,[mapsegs+2] ;foreground plane
mov bx,[es:si]
mov es,[mapsegs] ;background plane
mov si,[es:si]
mov es,[screenseg]
or bx,bx
jz @@singletile
jmp @@maskeddraw ;draw both together
;=============
;
; Draw single background tile from main memory
;
;=============
@@singletile:
shl si,1
mov ds,[grsegs+STARTTILE16*2+si]
xor si,si ;block is segment aligned
REPT 15
movsw
movsw
add di,dx
ENDM
movsw
movsw
mov ax,ss
mov ds,ax ;restore turbo's data segment
ret
;=========
;
; Draw a masked tile combo
; Interupts are disabled and the stack segment is reassigned
;
;=========
@@maskeddraw:
cli ; don't allow ints when SS is set
shl bx,1
mov ss,[grsegs+STARTTILE16M*2+bx]
shl si,1
mov ds,[grsegs+STARTTILE16*2+si]
xor si,si ;first word of tile data
REPT 16
mov ax,[si] ;background tile
and ax,[ss:si] ;mask
or ax,[ss:si+64] ;masked data
stosw
mov ax,[si+2] ;background tile
and ax,[ss:si+2] ;mask
or ax,[ss:si+66] ;masked data
stosw
add si,4
add di,dx
ENDM
mov ax,@DATA
mov ss,ax
sti
mov ds,ax
ret
ENDP
ENDIF
IFE GRMODE-EGAGR
;===========================================================================
;
; EGA refresh routines
;
;===========================================================================
TILEWIDTH = 2
;=================
;
; RFL_NewTile
;
; Draws a composit two plane tile to the master screen and sets the update
; spot to 1 in both update pages, forcing the tile to be copied to the
; view pages the next two refreshes
;
; Called to draw newlly scrolled on strips and animating tiles
;
; Assumes write mode 0
;
;=================
PROC RFL_NewTile updateoffset:WORD
PUBLIC RFL_NewTile
USES SI,DI
;
; mark both update lists at this spot
;
mov di,[updateoffset]
mov bx,[updatestart] ;page 0 pointer
mov [BYTE bx+di],1
mov bx,[updatestart+2] ;page 1 pointer
mov [BYTE bx+di],1
;
; set screenstartcs to the location in screenseg to draw the tile
;
shl di,1
mov si,[updatemapofs+di] ;offset in map from origin
add si,[originmap]
mov di,[blockstarts+di] ;screen location for tile
add di,[masterofs]
mov [cs:screenstartcs],di
;
; set BX to the foreground tile number and SI to the background number
; If either BX or SI = 0xFFFF, the tile does not need to be masked together
; as one of the planes totally eclipses the other
;
mov es,[mapsegs+2] ;foreground plane
mov bx,[es:si]
mov es,[mapsegs] ;background plane
mov si,[es:si]
mov es,[screenseg]
mov dx,SC_INDEX ;for stepping through map mask planes
or bx,bx
jz @@singletile
jmp @@maskeddraw ;draw both together
;=========
;
; No foreground tile, so draw a single background tile.
;
;=========
@@singletile:
mov bx,SCREENWIDTH-2 ;add to get to start of next line
shl si,1
mov ax,[cs:screenstartcs]
mov ds,[grsegs+STARTTILE16*2+si]
xor si,si ;block is segment aligned
mov ax,SC_MAPMASK+0001b*256 ;map mask for plane 0
mov cx,4 ;draw four planes
@@planeloop:
mov dx,SC_INDEX
WORDOUT
mov di,[cs:screenstartcs] ;start at same place in all planes
REPT 15
movsw
add di,bx
ENDM
movsw
shl ah,1 ;shift plane mask over for next plane
loop @@planeloop
mov ax,ss
mov ds,ax ;restore turbo's data segment
ret
;=========
;
; Draw a masked tile combo
; Interupts are disabled and the stack segment is reassigned
;
;=========
@@maskeddraw:
cli ; don't allow ints when SS is set
shl bx,1
mov ss,[grsegs+STARTTILE16M*2+bx]
shl si,1
mov ds,[grsegs+STARTTILE16*2+si]
xor si,si ;first word of tile data
mov ax,SC_MAPMASK+0001b*256 ;map mask for plane 0
mov di,[cs:screenstartcs]
@@planeloopm:
WORDOUT
tileofs = 0
lineoffset = 0
REPT 16
mov bx,[si+tileofs] ;background tile
and bx,[ss:tileofs] ;mask
or bx,[ss:si+tileofs+32] ;masked data
mov [es:di+lineoffset],bx
tileofs = tileofs + 2
lineoffset = lineoffset + SCREENWIDTH
ENDM
add si,32
shl ah,1 ;shift plane mask over for next plane
cmp ah,10000b
je @@done ;drawn all four planes
jmp @@planeloopm
@@done:
mov ax,@DATA
mov ss,ax
sti
mov ds,ax
ret
ENDP
ENDIF
IFE GRMODE-VGAGR
;============================================================================
;
; VGA refresh routines
;
;============================================================================
ENDIF
;============================================================================
;
; reasonably common refresh routines
;
;============================================================================
;=================
;
; RFL_UpdateTiles
;
; Scans through the update matrix pointed to by updateptr, looking for 1s.
; A 1 represents a tile that needs to be copied from the master screen to the
; current screen (a new row or an animated tiled). If more than one adjacent
; tile in a horizontal row needs to be copied, they will be copied as a group.
;
; Assumes write mode 1
;
;=================
; AX 0/1 for scasb, temp for segment register transfers
; BX width for block copies
; CX REP counter
; DX line width deltas
; SI source for copies
; DI scas dest / movsb dest
; BP pointer to UPDATETERMINATE
;
; DS
; ES
; SS
PROC RFL_UpdateTiles
PUBLIC RFL_UpdateTiles
USES SI,DI,BP
jmp SHORT @@realstart
@@done:
;
; all tiles have been scanned
;
ret
@@realstart:
mov di,[updateptr]
mov bp,(TILESWIDE+1)*TILESHIGH+1
add bp,di ; when di = bx, all tiles have been scanned
push di
mov cx,-1 ; definately scan the entire thing
;
; scan for a 1 in the update list, meaning a tile needs to be copied
; from the master screen to the current screen
;
@@findtile:
pop di ; place to continue scaning from
mov ax,ss
mov es,ax ; search in the data segment
mov ds,ax
mov al,1
repne scasb
cmp di,bp
je @@done
cmp [BYTE di],al
jne @@singletile
jmp @@tileblock
;============
;
; copy a single tile
;
;============
EVEN
@@singletile:
inc di ; we know the next tile is nothing
push di ; save off the spot being scanned
sub di,[updateptr]
shl di,1
mov di,[blockstarts-4+di] ; start of tile location on screen
mov si,di
add di,[bufferofs] ; dest in current screen
add si,[masterofs] ; source in master screen
mov dx,SCREENWIDTH-TILEWIDTH
mov ax,[screenseg]
mov ds,ax
mov es,ax
;--------------------------
IFE GRMODE-CGAGR
REPT 15
movsw
movsw
add si,dx
add di,dx
ENDM
movsw
movsw
ENDIF
;--------------------------
IFE GRMODE-EGAGR
REPT 15
movsb
movsb
add si,dx
add di,dx
ENDM
movsb
movsb
ENDIF
;--------------------------
jmp @@findtile
;============
;
; more than one tile in a row needs to be updated, so do it as a group
;
;============
EVEN
@@tileblock:
mov dx,di ; hold starting position + 1 in dx
inc di ; we know the next tile also gets updated
repe scasb ; see how many more in a row
push di ; save off the spot being scanned
mov bx,di
sub bx,dx ; number of tiles in a row
shl bx,1 ; number of bytes / row
mov di,dx ; lookup position of start tile
sub di,[updateptr]
shl di,1
mov di,[blockstarts-2+di] ; start of tile location
mov si,di
add di,[bufferofs] ; dest in current screen
add si,[masterofs] ; source in master screen
mov dx,SCREENWIDTH
sub dx,bx ; offset to next line on screen
IFE GRMODE-CGAGR
sub dx,bx ; bx is words wide in CGA tiles
ENDIF
mov ax,[screenseg]
mov ds,ax
mov es,ax
REPT 15
mov cx,bx
IFE GRMODE-CGAGR
rep movsw
ENDIF
IFE GRMODE-EGAGR
rep movsb
ENDIF
add si,dx
add di,dx
ENDM
mov cx,bx
IFE GRMODE-CGAGR
rep movsw
ENDIF
IFE GRMODE-EGAGR
rep movsb
ENDIF
dec cx ; was 0 from last rep movsb, now $ffff for scasb
jmp @@findtile
ENDP
;============================================================================
;=================
;
; RFL_MaskForegroundTiles
;
; Scan through update looking for 3's. If the foreground tile there is a
; masked foreground tile, draw it to the screen
;
;=================
PROC RFL_MaskForegroundTiles
PUBLIC RFL_MaskForegroundTiles
USES SI,DI,BP
jmp SHORT @@realstart
@@done:
;
; all tiles have been scanned
;
ret
@@realstart:
mov di,[updateptr]
mov bp,(TILESWIDE+1)*TILESHIGH+2
add bp,di ; when di = bx, all tiles have been scanned
push di
mov cx,-1 ; definately scan the entire thing
;
; scan for a 3 in the update list
;
@@findtile:
mov ax,ss
mov es,ax ; scan in the data segment
mov al,3
pop di ; place to continue scaning from
repne scasb
cmp di,bp
je @@done
;============
;
; found a tile, see if it needs to be masked on
;
;============
push di
sub di,[updateptr]
shl di,1
mov si,[updatemapofs-2+di] ; offset from originmap
add si,[originmap]
mov es,[mapsegs+2] ; foreground map plane segment
mov si,[es:si] ; foreground tile number
or si,si
jz @@findtile ; 0 = no foreground tile
mov bx,si
add bx,INTILE ;INTILE tile info table
mov es,[tinf]
test [BYTE PTR es:bx],80h ;high bit = masked tile
jz @@findtile
;-------------------
IFE GRMODE-CGAGR
;=================
;
; mask the tile CGA
;
;=================
mov di,[blockstarts-2+di]
add di,[bufferofs]
mov es,[screenseg]
shl si,1
mov ds,[grsegs+STARTTILE16M*2+si]
mov bx,64 ;data starts 64 bytes after mask
xor si,si
lineoffset = 0
REPT 16
mov ax,[es:di+lineoffset] ;background
and ax,[si] ;mask
or ax,[si+bx] ;masked data
mov [es:di+lineoffset],ax ;background
inc si
inc si
mov ax,[es:di+lineoffset+2] ;background
and ax,[si] ;mask
or ax,[si+bx] ;masked data
mov [es:di+lineoffset+2],ax ;background
inc si
inc si
lineoffset = lineoffset + SCREENWIDTH
ENDM
ENDIF
;-------------------
IFE GRMODE-EGAGR
;=================
;
; mask the tile
;
;=================
mov [BYTE planemask],1
mov [BYTE planenum],0
mov di,[blockstarts-2+di]
add di,[bufferofs]
mov [cs:screenstartcs],di
mov es,[screenseg]
shl si,1
mov ds,[grsegs+STARTTILE16M*2+si]
mov bx,32 ;data starts 32 bytes after mask
@@planeloopm:
mov dx,SC_INDEX
mov al,SC_MAPMASK
mov ah,[ss:planemask]
WORDOUT
mov dx,GC_INDEX
mov al,GC_READMAP
mov ah,[ss:planenum]
WORDOUT
xor si,si
mov di,[cs:screenstartcs]
lineoffset = 0
REPT 16
mov cx,[es:di+lineoffset] ;background
and cx,[si] ;mask
or cx,[si+bx] ;masked data
inc si
inc si
mov [es:di+lineoffset],cx
lineoffset = lineoffset + SCREENWIDTH
ENDM
add bx,32 ;the mask is now further away
inc [ss:planenum]
shl [ss:planemask],1 ;shift plane mask over for next plane
cmp [ss:planemask],10000b ;done all four planes?
je @@drawn ;drawn all four planes
jmp @@planeloopm
@@drawn:
ENDIF
;-------------------
mov ax,ss
mov ds,ax
mov cx,-1 ;definately scan the entire thing
jmp @@findtile
ENDP
END