**************************************************************************
*                                                                        *
*                      CoCo SDOS Graphics Package                        *
*                                                                        *
*                          Brought to you by                             *
*                                                                        *
*                             Bill Morita                                *
*                                                                        *
*                      Inception date:  May 11, 1986                     *
*                                                                        *
*                      Last Edit date:  May 21, 1986                     *
*                                                                        *
**************************************************************************


*******************************
*        Definitions          *
*******************************

*        Runtime package floating point entry point equates

FPTRAP   EQU   $0028

FLOAD    EQU   $0109
FSTORE   EQU   $010C
FCMP     EQU   $010F
FNEG     EQU   $0112
FADD     EQU   $0115
FSUB     EQU   $0118
FMUL     EQU   $011B
FDIV     EQU   $011E
FCONVO   EQU   $0121
FCONVI   EQU   $0124
FINT     EQU   $0127
FIX      EQU   $012A
FIX16    EQU   $012D
FLOAT    EQU   $0130

         PAGE

         ORG     $2A00

*
*        Entry point vectors
*
         JMP   CURS0RBLINK             Cursor blink control
         JMP   GRAPHICSMODE            Select new graphics mode and return old
         JMP   SETXY                   Set Cursor
         JMP   LINE                    Draw line to endpoint
         JMP   VECTOR                  Draw "vector" line
         JMP   CIRCLE                  Draw a circle
         JMP   SETBACKGROUND           Set background color
         JMP   FILL                    Fill a region
         JMP   SETPIXEL                Set a pixel
         JMP   DRAWBOX                 Draw (hollow) box
         JMP   DRAWBLOCK               Draw solid box
         JMP   GETWINDOW               Record a window from screen
         JMP   PUTWINDOW               Put a window onto screen
         JMP   DISPLAYTEXT             Display text to screen
         JMP   GETCURSORX              Return cursor X position
         JMP   GETCURSORY              Return cursor Y position
         JMP   GETPIXEL                Return pixel color
         JMP   GETBACKGROUND           Return background

         PAGE
*
*        Local Storage
*
GRFRTN   RMB   2                       Return address to BASIC
BOXROUTINE RMB 1                       Box routine pointer (solid/hollow)
CHARCOUNT RMB  2                       Character count for text output
TEXTADDR RMB   2                       Address of text string
*
* Point to Point Line drawing variables
*
LINEX1   RMB   2                       X1
LINEY1   RMB   2                       Y1
LINEX2   RMB   2                       X2
LINEY2   RMB   2                       Y2
LINEPOINT      RMB 2                   Address of line point display routine
LINEXSTEP      RMB 2                   Step for X (+1 or -1)
LINEYSTEP      RMB 2                   Step for Y (+1 or -1)
LINEDX         RMB 2                   Delta X for line (Absolute)
LINEDY         RMB 2                   Delta Y for line (Absolute)
LINEDECISION   RMB 2                   Decision variable for Y step
LINEDINC1      RMB 2                   Decision variable increment #1
LINEDINC2      RMB 2                   Decision variable increment #2
LINEX          RMB 2                   Untranslated X for line
LINEY          RMB 2                   Untranslated Y for line
LINEXEND       RMB 2                   Untranslated X end value
LINEYEND       RMB 2                   Untranslated Y end value
WRITEBUF FDB   0                       Write buffer for syscalls
*                                      (high order byte must remain 0)
         PAGE
*
*        Wrong Argument Count Exit
*
BADARGCOUNT
         LDX   #27                     Load BASIC error code
         SEC                           Flag error exit
         JMP   [GRFRTN]

*
*        Argument out of range
*
ARGOOR
         LDX   #99                     Load ?BASIC error code
         SEC                           Flag error exit
         JMP   [GRFRTN]

*
*        Check argument count and save return address
*
*        Inputs:      A-reg    Argument count from BASIC
*                     B-reg    Expected argument count
*                     2,S      Return address to BASIC
*
*        Outputs:     S        BASIC return removed
*                     GRFRTN   Set to BASIC return address
*
CHECKSAVE
         LDY   ,S++                    Get return
         LDU   ,S++                    Get BASIC return
         STU   GRFRTN                   and save it
         CBA                           Arg count ok ?
         BNE   BADARGCOUNT              No
         JMP   ,Y                       Yes, return

         PAGE
*
*        Get Integer Argument
*
*        Inputs:    X-reg     Argument list pointer
*                   B-reg     Max legal value (unsigned)
*
*        Outputs:   X-reg     Argument list pointer (updated)
*                   D-reg     Value (0-255)
*
*
GETINTARG
         LDY   4,X                     Get value address
         LDA   0,Y                     Integer value ?
         BEQ   GETINTINT                Yes
         PSHS  X,B                     Save arg list pointer and max limit
         TFR   Y,X                     Point to value for FLOAD
         JSR   FLOAD                   Load floating value to stack
         JSR   FIX16                   Try to convert to 16-bit binary
         BRA   *+4                     Skip if good return
         BRA   ARGOOR                  Argument out-of-range
         LDA   2,S                     Value negative or > 255 ?
         BNE   ARGOOR                   Yes
         LDA   3,S                     Get value
         LEAS  4,S                     Remove value from stack
         PULS  X,B                     Recover range limit and arg list ptr
         BRA   GETINTLIM               Go check limit

GETINTINT
         LDA   4,Y                     Value negative or > 255 ?
         BNE   ARGOOR                   Yes
         LDA   5,Y                     Get value into D
GETINTLIM
         CBA                           Greater than max value ?
         BHI   ARGOOR                   Yes
         TAB                           Return value
         CLRA                           in D-reg
         LEAX  6,X                     Step arg list ptr
         RTS                           Done


*
*        Get 16 bit Integer Argument
*
*        Inputs:    X-reg     Argument list pointer
*
*        Outputs:   X-reg     Argument list pointer (updated)
*                   D-reg     Value
*
*
GETINT16ARG
         LDY   4,X                     Get value address
         LDA   0,Y                     Integer value ?
         BEQ   GETINT16INT              Yes
         PSHS  X                       Save arg list pointer and max limit
         TFR   Y,X                     Point to value for FLOAD
         JSR   FLOAD                   Load floating value to stack
         JSR   FIX16                   Try to convert to 16-bit binary
         BRA   *+4                     Skip if good return
         BRA   ARGOOR                  Argument out-of-range
         LDD   2,S                     Get value
         LEAS  4,S                     Remove value from stack
         PULS  X                       Recover range limit and arg list ptr
         BRA   GETINT16RTS

GETINT16INT
         LDD   4,Y                     Value
GETINT16RTS
         LEAX  6,X                     Step arg list ptr
         RTS                           Done


*
*        Set Coordinates (Set cursor x, y)
*
*        Inputs:    X-reg     Arg list pointer
*
*        Outputs:   X-reg     Arg list pointer updated
*                   CURSORY   Set to 1nd value in list
*                   CURSORX   Set to 2st value in list
*
SETCOORDINATES
         LDB   #191                    Limit for Y
         JSR   GETINTARG               Get Y value
         STD   CURSORY                  and store it
         LDB   #255                    Limit for X
         JSR   GETINTARG               Get X value
         STD   CURSORX                  and store it
         RTS                           Done
         PAGE

*
*        Get Color parameter
*
*        Inputs:     X-reg     Arg list pointer
*
*        Outputs:    X-reg     Arg list pointer updated
*                    B-reg     Color (0 / 1)
*
GETCOLOR
         LDB   #4                      Color limits
         JSR   GETINTARG               Get color parameter
         TBA                           Copy parameter value
         CMPB  #1                      0/1 ?
         BLS   GETCOLORRTS              Yes
         EORB  CURRENTBACKGROUND       Get background color
         ANDB  #1                      Force 0/1
GETCOLORRTS
         RTS

*
*        Set a point on the screen routine
*
*        SETPIXEL(x,y)
*
SETPIXEL
         LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         LDB   #191                    Get Y
         JSR   GETINTARG
         PSHS  D                       Save Y on stack
         LDB   #255                    Get X
         JSR   GETINTARG
         TFR   D,X                     X = X coordinate
         PULS  D                       D = Y coordinate
         JSR   DRAWDOTATXY             Set dot
         CLC
         JMP   [GRFRTN]


*
*        Get Pixel value
*
*              CALL GETPIXEL(x,y)
*
GETPIXEL
         LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         JSR   SETCOORDINATES          Get X,Y
? **** Get pixel value into B-reg
         CLRA                          Clear upper 8 bits
         PSHD                          Push integer value
         CLRB
         PSHD
         PSHD
         CLC
         JMP   [GRFRTN]

*
*        Set X and Y coordinates
*
*              SETXY(x,y)
*
SETXY    LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         JSR   SETCOORDINATES          Get X,Y
         CLC
         JMP   [GRFRTN]

*
*        Draw Box routines
*
*        DRAWBOX(w,h)                  (Hollow)
*           or
*        DRAWBLOCK(w,h)                (Solid)
*
DRAWBOX
         LDX   #EMPTYBOX               Empty box draw routine
         BRA   B0XIT

DRAWBLOCK
         LDX   #SOLIDBOX               Solid box draw routine

B0XIT
         STX   BOXROUTINE              Set box routine pointer
         LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         LDB   #191                    Get height
         JSR   GETINTARG
         PSHS  D                       Save height on stack
         LDB   #255                    Get width
         JSR   GETINTARG
         TFR   D,X                     X = width
         PULS  D                       D = height
         JSR   [BOXROUTINE]            Do box
         CLC
         JMP   [GRFRTN]


*
*        Display text routine
*
*        DISPLAYTEXT("text",size)
*
*        Where:  size = 0 (42 char per line)
*                size = 1 (51 char per line)
*
*
DISPLAYTEXT
         LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         LDB   #1
         JSR   GETINTARG               Get text size flag
         STB   NARROWCHAR              Set size flag
         LDY   2,X                     Get text address
         STY   TEXTADDR                 and save it
         LDY   4,X                     Get count
         STY   CHARCOUNT                and save it
         BEQ   DISPLAYTEXTEXIT           No characters to display
DISPLAYTEXTLOOP
         LDX   TEXTADDR                Character pointer
         LDA   ,X+                     Get next character
         STX   TEXTADDR                Update pointer
         JSR   PUTCHAR                 Put character to screen
         LDD   CHARCOUNT               Count
         SUBD  #1                       down
         STD   CHARCOUNT                 to zero
         BNE   DISPLAYTEXTLOOP
DISPLAYTEXTEXIT
         CLC
         JMP   [GRFRTN]

*
*        Cursor Blink Control
*
*        CURSORBLINK(flag)
*
*        Where:  flag   0  =  Cursor off
*                   1-255  =  Cursor on
*
CURS0RBLINK
         LDB   #1                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         LDB   #255
         JSR   GETINTARG               Get cursor blink flag
         STD   WRITEBUF                Syscall write buffer
         LDX   #CURSE                  Cursor control block
         JSR   SYSCALL$                Issue cursor control
         BCS   CURSORBAD
         CLC
         JMP   [GRFRTN]

CURSORBAD                 ;Ignore errors
         SEC
         JMP   [GRFRTN]

         IFUND CC:CURSORCONTROL
CC:CURSORCONTROL EQU $23
         FIN

CURSE                                  ;Cursor control syscall block
         FCB   SYSCALL:CONTROL
         FCB   8
         FDB   CC:CURSORCONTROL
         FDB   WRITEBUF
         FDB   2

*
*        Set background color
*
*        SETBACKGROUND(flag)
*
*        Where:  flag   0  =  White
*                       1  =  Black
*
SETBACKGROUND
         LDB   #1                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         LDB   #1
         JSR   GETINTARG               Get color
         TSTB                          Black ?
         BNE   BLACKBACK                Yes
         LDA   #7                       No, White
BLACKBACK
         STA   WRITEBUF+1              Syscall write buffer
         LDX   #SETBACK                Background control block
         JSR   SYSCALL$                Issue control call
         BCS   BACKGROUNDBAD
         CLC
         JMP   [GRFRTN]

BACKGROUNDBAD                     ;Ignore errors
         SEC
         JMP   [GRFRTN]

         IFUND CC:BACKGROUND
CC:BACKGROUND  EQU $21
         FIN

SETBACK
         FCB   SYSCALL:CONTROL
         FCB   8
         FDB   CC:BACKGROUND
         FDB   WRITEBUF
         FDB   2



*
*        Set new graphics mode and return old
*
*        GRAPHICSMODE(mode)
*
*        Where:  mode    0  =  Inclusive OR mode
*                        1  =  Exclusive OR mode
*                        2  =  AND mode
*
*        Returns:  Previous mode (as above)
*
GRAPHICSMODE
         LDB   #1                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         LDB   #2
         JSR   GETINTARG               Get mode
         LSLB                          Convert mode to word index
         LDX   #GMODETABLE             Graphics mode selection table
         JSR   [B,X]                   Call graphics mode routine
         SUBD  #2                      Compute mode entry point
         LDX   #GMODETABLEEND          Graphics mode selection table end
         CMPD  ,--X                    AND mode ?
         BEQ   GRAPHICSMODERETURN       Yes
         CMPD  ,--X                    EOR mode ?
         BEQ   GRAPHICSMODERETURN       Yes
         CMPD  ,--X                    IOR mode ? (or anything else)
GRAPHICSMODERETURN
         TFR   X,D                     Get pointer into table
         SUBD  #GMODETABLE             Offset into table
         LSRD                          Convert to mode
         PSHS  D                       Push old mode value
         CLRA
         CLRB
         PSHS  D
         PSHS  D
         CLC
         JMP   [GRFRTN]

GMODETABLE
         FDB   SELECTIORMODE           Mode 0
         FDB   SELECTEORMODE           Mode 1
         FDB   SELECTANDMODE           Mode 2
GMODETABLEEND

*
*        Routines to return the values of the cursor coordinates
*
*        CURSORX
*
*        CURSORY
*
GETCURSORX
         LDD   CURSORX
         BRA   CURORD

GETCURSORY
         LDD   CURSORY

CURORD
         PSHS  D
         CLRA
         CLRB
         PSHS  D
         PSHS  D
         CLC
         JMP   [GRFRTN]

*
*        Line drawing routines
*
*        LINE(x,y)
*
*        VECTOR(dx,dy)
*
LINE
         LDD   CURSORX                 Set line start X
         STD   LINEX1
         LDD   CURSORY                 Set line start Y
         STD   LINEY1
         LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         JSR   SETCOORDINATES          Get X,Y for line endpoint
         BRA   GENLINE

JARGOOR  JMP   ARGOOR

VECTOR
         LDD   CURSORX                 Set line start X
         STD   LINEX1
         LDD   CURSORY                 Set line start Y
         STD   LINEY1
         LDB   #2                      Number of arguments
         JSR   CHECKSAVE               Save return and check arg count
         JSR   GETINT16ARG             Get delta Y
         ADDD  CURSORY                 Compute Y+dy
         CMPD  #191                    Value in range ?
         BHI   JARGOOR                  No
         STD   CURSORY                  Yes, update cursor
         JSR   GETINT16ARG             Get delta X
         ADDD  CURSORX                 Compute X+dy
         CMPD  #255                    Value in range ?
         BHI   JARGOOR                  No
         STD   CURSORX                  Yes, update cursor

GENLINE
         LDD   CURSORX                 Set line end coordinates
         STD   LINEX2
         LDD   CURSORY
         STD   LINEY2
         LDX   #0                      Set line start to origin
         STX   LINEX
         STX   LINEY
         LDX   #1                      Assume Delta X & Delta Y positive
         STX   LINEXSTEP
         STX   LINEYSTEP
         LDX   #-1                     Possible neg delta
         LDD   LINEY2                  Y2-Y1
         SUBD  LINEY1                  Neg delta Y ?
         STD   LINEYEND                Termination dY
         BPL   DRAWLINE1                No
         STX   LINEYSTEP                Yes, set neg step
         NEGD                          ABS(Y2-Y1)
DRAWLINE1
         STD   LINEDY                  Delta Y for line
         LDD   LINEX2                  X2-X1
         SUBD  LINEX1                  Neg delta X ?
         STD   LINEXEND                Termination dX
         BPL   DRAWLINE2                No
         STX   LINEXSTEP                Yes, set neg step
         NEGD                          ABS(X2-X1)
DRAWLINE2
         STD   LINEDX                  Delta X for line
         LDX   #LINEPOINTXY            Assume dX >= dY
         STX   LINEPOINT                and point to line output routine
         CMPD  LINEDY                  dX >= dY ?
         BHS   DRAWLINE3                Yes
         LDX   #LINEPOINTYX             No, set line output to
         STX   LINEPOINT                 swap X and Y
         LDX   LINEDY                  Swap dX and dY
         STX   LINEDX                   so dX >= dY
         STD   LINEDY                    is assured
         LDX   LINEXEND
         LDD   LINEYEND                X and Y are swapped so
         STD   LINEXEND                 terminate on dY value
         STX   LINEYEND
DRAWLINE3
         LDD   LINEDY                  d := 2 * dY - dX
         LSLD
         SUBD  LINEDX
         STD   LINEDECISION            Set y incr decision variable
         LDD   LINEDY                  incr1 := 2 * dY
         LSLD
         STD   LINEDINC1               Set decision variable incr #1
         LDD   LINEDY                  incr2 := 2 * (dY-dX)
         SUBD  LINEDX
         LSLD
         STD   LINEDINC2               Set decision variable incr #2
LINEDPOINT                       ; Draw a line point
         JSR   [LINEPOINT]
         LDD   LINEX                   Get current X
         CMPD  LINEXEND                X at end value ?
         BEQ   LINEENDDOT               Yes
         ADDD  LINEXSTEP                No, step X
         STD   LINEX                   X = X + Xstep
         LDD   LINEDECISION            Y step decision variable
         BPL   LINEDPOS                Decision variable >= 0
         ADDD  LINEDINC1               Step decision var by incr #1
         STD   LINEDECISION             and update
         BRA   LINEDPOINT              Go for next point

LINEDPOS
         ADDD  LINEDINC2               Step decision var by incr #2
         STD   LINEDECISION             and update
         LDD   LINEY                   Get current Y
         ADDD  LINEYSTEP                and step it
         STD   LINEY                   Y = Y + Ystep
         BRA   LINEDPOINT

LINEENDDOT
         LDD   LINEYEND                At end
         CMPD  LINEY                    point?
         BEQ   LINEDONE                  Yes
         STD   LINEY                     No, force
         JSR   [LINEPOINT]                end point display
LINEDONE
         CLC                           Flag no errors
         JMP   [GRFRTN]

*
* Routines to translate (LINEX,LINEY) to screen coordinates
*
LINEPOINTXY                            ; Translate by line start point
         LDD   LINEX
         ADDD  LINEX1
         TFR   D,X                     X
         LDD   LINEY
         ADDD  LINEY1                  Y
         JMP   DRAWDOTATXY             .

LINEPOINTYX                            ; Swap coordinates and translate
         LDD   LINEY
         ADDD  LINEX1
         TFR   D,X                     X
         LDD   LINEX
         ADDD  LINEY1                  Y
         JMP   DRAWDOTATXY             .



*
*        Routine to return background
*
*        GETBACKGROUND
*
*
GETBACKGROUND
         CLRA
         CLRB                          Assume white
         TST   CURRENTBACKGROUND       White ?
         BNE   GETBACKGROUNDRTN         Yes
         INCB                           No, black
GETBACKGROUNDRTN
         PSHS  D
         CLRB
         PSHS  D
         PSHS  D
         CLC
         JMP   [GRFRTN]

