pcs/graphcmd.asm

1992 lines
64 KiB
NASM
Raw Permalink Normal View History

2023-05-20 05:57:05 -04:00
name graphics
title PC Scheme Graphics
page 60,132
;-----------------------------------------------------------------------------
;
; TITLE: PC Scheme Graphics
; AUTHOR: Medford W. Haddock II (Rusty)
; DATE: October 20, 1983
; COMPUTER: Texas Instruments Professional Computer with 3-plane graphics
; IBM PC with Color, Enhanced, or Professional Graphics Adapters
; ABSTRACT: These routines are designed to interface between PC Scheme
; and the color graphics board for both the IBM and TI PCs.
; REVISIONS: ds - 9/25/86 - added support for the IBM EGA modes 14 and 16
; rb 11/7/86 - added point, line, box clipping (both TI and IBM)
; rb 11/24/86 - fix line drawn from p1 to p2 not same as
; line drawn from p2 to p1
; mrm 4/15/87 - modified set-mode! to run w/o screen flicker
; modified set-palette! to save EGA colors
; rb 6/13/87 - use CR for EGA mode 16 for illegal mode values
;
;-----------------------------------------------------------------------------
include pcmake.equ
page
;-----------------------------------------------------------------------------
; The "intersect" macro. in: none
; out: AX=intersect value
; destroys: AX,BX,CX,DX,SI
; usage: intersect L,y2,x2,x1,y1 (be careful of the funny ordering)
;
; Given a line that crosses a clipping edge, determine the point of
; intersection: one of the coordinates is that of the clipping edge,
; and this macro calculates the other coordinate.
;
; The equation pattern is: new-y = y1 + (y2 - y1) * (L - x1) / (x2 - x1).
;-----------------------------------------------------------------------------
intersect macro L,y2,x2,x1,y1
mov AX,L
mov BX,y2
mov CX,x2
mov DX,x1
mov SI,y1
sub BX,SI ;; y2 - y1
sub CX,DX ;; x2 - x1
sub AX,DX ;; L - x1
imul BX ;; (y2 - y1) * (L - x1) = q
idiv CX ;; q / (x2 - x1)
add AX,SI ;; y1 + q / (x2 - x1)
endm
;-----------------------------------------------------------------------------
; The "overlap" macro. in: none
; out: none (look at Z flag)
; destroys AX,BX,CX
; usage: overlap contained,disjoint
;
; Compares the two rectangles:
; (Curr_X,Curr_Y) - (Stop_X,Stop_Y) and
; (Clip_left,Clip-top) - (Clip_right,Clip-bottom)
; and returns status on their intersection.
;
; If the Curr/Stop rectangle is totally contained in the clipping rectangle,
; jump to label "contained" with the Z flag on. If they are disjoint, jump
; to label "disjoint" with the Z flag off. Otherwise, they intersect, so
; fall through. Both jumps are short relative jumps.
;-----------------------------------------------------------------------------
overlap macro contained,disjoint
mov AX,Curr_X
mov BX,Curr_Y
call Encode_XY
mov CH,CL
mov AX,Stop_X
mov BX,Stop_Y
call Encode_XY
cmp CX,0
jz contained ;;jump if Curr/Stop totally contained in CR
test CH,CL
jnz disjoint ;;jump if they're disjoint
endm
page
;-----------------------------------------------------------------------------
TI_CRT equ 49h
IBM_CRT equ 10h
DOS_FUN equ 21h
page
XGROUP group PROGX
DGROUP group DATA
DATA segment byte public 'DATA'
assume DS:DGROUP
public VID_MODE
extrn PC_MAKE:word
extrn char_hgt:word
;------------------------------------------------------------------------------
; Some TIPC system constants.
;------------------------------------------------------------------------------
X_MAX equ 720 ; Horizontal resolution
Y_MAX equ 300 ; Vertical resolution
Num_Colors equ 8 ; Number of colors displayable by TIPC
Bytes_per_Line equ 92 ; (720-displayed + extra word)/ 8-bits/byte
;-----------------------------------------------------------------------------
; These are the default values of the palette & misc. output latches.
;-----------------------------------------------------------------------------
DEF_RED equ 0AAh
DEF_GRN equ 0CCh
DEF_BLU equ 0F0h
TEXT_ON equ 040h ; This value is needed for bit-twiddling
TEXT_OFF equ 00h
YES_GRPH equ 0FFh
NO_GRAPH equ 00h
TRUE equ 0FFh
FALSE equ 00h
;-----------------------------------------------------------------------------
; Local variable storage.
;-----------------------------------------------------------------------------
Curr_X dw ? ; Current x-coordinate
Curr_Y dw ? ; Current y-coordinate
Stop_X dw ? ; Second endpoint x-coordinate for drawing
Stop_Y dw ? ; Second endpoint y-coordinate for drawing
clip_left dw ? ; Clipping rectangle (in screen coordinates)
clip_top dw ?
clip_right dw ?
clip_bottom dw ?
px dw ? ; Points to the independent variable
py dw ? ; Points to the dependent variable
Delta_X dw ? ; = Stop_X - Start_X
Delta_Y dw ? ; = Stop_Y - Start_Y
X_Dir dw ? ; -1,0,+1 : step of independent variable
Y_Dir dw ? ; -1,0,+1 : step of dependent variable
Xend dw ? ; End value of independent variable
Incr1 dw ? ; Step for using pnt below desired value
Incr2 dw ? ; Step for using pnt above desired value
GRAFIX_ON dw YES_GRPH ; TI Graphics are initially enabled
VID_MODE dw 3 ; Current video mode for TI (text & grafx on)
Box_Hite dw ? ; Box is this number of pixels high
Box_Width dw ? ; Number of bytes the box's width occupies
Left_Offset dw ? ; Byte offset into graphx planes of upper left box
Left_End dw ? ; Bit pattern of left end of solid box
Left_Side dw ? ; Bit pattern of left side of hollow box
Right_End dw ? ; Bit pattern of right end of solid box
Right_Side dw ? ; Bit pattern of right side of hollow box
Fill_Fig db ? ; True if box is to be filled
func db ? ; EGA function 0 or 18h
f_code db 7 ; and or xor function
st_word dw ? ; start sceen offset
st_bit dw ? ; start bit offset
ed_word dw ? ; ending word offset
ed_bit dw ? ; ending bit offset
w_p_row dw 40 ; # of words per row
b_p_wrds db 16 ; 16 bits per word
two dw 2 ; two
pix_c dw ? ; pixel color
gra_ram dw 0a000h ; EGA graphics ram address
y_val dw ?
;-----------------------------------------------------------------------------
; Local constants storage.
;-----------------------------------------------------------------------------
X_Resolution dw X_MAX
Y_Resolution dw Y_MAX
Bits_per_Byte dw 8
Color_Cycle db 8
;-----------------------------------------------------------------------------
; Stored here will be the current values for the latches should
; the (ab)user decide to change them later with (set-palette!).
;-----------------------------------------------------------------------------
RED_Latch db DEF_RED
GRN_Latch db DEF_GRN
BLU_Latch db DEF_BLU
;-----------------------------------------------------------------------------
; A table of zeroes for clearing the palettes before a mode change on
; the EGA.
; A table of current values for the EGA colors. The table will be
; modified by each set-palette! command for the EGA. These values
; will be used to restore the colors after a mode change on the EGA.
;-----------------------------------------------------------------------------
clear_pal db 17 dup(0)
save_pal db 0,1,2,3,4,5,6,7,38h,39h,3ah,3bh,3ch,3dh,3eh,3fh,0
;-----------------------------------------------------------------------------
; These are the segments for the three graphics bit-planes
; in the TIPC color graphics board. The order below is
; important - see XPCINIT
;-----------------------------------------------------------------------------
Bank_A dw 0C000h
Bank_B dw 0C800h
Bank_C dw 0D000h
Misc_Latch dw 0DF82h
;-----------------------------------------------------------------------------
; These are the segments of the Red, Green, Blue palette latches.
;-----------------------------------------------------------------------------
RED_Palette dw 0DF01h
GRN_Palette dw 0DF02h
BLU_Palette dw 0DF03h
;-----------------------------------------------------------------------------
; Color to palette bits translation
;-----------------------------------------------------------------------------
Palette_Trans label byte
db 00000001b
db 00000010b
db 00010000b
db 00100000b
db 00000100b
db 00001000b
db 01000000b
db 10000000b
;-----------------------------------------------------------------------------
; Single-bit-on words for setting individual pixels
;-----------------------------------------------------------------------------
Bit_Table label byte
; 01234567 (Pixel numbering - not bit numbering)
db 10000000b
db 01000000b
db 00100000b
db 00010000b
db 00001000b
db 00000100b
db 00000010b
db 00000001b
;-----------------------------------------------------------------------------
; Gradual bit filled bytes for the "left-side" of horizontal lines
;-----------------------------------------------------------------------------
Start_Line label byte
; 01234567 (Pixel numbering - not bit numbering)
db 11111111b
db 01111111b
db 00111111b
db 00011111b
db 00001111b
db 00000111b
db 00000011b
db 00000001b
;-----------------------------------------------------------------------------
; Gradual bit filled bytes for the "right-side" of horizontal lines
;-----------------------------------------------------------------------------
End_Line label byte
; 01234567 (Pixel numbering - not bit numbering)
db 10000000b
db 11000000b
db 11100000b
db 11110000b
db 11111000b
db 11111100b
db 11111110b
db 11111111b
;-----------------------------------------------------------------------------
; Clipping masks
;-----------------------------------------------------------------------------
; LTRB (left, top, right, bottom)
left_mask db 00001000b
top_mask db 00000100b
right_mask db 00000010b
bottom_mask db 00000001b
;-----------------------------------------------------------------------------
; Screen resolution table (for the different IBM video modes)
;-----------------------------------------------------------------------------
; The table contains the maximum *plottable* X,Y value for the mode.
Res_Table_IBM label word
dw 0,0 ;mode 0 not a graphics mode
dw 0,0 ;mode 1 not a graphics mode
dw 0,0 ;mode 2 not a graphics mode
dw 0,0 ;mode 3 not a graphics mode
dw 319,199 ;mode 4 is a graphics mode
dw 319,199 ;mode 5 is a graphics mode
dw 639,199 ;mode 6 is a graphics mode
dw 0,0 ;mode 7 not a graphics mode
dw 0,0 ;mode 8 PCjr only
dw 0,0 ;mode 9 PCjr only
dw 0,0 ;mode 10 PCjr only
dw 0,0 ;mode 11 EGA internal mode
dw 0,0 ;mode 12 EGA internal mode
dw 319,199 ;mode 13 is a graphics mode
dw 639,199 ;mode 14 is a graphics mode
dw 639,349 ;mode 15 is a graphics mode
dw 639,349 ;mode 16 is a graphics mode
;-----------------------------------------------------------------------------
; Jump table for graphit() based on op_code
;-----------------------------------------------------------------------------
OP_CODE dw SET_MODE
dw SETP
dw SET_PAL ; This used to be RESETP
dw LINE
dw GETP
dw VIDEO_MODE
dw BOX
dw FILLD_BX
dw SET_CLIP_RECT
table_len equ $ - OP_CODE
DATA ends
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
PROGX segment byte public 'PROGX'
assume CS:XGROUP,DS:DGROUP
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
; name GRAPHIT -- Scheme interface to Rusty's graphics routines
;
; synopsis graphit(op, arg1, arg2, arg3, arg4, arg5, arg6);
;
; description call the appropriate graphics routine based on the "op"
; argument:
; 0 - (set-video-mode! mode)
; 1 - (setp x y color)
; 2 - (set-palette! curr-color-id new-color-id)
; 3 - (line x1 y1 x2 y2 color)
; 4 - (point x y)
; 5 - (get-video-mode)
; 6 - (box x-ul y-ul x-len y-len color)
; 7 - (filled_box x-ul y-ul x-len y-len color xor)
; 8 - (set-clipping-rectangle! left top right bottom)
;
gr_args struc
dw ? ; caller's BP
dd ? ; return address
arg6 dw ? ; argument 6 -- dbs 10/10/86
arg5 dw ? ; argument 5
arg4 dw ? ; argument 4
arg3 dw ? ; argument 3
arg2 dw ? ; argument 2
arg1 dw ? ; argument 1
opcode dw ? ; sub operation code
gr_args ends
public graphit
graphit proc far
push BP ; save caller's BP
mov BP,SP
; Load sub opcode
mov BX,[BP].opcode ; load sub operation code
add BX,BX ; adjust for index into jump table
cmp BX,table_len ; bad op_code?
jae bad_op
; cmp BX,0 ; "jae" serves as well
; jl bad_op
; Call desired graphics function
call OP_CODE[BX]
jmp short gr_end
bad_op: mov AX,-1
; Return to caller
gr_end: mov SP,BP ; dump arguments off TIPC's stack
pop BP ; restore caller's BP
ret ; return to caller
graphit endp
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name SET_MODE - graphics initialize
;
; synopsis (set-video-mode! mode_number)
;
; description TIPC | IBM-PC
; MODE ACTION | MODE ACTION(same as AH=0,INT 10H)
; --------------------------+---------------------------
; 0 Clear graphics | 0 40x25 BW 4 320x200 Col
; 1 Text Enable | 1 40x25 Color 5 320x200 BW
; 2 Graphics Enable | 2 80x25 BW 6 640x200 BW
; 3 Text & Graphics Ena | 3 80x25 Color
; +---------------------------
; | extra EGA modes:
; | 13 320x200 16col 40x25 8x8cbox
; | 14 640x200 16col 80x25 8x8cbox
; | 15 640x350 4col 80x25 8x14cbox
; | 16 640x350 16col 80x25 8x14cbox
;
; returns nothing
;
SET_MODE proc near
push BP
push ES
mov AX,[BP].arg1 ; Get mode-number
push AX ; Save mode number for later
cmp PC_MAKE,TIPC ; set IBM mode?
je ti_mode
ibm_mode label near
comment % ;;; Protected Mode
Commented out 8/3/87 by TC
mov AH,12H ; Test for presence of EGA
mov BX,10H
int IBM_CRT ; IBM's video BIOS interrupt
cmp CX,0 ; Is there an EGA here ?
je ibm_cga ; Apparently not; assume CGA
push DS
pop ES
mov DX,offset clear_pal
mov AX,1002H ; Set EGA palettes to black for mode
int IBM_CRT ; change without screen flicker
pop AX
push AX
xor AH,AH ; Set video I/O mode (AH=0) (AL=MODE)
int IBM_CRT ; IBM's video BIOS interrupt
call Reset_CR_IBM ; reset clipping rectangle to full screen
Initialize a delay loop
mov AH,2CH ; Get time
int DOS_FUN ; DOS function request
inc DH ; Add 1 second delay to start time
mov BX,DX ; Save the ending time
cmp BH,59 ; Test for 59 seconds (impossible limit)
jl tm_loop ; OK
mov BH,0 ; Set it = 0 to avoid a long delay
tm_loop: mov AH,2CH ; Get time
int DOS_FUN ; DOS function request
cmp DX,BX ; Enough time yet ?
jle tm_loop ; No, loop again
mov DX,offset save_pal
mov AX,1002H ; Set EGA palettes to saved colors
int IBM_CRT ; IBM's video BIOS interrupt
jmp short mode_end
%
ibm_cga label near
pop AX
push AX
xor AH,AH ; Set video I/O mode (AH=0) (AL=MODE)
int IBM_CRT ; IBM's video BIOS interrupt
call Reset_CR_IBM ; reset clipping rectangle to full screen
jmp short mode_end
ti_mode: call Reset_CR_TI ; reset clipping rectangle to full screen
cmp AL,0 ; Clear TI graphics and re-init palette
je clr_grfx
cmp AL,1 ; Turn off Graphics and Text on
je textonly
cmp AL,2 ; Turn on Graphics and Text off
je grfxonly
cmp AL,3 ; Turn on both Graphics and Text
jne ti_err
jmp all_on
ti_err:
pop AX
xor AX,AX ; Bad op-code
not AX ; AX = -1
jmp short err_ret
mode_end: pop AX
mov VID_MODE,AX ; Save VID-MODE for (get-video-mode)[TI-only]
xor AX,AX ; Return something nice(?)
mov char_hgt,8
cmp vid_mode,14
jle err_ret
mov char_hgt,14
err_ret: pop ES ; Get the heck outta here
pop BP
ret
clr_grfx:
IFDEF PROMEM ;;; Protected Mode
reg_block struc ; register block
dw ? ; AX
dw ? ; BX
dw ? ; CX
dw ? ; DX
reg_block ends
push AX
push BX
push CX
push DX
mov DX,SP
mov AH,0C4h ; Issue Real Interrupt
mov AL,TI_CRT ; TI CRT interrupt number
int DOS_FUN ; (extended dos function for protected mode)
ELSE
mov AH,14h ; Clear graphics planes
int TI_CRT ; Send command to CRT device driver
ENDIF
mov RED_Latch,DEF_RED ; Reset palettes to default values
mov GRN_Latch,DEF_GRN
mov BLU_Latch,DEF_BLU
cmp byte ptr GRAFIX_ON,YES_GRPH
jne short mode_end
mov AL,RED_Latch ; if graphics are enabled reset the palettes
mov BL,GRN_Latch
mov CL,BLU_Latch
mov DL,YES_GRPH
call pal_set ; Set the graphics palettes on
jmp short mode_end
grfxonly label near
mov AL,RED_Latch
mov BL,GRN_Latch
mov CL,BLU_Latch
mov DL,YES_GRPH
call pal_set ; Set the graphics palettes on
mov AL,TEXT_OFF
call txt_set ; Turn text off
jmp short mode_end
textonly label near
xor AL,AL
mov BL,AL
mov CL,AL
mov DL,NO_GRAPH
call pal_set ; Set the graphics palettes off
mov AL,TEXT_ON
call txt_set ; Turn text on
jmp short mode_end
all_on label near
mov AL,RED_Latch
mov BL,GRN_Latch
mov CL,BLU_Latch
mov DL,YES_GRPH
call pal_set ; Set the graphics palettes on
mov AL,TEXT_ON
call txt_set ; Turn text on
jmp mode_end
pal_set label near
xor BP,BP ; Zero offset from palette segments
mov ES,RED_Palette
mov byte ptr ES:[BP],AL ; Set red palette
mov byte ptr ES:[BP]+16,BL ; Set green palette
mov byte ptr ES:[BP]+32,CL ; Set blue palette
mov byte ptr GRAFIX_ON,DL ; if graphics are on or not
ret
txt_set label near
xor BP,BP
mov ES,Misc_Latch
mov byte ptr ES:[BP],AL
ret
SET_MODE endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name SETP -- turn on a pixel at the given coordinates with
; the specified color.
;
; synopsis (setp x y color)
;
; description Turn on the pixel at (x,y) [origin at upper left] with
; one of 8 colors specified by 'color'.
; Point clipping is done; ignore the ";;" comments.
;
;; The arguments
;; need not be in their proper range (i.e. a MOD of x, y,
;; and color will be done with their proper values to get
;; them into the correct range. [0 <= x <= 719, 0 <= y <= 299,
;; 0 <= color <= 7]). This will give a "wrap-around" effect.
;; On the IBM-PC with graphics adapter no range checking is done
;; on either the (x,y) coordinates or the color.
;
; returns nothing
;
SETP proc near
push BP
push DI
push ES
;
mov AX,[BP].arg1 ; Get `x'
mov BX,[BP].arg2 ; Get `y'
; call Fix_XY ; Force x and y into their proper ranges
call Encode_XY ; Encode point's visibility
cmp CL,0 ; is it visible?
jnz Set_exit ; no, jump
mov CX,[BP].arg6 ; xor code
mov f_code,CL
mov CX,[BP].arg3 ; Get `color'
call LCL_SETP ; Display pixel
Set_exit: xor AX,AX ; Return code of zero
pop ES
pop DI
pop BP
ret
SETP endp ; End of SETP(,,)
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name SET_PAL -- Modify the current palette according to PC_MAKE
;
; synopsis (set-palette! curr-color-id new-color-id)
;
; description If PC_MAKE == TIPC then set-palette twiddles the TIPC
; graphics palette latches according to the colors specified.
;
; If PC_MAKE == [PC,XT,jr,AT] then use the IBM video I/O
; interrupt (10h), function 11, set color palette;
; or function 16, set palette registers if EGA is present.
;
; returns nothing
;
SET_PAL proc near
push BP
push ES
mov BX,[BP].arg1 ; Get current-color-id
mov CX,[BP].arg2 ; Get new-color-id
; **** WARNING **** Fix the IBM side of this swapping of A,BX <=> B,CX
;
cmp PC_MAKE,TIPC
jne ibm_pal
and BX,7 ; use only lower three bits
mov AL,Palette_Trans[BX] ; convert BL to 1-in-8 bits
mov AH,AL
not AH ; AH = 7-in-8 mask
mov BL,RED_Latch
call twiddle
mov RED_Latch,BL
mov BL,BLU_Latch
call twiddle
mov BLU_Latch,BL
mov BL,GRN_Latch
call twiddle
mov GRN_Latch,BL
cmp byte ptr GRAFIX_ON,YES_GRPH ; are graphics enabled?
jne pal_ret
mov AL,RED_Latch ; if yes, then update display palettes
mov CL,BLU_Latch
mov DL,YES_GRPH
call pal_set ; Set the graphics palettes on
jmp short pal_ret
twiddle label near
sar CL,1 ; Do we turn the bit on or off
jnc turn_off
or BL,AL ; Turn it on
ret
turn_off: and BL,AH ; Turn it off
ret
ibm_pal: mov AH,15 ; Get current video mode
int IBM_CRT ; IBM video I/O interrupt
cmp AL,4 ; Is mode = 4 ?
jne pal_ega ; No, jump
; CGA palette
mov BH,BL ; BH = palette color id being set
mov BL,CL ; BL = color value
mov AH,11 ; Set CGA color palette
int IBM_CRT ; IBM video I/O interrupt
jmp short pal_ret
; EGA palette
pal_ega: mov BH,CL ; BL = palette color id being set
; BH = color value
cmp BL,16 ; Is color id reasonable ?
jge pal_ret ; No, forget it
mov AX,1000H ; Set EGA color palette
int IBM_CRT ; IBM video I/O interrupt
mov BH,0 ; Use palette color id (BL) as index
mov DS:save_pal[BX],CL ; Save color value in palette table
pal_ret: xor AX,AX ; Return code of zero
pop ES
pop BP
ret
SET_PAL endp ; End of (set-palette!...)
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name VIDEO_MODE - return the current video mode
;
; synopsis (get-video-mode)
;
; description Returns the video mode number for the appropriate PC.
;
; returns video mode number
;
public VIDEO_MODE
VIDEO_MODE proc near
cmp PC_MAKE,TIPC
je get_ti_m
mov AH,15 ; IBM's get current video state
int IBM_CRT
cbw ; Convert to full word.
ret
get_ti_m: mov AX,VID_MODE ; This was squirreled away by SET_MODE (TI)
ret
VIDEO_MODE endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name LINE -- draw a line between the two sets of coordinates
; given with the specified color.
;
; synopsis (line x1 y1 x2 y2 color)
;
; description Draw a line between (x1,y1) and (x2,y2) with one of the 8
; colors specified by 'color'. The line is clipped.
;
; This routine is based upon Bresenham's Line Algorithm
; from page 435 in "Fundamentals of Interactive Computer
; Graphics" by Foley and Van Dam.
;
; The clipping algorithm is Cohen and Sutherland's.
; See pages 65-67, "Principles of Interactive Computer Graphics"
; (2nd edition) by Newman and Sproull.
;
; returns nothing
;
LINE proc near
push DI
push SI
push ES
; Clip line
mov AX,[BP].arg1 ; Get x1
mov BX,[BP].arg2 ; Get y1
mov CX,[BP].arg3 ; Get x2
mov DX,[BP].arg4 ; Get y2
cmp AX,CX ; is x1 <= x2?
jle x1_first ; yes, jump
; always draw from p1 to p2; otherwise the same line drawn
; in the opposite direction may not exactly overlay it
xchg AX,CX ; no, interchange the two points
xchg BX,DX
x1_first: mov Curr_X,AX
mov Curr_Y,BX
mov Stop_X,CX
mov Stop_Y,DX
call Clip_line
jz Do_line ; jump if line is visible
jmp Line_exit ; jump if line is invisible
; Line drawing proper
Do_line: mov px,offset Curr_X ; px = address of Curr_X
mov py,offset Curr_y ; py = address of Curr_Y
;
mov BX,[BP].arg6 ; get xored or not
mov f_code,BL
;
mov AX,Stop_X
mov BX,Stop_Y
mov Xend,AX ; Independent var's end-value unless swapped
sub BX,Curr_Y ; Delta_Y = y2 - y1
mov Delta_Y,BX
sub AX,Curr_X ; Delta_X = x2 - x1
mov Delta_X,AX
xchg AX,BX ; Put Delta_Y into ax; Delta_X into bx
;
jz Swap_Things ; Is Delta_X == 0 ?
cwd ; Ready dx for division
idiv BX
neg AX
jge Test_Slope
neg AX ; slope = ax = ABS(INT(dy/dx))
Test_Slope label near
cmp AX,1 ; IF slope >= 1 THEN
jl Get_X_Increment
;
Swap_Things label near
xchg Delta_Y,BX
mov Delta_X,BX ; swap(dx,dy)
mov CX,px
xchg py,CX
mov px,CX ; swap(px,py)
mov CX,Stop_Y
mov Xend,CX ; Xend = Stop_Y since variables'
; dependence was swapped.
; ENDIF
Get_X_Increment label near
or BX,BX ; X_Dir = sgn(Delta_X)
jz Save_X_Dir ; IF it's zero THEN we're done
mov BX,1 ; ELSE force bx = 1
jg Save_X_Dir ; IF Delta_X was < zero THEN
neg BX ; bx = -1
Save_X_Dir label near
mov X_Dir,BX
;
mov BX,Delta_Y
or BX,BX ; Y_Dir = sgn(Delta_Y)
jz Save_Y_Dir ; IF it's zero THEN we're done
mov BX,1 ; ELSE force bx = 1
jg Save_Y_Dir ; IF Delta_X was < zero THEN
neg BX ; bx = -1
Save_Y_Dir label near
mov Y_Dir,BX
;
mov AX,Delta_X ; Delta_X = ABS(Delta_X)
neg AX
jge Save_ABS_Dx
neg AX
Save_ABS_Dx label near
mov Delta_X,AX
;
mov BX,Delta_Y ; Delta_Y = ABS(Delta_Y)
neg BX
jge Save_ABS_Dy
neg BX
Save_ABS_Dy label near
mov Delta_Y,BX
;
shl BX,1
mov Incr1,BX ; Incr1 = Delta_Y * 2
sub BX,AX
push BX ; d = Delta_Y * 2 - Delta_X
sub BX,AX
mov incr2,BX ; Incr2 = (Delta_Y - Delta_X) * 2
;
mov CX,[BP].arg5 ; Push `color' for call to SETP
mov BX,Curr_Y ; Push `y'
mov AX,Curr_X ; Push `x'
call LCL_SETP ; Plot beginning point
;
mov DI,px ; Get pointer to independent variable
mov SI,py ; Get pointer to dependent variable
mov AX,X_Dir
mov BX,Y_Dir
mov CX,Xend
pop DX ; get D from stack
;
While label near
cmp CX,DS:[DI] ; While (px->start != xend) {
je While_End
add DS:[DI],AX ; Px->start += X_Dir
or DX,DX ; IF (D < 0) THEN
jge Inc_Dependent
add DX,Incr1 ; D += Incr1
jmp short End_If
Inc_Dependent label near ; ELSE
add [SI],BX ; Py->start += Y_Dir
add DX,Incr2 ; D += Incr2
End_If label near ; ENDIF
push AX ; Save X_Dir
push BX ; Save Y_Dir
push CX ; Save Xend
push DX ; Save D
push DI
;
mov CX,[BP].arg5 ; Push `color' for call to SETP
mov BX,Curr_Y ; Push `y'
mov AX,Curr_X ; Push `x'
call LCL_SETP ; Plot beginning point
;
pop DI
pop DX
pop CX
pop BX
pop AX
jmp short While
;
While_End label near
Line_exit label near
xor AX,AX ; Return code of zero
pop ES
pop SI
pop DI
ret
LINE endp ; End of LINE(,,,,)
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name GETP -- return the attribute (color) at the specified
; coordinates.
;
; synopsis (getp x y)
;
; description Return the pixel value (0 - 7) at the coordinates given
; as arguments. The coordinates are clipped.
;
; returns An unsigned integer in the range 0 to 7 , inclusive,
; if the pixel lies inside the clipping rectangle.
; The first bit-plane starting at 0C0000h will have its
; bit represented by the lsb of the returned word. The
; last bit-plane starting at 0D0000h will have its bit
; represented by bit number 2 (lsb = bit 0) of the returned
; word.
;
; If the pixel lies outside the clipping rectangle, return -1.
;
GETP proc near
push BP
push DI
push ES
;
mov AX,[BP].arg1 ; Get `x'
mov BX,[BP].arg2 ; Get `y'
; call Fix_XY ; Force x and y into their proper ranges
call Encode_XY ; Encode point's visibility in the CR
cmp CL,0 ; is point visible in the CR?
mov AX,-1
jne IBM_Ret_Clr ; no, jump (return -1 in AX)
mov AX,[BP].arg1 ; restore AX to 'x'
cmp PC_MAKE,TIPC
je ti_getp
;
mov dx,bx ; Do it the IBM way (ugh!)
mov cx,ax
mov ah,13
int IBM_CRT ; IBM Video BIOS
xor ah,ah ; Color is in AL
mov dx,ax
jmp short IBM_Ret_Clr
ti_getp label near
call GM_Offset ; Convert (x,y) to linear offset
;
; Read the specified bit in each of the graphics memory banks.
;
xor DX,DX ; Clear value to be returned
mov ES,Bank_C ; Get segment of 3rd bank
mov BH,ES:[DI] ; Copy the selected byte in graphics memory
and BH,AH ; Was the bit on ?
jz short Test_Bank_B
inc DX
;
Test_Bank_B label near
shl DX,1
mov ES,Bank_B ; Get segment of 2nd bank
mov BH,ES:[DI] ; Copy the selected byte in graphics memory
and BH,AH ; Was the bit on ?
jz short Test_Bank_A
inc DX
;
Test_Bank_A label near
shl DX,1
mov ES,Bank_A ; Get segment of 1st bank
mov BH,ES:[DI] ; Copy the selected byte in graphics memory
and BH,AH ; Was the bit on ?
jz short Return_Color
inc DX
;
Return_Color label near
mov AX,DX ; Put returning value into ax
IBM_Ret_Clr label near
pop ES
pop DI
pop BP
ret
GETP endp ; End of GETP(,)
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
; Encode_XY in: AX=X, BX=Y
; out: CL=code
; destroyed: CL
;
; Encode X,Y into a 4-bit code indicating its visibility in the clipping rectangle.
; The code is returned in CL: CL =0: point is visible
; CL<>0: point is invisible.
;-----------------------------------------------------------------------------
Encode_XY proc near
mov CL,0 ; clear CL; code is constructed here
cmp AX,clip_left ; x >= clip_left?
jge Enc_1 ; yes, jump
or CL,left_mask ; no, set bit
Enc_1: cmp BX,clip_top ; y >= clip_top?
jge Enc_2 ; yes, jump
or CL,top_mask ; no, set bit
Enc_2: cmp AX,clip_right ; x <= clip_right?
jle Enc_3 ; yes, jump
or CL,right_mask ; no, set bit
Enc_3: cmp BX,clip_bottom ; y <= clip_bottom?
jle Enc_4 ; yes, jump
or CL,bottom_mask ; no, set bit
Enc_4: ret
Encode_XY endp
page
;-----------------------------------------------------------------------------
; Clip_line in: none
; out: none (Z flag)
; destroyed: AX,BX,CX,DX,SI,DI
;
; The line between (Curr_X, Curr_Y) and (Stop_X, Stop_Y) is clipped.
; The two points' coordinates are possibly modified during the process.
; On exit: Z=0 if line is visible (onscreen); the final coordinates
; are in the Curr and Stop memory locations
; Z=1 if line is invisible (offscreen)
;-----------------------------------------------------------------------------
Clip_line proc
mov DI,offset Stop_X
overlap Cli_exit,Cli_exit ; if line's extents rectangle lies wholly
; inside or wholly outside clipping rectangle,
; exit immediately
jmp short Cli_loop ; else start clipping
; At this point AX=new X and BX=new Y.
; (Note this is executed *after* the loop. It's rearranged to
; get all the relative branches within range.)
Cli_join:
mov [DI],AX ; store X back into memory
mov [DI+2],BX ; ditto for Y
pop CX ; restore codes
call Encode_XY ; get code for new X and Y
cmp CX,0 ; is combined code zero?
jz Cli_exit ; yes, jump; line totally visible at last
test CH,CL ; do any encoded bits line up?
jz Cli_loop ; no, jump; some part of line is visible.
; if fall thru, line was invisible after all
Cli_exit: ret
; We have to clip the line.
Cli_loop: cmp CL,0 ; is this point visible?
jnz Cli_1 ; no, jump
xchg CH,CL ; yes, go work on other point
sub DI,4 ; set pointer to other point
Cli_1: push CX ; tempsave the codes
test CL,left_mask ; is point off left side?
jz Cli_2 ; no, jump
; The endpoint is to the left of the clipping rectangle.
intersect clip_left,Stop_Y,Stop_X,Curr_X,Curr_Y
mov BX,AX ; new Y
mov AX,clip_left ; new X
jmp Cli_join
Cli_2: test CL,top_mask ; is point off top side?
jz Cli_3 ; no, jump
; The endpoint is above the top of the clipping rectangle.
intersect clip_top,Stop_X,Stop_Y,Curr_Y,Curr_X
; AX contains new X already
mov BX,clip_top ; new Y
jmp Cli_join
Cli_3: test CL,right_mask ; is point off right side?
jz Cli_4 ; no, jump
; The endpoint is to the right of the clipping rectangle.
intersect clip_right,Stop_Y,Stop_X,Curr_X,Curr_Y
mov BX,AX ; new Y
mov AX,clip_right ; new X
jmp Cli_join
Cli_4: ; no need for more tests
; The endpoint is below the bottom of the clipping rectangle.
intersect clip_bottom,Stop_X,Stop_Y,Curr_Y,Curr_X
; AX contains new X already
mov BX,clip_bottom ; new Y
jmp Cli_join
Clip_line endp
page
;-----------------------------------------------------------------------------
; Clip_box in: none
; out: none
; destroyed: AX
;
; The box with corners (Curr_X, Curr_Y) and (Stop_X, Stop_Y) is clipped.
; (The corners should be (left,top) and (right,bottom) respectively.)
; The two points' coordinates are possibly modified during the process.
;-----------------------------------------------------------------------------
Clip_box proc
mov AX,clip_left
cmp Curr_X,AX
jge CB_1
mov Curr_X,AX
CB_1: mov AX,clip_top
cmp Curr_Y,AX
jge CB_2
mov Curr_Y,AX
CB_2: mov AX,clip_right
cmp Stop_X,AX
jle CB_3
mov Stop_X,AX
CB_3: mov AX,clip_bottom
cmp Stop_Y,AX
jle CB_4
mov Stop_Y,AX
CB_4: ret
Clip_box endp
page
;-----------------------------------------------------------------------------
comment ~
; NOTE: This routine is no longer called. Clipping is done instead. - rb
Fix_XY proc near ; Force x and y into their proper values
cmp PC_MAKE,TIPC
jne ibm_dsnt ; IBM doesn't do range checking, Y should I?
; On IBM, the ranges will vary with the mode
; On entry ax = `x', bx = `y'
; On exit ax = ax MOD 720, bx = bx MOD 300
; cx & dx = <changed>
; Get `x';fix to proper range (already in ax)
xor DX,DX ; Clear DX - unsigned dbl-word
div X_Resolution ; ax = INT(x / 720), dx = (x MOD 720)
mov CX,DX ; I want the MOD function....
;
mov AX,BX ; Get `y' and fix to proper range
xor DX,DX ; Clear DX - unsigned dbl-word
div Y_Resolution ; ax = INT(y / 300), dx = (y MOD 300)
; I want the MOD function....
mov BX,DX
mov AX,CX ; Put `x' back
ibm_dsnt: ret
Fix_XY endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
~ ;end comment
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
GM_Offset proc near
;
; Determine which word needs modifying and which bit to set.
; byte_offset = (Curr_Y * 736-bits/y_pixel * 1-byte/8-bits)
; + INT(Curr_X * 1-byte/8-x_pixels)
; bit-in-byte = Curr_X MOD 8 [0-msb, 8-lsb in byte]
;
; On entry ax = `x', bx = `y'
; On exit
; ah = bit-in-byte, bx = <changed>
; cx = <unchanged>, dx = <changed>
; di = byte-addr into graphics memory
xchg AX,BX ; now ax = `y' & bx = `x'
; neg AX ; Translate y=0 to bottom of screen
; add AX,Y_MAX-1 ; y_new = 299 - (y_old MOD 300)
; mul Bytes_per_Line ; Curr_Y * 736/8-bytes/y_pixel
shl AX,1 ; 2-clocks
shl AX,1 ; 2-clocks
mov DX,AX ; 2-clocks
shl AX,1 ; 2-clocks
add AX,DX ; 3-clocks
neg DX ; 3-clocks
shl AX,1 ; 2-clocks
shl AX,1 ; 2-clocks
shl AX,1 ; 2-clocks
add AX,DX ; 3-clocks
; TOTAL = 23-clocks
; MUL = (128-143)+EA
xchg AX,BX ; ........save partial sum
; and get `x' into accumulator
; xor DX,DX ; Clear DX - unsigned dbl-word
; div Bits_per_Byte ; ax = word offset from beginning of line
; dx = bit-in-byte (x MOD 8)
mov DX,7 ; mask all bits 'cept lower 3
; 4-clocks
and DX,AX ; 3-clocks
shr AX,1 ; 2-clocks
shr AX,1 ; 2-clocks
shr AX,1 ; 2-clocks
; TOTAL = 13-clocks
; DIV = (154-172)+EA
add AX,BX ; Ax = byte # offset into graphics bank
xor AL,1 ; fix byte offset address to jive with
; Intel's screwy byte ordering!!!
mov DI,AX ; move for addressing graphics memory
mov BX,DX ; Saves on number of memory accesses
mov AH,Bit_Table[bx] ; Ax = bit-pattern
mov AL,AH
not AL ; al = NOT ah - for turning bits off
ret
GM_Offset endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
public LCL_SETP
LCL_SETP proc near
cmp PC_MAKE,TIPC
je ti_setp
cmp VID_MODE,14
jl ibm_setp
cmp f_code,1
jne ibm_setp
or CL,080h ; set xor flag on
ibm_setp: mov DX,BX ; Move arguments around for IBM
xchg CX,AX
xor BH,BH ; video plane
mov AH,12 ; write dot
int IBM_CRT
ret
ti_setp label near
call GM_Offset ; Convert (x,y) to byte offset
;
; Determine which graphics memory banks get their bits twiddled.
;
Set_Byte: mov ES,Bank_A ; Get segment of 1st bank
call set_pixel
;
mov ES,Bank_B
call set_pixel ; Turn on the proper bit
;
mov ES,Bank_C
call set_pixel ; Turn on the proper bit
;
Quit_n_Quit label near ; Save the current X & Y and return
ret
LCL_SETP endp
set_pixel proc near
shr CL,1 ; Do we turn on/off bit in this bank?
jnc short this_bank ; If bit was on (one) then
cmp f_code,1 ; is the bit xored?
jne set_01
mov BL,ES:[DI] ; get current value
xor BL,AH ; xor with mask
mov ES:[DI],BL ; replace value
ret
set_01: or ES:[DI],AH
ret
this_bank label near
cmp f_code,1 ; xored?
je set_02
and ES:[DI],AL ; Turn off the proper bit
set_02: ret
set_pixel endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name BOX -- Draw a box in the graphics plane with the
; specified color.
;
; synopsis (box x-ul y-ul x-lr y-lr color)
;
; description Draw a box with graphics (not text characters). The
; upper left-hand corner is specified by (x-ul,y-ul)
; and the lower right-hand is specified by (x-lr,y-lr).
; Color indicates the pixel values that will make up the
; box. The interior will not be filled nor modified
; in any way. The box is clipped.
; Edges that are clipped are "shrunk inwards" to fit
; snug against the corresponding edges of the clipping
; rectangle. The result is another box and not just
; some line segments as you'd might expect.
;
; returns nothing
;
BOX proc near
mov Fill_Fig,FALSE ; This box ain't getting filled
BOX_2ND label near ; A secondary entry point for FILLED_BOX
push SI
mov AX,[BP].arg1 ; Get x upper-left
mov BX,[BP].arg2 ; Get y upper-left
; call Fix_XY ; Force x-ul and y-ul into correct ranges
mov Curr_X,AX
mov Curr_Y,BX
mov AX,[BP].arg3 ; Get x lower-right
mov BX,[BP].arg4 ; Get y lower-right
; call Fix_XY ; Force x-lr and y-lr into correct ranges
;
cmp AX,Curr_X
jg check_y ; Swap if x-lr < x-ul
xchg AX,Curr_X
check_y: cmp BX,Curr_Y
jg goodargs ; Swap if y-lr < y-ul (origin at top-left)
xchg BX,Curr_Y
;
goodargs: mov Stop_X,AX ; (var. Stop used during clipping only)
mov Stop_Y,BX
overlap box_1,box_done_1 ; if box totally inside CR, no need to clip
; if box totally outside, skip it
call Clip_box ; else clip box to the clipping rectangle
box_1: mov AX,Stop_X
mov BX,Stop_Y
;
sub BX,Curr_Y
inc BX ; BX = the height of the box (min=1-pixel)
mov Box_Hite,BX
mov BX,[BP].arg6 ; get function code
mov f_code,BL
mov BX,[BP].arg5 ; get the color
mov pix_c,BX
;
cmp PC_MAKE,TIPC ; All the "common" material taken care of
je BOX_TI
jmp BOX_IBM
;
box_done_1: jmp Box_done ; rel. branch not long enough
;
BOX_TI: mov BX,Curr_Y ; find upper right-hand corner address
mov y_val,BX
call GM_Offset
push DI ; save offset into graphics mem
push BX ; save bit-number
;
mov AX,Curr_X ; find upper left-hand corner address
mov BX,Curr_Y
call GM_Offset
mov Left_Offset,DI ; Offset into graphics plane of upper-left
xor DI,1 ; This craziness is due to *^&$%! Intel
;
mov AH,Start_Line[BX] ; Get left-end bit pattern
mov AL,AH
not AL ; Need (0ffh - AH) for Set_Byte()
mov DH,Bit_Table[BX] ; Get left-siding bit pattern
mov DL,DH
not DL ; Need (0ffh - DH) for Set_Byte()
mov Left_End,AX
mov Left_Side,DX
;
pop BX
mov AH,End_Line[BX] ; Get right-end bit pattern
mov AL,AH
not AL ; Need (0ffh - AH) for Set_Byte()
mov DH,Bit_Table[BX] ; Get right-siding bit pattern
mov DL,DH
not DL ; Need (0ffh - DH) for Set_Byte()
mov Right_End,AX
mov Right_Side,DX
;
pop CX
xor CL,1 ; This craziness due to #$%&! Intel
sub CX,DI
inc CL
mov Box_Width,CX ; CX = Number of bytes in box's width
cmp CL,1 ; are bits in the same byte? (narrow box)
jg wide_box ; jump if not
;
; We need to combine the "ends" and "sides"
; for a byte-wide box.
and AH,byte ptr Left_End+1 ; combine left-end and right-end
mov AL,AH
not AL
or DH,byte ptr Left_Side+1 ; combine left-side and right-side
mov DL,DH
not DL
mov Left_End,AX
mov Left_Side,DX
;
wide_box label near
mov DL,CL ; CL = width in bytes
mov DH,byte ptr [BP].arg5 ; get color of box
xor DI,1 ; This squirreliness is due to $%^&*! Intel
call Solid_Line ; Draw top of BOX
dec Box_Hite
Box_Loop: jz Box_Done
;
add Left_Offset,Bytes_per_Line ; goto next scan line
mov DI,Left_Offset
mov DL,byte ptr Box_Width ; just get the lower byte
cmp Box_Hite,1
je Bottom_Line
;
cmp Fill_Fig,TRUE ; Do we draw a filled or hollow box?
jne Do_Hollow
;
call Solid_Line ; Draw a solid horizontal line
jmp short BLoop_End
;
Do_Hollow: call Just_Ends ; Draw just the side points
BLoop_End: dec Box_Hite
jmp short Box_Loop
;
;
Bottom_Line: mov AX,stop_y
mov y_val,AX
call Solid_Line ; Draw the bottom of the box (if >1 high)
Box_Done: xor AX,AX ; Return a value of zero
pop SI
ret
;
;
Solid_Line label near
cmp f_code,1
jne S_Line_1
push DX
call ti_xxset
pop DX
ret
S_Line_1: mov AX,Left_End ; Get the bit pattern for left-most byte
mov CL,DH ; Get the color
call Set_Byte
xor DI,1 ; This craziness is due to %$&*@! INTEL!
dec DL
jz SLine_Done
S_Loop: cmp DL,1
je Last_Byte ; Jump if we need the right side
;
mov AX,0FF00h ; Get the solid (FFh) pattern
mov CL,DH
inc DI ; Point to next byte in graphics memory
xor DI,1 ; This craziness is due to %$&*@! INTEL!
call Set_byte
xor DI,1 ; This craziness is due to %$&*@! INTEL!
dec DL
jmp S_Loop
;
Last_Byte: mov AX,Right_End ; Get the bit pattern for right-most byte
inc DI
mov CL,DH ; Get color
xor DI,1 ; This craziness is due to %$&*@! INTEL!
call Set_Byte
SLine_Done: ret
;
Just_Ends label near
mov AX,Left_Side
mov CL,DH
call Set_Byte
xor DI,1 ; This craziness is due to %$&*@! INTEL!
dec DL
jz Hollow_End
add DI,Box_Width
dec DI ; Went one too far with addition
mov AX,Right_Side
mov CL,DH
xor DI,1 ; This craziness is due to %$&*@! INTEL!
call Set_Byte
Hollow_End: ret
;
;
; IBM (ugh!) version of draw box (sorry, but to maintain compatability
; among all the IBM video modes I've used the write-dot function (slow).
;
; modified - 10/10/86 for EGA
;
BOX_IBM label near
sub AX,Curr_X
inc AX ; Box_Width (number of pixels to draw line)
mov Box_Width,AX
call IBM_Solid ; Draw the top line of box
inc Curr_Y
dec Box_Hite
jz Box_Done
IBM_while: cmp Box_Hite,1
je IBM_botm ; Go draw bottom line
cmp Fill_Fig,TRUE ; Is box to be filled or not?
jne IBM_nofill
call IBM_Solid
jmp short IBM_fi
;
IBM_nofill: call IBM_epts ; Draw the side points for current scan line
IBM_fi: inc Curr_Y ; end of "if"
dec Box_Hite
jmp IBM_while
IBM_botm: call IBM_Solid ; Draw bottom line (needs to be solid)
jmp Box_Done
;
IBM_Solid label near ; Draw a solid horizontal line
mov DI,Box_Width ; sounds more like a room freshener :-)
mov DX,Curr_Y
mov CX,Curr_X
cmp vid_mode,14
jge ega_box
mov BL,byte ptr [BP].arg5 ; Get the color
I_Sloop: mov AH,0Ch ; write-dot function
mov AL,BL ; copy the color
int IBM_CRT ; WRITE-DOT(x,y,color)
inc CX
dec DI
jnz I_Sloop
ret
;
IBM_epts label near ; Draw the end points of a horizontal line
mov DX,Curr_Y
mov CX,Curr_X
mov BL,byte ptr [BP].arg5 ; Get the color
call epts
cmp Box_Width,1 ; Do we need to do the other end?
je I_eend
add CX,Box_Width
dec CX ; We added 1 too many
call epts
I_eend: ret
epts proc near
mov AH,0Ch ; write-dot function
mov AL,BL
cmp f_code,1
jne epts_01
or AL,080h ; set xor bit
epts_01: int IBM_CRT ; Write Left dot
ret
epts endp
;********************************************************************
;* *
;* EGA_BOX will draw a solid line on the EGA screen. This method *
;* is used in preference to write dot since write dot is so slow.*
;* *
;* DX = start row *
;* CX = start col *
;* DI = length *
;* *
;********************************************************************
ega_box: mov AX,CX ; put start col into AX
add AX,DI ; AX is not the ending column
dec AX ; added one too many
call xxset
ret
BOX endp
public xxset
XXSET PROC NEAR
PUSH ES
PUSH DX
PUSH DX
PUSH AX
MOV FUNC,0 ; DEFAULT TO DATA UNMODIFIED
CMP F_CODE,0 ; IS THIS An xor'ed box?
JE AND_TYPE
MOV FUNC,18H ; SET TO XOR
AND_TYPE:
MOV AX,CX ; PUT THE START COLUMN IN
MOV BX,DX ; PUT THE ROW IN
CALL GET_OFFSET ; CALCULATE START ADDR, OFFSET
CMP BX,8 ; ON A WORD BOUNDARY?
JL BYTE_01 ; YES, THEN CONTINBUE
INC AX ; BUMP THE WORD OFFSET
SUB BX,8 ; ADJUST FOR NEW BYTE ADDRESS
BYTE_01:
MOV ST_WORD,AX ; SAVE START ADDRESS AND
MOV ST_BIT,BX ; BIT OFFSET
POP AX ; RESET THE END COLUMN
POP BX ; POP DX INTO BX - ROW
CALL GET_OFFSET ; CALCULATE END ADDR, OFFSET
CMP BX,8 ; ON A WORD BOUNDARY?
JL BYTE_02 ; YES, THEN CONTINBUE
INC AX ; BUMP THE WORD OFFSET
SUB BX,8 ; ADJUST FOR NEW BYTE ADDRESS
BYTE_02:
MOV ED_WORD,AX ; SAVE START ADDRESS AND
MOV ED_BIT,BX ; BIT OFFSET
; Now to set up the addresses and masks and write to the planes
MOV DI,ST_WORD ; SET THE STARTING OFFSET
XOR_LOOP:
MOV AL,-1
CMP DI,ST_WORD ; STARTING OFFSET?
JNE END_OFF ; IF NOT, THEN CHECK FOR ENDING OFFSET
MOV CX,ST_BIT ; SUBTRACT THE STARTING BIT OFFSET
SHR AL,CL ; SET UP THE CORRECT MASK FOR START
END_OFF: ; End of offset processing
CMP DI,ED_WORD ; IS THIS THE LAST BYTE TO PROCESS?
JNE DO_XOR ; NO, THEN XOR THE DATA AND UPDATE
MOV AH,-1 ; INITIALIZE THE MASK
MOV CX,7
SUB CX,ED_BIT ; SUBTRACT THE # OF ENDING OFFSET
SHL AH,CL ; WANT TO SAVE ALL BUT BITS PAST END
AND AL,AH ; AND OFF ALL USELESS BITS
DO_XOR:
; Latch up the current mask
PUSH AX
MOV DX,3CEH ; LATCH PORT
MOV AL,8 ; BIT MASK = on
OUT DX,AL
INC DX
POP AX ; RESTORE THE CURRENT MASK
OUT DX,AL
CMP FUNC,18H
JNE WRT_ZEROS ; IF XOR, THE ONLY DO 1'S
; Set to XOR function
DEC DX
MOV AL,3 ; DATA ROTATE REGISTER
OUT DX,AL ; WRITE IT
MOV AL,FUNC ; SET THE XOR OPERATOR
INC DX ; to or everything on to the planes
OUT DX,AL
JMP WRT_ONES
WRT_ZEROS:
; Write the one to the planes that are set
MOV DX,3C4H ; SEQUENCER ADDRESS
MOV AL,2 ;
OUT DX,AL
MOV AX,PIX_C ; SET THE COLOR INTO THE AL
XOR AL,0FH ; SET THE ZERO PLANES TO ON
INC DX
OUT DX,AL ; ENABLE THIS PLANE
MOV ES,gra_ram ; GRAPHICS RAM ADDRESS
MOV AL,ES:[DI] ; LATCH UP THE EXISTING DATA
XOR AL,AL ; WRITE ZEROES
MOV ES:[DI],AL ; OR WORD IN GRAPHICS PLANE.
; Now write to the planes that are ONESes
WRT_ONES:
MOV DX,3C4H ; SEQUENCER ADDRESS
MOV AL,2 ;
OUT DX,AL
MOV AX,PIX_C ; SET THE COLOR INTO THE AL
INC DX
OUT DX,AL ; ENABLE THIS PLANE
MOV ES,GRA_RAM ; GRAPHICS RAM ADDRESS
MOV AL,ES:[DI] ; LATCH UP THE EXISTING DATA
MOV AL,0FFH ; WRITE ONES
MOV ES:[DI],AL ; OR WORD IN GRAPHICS PLANE.
; Now ready to update the pointers and continue
NEXT_BYTE:
CMP DI,ED_WORD ; PROCESSED LAST ONE?
JE XOR_EXIT
INC DI ; NEXT WORD IN THE GRAPHICS PLANES
JMP XOR_LOOP ; DO NEXT BYTE
XOR_EXIT:
MOV DX,3C4H ; SEQUENCER ADDRESS
MOV AL,2 ;
OUT DX,AL
MOV AL,0FFH ; ENABLE ALL BAMNK
INC DX
OUT DX,AL ; ENABLE THIS PLANE
MOV DX,3CEH ; SEQUENCER ADDRESS
MOV AL,3 ;
OUT DX,AL
MOV AL,0 ; NORMAL WRITES
INC DX
OUT DX,AL ; ENABLE THIS PLANE
DEC DX
MOV AL,8 ;
OUT DX,AL
MOV AL,0FFH ; ALL BITS
INC DX
OUT DX,AL ; ENABLE THIS PLANE
POP DX
POP ES
RET
;
XXSET ENDP
get_offset proc near
; AX has the pixel column number
; BX has the pixel row number
div b_p_wrds ; divide by bits per word
push AX ; save the bit offset
mov AX,BX ; get the pixel row
mul w_p_row ; row * 46 words per row
pop BX ; get words and bit within row
push BX ; save it again
xor BH,BH ; get rid of bit
add AX,BX ; bump to absolute offset
mul two ; byte offset!
pop BX
mov BL,BH ; shift bit count to bl
xor BH,BH
ret
; return - ax=word offset ; bx=bit offset
get_offset endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;***************************************************************************
; XXSET - PUT A LINE ON THE SCREEN AT THE START, END LOC AND OF LENGTH L
; AX=START COL, BX=START ROW , CX=END COL
; COLOR = COLOR
;***************************************************************************
public ti_xxset
ti_xxset proc near
push ES
;
mov AX,curr_x
mov BX,y_val
mov CX,stop_x
;
push BX ; save the start row
call get_offset ; convert row/col to word/bit offset
mov st_word,AX ; save the start row offset
mov st_bit,BX ; save the start bit offset
pop BX ; restore the start row
mov AX,CX ; get the ending col
call get_offset ; convert to word/bit offset
mov ed_word,AX ; save the ending word offset
mov ed_bit,BX ; save the ending bit offset
; Determine the starting word mask
mov BX,st_word ; get the starting word offset
ti_xloop:
mov DX,-1
cmp BX,st_word
jne ti_endoff
mov CX,st_bit ; starting bit offset
shr DX,CL ; shift off one bits until mask gotten
ti_endoff:
cmp BX,ed_word ; last byte to process?
jne ti_xor ; no. then xor and update
push DX ; save mask
mov DX,-1 ; initialize mask
mov CX,0fh
sub CX,ed_bit ;subtract the # of ending offset
shl DX,CL ; want to save allbut bits past end
pop AX ; and off all useless bits
and DX,AX
ti_xor: mov CX,pix_c ; get the color
call ti_xor_word
cmp BX,ed_word
je ti_exit
add BX,2 ; bump the offset to next word
jmp ti_xloop ; do next word
ti_exit:
pop ES
inc y_val
ret
;
ti_xxset endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;*****************************************************************************
; XOR_WORD - XOR THE MASK IN THE DX INTO THE 3 GRAPHICS PLANES AT OFFSET
; XOR THE DATA INTO THE THREE GRAPHICS PLANES
; BX = WORD OFFSET , DX=MASK , CX=COLOR
;****************************************************************************
ti_xor_word proc near
test CX,01h ; xor this plane only if bit set
jz xor_b ; no, then go to b plane
mov ES,bank_a ; get the seg addr of the a plane
call doit
;
xor_b:
test CX,02h ; xor this plane only if bit set
jz xor_c ; no, then go to c plane
mov ES,bank_b ; get the seg addr of the b plane
call doit
xor_c:
test CX,04h ; xor this plane only if bit set
jz xor_end ; no, then go bump the offset
mov ES,bank_c ; get the seg addr of the c plane
call doit
xor_end:
ret
ti_xor_word endp
doit proc near
mov AX,ES:[BX] ; get the word from a plane
xor AX,DX ; xor the word
mov ES:[BX],AX ; put it back
ret
doit endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name FILLED_BX -- Draw a solid box in the graphics plane with the
; specified color.
;
; synopsis (filled_box x-ul y-ul x-lr y-lr color)
;
; description Draw a filled box with graphics (not text characters).
; The upper left-hand corner is specified by (x-ul,y-ul)
; and the lower right-hand is specified by (x-lr,y-lr).
; Color indicates the pixel values that will make up the
; box. The interior will be filled with the same color
; as the box. The box is clipped.
;
; returns nothing
;
FILLD_BX proc near
mov Fill_Fig,TRUE
call BOX_2ND ; Call BOX at a second entry point
ret
FILLD_BX endp
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
page
;-----------------------------------------------------------------------------
; name SET_CLIP_RECT - Set the clipping rectangle.
;
; synopsis (set-clipping-rectangle! left top right bottom)
;
; description This routine sets the clipping rectangle for the screen.
; The coordinate values can be any signed integer. The
; intersection of the clipping rectangle and the screen is
; used as the final clipping rectangle. If this would be nil,
; the clipping rectangle is set to the full screen; we never
; let it become invisible.
;
; returns nothing
;
; in: no registers
; out: no registers
; destroyed: AX,BX,CX,DX
;-----------------------------------------------------------------------------
SET_CLIP_RECT proc near
cmp PC_MAKE,TIPC
je SCR_TI
call Reset_CR_IBM ; set CR to screen's full size
jmp short SCR_join
SCR_TI: call Reset_CR_TI ; set CR to screen's full size
SCR_join: mov AX,[BP].arg1
mov BX,[BP].arg2
mov CX,[BP].arg3
mov DX,[BP].arg4
; rearrange coordinates so first point is upper left hand corner
cmp CX,AX ; swap if x-lr < x-ul
jg SCR_1
xchg CX,AX
SCR_1: cmp DX,BX ; swap if y-lr < y-ul (origin at top left)
jg SCR_2
xchg DX,BX
; now we can continue
SCR_2: mov Curr_X,AX ; store for the overlap check
mov Curr_Y,BX
mov Stop_X,CX
mov Stop_Y,DX
overlap SCR_3,SCR_4 ; check how screen and CR overlap
call Clip_box ; they overlap, clip
SCR_3: mov AX,Curr_X ; move new coords to be final CR
mov clip_left,AX
mov BX,Curr_Y
mov clip_top,BX
mov AX,Stop_X
mov clip_right,AX
mov BX,Stop_Y
mov clip_bottom,BX
SCR_4: ret
SET_CLIP_RECT endp
page
;-----------------------------------------------------------------------------
; Reset the clipping rectangle to the full size of the screen for IBM modes.
; Destroys AX and BX.
;-----------------------------------------------------------------------------
Reset_CR_IBM proc near
mov AH,15 ; get the current video mode
int IBM_CRT
cmp al,16 ; cmp with max video mode (EGA 16)
jbe RCI_1
mov al,16 ; map out-of-range values to EGA 16
RCI_1: cbw
shl AX,1 ; multiply by 4
shl AX,1
mov BX,AX
mov clip_left,0 ; set the clipping rectangle accordingly
mov clip_top,0
mov AX,Res_Table_IBM[BX]
mov clip_right,AX
mov AX,Res_Table_IBM+2[BX]
mov clip_bottom,AX
ret
Reset_CR_IBM endp
;-----------------------------------------------------------------------------
; Reset the clipping rectangle to the full size of the screen for TIPC.
; No registers are affected.
;-----------------------------------------------------------------------------
Reset_CR_TI proc near
mov clip_left,0
mov clip_top,0
mov clip_right,X_max-1
mov clip_bottom,Y_max-1
ret
Reset_CR_TI endp
page
;-----------------------------------------------------------------------------
;-----------------------------------------------------------------------------
;
; name XPCINIT - Any special initialization required for a
; particular type PC (e.g. IBM)
;
; synopsis call far xpcinit (from PGROUP)
;
; description A C callable routine (well, almost) that should be used
; internally to PCS for any special initialization that may
; be needed for a particular PC.
;
; returns nothing ('cept personal satisfaction)
;
public XPCINIT
XPCINIT proc far
cmp PC_MAKE,TIPC
jne not_ti
IFDEF PROMEM ;;; Protected Mode
lea DI,Bank_A ; Segment Address of Bank A
mov SI,4
cld
INISEG: mov BX,[DI] ; Get real mode segment address
xor CX,CX
mov DX,0FFFFh ; Length of segment
mov AH,0C0H ; Create Real Data Window
int DOS_FUN ; (extended Dos function for protected mode)
stosw ; Save Segment Selector to memory address
dec SI
jnz iniseg
ENDIF
mov w_p_row,46
mov AX,offset XGROUP:endinit ; THIS IS REALLY UGLY!!!
push AX ; push return address (return from all_on)
push BP
push ES
push VID_MODE
jmp all_on ; Turn on TEXT, init & clear graphics
;
not_ti:
COMMENT %
IFDEF PROMEM ;;; Protected Mode
mov BX,GRA_RAM ; Segment Address of EGA GRAPHICS RAM
xor CX,CX
mov DX,0FFFFh ; Length of segment
mov AL,0C0H ; Create Real Data Window
int DOS_FUN ; Extended Dos function for protected mode
mov GRA_RAM,AX ; Save Segment Selector
ENDIF
%
cmp PC_MAKE,0FCh
jl not_ibm
mov AX,0500h ; Set active display page (for alpha modes)
int IBM_CRT ; should I check for graphics mode??? Nah!
mov AH,15 ; get current video mode
int IBM_CRT
xor AH,AH ; clear AH
mov VID_MODE,AX ; save videomode
mov w_p_row,40
cmp AX,16
jne short endinit
mov char_hgt,14
jmp short endinit
;
not_ibm label near ; Could there be a Zenith Z-100 out there?
; Not for now.
endinit: ret
XPCINIT endp
PROGX ends
end