691 lines
14 KiB
NASM
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
|
|
|