;-------------------------------------------------------------------------;
;                               TIGA 2.0                                  ;
;        Copyright (c) 1987-1990  Texas Instruments Incorporated.         ;
;			   All Rights Reserved				  ;
;-------------------------------------------------------------------------;
;   TIGA 2-D Graphics Library                                             ;
;-------------------------------------------------------------------------;
; styled_line function                                                    ;
;                                                                         ;
;   Draw a styled line from point (x1,y1) to point (x2,y2).               ;
;   A straight line is drawn using Bresenham's algorithm.                 ;
;   The line is only one pixel in thickness.                              ;
;                                                                         ;
;   The line style is specified in argument style, a long integer         ;
;   containing a 32-bit repeating line-style pattern.  Pattern bits are   ;
;   used in the order 0,1,...,31.  The pattern is repeated modulo 32, as  ;
;   the line is drawn.  A bit value of 1 in the pattern specifies that    ;
;   color1 is to be used to draw the corresponding pixel.  A bit value    ;
;   of 0 means either that the corresponding pixel is to be drawn in      ;
;   color0 (if mode = 1) or not drawn (if mode = 0).                      ;
;                                                                         ;
;   Four drawing modes are supported:                                     ;
;       mode 0 -- Don't draw background pixels (leave gaps), and          ;
;                 load new line-style pattern from style argument.        ;
;       mode 1 -- Draw background pixels in color0, and load new          ;
;                 line-style pattern from style argument.                 ;
;       mode 2 -- Don't draw background pixels (leave gaps), and          ;
;                 re-use old line-style pattern (ignore style arg).       ;
;       mode 3 -- Draw background pixels in color0, and re-use old        ;
;                 line-style pattern (ignore style argument).             ;
;-------------------------------------------------------------------------;
; Usage:  styled_line(x1, y1, x2, y2, style, mode);                       ;
;                                                                         ;
; Description of the arguments:                                           ;
;         long x1, y1;       /* coordinates of line starting point */     ;
;         long x2, y2;       /* coordinates of line ending point */       ;
;         long style;        /* line-style pattern (32-bit mask) */       ;
;         long mode;         /* drawing mode (range 0 to 1) */            ;
;                                                                         ;
; Returned in register A8:  void (undefined).                             ;
;                                                                         ;
; Registers altered:  A8                                                  ;
;-------------------------------------------------------------------------;
; Revision history:                                                       ;
;  09/14/87...Original version written...................Mike Denio       ;
;  07/12/88...Added header for TIGA compatability........W.S.Egr          ;
;  09/09/88...Access globals thru environment struct.....W.S.Egr          ;
;  04/26/89...Sped up inner loops........................J. Van Aken      ;
;  07/20/89...Added 34020 support........................A. Sharp         ;
;  08/09/89...Fix intermittent bug in COUNT calculation..G. Short
;-------------------------------------------------------------------------;
        .title    'styled line'
        .file     'stylline.asm'
;
;   INCLUDE FILES
;
        .include  gsptypes.inc        ;offsets into environment structure
        .include  gspglobs.inc
        .include  gspreg.inc
        .include  oem.inc
;
;     DECLARE GLOBAL FUNCTION NAME
;
        .globl    _styled_line
;
;     DEFINE REGISTER VARIABLE NAMES
;
D       .set      B0                  ;decision variable d
COUNT   .set      B10                 ;loop count
XYINC1  .set      B11                 ;diagonal xy increment
XYINC2  .set      B12                 ;nondiagonal xy increment
PATTRN  .set      B13                 ;32-bit line-style pattern
DINC1   .set      B7                  ;diagonal d increment
DINC2   .set      B14                 ;nondiagonal d increment
MODE    .set      B1                  ;drawing mode (0, 1, 2 or 3)

;
;    C-PACKET ENTRY POINT
;
_styled_line:

; Make sure that dstbm is pointing to the screen.
        MOVE      @(_env+ENVIRONMENT_DSTBM),A8,1 ;destination bit-map global
        JRNZ      DONE                ;if 0, dstbm points to screen

; Save registers; set field 0 size to 16 bits.
        MMTM      SP,B0,B1,B2,B7,B9,B10,B11,B12,B14
        MMTM      SP,A0,A1
        SETF      16,1,0              ;
; Put color0 value in 16 LSBs of B9, and color1 value in 16 MSBs.
        MOVE      COLOR0,A0
        MOVE      COLOR1,A1
; Pop function arguments.
        MOVE      STK,B14             ;copy program stack pointer
        MOVE      *-B14,B2,1          ;get starting coordinate xs
        MOVE      *-B14,B0,1          ;get starting coordinate ys
        SLL       16,B0               ;
        MOVY      B0,B2               ;concatenate xs and ys
        MOVE      *-B14,B0,1          ;get ending coordinate xe
        MOVE      *-B14,B1,1          ;get ending coordinate ye
        SLL       16,B1               ;
        MOVY      B1,B0               ;concatenate xe and ye
        MOVE      *-B14,B12,1         ;get line-style pattern
        MOVE      *-B14,B1,1          ;get draw mode
; Determine whether to load new pattern, or use old (rotated) pattern.
        BTST      1,B1                ;is draw mode < 2 ?
        JRNZ      OLDSTYLE            ;if mode >= 2, use old pattern
        MOVE      B12,B13             ;else load new line-style pattern
        JRUC      GOTSTYLE  
OLDSTYLE:
        MOVE      @_env+ENVIRONMENT_STYLEMASK,B13,1 ;load old line-style pattern

*------------------------------------------------------------------
*   At this point, xs is in 16 LSBs of B2, ys is in 16 MSBs of
*   B2, xe is in 16 LSBs of B0, ye is in 16 MSBs of B0,
*   the line-style pattern is in B13, and drawing mode is in B1.

        .if     GSP_34010 ; Code used if the processor is a 34010
GOTSTYLE:
*------------------------------------------------------------------
*   At this point, xs is in 16 LSBs of B2, ys is in 16 MSBs of
*   B2, xe is in 16 LSBs of B0, ye is in 16 MSBs of B0,
*   the line-style pattern is in B13, and drawing mode is in B1.
        SUBXY     B2,B0               ;calculate a and b
; Now set up B7 = (a,b) and B11 = (xinc1,yinc1) on assumption that
; a < 0 and b < 0.  If a >= 0 or b >= 0, make corrections later on.
        MOVI      -1,B11              ;xinc1 = yinc1 = -1
        MOVK      1,B12               ;constant = 1
        CLR       B7                  ;(clear register)
        SUBXY     B0,B7               ;B7 now contains (-a,-b)
        JRNC      L1                  ;jump if b < 0
; Deal with case b >= 0.
        MOVY      B0,B7               ;make a in B7 positive
        SRL       15,B11              ;change yinc1 to +1
L1:
        JRNV      L2                  ;jump if a < 0
; Deal with case a >= 0.
        MOVX      B0,B7               ;Take absolute value of a
        MOVX      B12,B11             ;change xinc1 to +1
L2:
        MOVX      B11,B12             ;xinc2 = xinc1, yinc2 = 0
; Compare magnitudes of a and b.
        MOVE      B7,B0               ;copy a and b
        SRL       16,B0               ;move b into 16 LSBs
        CMPXY     B0,B7               ;compare a and b
        JRNV      L3                  ;jump if a >= b
; Deal with case a < b.  Need to swap a and b so that a >= b.
        MOVX      B7,B0               ;copy b into B0
        RL        16,B7               ;swap a and b halves of register
        CLR       B12                 ;
        MOVY      B11,B12             ;xinc2 = 0, yinc2 = yinc1
L3:
; Convert starting xy coordinates to screen-relative coordinate system.
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),B14,1 ;get yorg::xorg
        ADDXY     B14,B2              ;convert to screen coordinates
; Calculate initial values of d, dinc1, dinc2 and loop count.
        ADD       B0,B0               ;put 2*b
        MOVE      B0,B14              ;dinc2 = 2*b
        CLRS      B10                 ;clear Y half of COUNT (added by GBS)
        MOVX      B7,B10
        SUB       B10,B0              ;initial d = 2*b-a
        MOVE      B0,B7               ;copy 2*b-a
        SUB       B10,B7              ;dinc1 = 2*b-2*a
        ADDK      1,B10               ;loop count = a+1

; Determine drawing mode, initial pattern bit, and sign of initial d.
; Is LSB of drawing mode 0 or 1?  (Leave gaps or use color0?)
        BTST      0,MODE              ;is LSB of drawing mode 0 or 1 ?
        JRNZ      BMODE               ;jump if LSB of mode is 1
        MOVE      A1,COLOR1

*------------------------------------------------------------------
*
* Drawing Mode 0:  0s in pattern are gaps in line (not drawn).
*
*------------------------------------------------------------------
; Is first pattern bit 0 or 1?
        BTST      0,PATTRN            ;test LSB of pattern
        JRNZ      GM_P1               ;jump if 1st pattern bit is 1
; First pattern bit is 0.  Is initial dec. var. d positive or negative?
        MOVE      D,D                 ;test sign of d
        JRGE      GNXT0B              ;jump if d >= 0
        JR        GNXT0A              ;case d < 0
; First pattern bit is 1.  Is initial dec. var. d positive or negative?
GM_P1:
        MOVE      D,D                 ;test sign of d
        JRGE      GNXT1B              ;jump if d >= 0
        JR        GNXT1A              ;case d < 0

*------------------------------------------------------------------
* CASE 0A:  pattern bit = 0, decision variable d < 0.
*
; Loop here as long as pattern bit = 0 and d < 0.
; Drawing is in a nondiagonal direction (horizontal or vertical).
GNXT0A:
        ADDXY     XYINC2,DADDR        ;draw pixel, x,y += xinc2,yinc2
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRC       GNEW1A              ;jump if new pattern bit = 1
; Jump here if pattern bit has just changed from 1 to 0.
GNEW0A:
        ADD       DINC2,D             ;d += dinc2
        JRGE      GEND0B              ;jump if d >= 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d>=0 to d<0.
GEND0A:
        DSJ       COUNT,GNXT0A        ;more pixels to draw?
        JR        DONE                ;if not, we're done

*------------------------------------------------------------------
* CASE 0B:  pattern bit = 0, decision variable d >= 0.
*
; Loop here as long as pattern bit = 0 and d >= 0.
; Drawing is in a diagonal direction.
GNXT0B:
        ADDXY     XYINC1,DADDR        ;draw pixel, x,y += xinc1,yinc1
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRC       GNEW1B              ;jump if new pattern bit = 1
; Jump here if pattern bit has just changed from 1 to 0.
GNEW0B:
        ADD       DINC1,D             ;d += dinc1
        JRLT      GEND0A              ;jump if d < 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d<0 to d>=0.
GEND0B:
        DSJ       COUNT,GNXT0B        ;more pixels to draw?
        JR        DONE                ;if not, we're done

*------------------------------------------------------------------
* CASE 1A:  pattern bit = 1, decision variable d < 0.
*
; Loop here as long as pattern bit = 1 and d < 0.
; Drawing is in a nondiagonal direction (horizontal or vertical).
GNXT1A:
        DRAV      XYINC2,DADDR        ;draw pixel, x,y += xinc2,yinc2
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRNC      GNEW0A              ;jump if new pattern bit = 0
; Jump here if pattern bit has just changed from 0 to 1.
GNEW1A:
        ADD       DINC2,D             ;d += dinc2
        JRGE      GEND1B              ;jump if d >= 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d>=0 to d<0.
GEND1A:
        DSJ       COUNT,GNXT1A        ;more pixels to draw?
        JR        DONE                ;if not, we're done

*------------------------------------------------------------------
* CASE 1B:  pattern bit = 1, decision variable d >= 0.
*
; Loop here as long as pattern bit = 1 and d >= 0.
; Drawing is in a diagonal direction.
GNXT1B:
        DRAV      XYINC1,DADDR        ;draw pixel, x,y += xinc1,yinc1
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRNC      GNEW0B              ;jump if new pattern bit = 0
; Jump here if pattern bit has just changed from 0 to 1.
GNEW1B:
        ADD       DINC1,D             ;d += dinc1
        JRLT      GEND1A              ;jump if d < 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d<0 to d>=0.
GEND1B:
        DSJ       COUNT,GNXT1B        ;more pixels to draw?
        JR        DONE                ;if not, we're done


*------------------------------------------------------------------
*
* Drawing Mode 1:  0s in pattern are drawn in color0.
*
*------------------------------------------------------------------
; Is first pattern bit 0 or 1?
BMODE:
        BTST      0,PATTRN            ;test LSB of pattern
        JRNZ      BM_P1               ;jump if 1st pattern bit is 1
; First pattern bit is 0.  Is initial dec. var. d positive or negative?
        MOVE      A0,COLOR1
        MOVE      D,D                 ;test sign of d
        JRGE      BNXT0B              ;jump if d >= 0
        JR        BNXT0A              ;case d < 0
; First pattern bit is 1.  Is initial dec. var. d positive or negative?
BM_P1:
        MOVE      A1,COLOR1
        MOVE      D,D                 ;test sign of d
        JRGE      BNXT1B              ;jump if d >= 0
        JR        BNXT1A              ;case d < 0

*------------------------------------------------------------------
* CASE 0A:  pattern bit = 0, decision variable d < 0.
*
; Jump here if pattern bit has just changed from 1 to 0.
BNEW0A:
        MOVE      A0,COLOR1
        ADD       DINC2,D             ;d += dinc2
        JRGE      BEND0B              ;jump if d >= 0
        DSJ       COUNT,BNXT0A        ;more pixels to draw?
        JR        DONE                ;if not, we're finished
; Loop here as long as pattern bit = 0 and d < 0.
; Drawing is in a nondiagonal direction (horizontal or vertical).
BNXT0A:
        DRAV      XYINC2,DADDR        ;draw pixel, x,y += xinc2,yinc2
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRC       BNEW1A              ;jump if new pattern bit = 1
        ADD       DINC2,D             ;d += dinc2
        JRGE      BEND0B              ;jump if d >= 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d>=0 to d<0.
BEND0A:
        DSJ       COUNT,BNXT0A        ;more pixels to draw?
        JR        DONE                ;if not, we're done

*------------------------------------------------------------------
* CASE 0B:  pattern bit = 0, decision variable d >= 0.
*
; Jump here if pattern bit has just changed from 1 to 0.
BNEW0B:
        MOVE      A0,COLOR1
        ADD       DINC1,D             ;d += dinc1
        JRLT      BEND0A              ;jump if d < 0
        DSJ       COUNT,BNXT0B        ;more pixels to draw?
        JR        DONE                ;if not, we're finished
; Loop here as long as pattern bit = 0 and d >= 0.
; Drawing is in a diagonal direction.
BNXT0B:
        DRAV      XYINC1,DADDR        ;draw pixel, x,y += xinc1,yinc1
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRC       BNEW1B              ;jump if new pattern bit = 1
        ADD       DINC1,D             ;d += dinc1
        JRLT      BEND0A              ;jump if d < 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d<0 to d>=0.
BEND0B:
        DSJ       COUNT,BNXT0B        ;more pixels to draw?
        JR        DONE                ;if not, we're done

*------------------------------------------------------------------
* CASE 1A:  pattern bit = 1, decision variable d < 0.
*
; Jump here if pattern bit has just changed from 0 to 1.
BNEW1A:
        MOVE      A1,COLOR1
        ADD       DINC2,D             ;d += dinc2
        JRGE      BEND1B              ;jump if d >= 0
        DSJ       COUNT,BNXT1A        ;more pixels to draw?
        JR        DONE                ;if not, we're finished
; Loop here as long as pattern bit = 1 and d < 0.
; Drawing is in a nondiagonal direction (horizontal or vertical).
BNXT1A:
        DRAV      XYINC2,DADDR        ;draw pixel, x,y += xinc2,yinc2
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRNC      BNEW0A              ;jump if new pattern bit = 0
        ADD       DINC2,D             ;d += dinc2
        JRGE      BEND1B              ;jump if d >= 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d>=0 to d<0.
BEND1A:
        DSJ       COUNT,BNXT1A        ;more pixels to draw?
        JR        DONE                ;if not, we're done

*------------------------------------------------------------------
* CASE 1B:  pattern bit = 1, decision variable d >= 0.
*
; Jump here if pattern bit has just changed from 0 to 1.
BNEW1B:
        MOVE      A1,COLOR1
        ADD       DINC1,D             ;d += dinc1
        JRLT      BEND1A              ;jump if d < 0
        DSJ       COUNT,BNXT1B        ;more pixels to draw?
        JR        DONE                ;if not, we're finished
; Loop here as long as pattern bit = 1 and d >= 0.
; Drawing is in a diagonal direction.
BNXT1B:
        DRAV      XYINC1,DADDR        ;draw pixel, x,y += xinc1,yinc1
        RL        31,PATTRN           ;roll next pattern bit into LSB
        JRNC      BNEW0B              ;jump if new pattern bit = 0
        ADD       DINC1,D             ;d += dinc1
        JRLT      BEND1A              ;jump if d < 0
; Jump here if last pixel drawn was foreground color, but
; decision variable changed from d<0 to d>=0.
BEND1B:
        DSJ       COUNT,BNXT1B        ;more pixels to draw?
        JR        DONE                ;if not, we're done
        .endif
;
        .if     GSP_34020 ; Code used if the processor is a 34020
GOTSTYLE:
* Convert from viewport relative coord's to screen coord's.
        MOVE      @(_env+ENVIRONMENT_XYORIGIN),B7,1     ;read xyorigin into A8
        ADDXY     B7,B0               ;add viewport offset
        ADDXY     B7,B2               ;add viewport offset
; Is LSB of drawing mode 0 or 1?  (Leave gaps or use color0?)
        SETF      6,0,0
        MOVE      @CONTROL,A8,0       ;save copy of last 6 bits of control
        BTST      0,MODE              ;is LSB of drawing mode 0 or 1 ?
        JRNZ      NOTRANP             ;jump if LSB of mode is 1
        MOVE      A8,B7               ;
        ORI       021H,B7             ;enable transparency mode 1
        MOVE      B7,@CONTROL,0
NOTRANP:
        MOVE      B0,B7               ;move end addr to B7 for LINIT
        LINIT
        JRC       OUT_OF_WINDOW       ;line is entirely outside window
CLIPTST:
        JRV       DRAW                ;clipping required, so use LINE
        CVXYL     B2,B2               ;convert to linear address
        MOVE      B11,B11             ;does line point up or down?
        JRLT      FDOWN
        FLINE      0                   ;draw patterned Bresenham line
        JRUC      EXIT                ;
FDOWN:
        FLINE      1                   ;draw patterned Bresenham line
        JRUC      EXIT                ;
DRAW:
        MOVE      B11,B11             ;does line point up or down?
        JRLT      DOWN
        LINE      0                   ;draw patterned Bresenham line
        JRUC      EXIT                ;
DOWN:
        LINE      1                   ;draw patterned Bresenham line
OUT_OF_WINDOW:
        NEG       B10
        RL        B10,B13             ;align the pattern as if the line were drawn
EXIT:
        MOVE      A8,@CONTROL,0       ;restore last 6 bits of control
        .endif
*------------------------------------------------------------------
* All done.  Restore registers and return
*
DONE:
        MOVE      B13,@_env+ENVIRONMENT_STYLEMASK,1  ;Save current line-style pattern
        MMFM      SP,A0,A1
        MMFM      SP,B0,B1,B2,B7,B9,B10,B11,B12,B14
        MOVE      *SP(32),STK,1       ;restore program stack pointer
        RETS      2                   ;return to caller
        .end
