pcs/graphcmd.asm

1992 lines
64 KiB
NASM
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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