.title plotto VT220 bitmap graphics ; ; PLOTTO.MAR implements TRS-80 style graphics for VT220 terminals. ; ; A downloadable character set is sent to the terminal containing the ; 64 characters required to produce a full set of 3x2 pixel combinations. ; The characters have ascii codes starting (in SIXEL tradition) from 63. ; To calculate the ASCII code to use, the add the pixel values in the ; following diagram together, then add 63: ; ; +----+----+ ; | 1 | 8 | ; +----+----+ ; | 2 | 16 | ; +----+----+ ; | 4 | 32 | ; +----+----+ ; ; This gives a graphic resolution of 160x72 in 80 column mode, and 264x72 in ; 132 column mode. ; ; PLOTTO implements three functions to manage these characters: ; ; PLOT_INIT: Downloads character set to terminal if necessary, initialises ; plotting routines. ; Usage: sts = PLOT_INIT ; sts: Condition code, long by value ; ; PLOT: Sets or resets a pixel. ; Usage: sts = PLOT( x, y [,colour]) ; sts: Condition code, long by value ; x: X coordinate of pixel to set, long by ref ; y: Y coordinate of pixel to set, long by ref ; colour: even to clear pixel, odd to set, long by ref ; ; UNPLOT: Resets a pixel. ; Usage: sts = UNPLOT( x, y) ; sts: Condition code, long by value ; x: X coordinate of pixel to clear, long by ref ; y: Y coordinate of pixel to clear, long by ref ; ; POINT: Returns pixel status. ; Usage: sts = POINT( x, y) ; sts: Pixel status, -1 if set else 0, long by value ; x: X coordinate of pixel to test, long by ref ; y: Y coordinate of pixel to test, long by ref ; ; DRAW: Draws a line. ; Usage: sts = DRAW( x, y, xdash, ydash) ; sts: Condition code, long by value ; x: X coordinate of start point, long by ref ; y: Y coordinate of start point, long by ref ; xdash: X coordinate of end point, long by ref ; ydash: Y coordinate of end point, long by ref ; ; UNDRAW: Erases a line. ; Usage: sts = UNDRAW( x, y, xdash, ydash) ; sts: Condition code, long by value ; x: X coordinate of start point, long by ref ; y: Y coordinate of start point, long by ref ; xdash: X coordinate of end point, long by ref ; ydash: Y coordinate of end point, long by ref ; ; PLOT_BATCH_START: Begins batch update of plot area. No further updates are ; made to the screen. ; Usage: sts = PLOT_BATCH_START() ; sts: Always SS$_NORMAL, long by value ; ; PLOT_BATCH_END: Completes batch update of plot area. All changes to are ; displayed on the screen. ; Usage: sts = PLOT_BATCH_END() ; sts: Condition code, long by value ; ; PLACE_CURSOR: Moves the text cursor to the location specified in plotting ; coordinates. Does not actually print text or graphics. ; Usage: sts = PLACE_CURSOR( x, y) ; sts: Condition code, long by value ; x: X coordinate, long by ref ; y: Y coordinate, long by ref ; ; Pixels are addressed from the top left hand corner of the screen, starting ; from 0. ; ; Note that at the present point in time, 132 column mode is not supported on ; the VT320 terminal. The logical name "PLOTTO_DOWNLOADED" indicates whether ; the graphics characters have been downloaded. To force the next invocation ; of PLOT_INIT to download these characters, simply deassign this logical name. ; ; VT100 terminals are partially supported, using inverse character cells to ; represent character cells with any bits set. ; .macro status, code, ?skip blbs code, skip movzwl code, R0 ret skip: .endm .psect plotto_data, long,noexe,wrt,noshr esc = 27 dcs = 144 st = 156 si = 15 so = 14 sixbits_220: .ascii "1;31;1{ @;FFFFF;wwwww/@@@@@;~~~~~/@@@@@;" - "/MMMMM;FFFFF/MMMMM;wwwww/NNNNN;~~~~~/NNNNN;" - "?????FFF;FFFFFFFF;wwwwwFFF/@@@@@;~~~~~FFF/@@@@@;" - "?????FFF/MMMMM;FFFFFFFF/MMMMM;wwwwwFFF/NNNNN;" - "~~~~~FFF/NNNNN;?????www/?????@@@;FFFFFwww/?????@@@;" - "wwwwwwww/@@@@@@@@;~~~~~www/@@@@@@@@;" - "?????www/MMMMM@@@;FFFFFwww/MMMMM@@@;" - "wwwwwwww/NNNNN@@@;~~~~~www/NNNNN@@@;" - "?????~~~/?????@@@;FFFFF~~~/?????@@@;" - "wwwww~~~/@@@@@@@@;~~~~~~~~/@@@@@@@@;" - "?????~~~/MMMMM@@@;FFFFF~~~/MMMMM@@@;" - "wwwww~~~/NNNNN@@@;~~~~~~~~/NNNNN@@@;" - "/?????MMM;FFFFF/?????MMM;wwwww/@@@@@MMM;" - "~~~~~/@@@@@MMM;/MMMMMMMM;FFFFF/MMMMMMMM;" - "wwwww/NNNNNMMM;~~~~~/NNNNNMMM;?????FFF/?????MMM;" - "FFFFFFFF/?????MMM;wwwwwFFF/@@@@@MMM;" - "~~~~~FFF/@@@@@MMM;?????FFF/MMMMMMMM;" - "FFFFFFFF/MMMMMMMM;wwwwwFFF/NNNNNMMM;" - "~~~~~FFF/NNNNNMMM;?????www/?????NNN;" - "FFFFFwww/?????NNN;wwwwwwww/@@@@@NNN;" - "~~~~~www/@@@@@NNN;?????www/MMMMMNNN;" - "FFFFFwww/MMMMMNNN;wwwwwwww/NNNNNNNN;" - "~~~~~www/NNNNNNNN;?????~~~/?????NNN;" - "FFFFF~~~/?????NNN;wwwww~~~/@@@@@NNN;" - "~~~~~~~~/@@@@@NNN;?????~~~/MMMMMNNN;" - "FFFFF~~~/MMMMMNNN;wwwww~~~/NNNNNNNN;" - "~~~~~~~~/NNNNNNNN" sixbits_220_l = .-sixbits_220 sixbits_320: .ascii "1;31;1;15;1;2;12;0{ @;" - "NNNNNNNN;oooooooo/BBBBBBBB;~~~~~~~~/BBBBBBBB;" - "/{{{{{{{{;NNNNNNNN/{{{{{{{{;oooooooo/~~~~~~~~;" - "~~~~~~~~/~~~~~~~~;????????NNNNNNN;" - "NNNNNNNNNNNNNNN;ooooooooNNNNNNN/BBBBBBBB;" - "~~~~~~~~NNNNNNN/BBBBBBBB;????????NNNNNNN/{{{{{{{{;" - "NNNNNNNNNNNNNNN/{{{{{{{{;ooooooooNNNNNNN/~~~~~~~~;" - "~~~~~~~~NNNNNNN/~~~~~~~~;" - "????????ooooooo/????????BBBBBBB;" - "NNNNNNNNooooooo/????????BBBBBBB;" - "ooooooooooooooo/BBBBBBBBBBBBBBB;" - "~~~~~~~~ooooooo/BBBBBBBBBBBBBBB;" - "????????ooooooo/{{{{{{{{BBBBBBB;" - "NNNNNNNNooooooo/{{{{{{{{BBBBBBB;" - "ooooooooooooooo/~~~~~~~~BBBBBBB;" - "~~~~~~~~ooooooo/~~~~~~~~BBBBBBB;" - "????????~~~~~~~/????????BBBBBBB;" - "NNNNNNNN~~~~~~~/????????BBBBBBB;" - "oooooooo~~~~~~~/BBBBBBBBBBBBBBB;" - "~~~~~~~~~~~~~~~/BBBBBBBBBBBBBBB;" - "????????~~~~~~~/{{{{{{{{BBBBBBB;" - "NNNNNNNN~~~~~~~/{{{{{{{{BBBBBBB;" - "oooooooo~~~~~~~/~~~~~~~~BBBBBBB;" - "~~~~~~~~~~~~~~~/~~~~~~~~BBBBBBB;" - "/????????{{{{{{{;NNNNNNNN/????????{{{{{{{;" - "oooooooo/BBBBBBBB{{{{{{{;~~~~~~~~/BBBBBBBB{{{{{{{;" - "/{{{{{{{{{{{{{{{;NNNNNNNN/{{{{{{{{{{{{{{{;" - "oooooooo/~~~~~~~~{{{{{{{;~~~~~~~~/~~~~~~~~{{{{{{{;" - "????????NNNNNNN/????????{{{{{{{;" - "NNNNNNNNNNNNNNN/????????{{{{{{{;" - "ooooooooNNNNNNN/BBBBBBBB{{{{{{{;" - "~~~~~~~~NNNNNNN/BBBBBBBB{{{{{{{;" - "????????NNNNNNN/{{{{{{{{{{{{{{{;" - "NNNNNNNNNNNNNNN/{{{{{{{{{{{{{{{;" - "ooooooooNNNNNNN/~~~~~~~~{{{{{{{;" - "~~~~~~~~NNNNNNN/~~~~~~~~{{{{{{{;" - "????????ooooooo/????????~~~~~~~;" - "NNNNNNNNooooooo/????????~~~~~~~;" - "ooooooooooooooo/BBBBBBBB~~~~~~~;" - "~~~~~~~~ooooooo/BBBBBBBB~~~~~~~;" - "????????ooooooo/{{{{{{{{~~~~~~~;" - "NNNNNNNNooooooo/{{{{{{{{~~~~~~~;" - "ooooooooooooooo/~~~~~~~~~~~~~~~;" - "~~~~~~~~ooooooo/~~~~~~~~~~~~~~~;" - "????????~~~~~~~/????????~~~~~~~;" - "NNNNNNNN~~~~~~~/????????~~~~~~~;" - "oooooooo~~~~~~~/BBBBBBBB~~~~~~~;" - "~~~~~~~~~~~~~~~/BBBBBBBB~~~~~~~;" - "????????~~~~~~~/{{{{{{{{~~~~~~~;" - "NNNNNNNN~~~~~~~/{{{{{{{{~~~~~~~;" - "oooooooo~~~~~~~/~~~~~~~~~~~~~~~;" - "~~~~~~~~~~~~~~~/~~~~~~~~~~~~~~~" sixbits_320_l = .-sixbits_320 firstinit: .ascii ") @" firstinit_l = .-firstinit screenmap: .byte 63[132*24] screenmap_upd: .byte 63[132*24] update_mode: .long 0 escseq_fao: .ascid "7""[!UL;!ULH""!1AD""8" faooutbuf_d: .long 256 .address faooutbuf faooutbuf: .blkb 256 vt100set_fao: .ascid "7""[0;7m""[!UL;!ULH ""8!+!+" vt100clr_fao: .ascid "7""[m""[!UL;!ULH ""8!+!+" chan: .blkw term: .ascid "SYS$COMMAND:" iosb: .blkw 4 first: .long 0 donelog: .ascid "PLOTTO_DOWNLOADED" table: .ascid "LNM$FILE_DEV" yes: .ascid "YES" x: .blkl y: .blkl colour: .blkl plot_arglst: .long 3 .long x .long y .long colour getdvi_itmlst: .word 4 .word DVI$_TT_DECCRT2 .long deccrt2 .long 0 .word 4 .word DVI$_TT_DECCRT3 .long deccrt3 .long 0 .long 0 deccrt2: .blkl deccrt3: .blkl update_fao: .ascid "7""[!UL;!ULH""!AD""8" place_fao: .ascid "[!UL;!ULH" .psect plotto_code, long,nowrt,exe,shr .entry PLOT_INIT, ^M<> $ASSIGN_S devnam=term, chan=chan status R0 ; Assign channel to term clrl first ; Clear first flag $GETDVIW_S chan=chan, iosb=iosb, itmlst=getdvi_itmlst status R0 ; Find out what kind of status iosb ; terminal we are $TRNLNM_S tabnam=table, lognam=donelog cmpl R0, #SS$_NORMAL ; Check of characters already bneq 1$ ; downloaded ret ; Stop now if so 1$: pushaq yes ; Set logical to indicate the pushaq donelog ; set is being downloaded calls #2, g^LIB$SET_LOGICAL status R0 blbs deccrt3, vt320 ; Go and download appropriate blbs deccrt2, vt220 ; code ret vt220: $QIOW_S chan=chan,iosb=iosb,func=#IO$_WRITEVBLK!IO$M_NOFORMAT,- p1=sixbits_220, p2=#sixbits_220_l status R0 status iosb ret vt320: $QIOW_S chan=chan,iosb=iosb,func=#IO$_WRITEVBLK!IO$M_NOFORMAT,- p1=sixbits_320, p2=#sixbits_320_l status R0 status iosb ret .entry unplot, ^M clrl R4 brb do_plot .entry plot, ^M movl #1, R4 ; default to plot cmpl (AP), #3 blss do_plot movl @12(AP), R4 ; R4 = set/reset do_plot: movl @4(AP), R2 ; R2 = X axis movl @8(AP), R3 ; R3 = Y axis blbs first, 3$ incl first $QIOW_S chan=chan,iosb=iosb,func=#IO$_WRITEVBLK!IO$M_NOFORMAT,- p1=firstinit, p2=#firstinit_l status R0 status iosb 3$: divl3 #2, R2, R5 ; R5 = column mull3 #2, R5, R0 subl2 R0, R2 ; R2 = X bit poition divl3 #3, R3, R6 ; R6 = row mull3 #3, R6, R0 subl2 R0, R3 ; R3 = y bit poition mull3 #132, R6, R1 addl2 R5, R1 ; R1 = offset into map movzbl screenmap(R1), R7 subl2 #63, R7 ; R7 = character bitmap mull3 #3, R2, R0 addl2 R3, R0 ashl R0, #1, R0 ; R0 = mask blbs R4, 1$ bicl2 R0, R7 ; clear pixel brb 2$ 1$: bisl2 R0, R7 ; set pixel 2$: addl2 #63, R7 cmpb R7, screenmap(R1) bneq 4$ ; Don't update if no change movl #SS$_NORMAL, R0 ret 4$: cvtlb R7, screenmap(R1) ; replace character tstl update_mode beql 6$ ; If batch updating then movl #SS$_NORMAL, R0 ; don't update either screen ret ; or second map. 6$: cvtlb R7, screenmap_upd(R1) incl R5 ; move column to base 1 incl R6 ; and row movaq escseq_fao, R2 ; Handle the unlikely blbs deccrt2, 5$ ; event that this is a movaq vt100set_fao, R2 ; VT100.... cmpl R7, #^A"?" bneq 5$ movaq vt100clr_fao, R2 5$: movw #20, faooutbuf_d movab screenmap(R1), R0 $FAO_S ctrstr=(R2), outbuf=faooutbuf_d, outlen=faooutbuf_d,- p1=R6, p2=R5, p3=#1, p4=R0 status R0 movzwl faooutbuf_d, R0 $QIOW_S chan=chan,func=#IO$_WRITEVBLK!IO$M_NOFORMAT,iosb=iosb,- p1=faooutbuf, p2=R0 status R0 status iosb ret ; ; POINT -- return status of pixel ; Usage: status = POINT(x,y) ; status = -1 if pixel is set, -1 if pixel is clear, long by value ; x = X axis address of pixel, long by reference ; y = Y axis address of pixel, long by reference ; .entry point, ^M movl @4(AP), R2 ; R2 = X axis movl @8(AP), R3 ; R3 = Y axis divl3 #2, R2, R5 ; R5 = column mull3 #2, R5, R0 subl2 R0, R2 ; R2 = X bit poition divl3 #3, R3, R6 ; R6 = row mull3 #3, R6, R0 subl2 R0, R3 ; R3 = y bit poition mull3 #132, R6, R1 addl2 R5, R1 ; R1 = offset into map movzbl screenmap(R1), R7 subl2 #63, R7 ; R7 = character bitmap mull3 #3, R2, R0 addl2 R3, R0 ; R0 = bit number bbs R0, R7, 1$ ; Test bit clrl R0 ; Return 0 for pixel clear ret 1$: movl #-1, R0 ; -1 for pixel set ret ; 4(AP) = x ; 8(AP) = y ; 12(AP) = x' ; 16(AP) = y' .entry undraw, ^M clrl colour brb do_draw .entry draw, ^M movl #-1, colour do_draw: calls #0, plot_batch_start subl3 @4(AP), @12(AP), R2 ; R2 = x-x' movl R2, R0 bgeq 1$ subl3 R2, #0, R0 ; R0 = abs(R2) 1$: subl3 @8(AP), @16(AP), R3 ; R3 = y-y' movl R3, R1 bgeq 2$ subl3 R3, #0, R1 ; R1 = abs(R3) 2$: cmpl R0, R1 ; Different code depending blss drawy ; on direction tstl R0 beql onedot movl @12(AP), R7 ; R7 = X' position movl @4(AP), R4 ; R4 = X position cvtlf @8(AP), R5 ; R5 = floating Y cmpl R7, R4 bgtr 3$ movl R7, R1 ; If coordinates back to front movl R4, R7 ; then swap, alter sign of movl R1, R4 ; Y-Y' distance subl3 R3, #0, R3 cvtlf @16(AP), R5 ; R5 = floating Y' 3$: addf2 #0.5, R5 ; Rounding cvtlf R0, R0 ; R0 = abs(distance x-x'), float cvtlf R3, R1 ; R1 = float distance y-y' divf3 R0, R1, R6 ; R6 = Y step xloop: cvtfl R5, y movl R4, x callg plot_arglst, g^plot ; Plot point addf2 R6, R5 ; Move Y by Y step aobleq R7, R4, xloop ; Move X by one, loop calls #0, plot_batch_end ret onedot: movl @4(AP), x ; Come here if only one dot movl @8(AP), y ; to plot -- plot it. callg plot_arglst, g^plot ; (divides by zero otherwise) calls #0, plot_batch_end ret drawy: tstl R1 beql onedot movl @16(AP), R7 ; R7 = y' position movl @8(AP), R4 ; R4 = y position cvtlf @4(AP), R5 ; R5 = floating x cmpl R7, R4 bgtr 3$ movl R7, R0 ; If coordinates back to front movl R4, R7 ; then swap, alter sign of movl R0, R4 ; Y-Y' distance subl3 R2, #0, R2 cvtlf @12(AP), R5 ; R5 = floating x' 3$: addf2 #0.5, R5 ; Rounding cvtlf R1, R0 ; R0 = abs(distance y-y'), float cvtlf R2, R1 ; R1 = float distance x-x' divf3 R0, R1, R6 ; R6 = x step yloop: cvtfl R5, x ; Plot point movl R4, y callg plot_arglst, g^plot addf2 R6, R5 ; Move X by X step aobleq R7, R4, yloop ; Move Y by one, loop calls #0, plot_batch_end ret .entry plot_batch_start, ^M<> blbc deccrt2, 1$ ; Not supported for VT100 incl update_mode 1$: movl #1, R0 ret .entry plot_batch_end, ^M blbs deccrt2, 5$ ; Not supported for VT100 7$: ret 5$: decl update_mode ; Decrement update mode counter bneq 7$ movl #0, R2 ; R2 = line counter 1$: mull3 #132, R2, R3 ; R3 = base address clrl R4 ; R4 = character counter movl #-1, R5 ; R5 = First change 2$: cmpb screenmap(R3)[R4], screenmap_upd(R3)[R4] beql 3$ movb screenmap(R3)[R4], screenmap_upd(R3)[R4] movab screenmap(R3)[R4], R6 ; R6 = last change tstl R5 bgtr 3$ movl R6, R5 ; R5 = first change 3$: aoblss #132, R4, 2$ ; End of char. loop tstl R5 ; If anything to change then blss 4$ ; update line jsb 6$ 4$: aoblss #24, R2, 1$ ; End of line loop ret 6$: subl2 R5, R6 incl R6 ; R6 = length movab screenmap-1(R3), R0 subl3 R0, R5, R0 ; R0 = Column on screen movl R2, R1 incl R1 ; R1 = Line on screen movl #256, faooutbuf_d ; Format output $FAO_S ctrstr=update_fao, - outbuf=faooutbuf_d, outlen=faooutbuf_d,- p1=R1, p2=R0, p3=R6, p4=R5 status R0 movzwl faooutbuf_d, R0 ; Print line $QIOW_S chan=chan,func=#IO$_WRITEVBLK!IO$M_NOFORMAT,iosb=iosb,- p1=faooutbuf, p2=R0 status R0 status iosb rsb .entry place_cursor, ^M<> divl3 #2, @4(AP), R0 divl3 #3, @8(AP), R1 incl R0 ; R0 = column incl R1 ; R1 = row movl #256, faooutbuf_d ; Format esc sequence $FAO_S ctrstr=place_fao, - outbuf=faooutbuf_d, outlen=faooutbuf_d,- p1=R1, p2=R0 status R0 movzwl faooutbuf_d, R0 ; Send to screen $QIOW_S chan=chan,func=#IO$_WRITEVBLK!IO$M_NOFORMAT,iosb=iosb,- p1=faooutbuf, p2=R0 status R0 status iosb ret .end