;-------------------------------------------------------------------------;
;                                  TIGA                                   ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA - Graphics Manager Extension                                     ;
;-------------------------------------------------------------------------;
; pen_line, patnpen_line, pen_polyline and patnpen_polyline functions     ;
;                                                                         ;
;   The pen_line function draws a straight line from (x0,y0) to (x1,y1)   ;
;   using a rectangular pen.  The pen is a solid-filled rectangle.  The   ;
;   ink color is specified in COLOR1.                                     ;
;                                                                         ;
;   The patnpen_line function draws a straight line from (x0,y0) to       ;
;   (x1,y1) using a rectangular pen.  The pen is a pattern-filled         ;
;   rectangle.  The pattern ink colors are specified in COLOR0 and        ;
;   COLOR1.                                                               ;
;                                                                         ;
;   The pen_polyline function draws multiple lines using a rectangular    ;
;   pen.  The pen is a solid-filled rectangle.  The ink color is          ;
;   specified in COLOR1.  The lines are specified by two arguments:       ;
;   (1) the number of lines to be drawn, (2) a point_list array           ;
;   specifying the x and y coordinates of each point.                     ;
;                                                                         ;
;   The pen_polyline function draws multiple lines using a rectangular    ;
;   pen.  The pen is a pattern-filled rectangle.  The pattern ink colors  ;
;   are specified in COLOR0 and COLOR1. The lines are specified by two    ;
;   arguments, similar to pen_polyline above.                             ;
;-------------------------------------------------------------------------;
;  Usage:    pen_line(x1, y1, x2, y2);      /* pen line */                ;
;            patnpen_line(x1, y1, x2, y2);  /* pattern pen line */        ;
;                                                                         ;
;  Stack arguments:  long x1, y1;  /* line starting coordinates */        ;
;                    long x2, y2;  /* line ending coordinates */          ;
;-------------------------                                                ;
;  Usage:    pen_polyline(npts, ptlist);                                  ;
;            patnpen_polyline(npts, ptlist);                              ;
;                                                                         ;
;  Stack arguments:  long npts;  /* no. of lines in list */               ;
;                    short ptlist[];  /* list of coordinates */           ;
;-------------------------                                                ;
;  Registers altered:  A8                                                 ;
;                                                                         ;
;  Value returned in A8:  Undefined                                       ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;   5/21/87...Original version written...................Jerry Van Aken   ;
;  07/18/88...Added TIGA direct mode and dstbm check.....W.S.Egr          ;
;  09/09/88...Access globals thru environment struct.....W.S.Egr          ;
;  07/26/89...Added 34020 support........................A. Sharp         ;
;  08/21/89...Simplified 34020 inner loop per JVA........A. Sharp         ;
;-------------------------------------------------------------------------;
;
        .title    'pen line'
        .file     'penline.asm'
        .include  gsptypes.inc      ;offsets into environment struct  
        .include  gspglobs.inc          
        .include  oem.inc
;
;
;  DEFINE GLOBAL FUNCTION NAMES
;
        .globl    _pen_line, _dm_pen_line
        .globl    _patnpen_line, _dm_patnpen_line
        .globl    _pen_polyline, _dm_pen_polyline
        .globl    _patnpen_polyline, _dm_patnpen_polyline
;
;    C-PACKET ENTRY POINT: patnpen_line() function
;
_patnpen_line:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Load subroutine addresses.
        MOVI      LOOP2,B0            ;address of pen_line inner loop
        move      @_pattern+PATTERN_HSRV,B1,1   ;subroutine for pattern fill
        jruc      CP_LINE
;
;    DIRECT-MODE ENTRY POINT: patnpen_line() function
;
_dm_patnpen_line:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MOVI      LOOP2,B0            ;address of pen_line inner loop
        move      @_pattern+PATTERN_HSRV,B1,1   ;subroutine for pattern fill
        jruc      DM_LINE
;
;    C-PACKET ENTRY POINT: pen_line() function
;
_pen_line:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Load subroutine address.
        MOVI      LOOP1,B0            ;address of pen_line inner loop
* Pop the four arguments off the stack (pen_line & patnpen_line c-packet calls)
CP_LINE:
        MOVE      *-A14,A0,1          ;get argument xstart
        MOVE      *-A14,A1,1          ;get argument ystart
        SLL       16,A1               ;
        MOVY      A1,A0               ;concatenate xstart and ystart
        MOVE      *-A14,A1,1          ;get argument xend
        MOVE      *-A14,A2,1          ;get argument yend
        SLL       16,A2               ;
        MOVY      A2,A1               ;concatenate xend and yend
        CALLR     FATLINE             ;draw the pen line
        jruc      LINE_EXIT
;
;    DIRECT-MODE ENTRY POINT: pen_line() function
;
_dm_pen_line:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MOVI      LOOP1,B0            ;address of pen_line inner loop
* Pop the four arguments off the stack (pen_line & patnpen_line dm calls)
DM_LINE:
        move      -*A14,A8,1          ;load address of dm-data area
        move      *A8+,A0,1           ;1st dword is ystart::xstart
        move      *A8,A1,1            ;2nd dword is yend::xend
        move      @(_env+ENVIRONMENT_DSTBM),A8,1    ;destination bit-map global variable
        jrnz      LINE_EXIT           ;if zero, dstbm is set to screen
        CALLR     FATLINE             ;draw the pen line
* Restore registers and return to calling routine (pen_line & patnpen_line)
LINE_EXIT:
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10
        MOVE      *SP(32),A14,1       ;restore program stack pointer
        RETS      2                   ;

;
;    C-PACKET ENTRY POINT: patnpen_polyline() function
;
_patnpen_polyline:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Load subroutine address.
        MOVI      LOOP2,B0            ;address of pen_line inner loop
        move      @_pattern+PATTERN_HSRV,B1,1   ;subroutine for pattern fill
        JRUC      CP_POLYLINE         ;
;
;    DIRECT-MODE ENTRY POINT: patnpen_polyline() function
;
_dm_patnpen_polyline:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Load subroutine address.
        MOVI      LOOP2,B0            ;address of pen_line inner loop
        move      @_pattern+PATTERN_HSRV,B1,1   ;subroutine for pattern fill
        JRUC      DM_POLYLINE         ;
;
;    C-PACKET ENTRY POINT: pen_polyline() function
;
_pen_polyline:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Load subroutine address.
        MOVI      LOOP1,B0            ;address of pen_line inner loop
* Pop three arguments off stack (pen_polyline & patnpen_polyline)
CP_POLYLINE:
        MOVE      *-A14,A11,1         ;get argument npts
        MOVE      *-A14,A13,1         ;get argument ptlist
        move      @(_env+ENVIRONMENT_DSTBM),A8,1    ;destination bit-map global variable
        jrnz      POLY_EXIT           ;if zero, dstbm is set to screen
        jruc      POLYDRAW
;
;    DIRECT-MODE ENTRY POINT: pen_polyline() function
;
_dm_pen_polyline:
        MMTM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A13
        MMTM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
* Load subroutine address.
        MOVI      LOOP1,B0            ;address of pen_line inner loop
* Pop three arguments off the stack (pen_polyline & patnpen_polyline dm calls)
DM_POLYLINE:
        move      -*A14,A13,1         ;will be address of point list
        setf      16,0,0
        move      *A13+,A11,0         ;1st word is #bytes
        srl       2,A11               ;Convert from bytes to # lines
        move      @(_env+ENVIRONMENT_DSTBM),A8,1    ;destination bit-map global variable
        jrnz      POLY_EXIT           ;if zero, dstbm is set to screen
* Draw number of lines specified by argument npts.
POLYDRAW:
        SETF      16,0,0     
        DEC       A11                 ;convert #points to #lines
POLYLOOP:
        MOVE      *A13+,A0,1          ;load (xstart,ystart) into A0
        MOVE      *A13,A1,1           ;load (xend,yend) into A1
        CALLR     FATLINE             ;draw the pen line
        DSJ       A11,POLYLOOP        ;loop while --npts > 0
* Restore registers and return to calling routine (pen_polyline &
* patnpen_polyline)
POLY_EXIT:
        MMFM      SP,B0,B1,B2,B7,B10,B11,B12,B13,B14
        MMFM      SP,A0,A1,A2,A3,A4,A5,A6,A7,A9,A10,A11,A13
        MOVE      *SP(32),A14,1       ;restore program stack pointer
        RETS      2                   ;

*----------------------------------------------------------------------
* The code below is common to pen_line, patnpen_line, pen_polyline and
* patnpen_polyline.  Each call to FATLINE draws one pen line.
*----------------------------------------------------------------------
FATLINE:
        MOVK      1,A10               ;constant 1
* Normalize to screen coordinates.
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),A2,1     ;viewport origin displacement
        ADDXY     A2,A0               ;normalize (xstart,ystart)
        ADDXY     A2,A1               ;normalize (xend,yend)
* If line points in -y direction, swap start and end points.
        MOVE      A1,A2               ;copy (xend,yend)
        SUBXY     A0,A2               ;(a=xend-xstart,b=yend-ystart)
        JRNC      NOTNEGY             ;jump if line points in +y direct'n
        MOVE      A0,A3               ;
        MOVE      A1,A0               ;
        MOVE      A3,A1               ;swap endpoints
        MOVE      A2,A3               ;
        CLR       A2                  ;
        SUBXY     A3,A2               ;a = -a, b = -b
NOTNEGY:
* Check for special case of horizontal line.
        JRNZ      NOTHORIZ            ;jump if line not horizontal
        JRNV      APOS                ;jump if x2 - x1 = a > 0
        NEG       A2                  ;|a|
        MOVX      A1,A0               ;substitute xend for xstart
APOS:
        MOVE      @(_env+ENVIRONMENT_PENSIZE),A6,1  ;get pen width and height
        MOVY      A6,A9               ;copy penhigh
        SRL       16,A9               ;count = penhigh
        ADDXY     A2,A6               ;(a + penwide) in 16 LSBs
        MOVE      A0,A3               ;copy xstart
        ADDXY     A3,A6               ;(xstart + a + penwide)
        SLL       16,A3               ;x1 = fixed point (xstart)
        SLL       16,A6               ;x2=fixed point (xstart+a+penwide)
        SRL       16,A0               ;move starting y to 16 LSBs
        CLR       A5                  ;dx1 = 0 (straight sides)
        CLR       A8                  ;dx2 = 0
        EXGPC     B0                  ;draw horizontal line
        RETS                          ;

* Calculate inverse of slope of line.
NOTHORIZ:
        RL        16,A0               ;swap x and y halves of (xs,ys)
        MOVI      07FFFh,A3           ;
        MOVY      A0,A3               ;form fixed point x1 = round(xs)
        MOVE      A2,A5               ;copy (a,b)
        SRL       16,A2               ;isolate b in 16 LSBs
        SLL       16,A5               ;isolate a in 16 MSBs
        DIVS      A2,A5               ;deltax = (a << 16) / b
        MOVE      A5,A4               ;
        SRA       1,A4                ;dxv2 = deltax / 2
* Get pen width and height.
        MOVE      @(_env+ENVIRONMENT_PENSIZE),A1,1  ;get pen height and width
        MOVE      A1,A6               ;
        SLL       16,A6               ;move pen width to 16 MSBs
        ADD       A3,A6               ;fixed point x2 = round(xs+penwide)
* Classify line as one of four cases.
        SRL       16,A1               ;isolate penhigh in 16 LSBs
        MOVE      A2,A7               ;copy b
        SUB       A1,A7               ;mid = b - penhigh
        JRGT      PL2                 ;jump if mid > 0
        ABS       A7                  ;take absolute value of mid
        MOVE      A2,A9               ;count = b
        MOVE      A2,A1               ;save copy of b
        MOVE      A5,A5               ;test sign of deltax
        JRLE      PL1                 ;jump if deltax <= 0
* Case 1:  Line is shorter than pen, and pen slants in +x direction.
        MOVE      A5,A8               ;dx2 = deltax
        CLR       A5                  ;dx1 = 0
        ADD       A4,A6               ;x2 += dxv2
        EXGPC     B0                  ;draw upper part of line
        SUB       A4,A6               ;x2 -= dxv2
        MOVE      A8,A4               ;save copy of deltax
        CLR       A8                  ;dx2 = 0
        MOVE      A7,A9               ;count = |mid|
        EXGPC     B0                  ;draw middle part of line
        MOVE      A4,A5               ;dx1 = deltax
        SRA       1,A4                ;dxv2 = deltax >> 1
        ADD       A4,A3               ;x1 += dxv2
        MOVE      A1,A9               ;count = b
        EXGPC     B0                  ;draw bottom part of line
        RETS                          ;

* Case 2:  Line is shorter than pen, and pen slants in -x direction.
PL1:
        CLR       A8                  ;dx2 = 0
        ADD       A4,A3               ;x1 += dxv2
        EXGPC     B0                  ;draw upper part of line
        SUB       A4,A3               ;x1 -= dxv2
        MOVE      A5,A4               ;save copy of deltax
        CLR       A5                  ;dx1 = 0
        MOVE      A7,A9               ;count = |mid|
        EXGPC     B0                  ;draw middle part of line
        MOVE      A4,A8               ;dx2 = deltax
        SRA       1,A4                ;dxv2 = deltax >> 1
        ADD       A4,A6               ;x2 += dxv2
        MOVE      A1,A9               ;count = b
        EXGPC     B0                  ;draw bottom part of line
        RETS                          ;

PL2:
        MOVE      A1,A9               ;count = penhigh
        MOVE      A5,A5               ;test sign of deltax
        JRLE      PL3                 ;jump if deltax <= 0
* Case 3:  Line is taller than pen, and pen slants in +x direction.
        MOVE      A5,A8               ;dx2 = deltax
        CLR       A5                  ;dx1 = 0
        ADD       A4,A6               ;x2 += dxv2
        EXGPC     B0                  ;draw upper part of line
        MOVE      A8,A5               ;dx1 = deltax
        ADD       A4,A3               ;x1 += dxv2
        MOVE      A7,A9               ;count = mid
        EXGPC     B0                  ;draw middle part of line
        CLR       A8                  ;dx2 = 0
        SUB       A4,A6               ;x2 -= dxv2
        MOVE      A1,A9               ;count = penhigh
        EXGPC     B0                  ;draw bottom part of line
        RETS                          ;

* Case 4:  Line is taller than pen, and pen slants in -x direction.
PL3:
        CLR       A8                  ;dx2 = 0
        ADD       A4,A3               ;x1 += dxv2
        EXGPC     B0                  ;draw upper part of line
        MOVE      A5,A8               ;dx2 = deltax
        ADD       A4,A6               ;x2 += dxv2
        MOVE      A7,A9               ;count = mid
        EXGPC     B0                  ;draw middle part of line
        CLR       A5                  ;dx1 = 0
        SUB       A4,A3               ;x1 -= dxv2
        MOVE      A1,A9               ;count = penhigh
        EXGPC     B0                  ;draw bottom part of line
        RETS                          ;

*----------------------------------------------------------------------
* Below are the two inner loops that actually draw the line.  LOOP1
* draws solid-filled lines, and LOOP2 draws pattern-filled lines.
* Register usage:  16 LSBs of A0 contain integer y coordinate
*                  A1 is used as a temporary
*                  A3 contains fixed point x1 (left edge of fill)
*                  A6 contains fixed point x2 (right edge of fill)
*                  A5 contains dx1 (increment to x1)
*                  A8 contains dx2 (increment to x2)
*                  A9 contains loop count
*                  B0  contains return address
*----------------------------------------------------------------------
* Draw portion of solid-filled line.

        .if     GSP_34010 ; Code used if the processor is a 34010
LOOP1:
        MOVE      A9,A9               ;
        JRLE      EXIT1               ;if count <= 0, return to caller
LOOP1A:
        MOVY      A3,A0               ;concatenate j with i1 = 16 MSBs x1
        MOVE      A0,B2               ;load DADDR with starting coord's
        RL        16,B2               ;i1 = 16 LSBs, j = 16 MSBs
        INC       A0                  ;++j
        MOVY      A6,A2               ;copy i2 = 16 MSBs of x2
        SUBXY     A3,A2               ;width = i2 - i1 (i1 = 16 MSBs x1)
        MOVX      A10,A2              ;height = 1
        RL        16,A2               ;width = 16 LSBs, height = 16 MSBs
        MOVE      A2,B7               ;DYDX = height::width
        FILL      XY                  ;do horizontal fill (solid)
        ADD       A5,A3               ;increment x1 by dx1
        ADD       A8,A6               ;increment x2 by dx2
        DSJ       A9,LOOP1A           ;loop while --count > 0
EXIT1:
        EXGPC     B0                  ;return to calling routine
        JRUC      LOOP1               ;
        .endif
        .if     GSP_34020 ; Code used if the processor is a 34020
LOOP1:
        MOVE      A9,A9               ;
        JRLE      EXIT1               ;if count <= 0, return to caller
        MOVE      A0,B11              ;load y value for tfill
        SLL       16,B11              ;shift to fixed format
        MOVE      B0,-*SP,1           ;save return address on stack
        MOVE      A3,B0               ;load x1
        MOVE      A5,B1               ;load dx1
        MOVE      A6,B7               ;load x2
        MOVE      A8,B10              ;load dx2
TUF:
        TFILL XY                      ;actual inner loop
        DSJ       A9,TUF

        MOVE      B0,A3               ;restore x1
        MOVE      B7,A6               ;restore x2
        MOVE      B11,A0              ;restore y
        SRL       16,A0               ;convert y from fixed format
        MOVE      *SP+,B0,1           ;restore return address from stack
EXIT1:
        EXGPC     B0                  ;return to calling routine
        JRUC      LOOP1               ;
        .endif

* Draw portion of pattern-filled line.
LOOP2:
        MOVE      A9,A9               ;
        JRLE      EXIT2               ;if count <= 0, return to caller
LOOP2A:
        MOVY      A3,A0               ;concatenate j with i1 = 16 MSBs x1
        MOVE      A0,B2               ;load DADDR with starting coord's
        RL        16,B2               ;i1 = 16 LSBs, j = 16 MSBs
        INC       A0                  ;++j
        MOVY      A6,A2               ;copy i2 = 16 MSBs of x2
        SUBXY     A3,A2               ;width = i2 - i1 (i1 = 16 MSBs x1)
        MOVX      A10,A2              ;height = 1
        RL        16,A2               ;width = 16 LSBs, height = 16 MSBs
        MOVE      A2,B7               ;DYDX = height::width
        CALL      B1                  ;do horizontal fill (pattern)
        ADD       A5,A3               ;increment x1 by dx1
        ADD       A8,A6               ;increment x2 by dx2
        DSJ       A9,LOOP2A           ;loop while --count > 0
EXIT2:
        EXGPC     B0                  ;return to calling routine
        JRUC      LOOP2               ;
        .end
