* QL WORLD DIY TOOLKIT - FAST pixel graphics routines
* Version 1.6, Copyright 1989,90 Simon N Goodwin.
* Modified 10/9/89 to support Thor XVI MODE 12.
* Modified 19/7/90 to suit Metacomco's Assembler.
*
xstore     equ      84              Offsets of old X & Y
ystore     equ      78              in the channel block
*
start      lea.l   define,a1
           move.w  $110,a2         BP.INIT vector
           jmp     (a2)
*
draw       lea.l   drawer,a4
           bra.s   get_params
plot       lea.l   plotter,a4
*
* Handler for 2 or 3 parameters
*
get_params move.w  $112,a2         Vector to get integers
           jsr     (a2)            CA.GTINT
           bne.s   bad_exit
           moveq   #1,d0           First assume channel 1
           subq.w  #2,d3           At least 2 parameters?
           beq.s   get_coords      Exactly 2,  use #1
           bmi.s   bad_param       Less than 2: an error  
           subq.w  #1,d3           Only 1 parameter left?
           bne.s   bad_param       No, too many, complain
           move.w  0(a1,a6.l),d0   Get BASIC channel No.
           addq.l  #2,a1           Discard channel param.
get_coords move.w  0(a1,a6.l),d1   Get X co-ordinate
           move.w  2(a1,a6.l),d2   Get Y co-ordinate
*
* Convert channel number in D0 to ID in A0 and call EXTOP
*
chan_sel   mulu    #40,d0          Channel table size
           add.l   $30(a6),d0      Add base offset
           cmp.l   $34(a6),d0 
           bge.s   what_chan       Past end of table?
           move.l  0(a6,d0.l),d0
           bmi.s   what_chan       Negative if closed
call_extop move.l  d0,a0           A0 is channel ID
           move.l  a4,a2           Address of routine
           moveq   #-1,d3          Allow infinite time
           moveq   #9,d0           SD.EXTOP key
           trap    #3              Call the device driver
           rts                      Return D0 from EXTOP
*
bad_param  moveq   #-15,d0         BAD PARAMETER error
           rts
what_chan  moveq   #-6,d0          CHANNEL NOT OPEN error
bad_exit   rts                      Error code is in D0
*
* Line DRAW routine
*
drawer     move.w  xstore(a0),d4   Fetch previous X
           move.w  ystore(a0),d5   Fetch previous Y
           bsr     range_chk       Line must fit window
find_DX    suba.l  a2,a2           DX := 0
           sub.w   d4,d1
           beq.s   set_X_step
           bmi.s   neg_DX
           addq.l  #1,a2           A2 := SIGN( Delta X )
           bra.s   set_X_step
neg_DX     subq.l  #1,a2
           neg.w   d1              D1 := ABS( Delta X )
set_X_step btst    #3,52(a6)       Check mode (SV.MCSTA)
           beq.s   find_DY         MODE 4, D1 & A2 are OK
           adda.l  a2,a2           MODE 8/12, double X step
           ror.w   #1,d1           And halve X dot count
find_DY    suba.l  a3,a3           DY := 0
           sub.w   d5,d2
           beq.s   find_DD
           bmi.s   neg_DY
           addq.l  #1,a3           A3 := SIGN( Delta Y )
           bra.s   find_DD
neg_DY     subq.l  #1,a3
           neg.w   d2              D2 := ABS( Delta Y )
find_DD    cmp.w   d1,d2           D1 := MAX( D1, D2 )
           bhi.s   y_bigger
no_match   move.w  a2,a4           DDX := DX
           suba.l  a5,a5           DDY := 0
           bra.s   find_TEMP
y_bigger   exg     d1,d2           D1 := MAX( D1,D2 )
           suba.l  a4,a4           DDX := 0
           move.w  a3,a5           DDY := DY
find_TEMP  move.w  d1,d0
           asr.w   #1,d0           TEMP := STEPS DIV 2
           move.w  d2,d6           D6 := PARTS
           move.w  d1,d2
           subq.w  #1,d2           D2 is DOT for DBRA
           bmi.s   null_draw       Exit if line length=0
           exg     d1,d4           OLDX = D1; STEPS = D4
           exg     d2,d5           OLDY = D2; DOT = D5
*
* Now draw a line of D5 pixels; D1,D2 = X,Y of next point
*
dot_loop   add.w   d6,d0           TEMP := TEMP + PARTS
           cmp.w   d4,d0           Flag TEMP - STEPS
           bcs.s   use_DD
           sub.w   d4,d0           TEMP := TEMP - STEPS
           add.w   a2,d1           OLDX := OLDX + DX
           add.w   a3,d2           OLDY := OLDY + DY
           bra.s   do_dot
*
use_DD     add.w   a4,d1           OLDX := OLDX + DDX
           add.w   a5,d2           OLDY := OLDY + DDY
do_dot     movem.w d1-d2,-(a7)     Preserve OLDX & OLDY
           bsr.s   plot_pixel
           movem.w (a7)+,d1-d2     Restore OLDX & OLDY
           dbra    d5,dot_loop
null_draw  moveq   #0,d0
           rts
*
* Co-ordinate checker; D1=X, D2=Y, ERR.OR if beyond window
*
range_chk  tst.b   51(a6)          Test SV.SCRST
           bne.s   screen_off      Abort if CTRL-F5 set
           tst.w   d2              Check Y >= 0
           bmi.s   range_err
           cmp.w   30(a0),d2       Check Y < CH.HEIGHT 
           bcc.s   range_err
           tst.w   d1              Check X >= 0
           bmi.s   range_err
           cmp.w   28(a0),d1       Check X < CH.WIDTH
           bcc.s   range_err
           move.w  #$8080,d7       Set MODE 4 pixel mask
           btst    #3,52(a6)       Check MODE (SV.MCSTA)
           beq.s   range_ok        MODE 4, no problems
           bclr    #0,d1           MODE 8/12, X must be EVEN
           btst    #2,52(a6)       Test Thor MODE 12 bit
           beq.s   not_a_thor
           move.w  #$C0C0,d7       Use the Thor mask
not_a_thor move.b  #$C0,d7         Mask 8 colours
range_ok   add.w   24(a0),d1       Add window offset to X
           add.w   26(a0),d2       Add window offset to Y
           move.w  d1,xstore(a0)   Store end X on SD.XORG
           move.w  d2,ystore(a0)   Store end Y on SD.YORG
           rts
*
screen_off moveq   #-1,d0          NOT COMPLETE error
           bra.s   quick_exit
range_err  moveq   #-4,d0          OUT OF RANGE error
quick_exit addq.l  #4,a7           Return to after TRAP
           rts
*
* Pixel PLOT code, uses A0, A6, D7; alters A1, D1, D2, D3
*
plotter    bsr.s   range_chk
           moveq   #0,d0           Preset ERR.OK report
plot_pixel move.l  62(a0),d3       Grab the ink mask
           btst    #0,d2           Find out if Y is odd
           beq.s   find_word       It's even, mask is OK
           swap    d3              Odd, so use other mask
*      
* Point A1 at the relevant word in video memory
*
find_word  move.l  50(a0),a1       A1 := screen RAM start
           lsl.w   #7,d2           1 line= 2^7= 128 bytes
           adda.w  d2,a1           A1 := line RAM start
           moveq   #7,d2
           and.w   d1,d2           Save X MOD 8 in D2
           lsr.w   #3,d1           D1 := offset on line
           add.w   d1,d1           Offset := 0-126 (EVEN)
           adda.w  d1,a1           A1 -> screen RAM word
*
* Set the pixel in MODE 4 or 8, allowing for OVER -1
*
set_pixel  move.w  d7,d1           Select pixel mask
           ror.w   d2,d1           Align pixel mask
           and.w   d1,d3           D3 := 1 pixel of ink
           btst    #3,66(a0)       Check for OVER -1
           bne.s   overplot
           not.w   d1              Mask out the rest
           and.w   (a1),d1         Fetch the background
           or.w    d3,d1           Insert the pixel
           move.w  d1,(a1)         Store the combination
           rts                      PLOT returns ERR.OK
overplot   eor.w   d3,(a1)         Exclusive OR the pixel
           rts
*
define     dc.w    2               Number of procs
           dc.w    plot-*
           dc.b    4,'PLOT'
           dc.w    draw-*
           dc.b    4,'DRAW'
           dc.w    0,0,0           End of procs, no fns
           end
