📄 paint.asm
字号:
PAGE 56,132
TITLE PAINT - iAPX 88/86 PAINT STATEMENT SUPPORT
;***
; PAINT - iAPX 88/86 PAINT STATEMENT SUPPORT
;
; Copyright <C> 1986, Microsoft Corporation
;
;Purpose:
;
; BASIC Syntax mapping to included runtime entry points:
;
; - PAINT Statement - Calls B$PAIN or B$PNTC, depending on 'paint' attribute
;
; PAINT (x,y) [[,paint [,boundary] ,background]]
; | |
; | Coord routines B$PAIN (if "paint" is numeric attribute)
; | or
; | B$PNTC (if "paint" is tile string)
; | |
; +------------------------------+
;
;******************************************************************************
INCLUDE switch.inc
INCLUDE rmacros.inc ; Runtime Macro Defintions
USESEG _DATA
USESEG _BSS
USESEG GR_TEXT
INCLUDE seg.inc ;define segments
INCLUDE baslibma.inc
INCLUDE idmac.inc
INCLUDE string.inc
sBegin _DATA
externW B$AC
sEnd _DATA
sBegin _BSS
;
;****************************************************************************
; External low-level function vectors
;****************************************************************************
;
externW b$LeftC
externW b$ChkDownC
externW b$ChkUpC
externW b$ScanL
externW b$ScanR
externW b$MapXYC
externW b$SetTile
externW b$PaintBound
externW B$C1SAVE ;defined in GWDATA.ASM
externW B$C2SAVE ;defined in GWDATA.ASM
externW B$C3SAVE ;defined in GWDATA.ASM
externW B$MOVCNT ;defined in GWDATA.ASM
externW B$SKPCNT ;defined in GWDATA.ASM
externB B$LFPROG ;defined in GWDATA.ASM
externB B$RTPROG ;defined in GWDATA.ASM
externB B$PDIREC ;defined in GWDATA.ASM
externW B$GXPOS ;defined in GWDATA.ASM
externW B$GYPOS ;defined in GWDATA.ASM
externW B$GX_OLD ;defined in GWDATA.ASM
externW B$GY_OLD ;defined in GWDATA.ASM
externW B$BGTLOC ;defined in GWDATA.ASM
externB b$Buf3 ; > 16-byte buffer, defined in GWINI.ASM
$BGTNUL EQU b$Buf3
externB B$TILFLG ;defined in GWDATA.ASM
externB B$TIPROG ;defined in GWDATA.ASM
externB B$TILLEN ;GWDATA - length of fground tile string (0-rel)
externB B$TILNDX ;GWDATA - index to pixel of fground tile string
externB B$TILPTR ;GWDATA - byte ptr to fground tile string
externW B$TILLOC ;GWDATA - pointer to start of fground tile str
externB B$TILHGT ;GWDATA - height of foreground tile
externB B$GRPLAN ;GWDATA - number of graphics planes
externW B$PQLEN ;defined in GWDATA.ASM
externW B$PQNUM ;defined in GWDATA.ASM
externW B$PQGET ;defined in GWDATA.ASM
externW B$PQPUT ;defined in GWDATA.ASM
externB b$Buf1 ; foreground tile string buffer
externB b$VTYP ;defined in GLOBAL.INC
sEnd _BSS
.RADIX 10
assumes CS,GR_TEXT
sBegin GR_TEXT
PUBLIC B$PAINTBEG
externNP B$STALCTMP
externNP B$STALCMAXTMPNC ; Allocate max string w/o compaction
externNP B$INVIEW
externNP B$COORD1
externNP B$CLRATR
;low-level routines:
externNP B$StoreC
externNP B$FetchC
externNP B$PaintInit
externNP B$GETFBC
externNP B$TileMod
externNP B$STALCMAXTMP
externNP B$STDALCTMP
externNP B$SCINIT ; Performs screen initialization
externNP B$ERR_FC
externNP B$ERR_OM
PAGE
SUBTTL PAINT ALGORITHM
B$PAINTBEG: ;Begin painting
CALL [b$PaintBound] ;Set Left and Right "C" for this line
MOV SI,1 ;ENTRY COUNT IS ONE (SKIP NO BORDER)
CALL SCANR1 ;SCAN RIGHT FROM INITIAL POSITION
JZ PNTEXT ;STARTED ON BORDER - GET TXTPTR & QUIT
PUSH BX ;SAVE NO. OF POINTS PAINTED TO RIGHT
CALL SCANL1 ;NOW SCAN LEFT FROM INITIAL POS.
POP SI ;GET RIGHT SCAN COUNT.
ADD SI,BX ;ADD TO LEFT SCAN COUNT
MOV DL,64 ;MAKE ENTRY FOR GOING DOWN
CALL ENTST1
MOV DL,0C0H ;CAUSE PAINTING UP
OR DL,B$TILNDX ;Add Tile index
JMP SHORT STPAIN ;START PAINTING.
PNTEXT: ;Exit PAINT statement
MOV B$TILFLG,0 ;Turn Tiling off
RET
;Register usage: (approximately)
; In main paint loop: SI=B$SKPCNT, BX=B$MOVCNT, DL=Direction/Tile Index
; In SCANR1,SCANL1: AX=Word 1 of graphics cursor,BX=Word 2,CX=Word 3
; MAIN PAINT LOOP
PNTLOP:
PNTLP1:
CALL GETQ ;Get one entry from queue
CALL B$StoreC
STPAIN:
MOV AL,DL ;GET DIRECTION
AND AL,63 ;Isolate Tile index
MOV B$TILNDX,AL ;and store it
MOV AH,B$GRPLAN ;get number of graphics planes
MUL AH ;product is in AX
MOV B$TILPTR,AL ;get real offset to fground tile string
MOV AL,DL ;reget direction byte
AND AL,0C0H ;Isolate direction bits
MOV B$PDIREC,AL
ADD AL,AL ;SEE WHETHER TO GO UP, DOWN, OR QUIT
JZ PNTEXT ;IF ZERO, ALL DONE.
JNB PDOWN ;IF POSITIVE, GO DOWN FIRST
CALL [b$ChkUpC] ;MOVE UP BEFORE SCANNING
JB PNTLP1 ;Off viewport - get next entry
CALL TILNDD ;Decrement tile index
JMP SHORT PNTLP2
PDOWN:
CALL [b$ChkDownC] ;SEE IF AT BOTTOM & MOVE DOWN IF NOT
JB PNTLP1 ;Off viewport - get next entry
CALL TILNDI ;Increment tile index
PNTLP2:
CALL [b$PaintBound] ;Set Left and Right "C" for this line
CALL SCANR1 ;SCAN RIGHT & SKIP UP TO B$SKPCNT BORDER
JZ PNTLP1 ;IF NO POINTS PAINTED, GET NEXT ENTRY
CALL SCANL1 ;NOW SCAN LEFT FROM START POINT
MOV SI,BX ;[SI] = LEFT B$MOVCNT
TEST B$TIPROG,255 ;Is this a background tile?
JNZ TPROG1 ;Yes: skip already painted check
OR CL,CL ;SEE IF LINE WAS ALREADY PAINTED
JZ PNTLP3 ;IT WAS - DON'T MAKE OVERHANG ENTRY
TPROG1:
CMP BX,1 ;SEE IF LEFT B$MOVCNT WAS .GT. 1
JLE PNTLP3 ;No: go make entry for left+right move count
;Yes: make entry in opposite direction for
;overhang
MOV AL,B$PDIREC
XOR AL,128
AND AL,0C0H ;Isolate new direction
OR AL,B$TILNDX ;Reverse direction and/or tile index
;++added 1 line (faster than doing it all in DL!)
MOV DL,AL
CALL B$FetchC ;Get current point address
CALL PUTQ
PNTLP3:
ADD SI,WORD PTR B$MOVCNT ;ADD COUNT PAINTED DURING RIGHT SCAN TO LEFT B$MOVCNT
CALL ENTSLR ;GO MAKE ENTRY.
;added 1 line
MOV CX,WORD PTR B$C3SAVE
MOV BX,WORD PTR B$C2SAVE ;SET CURRENT LOCATION BACK TO END
MOV AX,WORD PTR B$C1SAVE ;OF RIGHT SCAN.
CALL B$StoreC
PNTLP4:
MOV SI,WORD PTR B$SKPCNT ;CALC B$SKPCNT - B$MOVCNT TO SEE IF
SUB SI,WORD PTR B$MOVCNT ;ANY MORE BORDER TO SKIP
JZ GOPLOP ;NO MORE - END OF THIS SCAN
JB PNTLP6 ;RIGHT OVERHANG - SEE IF ENTRY NEEDED
CALL SCANR1 ;HERE IF NEED TO CONTINUE RIGHT SCAN
JZ GOPLOP ;NO MORE POINTS.
TEST B$TIPROG,255 ;Is this a background tile?
JNZ TPROG0 ;Yes: enter regardless if already painted or not
OR CL,CL ;SEE IF LINE ALREADY PAINTED
JZ PNTLP4 ;YES, DON'T ENTER ANYTHING
TPROG0:
MOV SI,BX ;ENTRY COUNT TO [SI]
;added 1 line
MOV CX,WORD PTR B$C3SAVE
MOV BX,WORD PTR B$C2SAVE ;MAKE ENTRY AT LOCATION SAVED BY ScanR
MOV AX,WORD PTR B$C1SAVE ;SO WE CAN ENTER A POSITIVE B$SKPCNT
MOV DL,B$PDIREC
CALL ENTSTK ;MAKE ENTRY
JMP SHORT PNTLP4 ;CONTINUE UNTIL B$SKPCNT .LE. 0
PNTLP6:
CMP SI,WORD PTR -1 ;If B$SKPCNT-B$MOVCNT .LT. -1
JGE GOPLOP ;No: overhang too small for entry
NEG SI ;Yes: Make right overhang entry
DEC SI ; of at least one point wide overhang
MOV CX,SI ; LeftC protects CX
RTOVH1:
CALL [b$LeftC] ;START IS -(B$SKPCNT-B$MOVCNT)-1 TO LEFT
LOOP RTOVH1
MOV AL,B$PDIREC ;MAKE ENTRY IN OPPOSITE DIRECTION
XOR AL,128
;++added 1 line (faster than doing it all in DL!)
MOV DL,AL
CALL ENTST1 ;MAKE ENTRY
GOPLOP:
JMP PNTLOP ;GO PROCESS NEXT ENTRY
ENTSLR:
MOV AL,B$LFPROG ;DON'T STACK IF LINE ALREADY PAINTED
OR AL,B$RTPROG
OR AL,B$TIPROG
JNZ ENTST0
RET ;Z IF SCAN LINE ALREADY PAINTED
ENTST0:
MOV DL,B$PDIREC
ENTST1:
CALL B$FetchC ;LOAD REGS WITH CURRENT "C"
ENTSTK:
OR DL,B$TILNDX ;Add tile index to direction
ENTST9:
JMP PUTQ
SCANR1:
;added 1 line
MOV DX,SI ;Can't change entry conditions for ScanR now...
CALL [b$ScanR] ;PERFORM LOW LEVEL RIGHT SCAN
MOV WORD PTR B$SKPCNT,DX ;SAVE UPDATED B$SKPCNT
MOV WORD PTR B$MOVCNT,BX ;SAVE B$MOVCNT
;added 3 lines
MOV WORD PTR B$C1SAVE,AX ;Save the "first non-BRDATR pixel
MOV WORD PTR B$C2SAVE,SI ; found during scan" in temp
MOV WORD PTR B$C3SAVE,DI
OR BX,BX ;SET CC'S ON B$MOVCNT
MOV AL,CL ;GET ALREADY-PAINTED FLAG FROM [C]
MOV B$RTPROG,AL
RET
SCANL1:
CALL B$FetchC ;GET CURRENT LOCATION
;added 1 line
PUSH CX
PUSH BX ;AND SWAP WITH CSV
PUSH AX
;added 1 line
MOV CX,WORD PTR B$C3SAVE
MOV BX,WORD PTR B$C2SAVE
MOV AX,WORD PTR B$C1SAVE
CALL B$StoreC ;REPOS AT BEGINNING OF SCAN
POP AX ;REGET PLACE WHERE RT SCN STOPPED
POP BX
;added 2 lines
POP CX
MOV WORD PTR B$C3SAVE,CX
MOV WORD PTR B$C2SAVE,BX ;AND SAVE IT IN TEMP LOCATION
MOV WORD PTR B$C1SAVE,AX
CALL [b$ScanL] ;NOW DO LOW LEVEL LEFT SCAN
MOV AL,CL ;GET ALREADY-PAINTED FLAG FROM [C]
MOV B$LFPROG,AL ;WHETHER IT WAS ALREADY PAINTED (faster than
; doing MOV B$LFPROG,CL!)
RET
PAGE
SUBTTL PAINT AND TILE SUPPORT ROUTINES
; Little helpers for PAINT and TILE
;
;FGSTRINI initialize foreground string
;
;Purpose:
; Check string for validity: its length must be less than 256 and
; greater than 0. Fill string buffer b$Buf1 with paint tile padded on the
; right with zeros. Initialize B$TILLOC to point at b$Buf1. Initialize
; B$GRPLAN to the number of graphics planes. Stores rounded up tile
; length in B$TILLEN and pixel height of tile in B$TILHGT (must be less
; than or equal to 64).
;
;Entry:
; BX = ptr to string descriptor
;
;Exit:
; variables updated as noted
;
;Modifies:
; CX,SI,DI
;
FGSTRINI: ;initialize paint string
MOV CX,WORD PTR 0[BX] ;[CX]= len
MOV SI,WORD PTR 2[BX] ;[SI]= addr
OR CH,CH ;Is CH=0?
JNE MATERR ;Length must be .LE. 255
MOV DI,OFFSET DGROUP:b$Buf1 ;DI points to b$Buf1
MOV WORD PTR B$TILLOC,DI ;Store adr
PUSH CX ;Save string length
CLD ;Clear direction flag
;Repeat until CX=0:
REP MOVSB ;Put Fill String in b$Buf1
POP CX ;Restore string length
PUSH CX ;Resave string length
SUB CX,256d ;CX:=CX-256
NEG CX ;CX:=-CX=remainder of BUF
XOR AL,AL ;Clear AL
;Repeat until CL=0:
REP STOSB ;Fill the rest of BUF with zeros
;tile string is now saved in the temp buffer so temp string can be deallocated
CALL B$STDALCTMP ; deallocate temp string pointed to by BX
;Check tile height
CALL B$TileMod ;Get number of graphics planes
POP CX ;Restore CL
MOV B$GRPLAN,AL ;in this screen mode
JCXZ MATERR ;See if at least one byte in tile string
XCHG AX,CX
DEC AX
DIV CL ;AX=(B$TILLEN-1)/B$GRPLAN
XOR AH,AH
INC AX ;AX=INT((B$TILLEN-1)/B$GRPLAN)+1=height in pixels rounded up
CMP AL,65
JNB MATERR ;Tile can only be 64 pixels long (IBM compatibility)
MOV B$TILHGT,AL ;Save pixel height of tile (always.LE.64)
MUL CL ;AX=INT(((B$TILLEN-1)/B$GRPLAN)+1)*B$GRPLAN
DEC AX ;make 0 based, guaranteed 1 or more
OR AH,AH ;Rounded up length must be .le. 255
JNZ materr ;Yes: this must be a multiplane with four or more planes
MOV B$TILLEN,AL ;Store rounded up length
RET ;return to caller
MATERR:
MOV B$TILFLG,0 ;Turn Tiling off
JMP B$ERR_FC
;***
; BGSTRINI - initialize background tile string
; Purpose:
; Insures that string length is between 1 and 255 inclusive.
; Initializes background string to specified background string.
;
; Entry:
; BX = ptr to string descriptor
; $BGTNUL = ptr to background tile string area
; Exit:
; None.
; Modifies:
; SI,DI,CX
;****
BGSTRINI:
MOV CX,[BX] ;[CX]= len
OR CH,CH
JNE materr ;Max len is 255
JCXZ materr ;See if at least one byte in background string
CMP CL,B$GRPLAN ;Ignore any extra bytes
JBE FILL_BGSTR
MOV CL,B$GRPLAN
FILL_BGSTR: ;Fill background string
MOV SI,WORD PTR 2[BX] ;[SI]= addr
MOV DI,OFFSET DGROUP:$BGTNUL ;Point DI at backgrd tile area
CLD ;Clear direction flag
REP MOVSB ;Fill with as much as user gave,
;rest are chr$(0)
JMP B$STDALCTMP ; deallocate temp string pointed to by BX
;***
; B$ClrBgStr - clear background string area
; Purpose:
; Initialize background string area by filling with zeros.
; Make sure there are no more than 16 graphics planes.
;
; Entry:
; $BGTNUL points to background string area
; Exit:
; None.
; Modifies:
; CX,DI,AX.
;****
cProc B$ClrBgStr,<NEAR> ;Clear background string
cBegin
MOV CX,16
CMP CL,B$GRPLAN ;Only allocated space for at most 16 planes
JB MATERR ;function call error
MOV DI,OFFSET DGROUP:$BGTNUL
XOR AL,AL
CLD
REP STOSB ;Fill 16 bytes with CHR$(0)
MOV B$BGTLOC,OFFSET DGROUP:$BGTNUL ;No BG tile, use null (00)
cEnd
; Set starting tile index to Starting Y axis and
; store in B$TILNDX.
; Set B$TILNDX to (Y MOD pixel height)*B$GRPLAN
;
;Entry - [DX] = Starting Y line
;
; Uses: [BX]
cProc B$SetTileIndex,<NEAR>
cBegin
CMP B$TILFLG,0
JZ STIND2 ;nothing if not tile
PUSH AX
PUSH DX ;Protect DX
MOV BX,DX ;[BX]=Y coord
MOV DL,B$TILHGT ;[DX]= height of tile
XOR DH,DH
STIND1:
SUB BX,DX
JNB STIND1 ;Find Y MOD pixel height
ADD BX,DX ;+len since overflowed
MOV B$TILNDX,BL ;get index of tile pixel
MOV AL,B$GRPLAN
XOR AH,AH
MUL BL ;AX=(Y MOD pixel height)*B$GRPLAN
MOV B$TILPTR,AL ;store fground tile string offset
POP DX ;get Y coord
POP AX
STIND2:
cEnd
; Scan Fill argument, set Fill color attr if numeric
; or set up tile attr if string.
; If string, check that its length .LE. 64*number of graphics planes
; and round up length to even multiple of number of graphics planes.
; MATCH3 Checks 3 consecutive lines in TILE$ for match
; with the background color or tile. If 3 lines
; are there, then give Illegal Function Call error.
; If this was not done, PAINT might infinite loop.
; Uses AX,BX,CX,DX,SI,DI
MATCH3:
CMP B$TILFLG,0
JZ MATC3X ;Do nothing if Tile wasn't given
XOR DH,DH
MOV DL,B$GRPLAN ;DX=tile "width"
MOV SI,WORD PTR B$TILLOC ;SI=pointer to tile string
XOR AH,AH
MOV AL,B$TILLEN
ADD AX,SI ;AX=end of tile string
CLD
MAT3LP:
CMP SI,AX ;Done entire tile string yet?
JA MATC3X ;Yes:
MOV DI,WORD PTR B$BGTLOC
CALL CMPST ;Matched 3 tiles in a row?
JE PNTERR ;Yes: barf
ADD SI,DX ;No: look at next set in tile string
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -